File size: 14.66Kb
<?php
require_once __DIR__ . '/../config/bootstrap.php';
require_once __DIR__ . '/../config/auth.php';
require_once __DIR__ . '/../config/functions.php';
require_login();
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $_SESSION['user_id']]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
include __DIR__ . '/../includes/header.php';
?>
<div class="container py-5">
<h2 class="mb-4 fw-bold text-center animate__animated animate__fadeInDown">
<i class="bi bi-gear-fill"></i> Настройки аккаунта
</h2>
<p class="text-center text-muted mb-5">
<i class="bi bi-info-circle"></i> Управление вашими персональными данными и настройками
</p>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-sm border-0 animate__animated animate__fadeInUp">
<div class="card-header bg-white border-0 pt-4">
<h5 class="card-title mb-0">
<i class="bi bi-person-circle text-primary"></i> Личные данные
</h5>
</div>
<div class="card-body">
<form id="settings-form" class="needs-validation" novalidate>
<?= csrf_input(); ?>
<div class="mb-4">
<label for="name" class="form-label fw-bold">
<i class="bi bi-person"></i> ФИО *
</label>
<input type="text"
class="form-control"
id="name"
name="name"
required
value="<?= e($user['name'] ?? '') ?>"
placeholder="Иванов Иван Иванович">
<div class="invalid-feedback">
Пожалуйста, введите ваше ФИО
</div>
</div>
<div class="mb-4">
<label for="email" class="form-label fw-bold">
<i class="bi bi-envelope"></i> Email *
</label>
<input type="email"
class="form-control"
id="email"
name="email"
required
value="<?= e($user['email']) ?>">
<div class="invalid-feedback">
Пожалуйста, введите корректный email
</div>
</div>
<div class="mb-4">
<label for="phone" class="form-label fw-bold">
<i class="bi bi-telephone"></i> Телефон
</label>
<input type="tel"
class="form-control"
id="phone"
name="phone"
value="<?= e($user['phone'] ?? '') ?>"
placeholder="+7 (999) 123-45-67">
<div class="invalid-feedback">
Пожалуйста, введите корректный номер телефона
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<label for="password" class="form-label fw-bold">
<i class="bi bi-lock"></i> Новый пароль
</label>
<input type="password"
class="form-control"
id="password"
name="password"
minlength="6"
placeholder="Введите новый пароль">
<div class="form-text">
<i class="bi bi-info-circle"></i> Минимум 6 символов
</div>
</div>
<div class="col-md-6">
<label for="password_confirm" class="form-label fw-bold">
<i class="bi bi-lock-fill"></i> Подтверждение пароля
</label>
<input type="password"
class="form-control"
id="password_confirm"
name="password_confirm"
minlength="6"
placeholder="Повторите пароль">
<div class="form-text">
<i class="bi bi-exclamation-circle"></i> Оставьте пустым, если не меняете
</div>
</div>
</div>
<div class="mb-4">
<label for="notifications" class="form-label fw-bold">
<i class="bi bi-bell"></i> Уведомления по email
</label>
<select class="form-select" id="notifications" name="notifications">
<option value="1" <?= ($user['notifications'] ?? 1) ? 'selected' : '' ?>>
<i class="bi bi-toggle-on"></i> Включены
</option>
<option value="0" <?= !($user['notifications'] ?? 1) ? 'selected' : '' ?>>
<i class="bi bi-toggle-off"></i> Выключены
</option>
</select>
<div class="form-text">
<i class="bi bi-info-circle"></i> Получать уведомления о статусе заказов
</div>
</div>
<div class="d-grid gap-3">
<button type="submit" class="btn btn-primary btn-lg">
<i class="bi bi-check-circle"></i> Сохранить изменения
</button>
</div>
<div id="settings-feedback" class="mt-3"></div>
</form>
</div>
<div class="card-footer bg-white border-0 text-center">
<small class="text-muted">
<i class="bi bi-shield-check"></i> Ваши данные защищены и не передаются третьим лицам
</small>
</div>
</div>
<div class="alert alert-info mt-4">
<div class="d-flex align-items-center">
<i class="bi bi-info-circle fs-4 me-3"></i>
<div>
<h6 class="alert-heading mb-1">
<i class="bi bi-question-circle"></i> Справка
</h6>
<p class="mb-0">
• Все поля, отмеченные *, обязательны для заполнения<br>
• Для изменения пароля заполните оба поля "Новый пароль"<br>
• Уведомления приходят на указанный email
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('settings-form');
const feedback = document.getElementById('settings-feedback');
const phoneInput = document.getElementById('phone');
if (phoneInput) {
phoneInput.addEventListener('input', function(e) {
let value = this.value.replace(/\D/g, '');
if (value.length > 0) {
if (value.startsWith('7')) {
value = '+7 ' + value.substring(1);
} else if (value.startsWith('8')) {
value = '+7 ' + value.substring(1);
} else {
value = '+7 ' + value;
}
value = value.substring(0, 15);
let formatted = '';
for (let i = 0; i < value.length; i++) {
if (i === 2 || i === 6 || i === 10 || i === 13) {
formatted += ' ';
}
formatted += value[i];
}
this.value = formatted.trim();
}
});
phoneInput.addEventListener('keydown', function(e) {
if (e.key === 'Backspace' || e.key === 'Delete') {
setTimeout(() => {
let value = this.value.replace(/\D/g, '');
if (value.length === 1 && value === '7') {
this.value = '';
}
}, 0);
}
});
}
form.addEventListener('submit', function(e) {
e.preventDefault();
if (!this.checkValidity()) {
e.stopPropagation();
this.classList.add('was-validated');
showFeedback('Пожалуйста, заполните все обязательные поля', 'warning');
return;
}
const formData = new FormData(form);
const password = formData.get('password');
const passwordConfirm = formData.get('password_confirm');
const phone = formData.get('phone') || '';
if (phone) {
const phoneClean = phone.replace(/\D/g, '');
if (phoneClean.length < 10) {
showFeedback('Номер телефона слишком короткий. Пример: +7 999 123-45-67', 'danger');
return;
}
}
if (password !== '' && password !== passwordConfirm) {
showFeedback('Пароли не совпадают', 'danger');
return;
}
if (password !== '' && password.length < 6) {
showFeedback('Пароль должен быть не менее 6 символов', 'danger');
return;
}
showFeedback(
'<div class="text-center">' +
'<i class="bi bi-hourglass text-info fs-1"></i>' +
'<p class="mt-2">Сохранение...</p>' +
'</div>',
'info'
);
fetch('<?= BASE_URL ?>ajax/settings_update.php', {
method: 'POST',
body: formData
})
.then(res => {
if (!res.ok) {
throw new Error('Network response was not ok');
}
return res.json();
})
.then(data => {
if (data.success) {
showFeedback(
'<div class="text-center">' +
'<i class="bi bi-check-circle-fill text-success fs-1"></i>' +
'<h5 class="mt-2">Успешно!</h5>' +
'<p>Настройки успешно сохранены.</p>' +
'</div>',
'success'
);
if (password !== '') {
form.querySelector('#password').value = '';
form.querySelector('#password_confirm').value = '';
}
const csrfField = form.querySelector('input[name="csrf"]');
if (csrfField && data.csrf_token) {
csrfField.value = data.csrf_token;
}
} else {
let errorMsg = data.error || 'Ошибка сохранения';
if (errorMsg.includes('CSRF')) {
errorMsg += '<br><small>Попробуйте обновить страницу (F5)</small>';
}
showFeedback(
'<div class="text-center">' +
'<i class="bi bi-exclamation-circle-fill text-danger fs-1"></i>' +
'<h5 class="mt-2">Ошибка</h5>' +
'<p>' + errorMsg + '</p>' +
'</div>',
'danger'
);
}
})
.catch(error => {
console.error('Error:', error);
showFeedback(
'<div class="text-center">' +
'<i class="bi bi-exclamation-circle-fill text-danger fs-1"></i>' +
'<h5 class="mt-2">Ошибка сети</h5>' +
'<p>Пожалуйста, проверьте соединение и попробуйте снова</p>' +
'</div>',
'danger'
);
});
});
function showFeedback(message, type = 'info') {
feedback.innerHTML = '<div class="alert alert-' + type + ' animate__animated animate__fadeIn">' +
message +
'</div>';
}
(function() {
'use strict';
const forms = document.querySelectorAll('.needs-validation');
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
})();
});
</script>
<?php
include __DIR__ . '/../includes/footer.php';
?>