@@ -6,8 +6,8 @@ import QRCodeScanner from "@/components/QRCodeScanner";
6
6
import { SessionTile } from "@/components/session" ;
7
7
import { SessionService } from "@/services/SessionService" ;
8
8
import { getUserFromQRCode } from "@/utils/utils" ;
9
- import { Ghost , UserMinus , UserPlus , Users } from "lucide-react" ;
10
- import { ReactNode , useEffect , useState } from "react" ;
9
+ import { Ghost , ScanEye , UserMinus , UserPlus , Users } from "lucide-react" ;
10
+ import { ReactNode , useCallback , useEffect , useRef , useState } from "react" ;
11
11
12
12
interface SessionCheckInScannerProps {
13
13
cannonToken : string ;
@@ -25,58 +25,105 @@ export default function SessionCheckInScanner({
25
25
const [ topCard , setTopCard ] = useState < ReactNode | undefined > ( ) ;
26
26
const [ bottomCard , setBottomCard ] = useState < ReactNode | undefined > ( ) ;
27
27
const [ statusCard , setStatusCard ] = useState < ReactNode | undefined > ( ) ;
28
- let cardsTimeout : NodeJS . Timeout ;
28
+ const [ unregisteredUsersCounter , setUnregisteredUsersCounter ] =
29
+ useState < number > ( 0 ) ;
30
+ const cardsTimeout = useRef < NodeJS . Timeout > ( ) ;
31
+ const updateSessionStatusTimeout = useRef < NodeJS . Timeout > ( ) ;
29
32
30
- async function handleQRCodeScanned ( data : string ) {
31
- const scannedUser = getUserFromQRCode ( data ) ;
32
- cardsTimeout && clearTimeout ( cardsTimeout ) ;
33
-
34
- if ( scannedUser ) {
35
- setBottomCard (
36
- < ListCard img = { scannedUser . img } title = { scannedUser . name } /> ,
37
- ) ;
33
+ const sessionUpdate = useCallback (
34
+ async ( data ?: { users ?: string [ ] ; unregisteredUsers ?: number } ) => {
38
35
const sessionStatus = await SessionService . checkInUser (
39
36
cannonToken ,
40
37
sinfoSession . id ,
41
- {
42
- users : [ scannedUser . id ] ,
43
- } ,
38
+ data || { } ,
44
39
) ;
45
- if ( ! sessionStatus )
46
- setStatusCard (
47
- < MessageCard
48
- type = "danger"
49
- content = "Failed to check-in user. Try again!"
50
- /> ,
51
- ) ;
52
- else {
53
- if ( sessionStatus . status === "already" )
54
- setStatusCard (
55
- < MessageCard type = "warning" content = "Already checked in" /> ,
56
- ) ;
57
- else if ( sessionStatus . status === "success" )
58
- setStatusCard (
59
- < MessageCard type = "success" content = "User checked in" /> ,
60
- ) ;
61
- else
62
- setStatusCard (
63
- < MessageCard type = "danger" content = "Invalid QR-Code" /> ,
64
- ) ;
40
+ if ( sessionStatus ) {
41
+ updateSessionStatusTimeout . current &&
42
+ clearTimeout ( updateSessionStatusTimeout . current ) ;
43
+ updateSessionStatusTimeout . current = setTimeout (
44
+ ( ) => sessionUpdate ( ) ,
45
+ 5 * 1000 ,
46
+ ) ; // Update every 5 seconds
65
47
setStatus ( {
48
+ participantsNumber : sessionStatus . participantsNumber ,
66
49
unregisteredParticipantsNumber :
67
50
sessionStatus . unregisteredParticipantsNumber ,
68
- participantsNumber : sessionStatus . participantsNumber ,
69
51
} ) ;
70
52
}
71
- } else {
72
- setBottomCard ( < MessageCard type = "danger" content = "Invalid QR-Code" /> ) ;
73
- }
53
+ return sessionStatus ;
54
+ } ,
55
+ [ cannonToken , sinfoSession . id ] ,
56
+ ) ;
74
57
75
- cardsTimeout = setTimeout ( ( ) => {
76
- setBottomCard ( null ) ;
77
- setStatusCard ( null ) ;
78
- } , 10 * 1000 ) ; // 10 seconds
79
- }
58
+ const handleQRCodeScanned = useCallback (
59
+ async ( data : string ) => {
60
+ const scannedUser = getUserFromQRCode ( data ) ;
61
+ cardsTimeout . current && clearTimeout ( cardsTimeout . current ) ;
62
+
63
+ if ( scannedUser ) {
64
+ setBottomCard (
65
+ < ListCard img = { scannedUser . img } title = { scannedUser . name } /> ,
66
+ ) ;
67
+ const sessionStatus = await sessionUpdate ( { users : [ scannedUser . id ] } ) ;
68
+ if ( ! sessionStatus )
69
+ setStatusCard (
70
+ < MessageCard
71
+ type = "danger"
72
+ content = "Failed to check-in user. Try again!"
73
+ /> ,
74
+ ) ;
75
+ else {
76
+ if ( sessionStatus . status === "already" )
77
+ setStatusCard (
78
+ < MessageCard type = "warning" content = "Already checked in" /> ,
79
+ ) ;
80
+ else if ( sessionStatus . status === "success" )
81
+ setStatusCard (
82
+ < MessageCard type = "success" content = "User checked in" /> ,
83
+ ) ;
84
+ else
85
+ setStatusCard (
86
+ < MessageCard type = "danger" content = "Invalid QR-Code" /> ,
87
+ ) ;
88
+ }
89
+ } else {
90
+ setBottomCard ( < MessageCard type = "danger" content = "Invalid QR-Code" /> ) ;
91
+ }
92
+
93
+ cardsTimeout . current = setTimeout ( ( ) => {
94
+ setBottomCard ( null ) ;
95
+ setStatusCard ( null ) ;
96
+ } , 10 * 1000 ) ; // 10 seconds
97
+ } ,
98
+ [ sessionUpdate ] ,
99
+ ) ;
100
+
101
+ const handleUnregisteredUser = useCallback (
102
+ async ( count : number ) => {
103
+ const sessionStatus = sessionUpdate ( { unregisteredUsers : count } ) ;
104
+ if ( ! sessionStatus ) {
105
+ setBottomCard (
106
+ < MessageCard
107
+ type = "danger"
108
+ content = "Failed to update unregistered users"
109
+ /> ,
110
+ ) ;
111
+ } else {
112
+ setBottomCard (
113
+ < MessageCard
114
+ type = "success"
115
+ content = {
116
+ count > 0
117
+ ? `Added ${ count } unregistered user`
118
+ : `Removed ${ count } unregistered user`
119
+ }
120
+ /> ,
121
+ ) ;
122
+ setUnregisteredUsersCounter ( ( c ) => c + count ) ;
123
+ }
124
+ } ,
125
+ [ sessionUpdate ] ,
126
+ ) ;
80
127
81
128
useEffect ( ( ) => {
82
129
setBottomCard ( ( card ) => (
@@ -92,7 +139,11 @@ export default function SessionCheckInScanner({
92
139
< div className = "flex flex-col justify-start gap-y-1" >
93
140
< SessionTile session = { sinfoSession } />
94
141
< div className = "flex justify-center items-center gap-x-4" >
95
- < button className = "button button-primary !bg-sinfo-secondary flex-1" >
142
+ < button
143
+ className = "button button-primary !bg-sinfo-secondary flex-1"
144
+ onClick = { ( ) => handleUnregisteredUser ( - 1 ) }
145
+ disabled = { unregisteredUsersCounter <= 0 }
146
+ >
96
147
< UserMinus size = { 32 } strokeWidth = { 1 } />
97
148
</ button >
98
149
< div className = "flex justify-center items-center bg-white rounded-md text-sm flex-1 p-4 gap-x-2" >
@@ -101,14 +152,24 @@ export default function SessionCheckInScanner({
101
152
/
102
153
< Ghost size = { 16 } />
103
154
< span > { status . unregisteredParticipantsNumber } </ span >
155
+ /
156
+ < ScanEye size = { 16 } />
157
+ < span > { unregisteredUsersCounter } </ span >
104
158
</ div >
105
- < button className = "button button-primary flex-1" >
159
+ < button
160
+ className = "button button-primary flex-1"
161
+ onClick = { ( ) => handleUnregisteredUser ( 1 ) }
162
+ >
106
163
< UserPlus size = { 32 } strokeWidth = { 1 } />
107
164
</ button >
108
165
</ div >
109
166
</ div > ,
110
167
) ;
111
- } , [ status , sinfoSession ] ) ;
168
+ } , [ status , sinfoSession , handleUnregisteredUser , unregisteredUsersCounter ] ) ;
169
+
170
+ useEffect ( ( ) => {
171
+ sessionUpdate ( ) ;
172
+ } , [ sessionUpdate ] ) ;
112
173
113
174
return (
114
175
< QRCodeScanner
0 commit comments