feat(showcase): add PouchDB sample component and storage page
- Implemented PouchSample component for managing POS configurations and item inventories using PouchDB. - Created StoragePage to encapsulate the PouchSample component. - Added UI components page with various UI elements including buttons, forms, and data grids. - Defined Electron type declarations for printing and auto-update functionalities. - Extended event registry with custom application events for printing and stock updates. - Configured Vite for the showcase application with React and Tailwind CSS support. - Updated package.json and pnpm-lock.yaml to include necessary dependencies for the showcase app.
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import {
|
||||
Card,
|
||||
Title,
|
||||
Text,
|
||||
Stack,
|
||||
Badge,
|
||||
Divider,
|
||||
} from '@repo/ui/components';
|
||||
|
||||
// ── Showcase Components ──────────────────────────────────────────
|
||||
import { CashierUI } from './printer/cashier.ui';
|
||||
import { PrinterListener } from './printer/printer.listener';
|
||||
import { LiveStockGrid } from './stock-grid/live-stock-grid.ui';
|
||||
import { ProfileSettingsUI } from './auth-sync/profile-settings.ui';
|
||||
import { StorageSyncListener } from './auth-sync/storage-sync.listener';
|
||||
import { DEVICE_EVENTS, AUTH_EVENTS } from '../../../../core/constants/events';
|
||||
|
||||
// ─── Events Demo Page ───────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Orchestrator page for all three Event Bus showcase demos.
|
||||
*
|
||||
* This component is completely self-contained within the
|
||||
* `events-demo/` folder and does not leak state or side-effects
|
||||
* into the rest of the application.
|
||||
*/
|
||||
export default function EventsDemoPage() {
|
||||
// ── Showcase 1: Printer status feedback ──────────────────────
|
||||
const [printerLog, setPrinterLog] = useState<string[]>([]);
|
||||
|
||||
// ── Showcase 3: Storage sync status feedback ─────────────────
|
||||
const [syncLog, setSyncLog] = useState<string[]>([]);
|
||||
|
||||
// ── Render counter to prove this parent is stable ────────────
|
||||
const renderCount = useRef(0);
|
||||
renderCount.current += 1;
|
||||
|
||||
// Keep log sizes bounded
|
||||
useEffect(() => {
|
||||
if (printerLog.length > 20) setPrinterLog((prev) => prev.slice(-20));
|
||||
}, [printerLog.length]);
|
||||
|
||||
useEffect(() => {
|
||||
if (syncLog.length > 20) setSyncLog((prev) => prev.slice(-20));
|
||||
}, [syncLog.length]);
|
||||
|
||||
return (
|
||||
<Stack gap="xl">
|
||||
<div>
|
||||
<Title order={2}>🔌 Event Bus Showcase</Title>
|
||||
<Text size="sm" c="dimmed">
|
||||
Three real-world demos of <code>@repo/core-events</code> — zero coupling, strict typing, high performance.
|
||||
</Text>
|
||||
<Badge color="brand" variant="light" mt="xs">
|
||||
Parent render count: {renderCount.current}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
{/* ═══════════════════════════════════════════════════════════
|
||||
SHOWCASE 1: Cross-Platform Printer Abstraction
|
||||
═══════════════════════════════════════════════════════════ */}
|
||||
<Card withBorder shadow="sm" radius="md" p="md">
|
||||
<Title order={4} mb="xs">
|
||||
🖨️ Showcase 1: Cross-Platform Printer Abstraction
|
||||
</Title>
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
The CashierUI publishes a <code>{DEVICE_EVENTS.PRINT_RECEIPT}</code> event.
|
||||
The PrinterListener listens for it and simulates interacting with a physical printer.
|
||||
</Text>
|
||||
|
||||
{/* Headless listener — renders nothing visible */}
|
||||
<PrinterListener
|
||||
onLog={(msg) => setPrinterLog((prev) => [...prev, `[${new Date().toLocaleTimeString()}] ${msg}`])}
|
||||
/>
|
||||
|
||||
<CashierUI />
|
||||
|
||||
{printerLog.length > 0 && (
|
||||
<>
|
||||
<Divider my="sm" />
|
||||
<Text size="sm" fw={600}>
|
||||
📋 Printer Log:
|
||||
</Text>
|
||||
<div
|
||||
style={{
|
||||
maxHeight: 120,
|
||||
overflow: 'auto',
|
||||
fontSize: 12,
|
||||
fontFamily: 'monospace',
|
||||
background: 'var(--mantine-color-dark-7, #1a1b1e)',
|
||||
color: 'var(--mantine-color-green-4, #69db7c)',
|
||||
padding: 8,
|
||||
borderRadius: 6,
|
||||
}}
|
||||
>
|
||||
{printerLog.map((line, i) => (
|
||||
<div key={i}>{line}</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
{/* ═══════════════════════════════════════════════════════════
|
||||
SHOWCASE 2: Extreme Performance — Live Stock Grid
|
||||
═══════════════════════════════════════════════════════════ */}
|
||||
<Card withBorder shadow="sm" radius="md" p="md">
|
||||
<Title order={4} mb="xs">
|
||||
📈 Showcase 2: High-Frequency Real-Time Data (50 updates/sec)
|
||||
</Title>
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
A mock WebSocket fires <code>WS:STOCK_UPDATE</code> every 20ms.
|
||||
Each StockRow subscribes to the global event but only updates when{' '}
|
||||
<code>payload.id === row.id</code>. The parent grid never re-renders.
|
||||
</Text>
|
||||
|
||||
<LiveStockGrid />
|
||||
</Card>
|
||||
|
||||
{/* ═══════════════════════════════════════════════════════════
|
||||
SHOWCASE 3: Auth/Profile → IndexedDB Sync
|
||||
═══════════════════════════════════════════════════════════ */}
|
||||
<Card withBorder shadow="sm" radius="md" p="md">
|
||||
<Title order={4} mb="xs">
|
||||
💾 Showcase 3: Auth/Profile Sync with <code>@repo/core-storage</code>
|
||||
</Title>
|
||||
<Text size="sm" c="dimmed" mb="md">
|
||||
ProfileSettingsUI publishes <code>{AUTH_EVENTS.PROFILE_UPDATED}</code>.
|
||||
StorageSyncListener silently catches it in the background and saves to IndexedDB via <code>secureIndexedDB</code>.
|
||||
</Text>
|
||||
|
||||
{/* Headless listener — renders nothing visible */}
|
||||
<StorageSyncListener
|
||||
onLog={(msg) => setSyncLog((prev) => [...prev, `[${new Date().toLocaleTimeString()}] ${msg}`])}
|
||||
/>
|
||||
|
||||
<ProfileSettingsUI />
|
||||
|
||||
{syncLog.length > 0 && (
|
||||
<>
|
||||
<Divider my="sm" />
|
||||
<Text size="sm" fw={600}>
|
||||
📋 Storage Sync Log:
|
||||
</Text>
|
||||
<div
|
||||
style={{
|
||||
maxHeight: 120,
|
||||
overflow: 'auto',
|
||||
fontSize: 12,
|
||||
fontFamily: 'monospace',
|
||||
background: 'var(--mantine-color-dark-7, #1a1b1e)',
|
||||
color: 'var(--mantine-color-blue-4, #4dabf7)',
|
||||
padding: 8,
|
||||
borderRadius: 6,
|
||||
}}
|
||||
>
|
||||
{syncLog.map((line, i) => (
|
||||
<div key={i}>{line}</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user