/** * @license * SPDX-License-Identifier: Apache-2.0 */ import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'motion/react'; import { LayoutDashboard, ShoppingCart, Package, Users, Megaphone, Settings, Activity, CloudLightning, Wifi, WifiOff, Clock, PhoneCall, UserCircle } from 'lucide-react'; import { TireProduct, StockHistoryItem, StaffUser, Invoice, SystemSettings, StaffRole } from './types'; import { INITIAL_PRODUCTS, INITIAL_HISTORY, INITIAL_STAFF, INITIAL_INVOICES, INITIAL_SETTINGS } from './initialData'; // Subcomponents import Dashboard from './components/Dashboard'; import InvoiceGenerator from './components/InvoiceGenerator'; import InventoryManager from './components/InventoryManager'; import StaffManager from './components/StaffManager'; import SocialPromoter from './components/SocialPromoter'; import SettingsComponent from './components/Settings'; export default function App() { const [activeTab, setActiveTab] = useState('dashboard'); const [isOnline, setIsOnline] = useState(true); const [currentTime, setCurrentTime] = useState(new Date()); // Core database state hooks const [settings, setSettings] = useState(INITIAL_SETTINGS); const [products, setProducts] = useState(INITIAL_PRODUCTS); const [invoices, setInvoices] = useState(INITIAL_INVOICES); const [history, setHistory] = useState(INITIAL_HISTORY); const [staffList, setStaffList] = useState(INITIAL_STAFF); const [currentStaff, setCurrentStaff] = useState(INITIAL_STAFF[1]); // Zin Brother as default cashier // Invoice review overlay trigger state const [selectedInvoiceForView, setSelectedInvoiceForView] = useState(null); // Initialize and load from local storage if existing useEffect(() => { // Clock tick const timer = setInterval(() => setCurrentTime(new Date()), 1000); const storedSettings = localStorage.getItem('HBT_SETTINGS'); const storedProducts = localStorage.getItem('HBT_PRODUCTS'); const storedInvoices = localStorage.getItem('HBT_INVOICES'); const storedHistory = localStorage.getItem('HBT_HISTORY'); const storedStaff = localStorage.getItem('HBT_STAFF'); const storedCurrent = localStorage.getItem('HBT_CURRENT_STAFF'); if (storedSettings) setSettings(JSON.parse(storedSettings)); if (storedProducts) setProducts(JSON.parse(storedProducts)); if (storedInvoices) setInvoices(JSON.parse(storedInvoices)); if (storedHistory) setHistory(JSON.parse(storedHistory)); if (storedStaff) setStaffList(JSON.parse(storedStaff)); if (storedCurrent) { const parsedCurrent = JSON.parse(storedCurrent); // Ensure currentStaff matches the parsed currentStaff safely setCurrentStaff(parsedCurrent); } else { setCurrentStaff(INITIAL_STAFF[1]); // Zain Brother manager } return () => clearInterval(timer); }, []); // Sync utilities to persistence const syncToLocalStorage = (key: string, data: any) => { localStorage.setItem(key, JSON.stringify(data)); }; // State Adjustments multipliers const handleUpdateSettings = (updated: SystemSettings) => { setSettings(updated); syncToLocalStorage('HBT_SETTINGS', updated); }; // Triggered from Dashboard replenishment alarms const handleQuickAddStock = (productId: string, amount: number) => { const adjustedProducts = products.map(p => { if (p.id === productId) { const resultingStock = p.stock + amount; // Append history log immediately const logItem: StockHistoryItem = { id: 'log_' + Math.random().toString(36).substr(2, 9), productId: p.id, productLabel: `${p.brand} ${p.model} (${p.size})`, dateTime: new Date().toISOString(), type: 'STOCK_IN', quantity: amount, resultingStock, adjustedBy: `${currentStaff.name} (${currentStaff.role})`, reason: `Quick Restock of Alarm: Restocked cargo pallet.` }; const updatedHistory = [logItem, ...history]; setHistory(updatedHistory); syncToLocalStorage('HBT_HISTORY', updatedHistory); return { ...p, stock: resultingStock }; } return p; }); setProducts(adjustedProducts); syncToLocalStorage('HBT_PRODUCTS', adjustedProducts); }; // Triggered from InventoryManager manual configurations const handleAdjustProductStock = ( productId: string, quantityChange: number, type: StockHistoryItem['type'], reason: string ) => { const adjustedProducts = products.map(p => { if (p.id === productId) { const resultingStock = p.stock + quantityChange; // Create log item const logItem: StockHistoryItem = { id: 'log_' + Math.random().toString(36).substr(2, 9), productId: p.id, productLabel: `${p.brand} ${p.model} (${p.size})`, dateTime: new Date().toISOString(), type, quantity: Math.abs(quantityChange), resultingStock, adjustedBy: `${currentStaff.name} (${currentStaff.role})`, reason }; const updatedHistory = [logItem, ...history]; setHistory(updatedHistory); syncToLocalStorage('HBT_HISTORY', updatedHistory); return { ...p, stock: resultingStock }; } return p; }); setProducts(adjustedProducts); syncToLocalStorage('HBT_PRODUCTS', adjustedProducts); }; const handleAddNewProduct = (prod: TireProduct) => { const updatedProducts = [prod, ...products]; setProducts(updatedProducts); syncToLocalStorage('HBT_PRODUCTS', updatedProducts); // Write initial STOCK_IN history entry const logItem: StockHistoryItem = { id: 'log_' + Math.random().toString(36).substr(2, 9), productId: prod.id, productLabel: `${prod.brand} ${prod.model} (${prod.size})`, dateTime: new Date().toISOString(), type: 'STOCK_IN', quantity: prod.stock, resultingStock: prod.stock, adjustedBy: `${currentStaff.name} (${currentStaff.role})`, reason: `First inventory system initialization of tyre profile SKU.` }; const updatedHistory = [logItem, ...history]; setHistory(updatedHistory); syncToLocalStorage('HBT_HISTORY', updatedHistory); }; const handleDeleteProduct = (productId: string) => { const updatedProducts = products.filter(p => p.id !== productId); setProducts(updatedProducts); syncToLocalStorage('HBT_PRODUCTS', updatedProducts); }; // Adding Client Invoice automatically reduces matching tire quantities and writes logs const handleAddInvoice = (newInv: Invoice) => { // Append invoice const updatedInvoices = [...invoices, newInv]; setInvoices(updatedInvoices); syncToLocalStorage('HBT_INVOICES', updatedInvoices); // Iterate items and decrease physical stock counts let revisedProducts = [...products]; let newLogs: StockHistoryItem[] = []; newInv.items.forEach((item) => { revisedProducts = revisedProducts.map(p => { if (p.id === item.productId) { const resultingStock = p.stock - item.quantity; // Construct checkout history block const logItem: StockHistoryItem = { id: 'log_' + Math.random().toString(36).substr(2, 9), productId: p.id, productLabel: `${p.brand} ${p.model} (${p.size})`, dateTime: new Date().toISOString(), type: 'STOCK_OUT', quantity: item.quantity, resultingStock, adjustedBy: `${currentStaff.name} (${currentStaff.role})`, reason: `Retail Invoice checkout sales: Ref ${newInv.invoiceNumber}` }; newLogs.push(logItem); return { ...p, stock: resultingStock }; } return p; }); }); const revisedHistory = [...newLogs, ...history]; setHistory(revisedHistory); setProducts(revisedProducts); syncToLocalStorage('HBT_PRODUCTS', revisedProducts); syncToLocalStorage('HBT_HISTORY', revisedHistory); }; // Staff managers const handleAddStaffMember = (newUser: StaffUser) => { const updated = [...staffList, newUser]; setStaffList(updated); syncToLocalStorage('HBT_STAFF', updated); }; const handleToggleStaffStatus = (staffId: string) => { const updated = staffList.map(s => s.id === staffId ? { ...s, active: !s.active } : s ); setStaffList(updated); syncToLocalStorage('HBT_STAFF', updated); }; const handleUpdateStaffRole = (staffId: string, role: StaffRole) => { const updated = staffList.map(s => s.id === staffId ? { ...s, role } : s ); setStaffList(updated); syncToLocalStorage('HBT_STAFF', updated); }; const handleSetCurrentStaff = (staff: StaffUser) => { setCurrentStaff(staff); syncToLocalStorage('HBT_CURRENT_STAFF', staff); }; // Decrypted Restore logic const handleRestoreDatabase = (decoded: { settings: SystemSettings; products: any[]; invoices: any[]; history: any[]; staff: any[]; }) => { setSettings(decoded.settings); setProducts(decoded.products); setInvoices(decoded.invoices); setHistory(decoded.history); setStaffList(decoded.staff); // Save and persist all entries syncToLocalStorage('HBT_SETTINGS', decoded.settings); syncToLocalStorage('HBT_PRODUCTS', decoded.products); syncToLocalStorage('HBT_INVOICES', decoded.invoices); syncToLocalStorage('HBT_HISTORY', decoded.history); syncToLocalStorage('HBT_STAFF', decoded.staff); // Set Owner as current operator safely if there's any owner in the backup list const firstOwner = decoded.staff.find(s => s.role === 'owner' && s.active); if (firstOwner) { setCurrentStaff(firstOwner); syncToLocalStorage('HBT_CURRENT_STAFF', firstOwner); } }; // Factory defaults const handleClearCacheToDefault = () => { localStorage.clear(); }; return (
{/* 1. COLLAPSIBLE OR RESPONSIVE STATIC SIDEBAR */} {/* 2. CORE WORKSPACE: HEADER + SCROLLABLE PAGE VIEWS */}
{/* Top Navbar */}
{/* Left info */}
SECURE CASHIER LEDGER | Store Support: {settings.shopPhone}
{/* Right systems specs */}
{/* Real-time Clock */}
{currentTime.toLocaleTimeString()}
{/* Offline vs Online Beacons and alarms */} {isOnline ? ( VAULT OK ) : ( AIR-GAPPED LOCAL )}
{/* Tab Pages dispatcher Router panel */}
{activeTab === 'dashboard' && ( { setSelectedInvoiceForView(inv); setActiveTab('invoices'); }} /> )} {activeTab === 'invoices' && ( )} {activeTab === 'inventory' && ( )} {activeTab === 'staff' && ( )} {activeTab === 'social' && ( )} {activeTab === 'settings' && ( setIsOnline(!isOnline)} onRestoreDatabase={handleRestoreDatabase} onClearCacheToDefault={handleClearCacheToDefault} activeProducts={products} activeInvoices={invoices} activeHistory={history} activeStaff={staffList} /> )}
); }