<?php
require_once __DIR__ . '/../config/bootstrap.php';
require_once __DIR__ . '/../config/auth.php';
require_once __DIR__ . '/../config/functions.php';
require_login();
if (!isset($_SESSION['cart']) || empty($_SESSION['cart'])) {
redirect(BASE_URL . 'cart.php');
}
$user_info = [];
try {
global $pdo;
$stmt = $pdo->prepare("SELECT name, phone FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user_info = $stmt->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
error_log('Error fetching user info: ' . $e->getMessage());
}
$cart_total = cart_total($_SESSION['cart']);
$discount_amount = 0;
$final_total = $cart_total;
if (!empty($_SESSION['discount'])) {
$discount_amount = $cart_total * ($_SESSION['discount']['percent'] / 100);
$final_total = $cart_total - $discount_amount;
}
include __DIR__ . '/../includes/header.php';
?>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-lg-10">
<div class="text-center mb-5">
<h2 class="fw-bold animate__animated animate__fadeInDown">
<i class="bi bi-bag-check"></i> Оформление заказа
</h2>
<p class="text-muted">Завершите оформление заказа, указав данные для доставки</p>
</div>
<div class="row g-4">
<div class="col-lg-6">
<div class="card shadow-sm border-0 h-100 animate__animated animate__fadeInLeft">
<div class="card-header bg-white border-0">
<h5 class="card-title mb-0">
<i class="bi bi-cart3 text-primary"></i> Ваша корзина
</h5>
</div>
<div class="card-body">
<?php if (empty($_SESSION['cart'])): ?>
<div class="alert alert-warning">
<i class="bi bi-exclamation-circle"></i> Ваша корзина пуста
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="table-light">
<tr>
<th style="width: 80px;">Фото</th>
<th>Формат</th>
<th class="text-center">Кол-во</th>
<th class="text-end">Цена</th>
<th class="text-end">Итого</th>
</tr>
</thead>
<tbody>
<?php
$subtotal = 0;
foreach ($_SESSION['cart'] as $id => $item):
$item_total = ($item['price'] ?? 0) * ($item['quantity'] ?? 1);
$subtotal += $item_total;
$photo_url = '';
$photo_path = '';
if (!empty($item['filename'])) {
$photo_path = UPLOAD_DIR . 'photos/' . $item['filename'];
$photo_url = BASE_URL . 'uploads/photos/' . $item['filename'];
}
?>
<tr data-id="<?= e($id) ?>">
<td>
<?php if (!empty($photo_url) && file_exists($photo_path)): ?>
<img src="<?= e($photo_url) ?>"
alt="Фото"
class="rounded"
style="width: 60px; height: 60px; object-fit: cover;">
<?php else: ?>
<div class="bg-light rounded d-flex align-items-center justify-content-center"
style="width: 60px; height: 60px;">
<i class="bi bi-image text-muted"></i>
</div>
<?php endif; ?>
</td>
<td>
<div class="fw-bold"><?= e($item['format_name'] ?? 'Не указан') ?></div>
<?php if (!empty($item['photo_id'])): ?>
<small class="text-muted">ID фото: <?= e($item['photo_id']) ?></small>
<?php endif; ?>
</td>
<td class="text-center">
<span class="badge bg-primary rounded-pill">
<?= e($item['quantity'] ?? 1) ?> шт.
</span>
</td>
<td class="text-end">
<?= number_format($item['price'] ?? 0, 2) ?> ₽
</td>
<td class="text-end fw-bold">
<?= number_format($item_total, 2) ?> ₽
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="border-top pt-3">
<div class="d-flex justify-content-between mb-2">
<span>Сумма заказа:</span>
<span id="cart-subtotal"><?= number_format($subtotal, 2) ?> ₽</span>
</div>
<?php if (!empty($_SESSION['discount'])): ?>
<div class="d-flex justify-content-between mb-2 text-success">
<span>
Скидка (<?= e($_SESSION['discount']['code']) ?>):
<span class="badge bg-success ms-1">
<?= e($_SESSION['discount']['percent']) ?>%
</span>
</span>
<span id="discount-amount">-<?= number_format($discount_amount, 2) ?> ₽</span>
</div>
<?php endif; ?>
<div class="d-flex justify-content-between mt-3 pt-2 border-top fs-5 fw-bold text-primary">
<span>Итого к оплате:</span>
<span id="final-total"><?= number_format($final_total, 2) ?> ₽</span>
</div>
</div>
<?php endif; ?>
<div class="mt-4">
<label for="discount_code" class="form-label fw-bold">
<i class="bi bi-percent"></i> Промокод
</label>
<div class="input-group">
<input type="text"
class="form-control"
id="discount_code"
placeholder="Введите код скидки"
value="<?= e($_SESSION['discount']['code'] ?? '') ?>">
<button class="btn btn-outline-primary" type="button" id="apply-discount">
<i class="bi bi-check-lg"></i> Применить
</button>
<?php if (!empty($_SESSION['discount'])): ?>
<button class="btn btn-outline-danger" type="button" id="remove-discount">
<i class="bi bi-x-lg"></i> Удалить
</button>
<?php endif; ?>
</div>
<div id="discount-feedback" class="mt-2"></div>
<small class="text-muted">
<i class="bi bi-info-circle"></i> Введите промокод для получения скидки
</small>
</div>
</div>
<div class="card-footer bg-white border-0">
<a href="<?= BASE_URL ?>cart.php" class="btn btn-outline-secondary w-100">
<i class="bi bi-arrow-left"></i> Вернуться в корзину
</a>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card shadow-sm border-0 h-100 animate__animated animate__fadeInRight">
<div class="card-header bg-white border-0">
<h5 class="card-title mb-0">
<i class="bi bi-truck text-success"></i> Данные для доставки
</h5>
</div>
<div class="card-body">
<form id="checkout-form" class="needs-validation" novalidate>
<?= csrf_input(); ?>
<div class="mb-3">
<label for="fullname" class="form-label fw-bold">
<i class="bi bi-person"></i> ФИО *
</label>
<input type="text"
class="form-control"
id="fullname"
name="fullname"
required
value="<?= e($user_info['name'] ?? $_SESSION['user_name'] ?? '') ?>"
placeholder="Иванов Иван Иванович">
<div class="invalid-feedback">
Пожалуйста, введите ваше ФИО
</div>
</div>
<div class="mb-3">
<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"
required
value="<?= e($user_info['phone'] ?? '') ?>"
placeholder="+7 (999) 123-45-67">
<div class="invalid-feedback">
Пожалуйста, введите корректный номер телефона
</div>
</div>
<div class="mb-4">
<label for="address" class="form-label fw-bold">
<i class="bi bi-geo-alt"></i> Адрес доставки *
</label>
<textarea class="form-control"
id="address"
name="address"
rows="3"
required
placeholder="Город, улица, дом, квартира"></textarea>
<div class="invalid-feedback">
Пожалуйста, введите адрес доставки
</div>
<small class="text-muted">
<i class="bi bi-info-circle"></i> Укажите полный адрес для доставки
</small>
</div>
<div class="mb-4">
<label for="comment" class="form-label fw-bold">
<i class="bi bi-chat-text"></i> Комментарий к заказу (необязательно)
</label>
<textarea class="form-control"
id="comment"
name="comment"
rows="2"
placeholder="Дополнительные пожелания или комментарии"></textarea>
</div>
<div class="form-check mb-4">
<input class="form-check-input" type="checkbox" id="agree_terms" required>
<label class="form-check-label" for="agree_terms">
Я соглашаюсь с
<a href="<?= BASE_URL ?>terms.php" target="_blank">условиями обработки персональных данных</a>
и
<a href="<?= BASE_URL ?>delivery.php" target="_blank">правилами доставки</a> *
</label>
<div class="invalid-feedback">
Необходимо согласиться с условиями
</div>
</div>
<button type="submit" class="btn btn-success btn-lg w-100" id="submit-order">
<i class="bi bi-bag-check"></i> Подтвердить и оплатить заказ
</button>
<div id="checkout-feedback" class="mt-3"></div>
<div class="text-center mt-3">
<small class="text-muted">
<i class="bi bi-shield-check"></i> Ваши данные защищены
</small>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<div class="alert alert-info">
<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">Информация о доставке</h6>
<p class="mb-0">
• Срок доставки: 1-3 рабочих дня<br>
• Бесплатная доставка при заказе от 1000 ₽<br>
• Оплата при получении или онлайн<br>
• Для вопросов: support@photoprint.ru
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const checkoutForm = document.getElementById('checkout-form');
const feedback = document.getElementById('checkout-feedback');
const applyDiscountBtn = document.getElementById('apply-discount');
const removeDiscountBtn = document.getElementById('remove-discount');
const discountInput = document.getElementById('discount_code');
const discountFeedback = document.getElementById('discount-feedback');
const submitOrderBtn = document.getElementById('submit-order');
const csrfField = document.querySelector('input[name="csrf"]');
window.CSRF_TOKEN = csrfField ? csrfField.value : '<?= $_SESSION['csrf_token'] ?? '' ?>';
if (applyDiscountBtn) {
applyDiscountBtn.addEventListener('click', function(e) {
e.preventDefault();
const code = discountInput.value.trim();
if (!code) {
showDiscountFeedback('Введите промокод', 'warning');
return;
}
const originalText = applyDiscountBtn.innerHTML;
applyDiscountBtn.innerHTML = '<i class="bi bi-hourglass"></i>';
applyDiscountBtn.disabled = true;
fetch('<?= BASE_URL ?>ajax/apply_discount.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
csrf: window.CSRF_TOKEN,
discount: code
})
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
applyDiscountBtn.innerHTML = originalText;
applyDiscountBtn.disabled = false;
if (data.success) {
showDiscountFeedback('Скидка применена!', 'success');
discountInput.value = data.discount_code || code;
const discountAmount = (data.original_total - data.discounted_total).toFixed(2);
const subtotal = parseFloat(document.getElementById('cart-subtotal').textContent.replace(/[^\d.]/g, ''));
updateOrderTotals({
subtotal: data.original_total.toFixed(2),
discount_amount: discountAmount,
final_total: data.discounted_total.toFixed(2),
discount_percent: data.discount_percent
});
if (removeDiscountBtn) {
removeDiscountBtn.style.display = 'inline-block';
}
} else {
showDiscountFeedback(data.error || 'Неверный промокод', 'danger');
}
})
.catch(error => {
console.error('Error:', error);
applyDiscountBtn.innerHTML = originalText;
applyDiscountBtn.disabled = false;
showDiscountFeedback('Ошибка сети', 'danger');
});
});
}
if (removeDiscountBtn) {
removeDiscountBtn.addEventListener('click', function(e) {
e.preventDefault();
showDiscountFeedback('Скидка удалена', 'success');
discountInput.value = '';
const subtotal = parseFloat(document.getElementById('cart-subtotal').textContent.replace(/[^\d.]/g, ''));
updateOrderTotals({
subtotal: subtotal.toFixed(2),
discount_amount: '0.00',
final_total: subtotal.toFixed(2),
discount_percent: 0
});
removeDiscountBtn.style.display = 'none';
fetch('<?= BASE_URL ?>ajax/remove_discount.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
csrf: window.CSRF_TOKEN
})
});
});
}
checkoutForm.addEventListener('submit', function(e) {
e.preventDefault();
if (!document.getElementById('agree_terms').checked) {
showCheckoutFeedback('Необходимо согласиться с условиями', 'warning');
return;
}
if (!this.checkValidity()) {
e.stopPropagation();
this.classList.add('was-validated');
showCheckoutFeedback('Пожалуйста, заполните все обязательные поля', 'warning');
return;
}
const originalText = submitOrderBtn.innerHTML;
submitOrderBtn.innerHTML = '<i class="bi bi-hourglass"></i> Обработка...';
submitOrderBtn.disabled = true;
const formData = new FormData(this);
const discountCode = discountInput.value.trim();
if (discountCode) {
formData.append('discount_code', discountCode);
}
fetch('<?= BASE_URL ?>ajax/checkout.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
console.log('Checkout response:', data);
if (data.success) {
showCheckoutFeedback(
'<div class="text-center">' +
'<i class="bi bi-check-circle-fill text-success fs-1"></i>' +
'<h5 class="mt-2">Заказ успешно оформлен!</h5>' +
'<p>Номер вашего заказа: <strong>#' + data.order_id + '</strong></p>' +
'<p>Сумма заказа: <strong>' + (data.total || '0.00 ₽') + '</strong></p>' +
'<p>Мы свяжемся с вами для подтверждения заказа.</p>' +
'</div>',
'success'
);
checkoutForm.querySelectorAll('input, textarea, button').forEach(el => {
el.disabled = true;
});
setTimeout(() => {
window.location.href = '<?= BASE_URL ?>orders.php?order_id=' + data.order_id;
}, 3000);
} else {
let errorMsg = data.error || 'Неизвестная ошибка';
if (errorMsg.includes('CSRF')) {
errorMsg += '<br><small>Попробуйте обновить страницу (F5)</small>';
}
showCheckoutFeedback(
'<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'
);
submitOrderBtn.innerHTML = originalText;
submitOrderBtn.disabled = false;
}
})
.catch(error => {
console.error('Error:', error);
showCheckoutFeedback(
'<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'
);
submitOrderBtn.innerHTML = originalText;
submitOrderBtn.disabled = false;
});
});
function showDiscountFeedback(message, type = 'info') {
discountFeedback.innerHTML = '<div class="alert alert-' + type + ' alert-dismissible fade show">' +
message +
'<button type="button" class="btn-close" data-bs-dismiss="alert"></button>' +
'</div>';
setTimeout(() => {
const alert = discountFeedback.querySelector('.alert');
if (alert && alert.classList.contains('show')) {
alert.classList.remove('show');
setTimeout(() => alert.remove(), 300);
}
}, 5000);
}
function showCheckoutFeedback(message, type = 'info') {
feedback.innerHTML = '<div class="alert alert-' + type + ' animate__animated animate__fadeIn">' +
message +
'</div>';
}
function updateOrderTotals(data) {
const subtotalEl = document.getElementById('cart-subtotal');
const finalTotalEl = document.getElementById('final-total');
if (subtotalEl) subtotalEl.textContent = data.subtotal + ' ₽';
if (finalTotalEl) finalTotalEl.textContent = data.final_total + ' ₽';
if (data.discount_percent > 0 && data.discount_amount !== '0.00') {
let discountRow = document.querySelector('.discount-row');
if (!discountRow) {
const totalSection = document.querySelector('.border-top.pt-3');
const totalDiv = totalSection.querySelector('.d-flex.justify-content-between.fs-5');
totalDiv.insertAdjacentHTML('beforebegin',
'<div class="d-flex justify-content-between mb-2 text-success discount-row">' +
'<span>Скидка (' + data.discount_percent + '%):</span>' +
'<span id="discount-amount">-' + data.discount_amount + ' ₽</span>' +
'</div>'
);
} else {
document.getElementById('discount-amount').textContent = '-' + data.discount_amount + ' ₽';
}
} else {
const discountRow = document.querySelector('.discount-row');
if (discountRow) {
discountRow.remove();
}
}
}
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);
}
});
}
(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';
?>