Files
shop10/src/views/admin/promo-codes.ejs
T
shop 9b688b2af4 feat: скидки на товары и редактирование промокодов в админке
Цена со скидкой и срок акции на товаре; отображение в каталоге и корзине. Улучшенный UI промокодов с редактированием.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 14:08:03 +03:00

116 lines
6.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<%- include('../partials/layout-start') %>
<div class="admin-header">
<h1>Промокоды и скидки</h1>
<nav class="admin-nav">
<a href="/admin" class="admin-nav__link">Обзор</a>
<a href="/admin/orders" class="admin-nav__link">Заказы</a>
<a href="/admin/users" class="admin-nav__link">Пользователи</a>
<a href="/admin/products" class="admin-nav__link">Товары</a>
<a href="/admin/promo-codes" class="admin-nav__link admin-nav__link--active">Промокоды</a>
<a href="/admin/reservations" class="admin-nav__link">Бронирования</a>
<a href="/" class="admin-nav__link">В магазин</a>
</nav>
</div>
<% if (created) { %><p class="alert alert--success">Промокод создан</p><% } %>
<% if (updated) { %><p class="alert alert--success">Промокод обновлён</p><% } %>
<section class="card account-section--narrow" style="margin-bottom:1.5rem">
<h2>Новый промокод</h2>
<form action="/admin/promo-codes" method="post" class="form form--grid">
<label class="label">Код <input type="text" name="code" class="input" required placeholder="SUMMER20"></label>
<label class="label">Описание <input type="text" name="description" class="input" placeholder="Летняя скидка"></label>
<label class="label">Тип скидки
<select name="discount_type" class="input" id="promo-type-new">
<option value="percent">Процент (%)</option>
<option value="fixed">Фиксированная сумма (₽)</option>
</select>
</label>
<label class="label">
<span id="promo-value-label-new">Размер скидки (%)</span>
<input type="number" name="discount_value" class="input" min="1" required placeholder="10">
</label>
<label class="label">Действует (дней с сегодня) <input type="number" name="valid_days" class="input" value="30" min="1"></label>
<label class="label">Мин. сумма заказа (₽) <input type="number" name="min_order_rub" class="input" value="0" min="0" step="1"></label>
<label class="label">Лимит использований <input type="number" name="max_uses" class="input" min="1" placeholder="без лимита"></label>
<button type="submit" class="btn btn--primary">Создать</button>
</form>
</section>
<table class="cart-table">
<thead>
<tr>
<th>Код</th>
<th>Настройки скидки</th>
<th>Срок / лимит</th>
<th>Использовано</th>
<th></th>
</tr>
</thead>
<tbody>
<% promos.forEach(p => { %>
<tr>
<td><strong><%= p.code %></strong></td>
<td>
<form action="/admin/promo-codes/<%= p.id %>/update" method="post" class="admin-promo-form">
<input type="text" name="description" class="input input--sm" value="<%= p.description || '' %>" placeholder="Описание">
<select name="discount_type" class="input input--sm promo-type-select">
<option value="percent"<%= p.discount_type === 'percent' ? ' selected' : '' %>>%</option>
<option value="fixed"<%= p.discount_type === 'fixed' ? ' selected' : '' %>>₽</option>
</select>
<input type="number" name="discount_value" class="input input--sm" min="1" required
value="<%= p.discount_type === 'percent' ? p.discount_value : (p.discount_value / 100) %>"
title="<%= p.discount_type === 'percent' ? 'Процент' : 'Рубли' %>">
<label class="label label--inline muted">мин. заказ ₽
<input type="number" name="min_order_rub" class="input input--sm" min="0"
value="<%= Math.round(p.min_order_cents / 100) %>">
</label>
<button type="submit" class="btn btn--ghost btn--sm">Сохранить</button>
</form>
</td>
<td>
<form action="/admin/promo-codes/<%= p.id %>/update" method="post" class="admin-promo-form">
<input type="hidden" name="description" value="<%= p.description || '' %>">
<input type="hidden" name="discount_type" value="<%= p.discount_type %>">
<input type="hidden" name="discount_value" value="<%= p.discount_type === 'percent' ? p.discount_value : (p.discount_value / 100) %>">
<input type="hidden" name="min_order_rub" value="<%= Math.round(p.min_order_cents / 100) %>">
<label class="label label--inline">ещё дней
<input type="number" name="valid_days" class="input input--sm" value="7" min="1">
</label>
<label class="label label--inline">лимит
<input type="number" name="max_uses" class="input input--sm" min="1"
value="<%= p.max_uses || '' %>" placeholder="∞">
</label>
<button type="submit" class="btn btn--ghost btn--sm">Продлить</button>
<p class="muted" style="margin:0.25rem 0 0;font-size:0.85rem">до <%= new Date(p.expires_at).toLocaleString('ru-RU') %></p>
</form>
</td>
<td><%= p.use_count %><% if (p.max_uses) { %> / <%= p.max_uses %><% } %></td>
<td>
<span class="badge<%= p.active ? '' : ' badge--muted' %>"><%= p.active ? 'Активен' : 'Выкл.' %></span>
<form action="/admin/promo-codes/<%= p.id %>/toggle" method="post" style="margin-top:0.35rem">
<button type="submit" class="btn btn--ghost btn--sm"><%= p.active ? 'Выключить' : 'Включить' %></button>
</form>
</td>
</tr>
<% }) %>
</tbody>
</table>
<script>
function bindPromoType(selectId, labelId) {
const sel = document.getElementById(selectId);
const lab = document.getElementById(labelId);
if (!sel || !lab) return;
const sync = () => {
lab.textContent = sel.value === 'fixed' ? 'Скидка (₽)' : 'Размер скидки (%)';
};
sel.addEventListener('change', sync);
sync();
}
bindPromoType('promo-type-new', 'promo-value-label-new');
</script>
<%- include('../partials/layout-end') %>