From 3f9e125412cb551f1b2a7c8d6cdada4aabffb3e2 Mon Sep 17 00:00:00 2001 From: ryan Date: Sun, 5 Apr 2026 19:51:39 +0000 Subject: [PATCH 1/3] fix: move PIN warning banner to authenticated layout for all pages Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/admin/src/routes/_authenticated.tsx | 22 ++++++++++++++++++- .../src/routes/_authenticated/profile.tsx | 20 +---------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/admin/src/routes/_authenticated.tsx b/packages/admin/src/routes/_authenticated.tsx index d790e1c..f22f845 100644 --- a/packages/admin/src/routes/_authenticated.tsx +++ b/packages/admin/src/routes/_authenticated.tsx @@ -8,7 +8,8 @@ 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, ShoppingCart } 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, AlertTriangle } from 'lucide-react' +import { Alert, AlertTitle, AlertDescription } from '@/components/ui/alert' export const Route = createFileRoute('/_authenticated')({ beforeLoad: () => { @@ -112,6 +113,13 @@ function AuthenticatedLayout() { const setPermissions = useAuthStore((s) => s.setPermissions) const permissionsLoaded = useAuthStore((s) => s.permissionsLoaded) + // Fetch profile for PIN warning + const { data: profile } = useQuery(queryOptions({ + queryKey: ['auth', 'me'], + queryFn: () => api.get<{ hasPin: boolean }>('/v1/auth/me'), + enabled: !!useAuthStore.getState().token, + })) + // Fetch permissions on mount const { data: permData } = useQuery({ ...myPermissionsOptions(), @@ -263,6 +271,18 @@ function AuthenticatedLayout() {
+ {profile && !profile.hasPin && ( + + + POS PIN not set + + You need a PIN to use the Point of Sale.{' '} + + Set your PIN + + + + )}
diff --git a/packages/admin/src/routes/_authenticated/profile.tsx b/packages/admin/src/routes/_authenticated/profile.tsx index e938c62..a651f15 100644 --- a/packages/admin/src/routes/_authenticated/profile.tsx +++ b/packages/admin/src/routes/_authenticated/profile.tsx @@ -12,8 +12,7 @@ import { Label } from '@/components/ui/label' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Separator } from '@/components/ui/separator' import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs' -import { Alert, AlertTitle, AlertDescription } from '@/components/ui/alert' -import { Sun, Moon, Monitor, AlertTriangle } from 'lucide-react' +import { Sun, Moon, Monitor } from 'lucide-react' import { toast } from 'sonner' import { AvatarUpload } from '@/components/shared/avatar-upload' @@ -53,23 +52,6 @@ function ProfilePage() {

Profile

- {profile && !profile.hasPin && ( - - - POS PIN not set - - You need a PIN to use the Point of Sale.{' '} - - Set your PIN - - - - )} - Account From 2cd646ddea2cd3d23e6703ede12b0f9bc802bd57 Mon Sep 17 00:00:00 2001 From: ryan Date: Sun, 5 Apr 2026 19:57:31 +0000 Subject: [PATCH 2/3] fix: remove unused Link import from profile page Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/admin/src/routes/_authenticated/profile.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/admin/src/routes/_authenticated/profile.tsx b/packages/admin/src/routes/_authenticated/profile.tsx index a651f15..cbf322c 100644 --- a/packages/admin/src/routes/_authenticated/profile.tsx +++ b/packages/admin/src/routes/_authenticated/profile.tsx @@ -1,4 +1,4 @@ -import { createFileRoute, Link } from '@tanstack/react-router' +import { createFileRoute } from '@tanstack/react-router' import { useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { queryOptions } from '@tanstack/react-query' From 924a28e201b9723d26c6954c48ff1a72c3539c73 Mon Sep 17 00:00:00 2001 From: ryan Date: Sun, 5 Apr 2026 20:01:14 +0000 Subject: [PATCH 3/3] feat: forced PIN setup modal on all authenticated pages Replaces the alert banner with a blocking modal dialog that requires users to set a PIN before they can use the app. Cannot be dismissed. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/admin/src/routes/_authenticated.tsx | 73 ++++++++++++++++---- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/packages/admin/src/routes/_authenticated.tsx b/packages/admin/src/routes/_authenticated.tsx index f22f845..64367af 100644 --- a/packages/admin/src/routes/_authenticated.tsx +++ b/packages/admin/src/routes/_authenticated.tsx @@ -1,5 +1,5 @@ import { createFileRoute, Outlet, Link, redirect, useRouter } from '@tanstack/react-router' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query' import { queryOptions } from '@tanstack/react-query' import { useEffect, useState } from 'react' import { api } from '@/lib/api-client' @@ -8,8 +8,10 @@ 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, ShoppingCart, AlertTriangle } from 'lucide-react' -import { Alert, AlertTitle, AlertDescription } from '@/components/ui/alert' +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' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { toast } from 'sonner' export const Route = createFileRoute('/_authenticated')({ beforeLoad: () => { @@ -105,6 +107,58 @@ function NavGroup({ label, children, collapsed }: { label: string; children: Rea ) } +function SetPinModal() { + const queryClient = useQueryClient() + const [pin, setPin] = useState('') + const [confirmPin, setConfirmPin] = useState('') + const [error, setError] = useState('') + + const setPinMutation = useMutation({ + mutationFn: () => api.post('/v1/auth/set-pin', { pin }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['auth', 'me'] }) + toast.success('PIN set successfully') + }, + onError: (err) => setError(err.message), + }) + + function handleSubmit(e: React.FormEvent) { + e.preventDefault() + setError('') + if (pin.length < 4 || pin.length > 6) { setError('PIN must be 4-6 digits'); return } + if (!/^\d+$/.test(pin)) { setError('PIN must be digits only'); return } + if (pin !== confirmPin) { setError('PINs do not match'); return } + setPinMutation.mutate() + } + + return ( +
+
+

Set your POS PIN

+

+ A PIN is required to use the Point of Sale. Choose a 4-6 digit PIN you'll use to unlock the terminal. +

+
+
+
+ + setPin(e.target.value)} placeholder="****" autoFocus /> +
+
+ + setConfirmPin(e.target.value)} placeholder="****" /> +
+
+ {error &&

{error}

} + +
+
+
+ ) +} + function AuthenticatedLayout() { const router = useRouter() const user = useAuthStore((s) => s.user) @@ -271,18 +325,7 @@ function AuthenticatedLayout() {
- {profile && !profile.hasPin && ( - - - POS PIN not set - - You need a PIN to use the Point of Sale.{' '} - - Set your PIN - - - - )} + {profile && !profile.hasPin && }