views(admin): add coupon and review management pages
This commit is contained in:
1 parent
244e502bad
commit
f9741f89ef
3 files changed
+174
No files matched your search
@@ -0,0 +1,62 @@
|
||||
<div class="admin__head">
|
||||
<div>
|
||||
<h1 style="margin:0">New coupon</h1>
|
||||
<p class="muted" style="margin:0">Create a discount code.</p>
|
||||
</div>
|
||||
<a class="btn btn--ghost" href="/admin/coupons">Back</a>
|
||||
</div>
|
||||
|
||||
<form method="post" action="/admin/coupons" class="panel panel--pad" style="max-width:640px">
|
||||
<input type="hidden" name="csrfToken" value="<?= e($csrfToken) ?>">
|
||||
|
||||
<label class="field">
|
||||
<span class="field__label">Code</span>
|
||||
<input class="input" type="text" name="code" value="<?= e($_POST['code'] ?? '') ?>" placeholder="SAVE10" required>
|
||||
<?php if (!empty($errors['code'])): ?><span class="field__error"><?= e($errors['code']) ?></span><?php endif; ?>
|
||||
</label>
|
||||
|
||||
<div class="row" style="gap:16px">
|
||||
<label class="field" style="flex:1">
|
||||
<span class="field__label">Type</span>
|
||||
<select class="select" name="type">
|
||||
<option value="percent">Percent</option>
|
||||
<option value="fixed">Fixed amount</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field" style="flex:1">
|
||||
<span class="field__label">Value (percent, or amount)</span>
|
||||
<input class="input" type="number" name="value" step="0.01" min="0" value="<?= e($_POST['value'] ?? '') ?>" required>
|
||||
<?php if (!empty($errors['value'])): ?><span class="field__error"><?= e($errors['value']) ?></span><?php endif; ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="row" style="gap:16px">
|
||||
<label class="field" style="flex:1">
|
||||
<span class="field__label">Minimum cart</span>
|
||||
<input class="input" type="number" name="minSubtotal" step="0.01" min="0" value="<?= e($_POST['minSubtotal'] ?? '0') ?>">
|
||||
</label>
|
||||
<label class="field" style="flex:1">
|
||||
<span class="field__label">Max redemptions (blank = unlimited)</span>
|
||||
<input class="input" type="number" name="maxRedemptions" min="1" value="<?= e($_POST['maxRedemptions'] ?? '') ?>">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="row" style="gap:16px">
|
||||
<label class="field" style="flex:1">
|
||||
<span class="field__label">Starts at</span>
|
||||
<input class="input" type="date" name="startsAt" value="<?= e($_POST['startsAt'] ?? '') ?>">
|
||||
</label>
|
||||
<label class="field" style="flex:1">
|
||||
<span class="field__label">Expires at</span>
|
||||
<input class="input" type="date" name="expiresAt" value="<?= e($_POST['expiresAt'] ?? '') ?>">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="isActive" checked> Active
|
||||
</label>
|
||||
|
||||
<div class="mt-lg">
|
||||
<button class="btn btn--primary" type="submit">Create coupon</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,49 @@
|
||||
<div class="admin__head">
|
||||
<div>
|
||||
<h1 style="margin:0">Coupons</h1>
|
||||
<p class="muted" style="margin:0">Percentage or fixed discounts with limits and windows.</p>
|
||||
</div>
|
||||
<a class="btn btn--primary" href="/admin/coupons/create">New coupon</a>
|
||||
</div>
|
||||
|
||||
<?php if (empty($coupons)): ?>
|
||||
<div class="empty"><p class="muted" style="margin:0">No coupons yet.</p></div>
|
||||
<?php else: ?>
|
||||
<div class="table-wrap">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr><th>Code</th><th>Discount</th><th class="num">Min cart</th><th>Redemptions</th><th>Window</th><th>Status</th><th></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($coupons as $coupon): ?>
|
||||
<tr>
|
||||
<td class="mono" style="font-weight:600"><?= e($coupon['code']) ?></td>
|
||||
<td>
|
||||
<?php if ($coupon['type'] === 'percent'): ?>
|
||||
<?= (int) $coupon['value'] ?>%
|
||||
<?php else: ?>
|
||||
<?= e(formatMoney((int) $coupon['value'], $currency)) ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="num mono"><?= e(formatMoney((int) $coupon['minSubtotalCents'], $currency)) ?></td>
|
||||
<td>
|
||||
<?= (int) $coupon['redeemedCount'] ?><?= $coupon['maxRedemptions'] !== null ? ' / ' . (int) $coupon['maxRedemptions'] : '' ?>
|
||||
</td>
|
||||
<td class="small muted">
|
||||
<?= $coupon['startsAt'] ? e(substr($coupon['startsAt'], 0, 10)) : '-' ?>
|
||||
→
|
||||
<?= $coupon['expiresAt'] ? e(substr($coupon['expiresAt'], 0, 10)) : '-' ?>
|
||||
</td>
|
||||
<td><span class="badge badge--<?= (int) $coupon['isActive'] === 1 ? 'stock' : 'out' ?>"><?= (int) $coupon['isActive'] === 1 ? 'active' : 'off' ?></span></td>
|
||||
<td>
|
||||
<form method="post" action="/admin/coupons/<?= (int) $coupon['id'] ?>/delete" onsubmit="return confirm('Delete this coupon?')">
|
||||
<input type="hidden" name="csrfToken" value="<?= e($csrfToken) ?>">
|
||||
<button class="btn btn--danger btn--sm" type="submit">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
@@ -0,0 +1,63 @@
|
||||
<div class="admin__head">
|
||||
<div>
|
||||
<h1 style="margin:0">Reviews</h1>
|
||||
<p class="muted" style="margin:0"><?= count($pending) ?> awaiting moderation.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-head"><h3 style="margin:0">Pending</h3></div>
|
||||
<?php if (empty($pending)): ?>
|
||||
<div class="empty"><p class="muted" style="margin:0">Nothing to moderate.</p></div>
|
||||
<?php else: ?>
|
||||
<div class="stack" style="gap:12px">
|
||||
<?php foreach ($pending as $review): ?>
|
||||
<div class="panel panel--pad review-card">
|
||||
<div class="row" style="justify-content:space-between;align-items:flex-start">
|
||||
<div>
|
||||
<span class="rating__stars"><?= str_repeat('*', (int) $review['rating']) ?><span class="rating__off"><?= str_repeat('*', 5 - (int) $review['rating']) ?></span></span>
|
||||
<strong style="margin-left:8px"><?= e($review['title'] !== '' ? $review['title'] : 'Review') ?></strong>
|
||||
<div class="small muted">
|
||||
<a href="/products/<?= e($review['productSlug']) ?>"><?= e($review['productName']) ?></a>
|
||||
· <?= e($review['authorName']) ?> (<?= e($review['authorEmail']) ?>)
|
||||
· <?= e(substr((string) $review['createdAt'], 0, 10)) ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="gap:8px">
|
||||
<form method="post" action="/admin/reviews/<?= (int) $review['id'] ?>/approve">
|
||||
<input type="hidden" name="csrfToken" value="<?= e($csrfToken) ?>">
|
||||
<button class="btn btn--primary btn--sm" type="submit">Approve</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/reviews/<?= (int) $review['id'] ?>/reject">
|
||||
<input type="hidden" name="csrfToken" value="<?= e($csrfToken) ?>">
|
||||
<button class="btn btn--danger btn--sm" type="submit">Reject</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($review['body'] !== ''): ?>
|
||||
<p style="margin:10px 0 0"><?= nl2br(e($review['body'])) ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="section-head mt-lg"><h3 style="margin:0">Approved (<?= count($approved) ?>)</h3></div>
|
||||
<?php if (empty($approved)): ?>
|
||||
<div class="empty"><p class="muted" style="margin:0">None yet.</p></div>
|
||||
<?php else: ?>
|
||||
<div class="table-wrap">
|
||||
<table class="table">
|
||||
<thead><tr><th>Product</th><th>Rating</th><th>Title</th><th>Author</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($approved as $review): ?>
|
||||
<tr>
|
||||
<td><a href="/products/<?= e($review['productSlug']) ?>"><?= e($review['productName']) ?></a></td>
|
||||
<td><?= str_repeat('*', (int) $review['rating']) ?></td>
|
||||
<td><?= e($review['title']) ?></td>
|
||||
<td class="muted"><?= e($review['authorName']) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
Reference in new issue
Block a user