122 lines
4.9 KiB
TypeScript
122 lines
4.9 KiB
TypeScript
/**
|
|
* PHASE 3 verification harness — THROWAWAY, delete with the spike folder.
|
|
*
|
|
* The ten screens that consume consoleUi sit behind a login, so this renders
|
|
* the seven rewritten primitives directly with stand-in data. It imports them
|
|
* by their original names through the original module path, which is the point:
|
|
* if these render, the adapters are signature-compatible.
|
|
*/
|
|
|
|
import React, { useState } from 'react';
|
|
import {
|
|
Card,
|
|
FilterBar,
|
|
TableShell,
|
|
Skeleton,
|
|
Tooltip,
|
|
LiveStatus,
|
|
SlideDrawer,
|
|
Pill,
|
|
StatusChip,
|
|
MetricPill,
|
|
StampCell,
|
|
SearchPill,
|
|
KpiStrip,
|
|
ORDER_STATUS,
|
|
DELIVERY_STATUS,
|
|
statusColor,
|
|
BRAND,
|
|
} from '../consoleUi';
|
|
import { Package } from 'lucide-react';
|
|
import { ConfirmModal } from '../ConfirmModal';
|
|
import { useNotify } from '../Toasts';
|
|
|
|
export default function ConsoleUiProbe() {
|
|
const { notifyOk, notifyFail } = useNotify();
|
|
const [confirm, setConfirm] = useState(false);
|
|
const [drawer, setDrawer] = useState(false);
|
|
const [q, setQ] = useState('');
|
|
const [tab, setTab] = useState('pending');
|
|
|
|
return (
|
|
<div style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 20 }}>
|
|
<h2 className="text-xl font-extrabold">consoleUi — Phase 3 adapters</h2>
|
|
|
|
<KpiStrip
|
|
items={[
|
|
{ label: 'Orders', value: '1,248', color: BRAND, icon: <Package /> },
|
|
{ label: 'Delivered', value: '1,102', color: '#10b981', icon: <Package />, badge: '88%' },
|
|
{ label: 'Pending', value: '94', color: '#f59e0b', icon: <Package /> },
|
|
{ label: 'Cancelled', value: '52', color: '#ef4444', icon: <Package /> },
|
|
]}
|
|
/>
|
|
|
|
<FilterBar>
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<LiveStatus state="live" label="Live" />
|
|
<LiveStatus state="loading" label="Syncing" />
|
|
<LiveStatus state="error" label="Failed" />
|
|
<div className="w-64"><SearchPill value={q} onChange={setQ} placeholder="Search orders…" /></div>
|
|
{['pending', 'confirmed', 'delivered', 'cancelled'].map((s) => (
|
|
<Pill key={s} active={tab === s} color={statusColor(ORDER_STATUS, s)} onClick={() => setTab(s)} count={12}>
|
|
{s}
|
|
</Pill>
|
|
))}
|
|
<Tooltip content="Astryx tooltip — now opens on keyboard focus too.">
|
|
<span className="text-xs font-bold underline decoration-dotted">hover me</span>
|
|
</Tooltip>
|
|
<button className="text-xs font-bold underline" onClick={() => setDrawer(true)}>open drawer</button>
|
|
</div>
|
|
</FilterBar>
|
|
|
|
<TableShell head={['Order', 'Status', 'Distance', 'Amount', 'Placed']} minWidth={720}>
|
|
{[
|
|
{ id: '#1043', s: 'delivered', km: '4.2', amt: '₹248' },
|
|
{ id: '#1041', s: 'cancelled', km: '1.1', amt: '₹89' },
|
|
{ id: '#1040', s: 'pending', km: '7.8', amt: '₹156' },
|
|
].map((r) => (
|
|
<tr key={r.id}>
|
|
<td className="px-4 py-3 font-bold">{r.id}</td>
|
|
<td className="px-4 py-3"><StatusChip label={r.s} color={statusColor(ORDER_STATUS, r.s)} /></td>
|
|
<td className="px-4 py-3 text-right"><MetricPill color={statusColor(DELIVERY_STATUS, 'active')}>{r.km} km</MetricPill></td>
|
|
<td className="px-4 py-3 text-right font-mono font-bold">{r.amt}</td>
|
|
<td className="px-4 py-3 text-right"><StampCell date="12 Aug" time="10:42" /></td>
|
|
</tr>
|
|
))}
|
|
</TableShell>
|
|
|
|
<Card className="p-4">
|
|
<div className="text-xs font-bold mb-2">Skeletons</div>
|
|
<div className="flex gap-2">
|
|
<Skeleton className="h-4 w-24" />
|
|
<Skeleton className="h-4 w-40" />
|
|
<Skeleton className="h-4 w-16" />
|
|
</div>
|
|
</Card>
|
|
|
|
<Card className="p-4">
|
|
<div className="text-xs font-bold mb-2">Phase 5 — overlays & toasts</div>
|
|
<div className="flex gap-3">
|
|
<button className="text-xs font-bold underline" onClick={() => setConfirm(true)}>open confirm dialog</button>
|
|
<button className="text-xs font-bold underline" onClick={() => notifyOk('Published to all outlets')}>toast: ok</button>
|
|
<button className="text-xs font-bold underline" onClick={() => notifyFail(new Error('Set a price before publishing.'))}>toast: error</button>
|
|
</div>
|
|
</Card>
|
|
|
|
<ConfirmModal
|
|
isOpen={confirm}
|
|
title="Unpublish product"
|
|
message="This removes it from every outlet under the tenant. Stock and history are kept."
|
|
confirmText="Unpublish"
|
|
isDestructive
|
|
onConfirm={() => { setConfirm(false); notifyOk('Unpublished from 3 outlets'); }}
|
|
onCancel={() => setConfirm(false)}
|
|
/>
|
|
|
|
<SlideDrawer isOpen={drawer} onClose={() => setDrawer(false)} title="Order #1043">
|
|
<p className="text-sm">Escape should close this, and focus should return to the button that opened it.</p>
|
|
</SlideDrawer>
|
|
</div>
|
|
);
|
|
}
|