Initial dev export (exclude uploads/runtime)
This commit is contained in:
224
plugins/store/views/admin/customers.php
Normal file
224
plugins/store/views/admin/customers.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
$pageTitle = $title ?? 'Store Customers';
|
||||
$customers = $customers ?? [];
|
||||
$currency = (string)($currency ?? 'GBP');
|
||||
$q = (string)($q ?? '');
|
||||
ob_start();
|
||||
?>
|
||||
<section class="admin-card customers-page">
|
||||
<div class="badge">Store</div>
|
||||
<div class="customers-header">
|
||||
<div>
|
||||
<h1 class="customers-title">Customers</h1>
|
||||
<p class="customers-sub">Customer activity, value, and latest order access.</p>
|
||||
</div>
|
||||
<a href="/admin/store" class="btn outline">Back</a>
|
||||
</div>
|
||||
|
||||
<div class="customers-tabs">
|
||||
<a href="/admin/store" class="btn outline small">Overview</a>
|
||||
<a href="/admin/store/settings" class="btn outline small">Settings</a>
|
||||
<a href="/admin/store/orders" class="btn outline small">Orders</a>
|
||||
<a href="/admin/store/customers" class="btn outline small">Customers</a>
|
||||
</div>
|
||||
|
||||
<form method="get" action="/admin/store/customers" class="customers-search">
|
||||
<input type="text" name="q" value="<?= htmlspecialchars($q, ENT_QUOTES, 'UTF-8') ?>" placeholder="Search by email, name, or order number">
|
||||
<button type="submit" class="btn small">Search</button>
|
||||
<?php if ($q !== ''): ?>
|
||||
<a href="/admin/store/customers" class="btn outline small">Clear</a>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<?php if (!$customers): ?>
|
||||
<div class="customers-empty">No customers yet.</div>
|
||||
<?php else: ?>
|
||||
<div class="customers-table-wrap">
|
||||
<table class="customers-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Customer</th>
|
||||
<th>Orders</th>
|
||||
<th>Revenue</th>
|
||||
<th>Latest Order</th>
|
||||
<th>Last Seen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($customers as $customer): ?>
|
||||
<?php
|
||||
$ips = is_array($customer['ips'] ?? null) ? $customer['ips'] : [];
|
||||
$email = (string)($customer['email'] ?? '');
|
||||
$lastOrderNo = (string)($customer['last_order_no'] ?? '');
|
||||
$lastOrderId = (int)($customer['last_order_id'] ?? 0);
|
||||
$lastSeen = (string)($customer['last_order_at'] ?? $customer['created_at'] ?? '');
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="customer-email"><?= htmlspecialchars($email, ENT_QUOTES, 'UTF-8') ?></div>
|
||||
<?php if ($ips): ?>
|
||||
<div class="customer-ips">
|
||||
<?php foreach ($ips as $entry): ?>
|
||||
<?php
|
||||
$ip = (string)($entry['ip'] ?? '');
|
||||
$ipLastSeen = (string)($entry['last_seen'] ?? '');
|
||||
if ($ip === '') { continue; }
|
||||
?>
|
||||
<span class="ip-chip" title="<?= htmlspecialchars($ipLastSeen, ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($ip, ENT_QUOTES, 'UTF-8') ?></span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="num"><?= (int)($customer['order_count'] ?? 0) ?></td>
|
||||
<td class="num"><?= htmlspecialchars($currency, ENT_QUOTES, 'UTF-8') ?> <?= number_format((float)($customer['revenue'] ?? 0), 2) ?></td>
|
||||
<td>
|
||||
<?php if ($lastOrderId > 0): ?>
|
||||
<a href="/admin/store/order?id=<?= $lastOrderId ?>" class="order-link">
|
||||
<?= htmlspecialchars($lastOrderNo !== '' ? $lastOrderNo : ('#' . $lastOrderId), ENT_QUOTES, 'UTF-8') ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<span class="muted">No orders</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="muted"><?= htmlspecialchars($lastSeen, ENT_QUOTES, 'UTF-8') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.customers-page { display:grid; gap:14px; }
|
||||
.customers-header { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-top:14px; }
|
||||
.customers-title { margin:0; font-size:28px; line-height:1.1; }
|
||||
.customers-sub { margin:6px 0 0; color:var(--muted); font-size:14px; }
|
||||
.customers-tabs { display:flex; flex-wrap:wrap; gap:8px; }
|
||||
.customers-search { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
|
||||
.customers-search input {
|
||||
height:36px;
|
||||
min-width:280px;
|
||||
border-radius:10px;
|
||||
border:1px solid rgba(255,255,255,.15);
|
||||
background:rgba(255,255,255,.04);
|
||||
color:#fff;
|
||||
padding:0 12px;
|
||||
}
|
||||
|
||||
.customers-empty {
|
||||
padding:16px;
|
||||
border-radius:12px;
|
||||
border:1px solid rgba(255,255,255,.08);
|
||||
background:rgba(0,0,0,.15);
|
||||
color:var(--muted);
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.customers-table-wrap {
|
||||
border:1px solid rgba(255,255,255,.1);
|
||||
border-radius:14px;
|
||||
overflow:hidden;
|
||||
background:rgba(0,0,0,.2);
|
||||
}
|
||||
|
||||
.customers-table {
|
||||
width:100%;
|
||||
border-collapse:separate;
|
||||
border-spacing:0;
|
||||
table-layout:fixed;
|
||||
}
|
||||
|
||||
.customers-table th {
|
||||
text-align:left;
|
||||
font-size:11px;
|
||||
letter-spacing:.16em;
|
||||
text-transform:uppercase;
|
||||
color:var(--muted);
|
||||
padding:14px 16px;
|
||||
background:rgba(255,255,255,.03);
|
||||
border-bottom:1px solid rgba(255,255,255,.1);
|
||||
}
|
||||
|
||||
.customers-table td {
|
||||
padding:14px 16px;
|
||||
vertical-align:top;
|
||||
border-bottom:1px solid rgba(255,255,255,.06);
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.customers-table tbody tr:last-child td { border-bottom:none; }
|
||||
.customers-table tbody tr:hover { background:rgba(255,255,255,.03); }
|
||||
|
||||
.customer-email {
|
||||
font-size:16px;
|
||||
font-weight:600;
|
||||
line-height:1.25;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
|
||||
.customer-name {
|
||||
margin-top:4px;
|
||||
color:var(--muted);
|
||||
font-size:13px;
|
||||
}
|
||||
|
||||
.customer-ips {
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
gap:6px;
|
||||
margin-top:8px;
|
||||
}
|
||||
|
||||
.ip-chip {
|
||||
display:inline-flex;
|
||||
align-items:center;
|
||||
padding:3px 8px;
|
||||
border-radius:999px;
|
||||
border:1px solid rgba(255,255,255,.14);
|
||||
background:rgba(255,255,255,.04);
|
||||
color:#d8def1;
|
||||
font-size:11px;
|
||||
line-height:1;
|
||||
}
|
||||
|
||||
.num {
|
||||
font-weight:600;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
.order-link {
|
||||
display:inline-flex;
|
||||
max-width:100%;
|
||||
color:#dce8ff;
|
||||
text-decoration:none;
|
||||
border-bottom:1px dashed rgba(220,232,255,.4);
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
|
||||
.order-link:hover { color:#fff; border-bottom-color:rgba(255,255,255,.8); }
|
||||
.muted { color:var(--muted); }
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.customers-table th:nth-child(3),
|
||||
.customers-table td:nth-child(3),
|
||||
.customers-table th:nth-child(5),
|
||||
.customers-table td:nth-child(5) { display:none; }
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.customers-header { flex-direction:column; }
|
||||
.customers-table { table-layout:auto; }
|
||||
.customers-table th:nth-child(2),
|
||||
.customers-table td:nth-child(2) { display:none; }
|
||||
.customer-email { font-size:15px; }
|
||||
.customers-search input { min-width:100%; width:100%; }
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
$content = ob_get_clean();
|
||||
require __DIR__ . '/../../../../modules/admin/views/layout.php';
|
||||
Reference in New Issue
Block a user