feat: add POS register screen with full-screen touch-optimized layout

Standalone register at /pos bypassing the admin sidebar layout:
- Two-panel layout: product search/grid (60%) + cart/payment (40%)
- Product search with barcode scan support (UPC lookup on Enter)
- Custom item entry dialog for ad-hoc items
- Cart with line items, tax, totals, and remove-item support
- Payment dialogs: cash (quick amounts + change calc), card, check
- Drawer open/close with balance reconciliation and over/short
- Auto-creates pending transaction on first item added
- POS link added to admin sidebar nav (module-gated)
- Zustand store for POS session state, React Query for server data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ryan
2026-04-04 19:29:37 +00:00
parent bd5f0ca511
commit bd3a25aa1c
11 changed files with 1180 additions and 1 deletions

View File

@@ -8,7 +8,7 @@ import { myPermissionsOptions } from '@/api/rbac'
import { moduleListOptions } from '@/api/modules'
import { Avatar } from '@/components/shared/avatar-upload'
import { Button } from '@/components/ui/button'
import { Users, UserRound, HelpCircle, Shield, UserCog, LogOut, User, Wrench, Package, ClipboardList, FolderOpen, KeyRound, Settings, PanelLeftClose, PanelLeft, CalendarDays, GraduationCap, CalendarRange, BookOpen, BookMarked, Package2, Tag, Truck } from 'lucide-react'
import { Users, UserRound, HelpCircle, Shield, UserCog, LogOut, User, Wrench, Package, ClipboardList, FolderOpen, KeyRound, Settings, PanelLeftClose, PanelLeft, CalendarDays, GraduationCap, CalendarRange, BookOpen, BookMarked, Package2, Tag, Truck, ShoppingCart } from 'lucide-react'
export const Route = createFileRoute('/_authenticated')({
beforeLoad: () => {
@@ -145,6 +145,7 @@ function AuthenticatedLayout() {
const canViewLessons = !permissionsLoaded || hasPermission('lessons.view')
const canViewInventory = !permissionsLoaded || hasPermission('inventory.view')
const canViewUsers = !permissionsLoaded || hasPermission('users.view')
const canViewPOS = !permissionsLoaded || hasPermission('pos.view')
const [collapsed, setCollapsed] = useState(false)
@@ -173,6 +174,11 @@ function AuthenticatedLayout() {
{/* Scrollable nav links */}
<div className="flex-1 overflow-y-auto px-2 space-y-1 scrollbar-thin">
{isModuleEnabled('pos') && canViewPOS && (
<div className="mb-2">
<NavLink to="/pos" icon={<ShoppingCart className="h-4 w-4" />} label="Point of Sale" collapsed={collapsed} />
</div>
)}
{canViewAccounts && (
<NavGroup label="Customers" collapsed={collapsed}>
<NavLink to="/accounts" icon={<Users className="h-4 w-4" />} label="Accounts" collapsed={collapsed} />