Initial dev export (exclude uploads/runtime)

This commit is contained in:
AudioCore Bot
2026-03-04 20:46:11 +00:00
commit b2afadd539
120 changed files with 20410 additions and 0 deletions

View File

@@ -0,0 +1,325 @@
<?php
declare(strict_types=1);
$pageTitle = $title ?? 'Account';
$isLoggedIn = (bool)($is_logged_in ?? false);
$email = (string)($email ?? '');
$orders = is_array($orders ?? null) ? $orders : [];
$downloads = is_array($downloads ?? null) ? $downloads : [];
$message = (string)($message ?? '');
$error = (string)($error ?? '');
$downloadLimit = (int)($download_limit ?? 5);
$downloadExpiryDays = (int)($download_expiry_days ?? 30);
$orderCount = count($orders);
$downloadCount = count($downloads);
$downloadsByOrder = [];
$nowTs = time();
foreach ($downloads as $d) {
if (!is_array($d)) {
continue;
}
$orderNo = (string)($d['order_no'] ?? '');
if ($orderNo === '') {
$orderNo = '__unknown__';
}
if (!isset($downloadsByOrder[$orderNo])) {
$downloadsByOrder[$orderNo] = [];
}
$downloadsByOrder[$orderNo][] = $d;
}
ob_start();
?>
<section class="card account-wrap">
<div class="badge">Store</div>
<div class="account-title-row">
<h1 style="margin:0; font-size:32px;">Account</h1>
<span class="account-subtle">Download hub</span>
</div>
<?php if ($message !== ''): ?>
<div class="account-alert success"><?= htmlspecialchars($message, ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
<?php if ($error !== ''): ?>
<div class="account-alert error"><?= htmlspecialchars($error, ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
<?php if (!$isLoggedIn): ?>
<div class="account-grid">
<div class="account-panel">
<div class="badge" style="font-size:9px;">Login</div>
<p class="account-copy">Enter your order email and we will send a secure one-time access link.</p>
<form method="post" action="/account/request-login" class="account-form">
<label class="account-label">Email</label>
<input name="email" type="email" class="account-input" placeholder="you@example.com" required>
<button type="submit" class="account-btn">Send Login Link</button>
</form>
</div>
<div class="account-panel">
<div class="badge" style="font-size:9px;">Download Policy</div>
<ul class="account-policy-list">
<li>Each file can be downloaded up to <?= $downloadLimit ?> times.</li>
<li>Download links expire after <?= $downloadExpiryDays ?> days.</li>
<li>After expiry or limit, a new order is required.</li>
</ul>
</div>
</div>
<?php else: ?>
<div class="account-panel account-panel-head">
<div>
<div class="badge" style="font-size:9px;">Signed In</div>
<div class="account-email" title="<?= htmlspecialchars($email, ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($email, ENT_QUOTES, 'UTF-8') ?></div>
</div>
<div class="account-actions">
<div class="account-stat">
<span class="account-stat-label">Orders</span>
<strong><?= $orderCount ?></strong>
</div>
<div class="account-stat">
<span class="account-stat-label">Files</span>
<strong><?= $downloadCount ?></strong>
</div>
<a class="account-logout" href="/account/logout">Logout</a>
</div>
</div>
<div class="account-panel">
<div class="badge" style="font-size:9px;">Orders</div>
<?php if (!$orders): ?>
<p class="account-copy">No orders found for this account.</p>
<?php else: ?>
<div class="account-list">
<?php foreach ($orders as $idx => $order): ?>
<?php
$orderNo = (string)($order['order_no'] ?? '');
$orderDownloads = $downloadsByOrder[$orderNo] ?? [];
$activeCount = 0;
foreach ($orderDownloads as $dl) {
$limit = max(0, (int)($dl['download_limit'] ?? 0));
$used = max(0, (int)($dl['downloads_used'] ?? 0));
$remaining = $limit > 0 ? max(0, $limit - $used) : 0;
$expires = trim((string)($dl['expires_at'] ?? ''));
$expired = false;
if ($expires !== '') {
$expTs = strtotime($expires);
if ($expTs !== false && $expTs < $nowTs) {
$expired = true;
}
}
if ($remaining > 0 && !$expired) {
$activeCount++;
}
}
$hasDownloads = !empty($orderDownloads);
$isExpired = $hasDownloads && $activeCount === 0;
$modalId = 'orderDlModal' . $idx;
?>
<div class="account-order-row">
<div>
<div class="account-line-title"><?= htmlspecialchars($orderNo, ENT_QUOTES, 'UTF-8') ?></div>
<div class="account-line-meta">
<span class="account-status-pill"><?= htmlspecialchars((string)($order['status'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
<span><?= htmlspecialchars((string)($order['currency'] ?? 'GBP'), ENT_QUOTES, 'UTF-8') ?> <?= number_format((float)($order['total'] ?? 0), 2) ?></span>
<span><?= htmlspecialchars((string)($order['created_at'] ?? ''), ENT_QUOTES, 'UTF-8') ?></span>
<?php if ($hasDownloads): ?>
<span><?= $activeCount ?> active download<?= $activeCount === 1 ? '' : 's' ?></span>
<?php endif; ?>
</div>
</div>
<div class="account-order-right">
<?php if (!$hasDownloads): ?>
<button type="button" class="account-download-btn is-disabled" disabled>No Downloads</button>
<?php elseif ($isExpired): ?>
<button type="button" class="account-download-btn is-expired" disabled>Expired</button>
<?php else: ?>
<button type="button" class="account-download-btn" data-open-modal="<?= htmlspecialchars($modalId, ENT_QUOTES, 'UTF-8') ?>">Downloads</button>
<?php endif; ?>
</div>
</div>
<?php if ($hasDownloads): ?>
<div id="<?= htmlspecialchars($modalId, ENT_QUOTES, 'UTF-8') ?>" class="account-modal" aria-hidden="true">
<div class="account-modal-backdrop" data-close-modal="<?= htmlspecialchars($modalId, ENT_QUOTES, 'UTF-8') ?>"></div>
<div class="account-modal-card" role="dialog" aria-modal="true" aria-label="Order downloads">
<div class="account-modal-head">
<div>
<div class="badge" style="font-size:9px;">Order Downloads</div>
<div class="account-modal-title"><?= htmlspecialchars($orderNo, ENT_QUOTES, 'UTF-8') ?></div>
</div>
<button type="button" class="account-modal-close" data-close-modal="<?= htmlspecialchars($modalId, ENT_QUOTES, 'UTF-8') ?>">&times;</button>
</div>
<div class="account-modal-list">
<?php foreach ($orderDownloads as $dl): ?>
<?php
$limit = max(0, (int)($dl['download_limit'] ?? 0));
$used = max(0, (int)($dl['downloads_used'] ?? 0));
$remaining = $limit > 0 ? max(0, $limit - $used) : 0;
$expires = trim((string)($dl['expires_at'] ?? ''));
$expired = false;
if ($expires !== '') {
$expTs = strtotime($expires);
if ($expTs !== false && $expTs < $nowTs) {
$expired = true;
}
}
$canDownload = ($remaining > 0 && !$expired);
$dlUrl = (string)($dl['url'] ?? '#');
?>
<div class="account-modal-item">
<div>
<div class="account-line-title"><?= htmlspecialchars((string)($dl['file_name'] ?? 'Download'), ENT_QUOTES, 'UTF-8') ?></div>
<div class="account-line-meta">
Remaining: <?= $remaining ?>
<?php if ($expires !== ''): ?>
&middot; Expires: <?= htmlspecialchars($expires, ENT_QUOTES, 'UTF-8') ?>
<?php endif; ?>
</div>
</div>
<?php if ($canDownload): ?>
<a href="<?= htmlspecialchars($dlUrl, ENT_QUOTES, 'UTF-8') ?>" class="account-download-btn">Download</a>
<?php else: ?>
<button type="button" class="account-download-btn is-expired" disabled>Expired</button>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php endif; ?>
</section>
<style>
.account-wrap { display:grid; gap:14px; }
.account-title-row {
display:flex;
align-items:flex-end;
justify-content:space-between;
gap:12px;
flex-wrap:wrap;
}
.account-subtle {
color:var(--muted);
font-size:12px;
letter-spacing:.14em;
text-transform:uppercase;
}
.account-grid { display:grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap:14px; }
.account-panel { padding:18px; border-radius:14px; border:1px solid rgba(255,255,255,.1); background:rgba(0,0,0,.2); }
.account-panel-head { display:flex; align-items:flex-end; justify-content:space-between; gap:18px; flex-wrap:wrap; }
.account-alert { padding:14px; border-radius:12px; font-weight:600; }
.account-alert.success { border:1px solid rgba(34,242,165,.4); background:rgba(34,242,165,.12); color:#d3ffef; }
.account-alert.error { border:1px solid rgba(243,176,176,.45); background:rgba(243,176,176,.12); color:#ffd6d6; }
.account-email {
margin-top:8px;
font-weight:700;
font-size:36px;
line-height:1.05;
max-width:100%;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
.account-actions { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.account-stat { min-width:96px; padding:10px 12px; border-radius:10px; border:1px solid rgba(255,255,255,.1); background:rgba(255,255,255,.03); text-align:center; }
.account-stat-label { display:block; font-size:10px; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
.account-logout { display:inline-flex; align-items:center; justify-content:center; height:42px; padding:0 20px; border-radius:999px; border:1px solid rgba(255,255,255,.2); background:rgba(255,255,255,.06); color:#fff; text-decoration:none; font-size:12px; text-transform:uppercase; letter-spacing:.14em; font-weight:700; }
.account-logout:hover { background:rgba(255,255,255,.14); }
.account-list { display:grid; gap:10px; margin-top:10px; }
.account-order-row { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:14px; align-items:center; padding:14px; border-radius:12px; border:1px solid rgba(255,255,255,.1); background:rgba(255,255,255,.03); }
.account-order-right { display:grid; gap:8px; justify-items:end; }
.account-line-title { font-weight:600; font-size:22px; line-height:1.2; }
.account-line-meta { color:var(--muted); font-size:13px; margin-top:6px; display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
.account-status-pill {
display:inline-flex;
align-items:center;
padding:3px 8px;
border-radius:999px;
border:1px solid rgba(255,255,255,.18);
background:rgba(255,255,255,.05);
text-transform:uppercase;
letter-spacing:.08em;
font-size:10px;
color:#cfd5e7;
}
.account-download-btn { display:inline-flex; align-items:center; justify-content:center; height:40px; padding:0 20px; border-radius:999px; border:1px solid rgba(34,242,165,.5); background:rgba(34,242,165,.22); color:#d7ffef; text-decoration:none; text-transform:uppercase; letter-spacing:.14em; font-size:11px; font-weight:700; white-space:nowrap; }
.account-download-btn:hover { background:rgba(34,242,165,.32); }
.account-download-btn.is-expired,
.account-download-btn.is-disabled { border-color:rgba(255,255,255,.18); background:rgba(255,255,255,.08); color:rgba(255,255,255,.55); cursor:not-allowed; }
.account-copy { margin:10px 0 0; color:var(--muted); }
.account-form { display:grid; gap:10px; max-width:460px; }
.account-label { font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:.18em; }
.account-input { height:44px; border-radius:10px; border:1px solid rgba(255,255,255,.2); background:rgba(255,255,255,.05); color:#fff; padding:0 12px; }
.account-btn{ height:42px; border-radius:999px; border:1px solid rgba(34,242,165,.45); background:rgba(34,242,165,.18); color:#cbfff1; font-weight:700; letter-spacing:.12em; text-transform:uppercase; cursor:pointer; max-width:260px; }
.account-btn:hover { background:rgba(34,242,165,.28); }
.account-policy-list { margin:10px 0 0; padding-left:18px; color:var(--muted); line-height:1.7; max-width:560px; }
.account-modal { position:fixed; inset:0; display:none; z-index:2000; }
.account-modal.is-open { display:block; }
.account-modal-backdrop { position:absolute; inset:0; background:rgba(0,0,0,.7); }
.account-modal-card { position:relative; max-width:760px; margin:6vh auto; width:calc(100% - 24px); max-height:88vh; overflow:auto; background:#12141b; border:1px solid rgba(255,255,255,.12); border-radius:14px; padding:16px; box-shadow:0 24px 64px rgba(0,0,0,.55); }
.account-modal-head { display:flex; justify-content:space-between; align-items:flex-start; gap:10px; margin-bottom:12px; }
.account-modal-title { margin-top:8px; font-weight:700; font-size:20px; }
.account-modal-close { width:38px; height:38px; border-radius:10px; border:1px solid rgba(255,255,255,.2); background:rgba(255,255,255,.08); color:#fff; font-size:20px; line-height:1; cursor:pointer; }
.account-modal-list { display:grid; gap:10px; }
.account-modal-item { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:10px; align-items:center; padding:12px; border-radius:10px; border:1px solid rgba(255,255,255,.1); background:rgba(255,255,255,.03); }
@media (max-width: 980px) {
.account-grid { grid-template-columns: 1fr; }
.account-email { font-size:30px; }
}
@media (max-width: 640px) {
.account-email { font-size:24px; }
.account-actions { width:100%; }
.account-logout { width:100%; }
.account-order-row,
.account-modal-item { grid-template-columns: 1fr; }
.account-line-total { justify-self:start; }
.account-download-btn { width:100%; }
.account-order-right { justify-items:stretch; width:100%; }
.account-modal-card { margin:2vh auto; max-height:94vh; }
}
</style>
<script>
(function () {
const openBtns = document.querySelectorAll('[data-open-modal]');
const closeBtns = document.querySelectorAll('[data-close-modal]');
openBtns.forEach((btn) => {
btn.addEventListener('click', () => {
const id = btn.getAttribute('data-open-modal');
const modal = document.getElementById(id);
if (!modal) return;
modal.classList.add('is-open');
modal.setAttribute('aria-hidden', 'false');
});
});
closeBtns.forEach((btn) => {
btn.addEventListener('click', () => {
const id = btn.getAttribute('data-close-modal');
const modal = document.getElementById(id);
if (!modal) return;
modal.classList.remove('is-open');
modal.setAttribute('aria-hidden', 'true');
});
});
document.addEventListener('keydown', (e) => {
if (e.key !== 'Escape') return;
document.querySelectorAll('.account-modal.is-open').forEach((modal) => {
modal.classList.remove('is-open');
modal.setAttribute('aria-hidden', 'true');
});
});
})();
</script>
<?php
$content = ob_get_clean();
require __DIR__ . '/../../../../views/site/layout.php';

View File

@@ -0,0 +1,201 @@
<?php
declare(strict_types=1);
$pageTitle = $title ?? 'Cart';
$items = is_array($items ?? null) ? $items : [];
$totals = is_array($totals ?? null) ? $totals : ['count' => 0, 'subtotal' => 0.0, 'discount_amount' => 0.0, 'amount' => 0.0, 'currency' => 'GBP', 'discount_code' => ''];
$discountCode = (string)($totals['discount_code'] ?? '');
ob_start();
?>
<section class="card" style="display:grid; gap:16px;">
<a href="/releases" class="badge" style="text-decoration:none; display:inline-block;">Continue shopping</a>
<h1 style="margin:0; font-size:32px;">Your Cart</h1>
<?php if (!$items): ?>
<div style="padding:14px; border-radius:12px; border:1px solid rgba(255,255,255,.1); background:rgba(0,0,0,.2); color:var(--muted);">
Your basket is empty.
</div>
<?php else: ?>
<div style="display:grid; gap:10px;">
<?php foreach ($items as $item): ?>
<?php
$key = (string)($item['key'] ?? '');
$title = (string)($item['title'] ?? 'Item');
$coverUrl = (string)($item['cover_url'] ?? '');
$qty = max(1, (int)($item['qty'] ?? 1));
$price = (float)($item['price'] ?? 0);
$currency = (string)($item['currency'] ?? ($totals['currency'] ?? 'GBP'));
?>
<div style="display:grid; grid-template-columns:58px minmax(0,1fr) auto auto; align-items:center; gap:12px; padding:12px; border-radius:12px; border:1px solid rgba(255,255,255,.08); background:rgba(0,0,0,.2);">
<div style="width:58px; height:58px; border-radius:10px; overflow:hidden; border:1px solid rgba(255,255,255,.1); background:rgba(255,255,255,.06);">
<?php if ($coverUrl !== ''): ?>
<img src="<?= htmlspecialchars($coverUrl, ENT_QUOTES, 'UTF-8') ?>" alt="" style="width:100%; height:100%; object-fit:cover; display:block;">
<?php else: ?>
<div style="width:100%; height:100%; display:grid; place-items:center; font-size:10px; color:var(--muted);">AC</div>
<?php endif; ?>
</div>
<div style="min-width:0;">
<div style="font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;"><?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8') ?></div>
<div style="font-size:12px; color:var(--muted); margin-top:4px;"><?= htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') ?> <?= number_format($price, 2) ?> x <?= $qty ?></div>
</div>
<div style="font-weight:700;"><?= htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') ?> <?= number_format($price * $qty, 2) ?></div>
<form method="post" action="/cart/remove" style="margin:0;">
<input type="hidden" name="key" value="<?= htmlspecialchars($key, ENT_QUOTES, 'UTF-8') ?>">
<input type="hidden" name="return_url" value="/cart">
<button type="submit" class="cart-btn cart-btn-ghost">Remove</button>
</form>
</div>
<?php endforeach; ?>
</div>
<div style="display:grid; gap:12px; padding:14px; border-radius:12px; border:1px solid rgba(255,255,255,.1); background:rgba(0,0,0,.25);">
<div style="display:flex; justify-content:space-between; align-items:center; gap:12px;">
<div style="color:var(--muted);"><?= (int)($totals['count'] ?? 0) ?> item(s)</div>
<div style="display:grid; justify-items:end; gap:4px;">
<div style="font-size:12px; color:var(--muted);">Subtotal: <?= htmlspecialchars((string)($totals['currency'] ?? 'GBP'), ENT_QUOTES, 'UTF-8') ?> <?= number_format((float)($totals['subtotal'] ?? 0), 2) ?></div>
<?php if ((float)($totals['discount_amount'] ?? 0) > 0): ?>
<div style="font-size:12px; color:#9be7c6;">Discount (<?= htmlspecialchars($discountCode, ENT_QUOTES, 'UTF-8') ?>): -<?= htmlspecialchars((string)($totals['currency'] ?? 'GBP'), ENT_QUOTES, 'UTF-8') ?> <?= number_format((float)($totals['discount_amount'] ?? 0), 2) ?></div>
<?php endif; ?>
<div style="font-size:20px; font-weight:700;"><?= htmlspecialchars((string)($totals['currency'] ?? 'GBP'), ENT_QUOTES, 'UTF-8') ?> <?= number_format((float)($totals['amount'] ?? 0), 2) ?></div>
</div>
</div>
<div id="discountWrap" class="cart-discount-wrap<?= $discountCode !== '' ? ' is-open' : '' ?>">
<div style="display:flex; flex-wrap:wrap; align-items:center; gap:8px;">
<?php if ($discountCode !== ''): ?>
<span style="font-size:12px; color:var(--muted);">Applied discount</span>
<span class="cart-discount-chip"><?= htmlspecialchars($discountCode, ENT_QUOTES, 'UTF-8') ?></span>
<form method="post" action="/cart/discount/remove" style="margin:0;">
<input type="hidden" name="return_url" value="/cart">
<button type="submit" class="cart-btn cart-btn-danger">Remove</button>
</form>
<?php endif; ?>
</div>
<div id="discountBox" class="cart-discount-box<?= $discountCode !== '' ? ' is-open' : '' ?>">
<form method="post" action="/cart/discount/apply" style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
<input type="hidden" name="return_url" value="/cart">
<input name="discount_code" value="<?= htmlspecialchars($discountCode, ENT_QUOTES, 'UTF-8') ?>" class="input cart-discount-input" placeholder="Enter discount code">
<button type="submit" class="cart-btn cart-btn-primary">Apply code</button>
</form>
</div>
</div>
</div>
<div style="display:flex; justify-content:flex-end; gap:10px; flex-wrap:wrap;">
<button type="button" class="cart-btn cart-btn-ghost" id="toggleDiscountBox">
<?= $discountCode !== '' ? 'Discount Active' : 'Have a discount code?' ?>
</button>
<a href="/checkout" class="cart-btn cart-btn-primary">Checkout</a>
</div>
<?php endif; ?>
</section>
<style>
.cart-btn {
display: inline-flex;
align-items: center;
justify-content: center;
height: 36px;
padding: 0 14px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,.18);
background: rgba(255,255,255,.08);
color: #e9eefc;
text-decoration: none;
font-size: 12px;
letter-spacing: .12em;
text-transform: uppercase;
font-family: 'IBM Plex Mono', monospace;
font-weight: 600;
cursor: pointer;
}
.cart-btn:hover { background: rgba(255,255,255,.14); }
.cart-btn-primary {
background: rgba(34,242,165,.18);
border-color: rgba(34,242,165,.48);
color: #cffff0;
}
.cart-btn-primary:hover { background: rgba(34,242,165,.28); }
.cart-btn-ghost {
background: rgba(255,255,255,.06);
}
.cart-btn-danger {
border-color: rgba(255, 120, 120, 0.4);
color: #ffd4d4;
background: rgba(255, 120, 120, 0.12);
}
.cart-btn-danger:hover {
background: rgba(255, 120, 120, 0.2);
}
.cart-discount-wrap {
display: none;
border: 1px solid rgba(255,255,255,.12);
border-radius: 14px;
padding: 12px;
background:
linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,.01)),
rgba(10, 12, 18, 0.72);
box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
}
.cart-discount-wrap.is-open {
display: block;
}
.cart-discount-chip {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 28px;
padding: 0 10px;
border-radius: 999px;
border: 1px solid rgba(34,242,165,.38);
background: rgba(34,242,165,.14);
color: #cffff0;
font-size: 11px;
letter-spacing: .12em;
text-transform: uppercase;
font-family: 'IBM Plex Mono', monospace;
font-weight: 600;
}
.cart-discount-box {
display: none;
margin-top: 10px;
padding-top: 2px;
}
.cart-discount-box.is-open {
display: block;
}
.cart-discount-input {
min-width: 220px;
height: 38px;
border-radius: 10px;
border: 1px solid rgba(255,255,255,.18);
background: rgba(7,9,14,.72);
color: #f0f4ff;
padding: 0 12px;
}
.cart-discount-input::placeholder {
color: rgba(220,228,245,.42);
}
.cart-discount-input:focus {
outline: none;
border-color: rgba(34,242,165,.5);
box-shadow: 0 0 0 2px rgba(34,242,165,.14);
}
@media (max-width: 720px) {
.cart-discount-input {
min-width: 100%;
width: 100%;
}
}
</style>
<script>
(function () {
const toggleBtn = document.getElementById('toggleDiscountBox');
const box = document.getElementById('discountBox');
const wrap = document.getElementById('discountWrap');
if (!toggleBtn || !box || !wrap) return;
toggleBtn.addEventListener('click', function () {
box.classList.toggle('is-open');
wrap.classList.toggle('is-open');
});
})();
</script>
<?php
$content = ob_get_clean();
require __DIR__ . '/../../../../views/site/layout.php';

View File

@@ -0,0 +1,208 @@
<?php
declare(strict_types=1);
$pageTitle = $title ?? 'Checkout';
$items = is_array($items ?? null) ? $items : [];
$total = (float)($total ?? 0);
$subtotal = (float)($subtotal ?? $total);
$discountAmount = (float)($discount_amount ?? 0);
$discountCode = (string)($discount_code ?? '');
$currency = (string)($currency ?? 'GBP');
$success = (string)($success ?? '');
$orderNo = (string)($order_no ?? '');
$error = (string)($error ?? '');
$downloadLinks = is_array($download_links ?? null) ? $download_links : [];
$downloadNotice = (string)($download_notice ?? '');
$downloadLimit = (int)($download_limit ?? 5);
$downloadExpiryDays = (int)($download_expiry_days ?? 30);
ob_start();
?>
<section class="card checkout-wrap">
<div class="badge">Store</div>
<h1 style="margin:0; font-size:32px;">Checkout</h1>
<?php if ($success !== ''): ?>
<div style="padding:14px; border-radius:12px; border:1px solid rgba(34,242,165,.4); background:rgba(34,242,165,.12);">
<div style="font-weight:700;">Order complete</div>
<?php if ($orderNo !== ''): ?>
<div style="margin-top:4px; color:var(--muted);">Order: <?= htmlspecialchars($orderNo, ENT_QUOTES, 'UTF-8') ?></div>
<?php endif; ?>
</div>
<div class="checkout-panel">
<div class="badge" style="font-size:9px;">Your Downloads</div>
<?php if ($downloadLinks): ?>
<div style="display:grid; gap:10px; margin-top:10px;">
<?php foreach ($downloadLinks as $link): ?>
<?php
$label = trim((string)($link['label'] ?? 'Download'));
$url = trim((string)($link['url'] ?? ''));
if ($url === '') {
continue;
}
?>
<a href="<?= htmlspecialchars($url, ENT_QUOTES, 'UTF-8') ?>" class="checkout-download-link">
<span><?= htmlspecialchars($label !== '' ? $label : 'Download', ENT_QUOTES, 'UTF-8') ?></span>
<span class="checkout-download-link-arrow">Download</span>
</a>
<?php endforeach; ?>
</div>
<?php else: ?>
<p style="margin:10px 0 0; color:var(--muted); font-size:13px;">
<?= htmlspecialchars($downloadNotice !== '' ? $downloadNotice : 'No downloads available for this order yet.', ENT_QUOTES, 'UTF-8') ?>
</p>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if ($error !== ''): ?>
<div style="padding:14px; border-radius:12px; border:1px solid rgba(243,176,176,.45); background:rgba(243,176,176,.12); color:#ffd6d6;">
<?= htmlspecialchars($error, ENT_QUOTES, 'UTF-8') ?>
</div>
<?php endif; ?>
<?php if (!$items): ?>
<div style="padding:14px; border-radius:12px; border:1px solid rgba(255,255,255,.1); background:rgba(0,0,0,.2); color:var(--muted);">
Your cart is empty.
</div>
<div><a href="/releases" class="btn">Browse releases</a></div>
<?php else: ?>
<div class="checkout-grid">
<div class="checkout-panel">
<div class="badge" style="font-size:9px;">Order Summary</div>
<div style="display:grid; gap:10px; margin-top:10px;">
<?php foreach ($items as $item): ?>
<?php
$title = (string)($item['title'] ?? 'Item');
$qty = max(1, (int)($item['qty'] ?? 1));
$price = (float)($item['price'] ?? 0);
$lineCurrency = (string)($item['currency'] ?? $currency);
?>
<div class="checkout-line">
<div class="checkout-line-title"><?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8') ?></div>
<div class="checkout-line-meta"><?= htmlspecialchars($lineCurrency, ENT_QUOTES, 'UTF-8') ?> <?= number_format($price, 2) ?> x <?= $qty ?></div>
<div class="checkout-line-total"><?= htmlspecialchars($lineCurrency, ENT_QUOTES, 'UTF-8') ?> <?= number_format($price * $qty, 2) ?></div>
</div>
<?php endforeach; ?>
</div>
<div class="checkout-total">
<span>Subtotal</span>
<strong><?= htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') ?> <?= number_format($subtotal, 2) ?></strong>
</div>
<?php if ($discountAmount > 0): ?>
<div class="checkout-total" style="margin-top:8px;">
<span>Discount (<?= htmlspecialchars($discountCode, ENT_QUOTES, 'UTF-8') ?>)</span>
<strong style="color:#9be7c6;">-<?= htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') ?> <?= number_format($discountAmount, 2) ?></strong>
</div>
<?php endif; ?>
<div class="checkout-total" style="margin-top:8px;">
<span>Order total</span>
<strong><?= htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') ?> <?= number_format($total, 2) ?></strong>
</div>
</div>
<div class="checkout-panel">
<div class="badge" style="font-size:9px;">Buyer Details</div>
<form method="post" action="/checkout/place" style="display:grid; gap:12px; margin-top:10px;">
<label style="font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:.18em;">Email</label>
<input name="email" type="email" value="" placeholder="you@example.com" class="checkout-input" required>
<div class="checkout-terms">
<div class="badge" style="font-size:9px;">Terms</div>
<p style="margin:8px 0 0; color:var(--muted); font-size:13px; line-height:1.5;">
Digital download products are non-refundable once purchased and delivered. Please check your order details before placing the order.
Files are limited to <?= $downloadLimit ?> downloads and expire after <?= $downloadExpiryDays ?> days.
</p>
<label style="margin-top:10px; display:flex; gap:8px; align-items:flex-start; color:#d7def2; font-size:13px;">
<input type="checkbox" name="accept_terms" value="1" required style="margin-top:2px;">
<span>I agree to the terms and understand all sales are final.</span>
</label>
</div>
<button type="submit" class="checkout-place-btn">Place Order</button>
</form>
</div>
</div>
<?php endif; ?>
</section>
<style>
.checkout-wrap { display:grid; gap:14px; }
.checkout-grid { display:grid; grid-template-columns: minmax(0,1fr) 420px; gap:14px; }
.checkout-panel {
padding:14px;
border-radius:12px;
border:1px solid rgba(255,255,255,.1);
background:rgba(0,0,0,.2);
}
.checkout-line {
display:grid;
grid-template-columns:minmax(0,1fr) auto;
gap:8px;
padding:10px;
border-radius:10px;
border:1px solid rgba(255,255,255,.08);
background:rgba(255,255,255,.03);
}
.checkout-line-title { font-weight:600; }
.checkout-line-meta { color:var(--muted); font-size:12px; margin-top:4px; grid-column:1/2; }
.checkout-line-total { font-weight:700; grid-column:2/3; grid-row:1/3; align-self:center; }
.checkout-total {
margin-top:10px;
display:flex;
align-items:center;
justify-content:space-between;
padding:12px;
border-radius:10px;
border:1px solid rgba(255,255,255,.1);
background:rgba(255,255,255,.04);
}
.checkout-total strong { font-size:22px; }
.checkout-input {
height:40px;
border-radius:10px;
border:1px solid rgba(255,255,255,.2);
background:rgba(255,255,255,.05);
color:#fff;
padding:0 12px;
}
.checkout-terms {
padding:12px;
border-radius:10px;
border:1px solid rgba(255,255,255,.1);
background:rgba(255,255,255,.03);
}
.checkout-place-btn{
height:40px;
border-radius:999px;
border:1px solid rgba(34,242,165,.45);
background:rgba(34,242,165,.18);
color:#cbfff1;
font-weight:700;
letter-spacing:.1em;
text-transform:uppercase;
cursor:pointer;
}
.checkout-place-btn:hover { background:rgba(34,242,165,.28); }
.checkout-download-link {
display:flex;
align-items:center;
justify-content:space-between;
gap:10px;
padding:12px;
border-radius:10px;
border:1px solid rgba(34,242,165,.35);
background:rgba(34,242,165,.1);
color:#d7ffef;
text-decoration:none;
font-weight:600;
}
.checkout-download-link:hover { background:rgba(34,242,165,.18); }
.checkout-download-link-arrow {
font-size:11px;
text-transform:uppercase;
letter-spacing:.14em;
color:#8df7d1;
}
@media (max-width: 900px) {
.checkout-grid { grid-template-columns: 1fr; }
}
</style>
<?php
$content = ob_get_clean();
require __DIR__ . '/../../../../views/site/layout.php';