Initial dev export (exclude uploads/runtime)
This commit is contained in:
325
plugins/store/views/site/account.php
Normal file
325
plugins/store/views/site/account.php
Normal 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') ?>">×</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 !== ''): ?>
|
||||
· 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';
|
||||
Reference in New Issue
Block a user