@@ -0,0 +1,15 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<div class="account">
|
||||
<h1>Личный кабинет</h1>
|
||||
<div class="card account-card">
|
||||
<p><strong><%= user.name %></strong></p>
|
||||
<p class="muted"><%= user.email %></p>
|
||||
<p class="muted">С нами с <%= new Date(user.created_at).toLocaleDateString('ru-RU') %></p>
|
||||
<div class="account-actions">
|
||||
<a href="/orders" class="btn btn--primary">Мои заказы (<%= orderCount %>)</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,54 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<h1>Корзина</h1>
|
||||
|
||||
<% if (error) { %><p class="alert alert--error"><%= error %></p><% } %>
|
||||
|
||||
<% if (!items.length) { %>
|
||||
<p class="empty">Корзина пуста. <a href="/">Перейти в каталог</a></p>
|
||||
<% } else { %>
|
||||
<form action="/cart/update" method="post" class="cart-table-wrap">
|
||||
<table class="cart-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Товар</th>
|
||||
<th>Цена</th>
|
||||
<th>Кол-во</th>
|
||||
<th>Сумма</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% items.forEach(item => { %>
|
||||
<tr>
|
||||
<td class="cart-table__product">
|
||||
<% if (item.image_url) { %>
|
||||
<img src="<%= item.image_url %>" alt="" class="cart-table__thumb">
|
||||
<% } %>
|
||||
<a href="/product/<%= item.slug %>"><%= item.name %></a>
|
||||
</td>
|
||||
<td><%= formatPrice(item.price_cents) %></td>
|
||||
<td>
|
||||
<input type="number" name="items[<%= item.id %>]" value="<%= item.quantity %>" min="0" max="<%= item.stock %>" class="input input--qty">
|
||||
</td>
|
||||
<td><%= formatPrice(item.line_total) %></td>
|
||||
<td>
|
||||
<button type="submit" formaction="/cart/remove/<%= item.id %>" formmethod="post" class="btn btn--ghost btn--sm" title="Удалить">×</button>
|
||||
</td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="cart-actions">
|
||||
<button type="submit" class="btn btn--ghost">Обновить</button>
|
||||
<p class="cart-total">Итого: <strong><%= formatPrice(total) %></strong></p>
|
||||
<% if (user) { %>
|
||||
<a href="/checkout" class="btn btn--primary btn--lg">Оформить заказ</a>
|
||||
<% } else { %>
|
||||
<p class="hint"><a href="/login?next=/checkout">Войдите</a>, чтобы оформить заказ.</p>
|
||||
<% } %>
|
||||
</div>
|
||||
</form>
|
||||
<% } %>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,43 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<h1>Оформление заказа</h1>
|
||||
|
||||
<% if (error) { %><p class="alert alert--error"><%= error %></p><% } %>
|
||||
|
||||
<div class="checkout-layout">
|
||||
<form action="/checkout" method="post" class="form card">
|
||||
<h2>Данные доставки</h2>
|
||||
<label class="label">
|
||||
Имя
|
||||
<input type="text" name="name" class="input" required value="<%= user ? user.name : '' %>">
|
||||
</label>
|
||||
<label class="label">
|
||||
Email
|
||||
<input type="email" name="email" class="input" required value="<%= user ? user.email : '' %>">
|
||||
</label>
|
||||
<label class="label">
|
||||
Телефон
|
||||
<input type="tel" name="phone" class="input" placeholder="+7 …">
|
||||
</label>
|
||||
<label class="label">
|
||||
Адрес доставки
|
||||
<textarea name="address" class="input" rows="3" required placeholder="Город, улица, дом, квартира"></textarea>
|
||||
</label>
|
||||
<button type="submit" class="btn btn--primary btn--lg btn--block">Подтвердить заказ</button>
|
||||
</form>
|
||||
|
||||
<aside class="checkout-summary card">
|
||||
<h2>Ваш заказ</h2>
|
||||
<ul class="checkout-list">
|
||||
<% items.forEach(item => { %>
|
||||
<li>
|
||||
<span><%= item.name %> × <%= item.quantity %></span>
|
||||
<span><%= formatPrice(item.line_total) %></span>
|
||||
</li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
<p class="checkout-total">Итого: <strong><%= formatPrice(total) %></strong></p>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,9 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<div class="error-page">
|
||||
<h1><%= code %></h1>
|
||||
<p><%= message %></p>
|
||||
<a href="/" class="btn btn--primary">На главную</a>
|
||||
</div>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,47 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<section class="hero">
|
||||
<h1>Каталог товаров</h1>
|
||||
<p>Доставка по России. Оплата при получении.</p>
|
||||
</section>
|
||||
|
||||
<% if (categories.length) { %>
|
||||
<nav class="categories" aria-label="Категории">
|
||||
<a href="/" class="chip <%= !activeCategory ? 'chip--active' : '' %>">Все</a>
|
||||
<% categories.forEach(c => { %>
|
||||
<a href="/?category=<%= c.slug %>" class="chip <%= activeCategory === c.slug ? 'chip--active' : '' %>"><%= c.name %></a>
|
||||
<% }) %>
|
||||
</nav>
|
||||
<% } %>
|
||||
|
||||
<% if (!products.length) { %>
|
||||
<p class="empty">Товары не найдены. Попробуйте другой запрос.</p>
|
||||
<% } else { %>
|
||||
<div class="grid">
|
||||
<% products.forEach(p => { %>
|
||||
<article class="card">
|
||||
<a href="/product/<%= p.slug %>" class="card__image-wrap">
|
||||
<% if (p.image_url) { %>
|
||||
<img src="<%= p.image_url %>" alt="<%= p.name %>" class="card__image" loading="lazy">
|
||||
<% } else { %>
|
||||
<div class="card__placeholder">Нет фото</div>
|
||||
<% } %>
|
||||
</a>
|
||||
<div class="card__body">
|
||||
<% if (p.category_name) { %>
|
||||
<span class="card__category"><%= p.category_name %></span>
|
||||
<% } %>
|
||||
<h2 class="card__title"><a href="/product/<%= p.slug %>"><%= p.name %></a></h2>
|
||||
<p class="card__price"><%= formatPrice(p.price_cents) %></p>
|
||||
<form action="/cart/add" method="post" class="card__form">
|
||||
<input type="hidden" name="product_id" value="<%= p.id %>">
|
||||
<input type="hidden" name="redirect" value="/cart">
|
||||
<button type="submit" class="btn btn--primary btn--block">В корзину</button>
|
||||
</form>
|
||||
</div>
|
||||
</article>
|
||||
<% }) %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,21 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<div class="auth">
|
||||
<form action="/login" method="post" class="form card">
|
||||
<h1>Вход</h1>
|
||||
<% if (error) { %><p class="alert alert--error"><%= error %></p><% } %>
|
||||
<input type="hidden" name="next" value="<%= next %>">
|
||||
<label class="label">
|
||||
Email
|
||||
<input type="email" name="email" class="input" required value="<%= values.email || '' %>">
|
||||
</label>
|
||||
<label class="label">
|
||||
Пароль
|
||||
<input type="password" name="password" class="input" required>
|
||||
</label>
|
||||
<button type="submit" class="btn btn--primary btn--block">Войти</button>
|
||||
<p class="form-footer">Нет аккаунта? <a href="/register">Регистрация</a></p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,30 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<h1>Заказ #<%= order.id %></h1>
|
||||
|
||||
<% if (success) { %>
|
||||
<p class="alert alert--success">Заказ успешно оформлен! Мы свяжемся с вами по email.</p>
|
||||
<% } %>
|
||||
|
||||
<div class="card order-card">
|
||||
<% const statusLabels = { pending: 'Ожидает обработки', paid: 'Оплачен', shipped: 'Отправлен', cancelled: 'Отменён' }; %>
|
||||
<p><strong>Статус:</strong> <span class="status status--<%= order.status %>"><%= statusLabels[order.status] || order.status %></span></p>
|
||||
<p><strong>Дата:</strong> <%= new Date(order.created_at).toLocaleString('ru-RU') %></p>
|
||||
<p><strong>Доставка:</strong> <%= order.address %></p>
|
||||
<p><strong>Контакт:</strong> <%= order.customer_name %>, <%= order.customer_email %><% if (order.customer_phone) { %>, <%= order.customer_phone %><% } %></p>
|
||||
|
||||
<h2>Состав заказа</h2>
|
||||
<ul class="checkout-list">
|
||||
<% items.forEach(item => { %>
|
||||
<li>
|
||||
<span><a href="/product/<%= item.slug %>"><%= item.name %></a> × <%= item.quantity %></span>
|
||||
<span><%= formatPrice(item.price_cents * item.quantity) %></span>
|
||||
</li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
<p class="checkout-total">Итого: <strong><%= formatPrice(order.total_cents) %></strong></p>
|
||||
</div>
|
||||
|
||||
<p><a href="/orders" class="link-back">← Все заказы</a></p>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,33 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<h1>Мои заказы</h1>
|
||||
|
||||
<% if (!orders.length) { %>
|
||||
<p class="empty">Заказов пока нет. <a href="/">Перейти в каталог</a></p>
|
||||
<% } else { %>
|
||||
<table class="cart-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>№</th>
|
||||
<th>Дата</th>
|
||||
<th>Статус</th>
|
||||
<th>Сумма</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% const statusLabels = { pending: 'Ожидает', paid: 'Оплачен', shipped: 'Отправлен', cancelled: 'Отменён' }; %>
|
||||
<% orders.forEach(o => { %>
|
||||
<tr>
|
||||
<td>#<%= o.id %></td>
|
||||
<td><%= new Date(o.created_at).toLocaleString('ru-RU') %></td>
|
||||
<td><span class="status status--<%= o.status %>"><%= statusLabels[o.status] || o.status %></span></td>
|
||||
<td><%= formatPrice(o.total_cents) %></td>
|
||||
<td><a href="/orders/<%= o.id %>">Подробнее</a></td>
|
||||
</tr>
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% } %>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,8 @@
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p>© <%= new Date().getFullYear() %> Shop — локальный интернет-магазин на Node.js + SQLite</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><%= title %> — Shop</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="header">
|
||||
<div class="container header__inner">
|
||||
<a href="/" class="logo">Shop</a>
|
||||
<form class="search" action="/" method="get">
|
||||
<input type="search" name="q" placeholder="Поиск товаров…" value="<%= typeof searchQuery !== 'undefined' ? searchQuery : '' %>" aria-label="Поиск">
|
||||
<button type="submit" class="btn btn--ghost">Найти</button>
|
||||
</form>
|
||||
<nav class="nav">
|
||||
<a href="/cart" class="nav__link nav__cart">
|
||||
Корзина
|
||||
<% if (cartCount > 0) { %><span class="badge"><%= cartCount %></span><% } %>
|
||||
</a>
|
||||
<% if (user) { %>
|
||||
<a href="/account" class="nav__link"><%= user.name %></a>
|
||||
<form action="/logout" method="post" class="inline-form">
|
||||
<button type="submit" class="btn btn--ghost btn--sm">Выйти</button>
|
||||
</form>
|
||||
<% } else { %>
|
||||
<a href="/login" class="nav__link">Вход</a>
|
||||
<a href="/register" class="btn btn--primary btn--sm">Регистрация</a>
|
||||
<% } %>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<main class="main container">
|
||||
@@ -0,0 +1,37 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<article class="product-detail">
|
||||
<div class="product-detail__media">
|
||||
<% if (product.image_url) { %>
|
||||
<img src="<%= product.image_url %>" alt="<%= product.name %>" class="product-detail__image">
|
||||
<% } else { %>
|
||||
<div class="card__placeholder product-detail__image">Нет фото</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="product-detail__info">
|
||||
<% if (product.category_name) { %>
|
||||
<a href="/?category=<%= product.category_slug %>" class="card__category"><%= product.category_name %></a>
|
||||
<% } %>
|
||||
<h1><%= product.name %></h1>
|
||||
<p class="product-detail__price"><%= formatPrice(product.price_cents) %></p>
|
||||
<p class="product-detail__desc"><%= product.description %></p>
|
||||
<p class="product-detail__stock">В наличии: <strong><%= product.stock %></strong> шт.</p>
|
||||
|
||||
<% if (product.stock > 0) { %>
|
||||
<form action="/cart/add" method="post" class="product-detail__form">
|
||||
<input type="hidden" name="product_id" value="<%= product.id %>">
|
||||
<label class="label">
|
||||
Количество
|
||||
<input type="number" name="quantity" value="1" min="1" max="<%= product.stock %>" class="input input--qty">
|
||||
</label>
|
||||
<input type="hidden" name="redirect" value="/cart">
|
||||
<button type="submit" class="btn btn--primary btn--lg">Добавить в корзину</button>
|
||||
</form>
|
||||
<% } else { %>
|
||||
<p class="alert alert--warn">Нет в наличии</p>
|
||||
<% } %>
|
||||
<a href="/" class="link-back">← Назад в каталог</a>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
@@ -0,0 +1,28 @@
|
||||
<%- include('partials/layout-start') %>
|
||||
|
||||
<div class="auth">
|
||||
<form action="/register" method="post" class="form card">
|
||||
<h1>Регистрация</h1>
|
||||
<% if (error) { %><p class="alert alert--error"><%= error %></p><% } %>
|
||||
<label class="label">
|
||||
Имя
|
||||
<input type="text" name="name" class="input" required value="<%= values.name || '' %>">
|
||||
</label>
|
||||
<label class="label">
|
||||
Email
|
||||
<input type="email" name="email" class="input" required value="<%= values.email || '' %>">
|
||||
</label>
|
||||
<label class="label">
|
||||
Пароль
|
||||
<input type="password" name="password" class="input" required minlength="6">
|
||||
</label>
|
||||
<label class="label">
|
||||
Повторите пароль
|
||||
<input type="password" name="password2" class="input" required>
|
||||
</label>
|
||||
<button type="submit" class="btn btn--primary btn--block">Создать аккаунт</button>
|
||||
<p class="form-footer">Уже есть аккаунт? <a href="/login">Войти</a></p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<%- include('partials/layout-end') %>
|
||||
Reference in New Issue
Block a user