Add orders table mockup to post-login dashboard
Static layout per design mock: order queue table with selection, search, prepayment inputs, status badges, and bulk-receipt button. Uses mock data only — no API wiring, per project rule to not build order features against a guessed CRM shape ahead of stage 3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
import '@/pages/DashboardPage.css'
|
||||
import { useAuth } from '@/features/auth/useAuth'
|
||||
|
||||
@@ -7,12 +9,68 @@ const ROLE_LABEL: Record<string, string> = {
|
||||
viewer: 'Наблюдатель',
|
||||
}
|
||||
|
||||
type OrderStatus = 'processing' | 'new' | 'delivered'
|
||||
|
||||
const STATUS_LABEL: Record<OrderStatus, string> = {
|
||||
processing: 'Обработка',
|
||||
new: 'Новый',
|
||||
delivered: 'Доставлен',
|
||||
}
|
||||
|
||||
interface OrderRow {
|
||||
id: string
|
||||
ttn: string
|
||||
client: string
|
||||
totalLabel: string
|
||||
prepayment: string
|
||||
status: OrderStatus
|
||||
fiscalized: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Временная заглушка. Очередь «получено, чек не пробит» — этап 6 плана,
|
||||
* пока здесь только подтверждение, что вход и защищённый роут работают.
|
||||
* Вёрстка макета из ТЗ — статичные данные, реальная очередь «доставлено, чек
|
||||
* не пробит» приедет на этапе 3+ вместе с CrmClient/StubCrmClient и заказами
|
||||
* из БД. Пока не подключаем это к API, чтобы не гадать форму данных CRM.
|
||||
*/
|
||||
const MOCK_ORDERS: OrderRow[] = [
|
||||
{ id: '#ORD-24810', ttn: '20400123456', client: 'Иван Смирнов', totalLabel: '45 990 ₴', prepayment: '', status: 'processing', fiscalized: false },
|
||||
{ id: '#ORD-24809', ttn: '20400123457', client: 'Ольга Ткаченко', totalLabel: '12 450 ₴', prepayment: '0%', status: 'new', fiscalized: false },
|
||||
{ id: '#ORD-24808', ttn: '20400123458', client: 'Иван Смирнов', totalLabel: '45 990 ₴', prepayment: '15%', status: 'new', fiscalized: false },
|
||||
{ id: '#ORD-24807', ttn: '20400123459', client: 'Марія Бondar', totalLabel: '8 200 ₴', prepayment: '20%', status: 'delivered', fiscalized: false },
|
||||
{ id: '#ORD-24806', ttn: '20400123460', client: 'Петро Коваль', totalLabel: '31 000 ₴', prepayment: '0%', status: 'delivered', fiscalized: false },
|
||||
{ id: '#ORD-24805', ttn: '20400123461', client: 'Іван Смирнов', totalLabel: '45 990 ₴', prepayment: '0%', status: 'delivered', fiscalized: false },
|
||||
]
|
||||
|
||||
export function DashboardPage() {
|
||||
const { user, logout } = useAuth()
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set())
|
||||
const [search, setSearch] = useState('')
|
||||
|
||||
const filtered = useMemo(() => {
|
||||
const query = search.trim().toLowerCase()
|
||||
if (!query) return MOCK_ORDERS
|
||||
return MOCK_ORDERS.filter(
|
||||
(order) =>
|
||||
order.id.toLowerCase().includes(query) ||
|
||||
order.ttn.includes(query) ||
|
||||
order.client.toLowerCase().includes(query),
|
||||
)
|
||||
}, [search])
|
||||
|
||||
const allSelected = filtered.length > 0 && filtered.every((order) => selected.has(order.id))
|
||||
|
||||
function toggleAll() {
|
||||
setSelected(allSelected ? new Set() : new Set(filtered.map((order) => order.id)))
|
||||
}
|
||||
|
||||
function toggleOne(id: string) {
|
||||
setSelected((prev) => {
|
||||
const next = new Set(prev)
|
||||
if (next.has(id)) next.delete(id)
|
||||
else next.add(id)
|
||||
return next
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="dashboard-shell">
|
||||
@@ -27,13 +85,83 @@ export function DashboardPage() {
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main className="dashboard-body">
|
||||
<div className="dashboard-placeholder">
|
||||
<h2>Очередь заказов появится здесь</h2>
|
||||
<p>
|
||||
Вход выполнен успешно. Экран «получено, чек не пробит» будет добавлен на следующих
|
||||
этапах — после интеграций с Новой Поштой и Checkbox.
|
||||
</p>
|
||||
<main className="orders-body">
|
||||
<div className="orders-toolbar">
|
||||
<h2>Заказы</h2>
|
||||
<button type="button" className="orders-create-btn" disabled={selected.size === 0}>
|
||||
Создать чеки по выбранным ({selected.size})
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="orders-filterbar">
|
||||
<span className="orders-selected-count">Выбрано: {selected.size} заказов</span>
|
||||
<input
|
||||
type="search"
|
||||
className="orders-search"
|
||||
placeholder="Поиск по ID, ТТН, клиенту"
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
<button type="button" className="orders-filter-btn">
|
||||
Фильтр
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="orders-table-wrap">
|
||||
<table className="orders-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="orders-checkbox-col">
|
||||
<input type="checkbox" checked={allSelected} onChange={toggleAll} aria-label="Выбрать всё" />
|
||||
</th>
|
||||
<th>ID заказа</th>
|
||||
<th>Номер ТТН</th>
|
||||
<th>Клиент</th>
|
||||
<th>Сумма</th>
|
||||
<th>Предоплата</th>
|
||||
<th>Статус</th>
|
||||
<th>Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{filtered.map((order) => (
|
||||
<tr key={order.id}>
|
||||
<td>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selected.has(order.id)}
|
||||
onChange={() => toggleOne(order.id)}
|
||||
aria-label={`Выбрать заказ ${order.id}`}
|
||||
/>
|
||||
</td>
|
||||
<td>{order.id}</td>
|
||||
<td>{order.ttn}</td>
|
||||
<td>{order.client}</td>
|
||||
<td>{order.totalLabel}</td>
|
||||
<td>
|
||||
<input type="text" className="orders-prepayment-input" defaultValue={order.prepayment} placeholder="0%" />
|
||||
</td>
|
||||
<td>
|
||||
<span className={`orders-status orders-status--${order.status}`}>
|
||||
{STATUS_LABEL[order.status]}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" className="orders-receipt-btn" disabled={order.status !== 'delivered'}>
|
||||
Чек
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{filtered.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={8} className="orders-empty">
|
||||
Ничего не найдено
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user