@@ -49,7 +49,7 @@ export function PosForm({ students, studentIdsWithTransactions, userName }: PosF
4949 const [ cardUid , setCardUid ] = useState < string > ( "" ) ;
5050 const [ amount , setAmount ] = useState ( "" ) ;
5151 const [ description , setDescription ] = useState ( "" ) ;
52- const [ staff , setStaff ] = useState ( "" ) ;
52+ const [ staff , setStaff ] = useState ( userName || "" ) ;
5353 const [ error , setError ] = useState ( "" ) ;
5454 const [ success , setSuccess ] = useState ( "" ) ;
5555 const [ transactionId , setTransactionId ] = useState < number | null > ( null ) ;
@@ -64,30 +64,16 @@ export function PosForm({ students, studentIdsWithTransactions, userName }: PosF
6464 selectedReaderRef . current = selectedReader ;
6565 } , [ selectedReader ] ) ;
6666
67- // Auto-fill staff name with current user's name
68- useEffect ( ( ) => {
69- if ( userName && ! staff ) {
70- setStaff ( userName ) ;
71- }
72- } , [ userName , staff ] ) ;
73-
7467 // Dialog state for Tap mode
7568 const [ dialogOpen , setDialogOpen ] = useState ( false ) ;
7669 const [ dialogStudentId , setDialogStudentId ] = useState < number > ( 0 ) ;
7770 const [ dialogCardUid , setDialogCardUid ] = useState < string > ( "" ) ;
7871 const [ dialogAmount , setDialogAmount ] = useState ( "" ) ;
7972 const [ dialogDescription , setDialogDescription ] = useState ( "" ) ;
80- const [ dialogStaff , setDialogStaff ] = useState ( "" ) ;
73+ const [ dialogStaff , setDialogStaff ] = useState ( userName || "" ) ;
8174 const [ dialogError , setDialogError ] = useState ( "" ) ;
8275 const [ dialogLoading , setDialogLoading ] = useState ( false ) ;
8376
84- // Auto-fill dialog staff name with current user's name
85- useEffect ( ( ) => {
86- if ( userName && ! dialogStaff ) {
87- setDialogStaff ( userName ) ;
88- }
89- } , [ userName , dialogStaff ] ) ;
90-
9177 // Enrollment dialog state for unknown cards
9278 const [ enrollDialogOpen , setEnrollDialogOpen ] = useState ( false ) ;
9379 const [ enrollCardUid , setEnrollCardUid ] = useState < string > ( "" ) ;
@@ -107,6 +93,43 @@ export function PosForm({ students, studentIdsWithTransactions, userName }: PosF
10793 const readerLabel =
10894 selectedReader === "reader-1" ? "Reader 1 (USB0)" : "Reader 2 (USB1)" ;
10995
96+ const handleCardTap = async ( uid : string ) => {
97+ setCardUid ( uid ) ;
98+
99+ // Look up the card to find the student
100+ const cardResult = await getCardByUidAction ( uid ) ;
101+
102+ if ( ! cardResult . success || ! cardResult . data ) {
103+ // Card not found - offer enrollment
104+ setEnrollCardUid ( uid ) ;
105+ setEnrollName ( "" ) ;
106+ setEnrollError ( "" ) ;
107+ setEnrollDialogOpen ( true ) ;
108+ return ;
109+ }
110+
111+ if ( cardResult . data . status !== "active" ) {
112+ setError ( `Card ${ uid } is not active` ) ;
113+ return ;
114+ }
115+
116+ const student = students . find ( ( s ) => s . id === cardResult . data . student_id ) ;
117+
118+ if ( ! student ) {
119+ setError ( "Student not found" ) ;
120+ return ;
121+ }
122+
123+ // Tap-first mode: open dialog for amount entry
124+ setDialogStudentId ( student . id ) ;
125+ setDialogCardUid ( uid ) ;
126+ setDialogAmount ( "" ) ;
127+ setDialogDescription ( "" ) ;
128+ setDialogStaff ( userName ) ;
129+ setDialogError ( "" ) ;
130+ setDialogOpen ( true ) ;
131+ } ;
132+
110133 // WebSocket connection for tap events (only in tap-first mode)
111134 const { isConnected, statusMessage : tapStatus } = useNFCWebSocket ( {
112135 lane : selectedReader ,
@@ -163,42 +186,6 @@ export function PosForm({ students, studentIdsWithTransactions, userName }: PosF
163186 }
164187 } , [ searchParams ] ) ;
165188
166- const handleCardTap = async ( uid : string ) => {
167- setCardUid ( uid ) ;
168-
169- // Look up the card to find the student
170- const cardResult = await getCardByUidAction ( uid ) ;
171-
172- if ( ! cardResult . success || ! cardResult . data ) {
173- // Card not found - offer enrollment
174- setEnrollCardUid ( uid ) ;
175- setEnrollName ( "" ) ;
176- setEnrollError ( "" ) ;
177- setEnrollDialogOpen ( true ) ;
178- return ;
179- }
180-
181- if ( cardResult . data . status !== "active" ) {
182- setError ( `Card ${ uid } is not active` ) ;
183- return ;
184- }
185-
186- const student = students . find ( ( s ) => s . id === cardResult . data . student_id ) ;
187-
188- if ( ! student ) {
189- setError ( "Student not found" ) ;
190- return ;
191- }
192-
193- // Tap-first mode: open dialog for amount entry
194- setDialogStudentId ( student . id ) ;
195- setDialogCardUid ( uid ) ;
196- setDialogAmount ( "" ) ;
197- setDialogDescription ( "" ) ;
198- setDialogStaff ( userName ) ;
199- setDialogError ( "" ) ;
200- setDialogOpen ( true ) ;
201- } ;
202189
203190 const handleEnrollCard = async ( action : 'checkout' | 'topup' | 'none' ) => {
204191 setEnrollError ( "" ) ;
@@ -446,6 +433,12 @@ export function PosForm({ students, studentIdsWithTransactions, userName }: PosF
446433 step = "0.1"
447434 value = { dialogAmount }
448435 onChange = { ( e ) => setDialogAmount ( e . target . value ) }
436+ onWheel = { ( e ) => e . currentTarget . blur ( ) }
437+ onKeyDown = { ( e ) => {
438+ if ( e . key === "ArrowUp" || e . key === "ArrowDown" ) {
439+ e . preventDefault ( ) ;
440+ }
441+ } }
449442 placeholder = "Enter amount (e.g., 5.5)"
450443 required
451444 autoFocus
@@ -655,6 +648,12 @@ export function PosForm({ students, studentIdsWithTransactions, userName }: PosF
655648 step = "0.1"
656649 value = { amount }
657650 onChange = { ( e ) => setAmount ( e . target . value ) }
651+ onWheel = { ( e ) => e . currentTarget . blur ( ) }
652+ onKeyDown = { ( e ) => {
653+ if ( e . key === "ArrowUp" || e . key === "ArrowDown" ) {
654+ e . preventDefault ( ) ;
655+ }
656+ } }
658657 placeholder = "Enter amount (e.g., 5.5)"
659658 required
660659 className = "text-base h-12"
0 commit comments