@@ -4,13 +4,20 @@ import { MatchForm } from "@/components/matching/matching-form";
4
4
import { SearchProgress } from "@/components/matching/search-progress" ;
5
5
import { SelectionSummary } from "@/components/matching/selection-summary" ;
6
6
import { useToast } from "@/components/hooks/use-toast" ;
7
+ import { useAuth } from "@/app/auth/auth-context" ;
8
+ import { joinMatchQueue } from "@/lib/join-match-queue" ;
9
+ import { leaveMatchQueue } from "@/lib/leave-match-queue" ;
10
+ import { subscribeMatch } from "@/lib/subscribe-match" ;
7
11
8
12
export default function FindMatch ( ) {
9
13
const [ selectedDifficulty , setSelectedDifficulty ] = useState < string > ( "" ) ;
10
14
const [ selectedTopic , setSelectedTopic ] = useState < string > ( "" ) ;
11
15
const [ isSearching , setIsSearching ] = useState < boolean > ( false ) ;
12
16
const [ waitTime , setWaitTime ] = useState < number > ( 0 ) ;
13
17
const { toast } = useToast ( ) ;
18
+ const auth = useAuth ( ) ;
19
+
20
+ const waitTimeout = 60000 ;
14
21
15
22
useEffect ( ( ) => {
16
23
let interval : NodeJS . Timeout | undefined ;
@@ -21,24 +28,155 @@ export default function FindMatch() {
21
28
} else {
22
29
setWaitTime ( 0 ) ;
23
30
}
24
- return ( ) => clearInterval ( interval ) ;
31
+
32
+ return ( ) => {
33
+ clearInterval ( interval ) ;
34
+ } ;
25
35
} , [ isSearching ] ) ;
26
36
27
- const handleSearch = ( ) => {
28
- if ( selectedDifficulty && selectedTopic ) {
29
- setIsSearching ( true ) ;
30
- } else {
37
+ const handleSearch = async ( ) => {
38
+ if ( ! selectedDifficulty || ! selectedTopic ) {
31
39
toast ( {
32
40
title : "Invalid Selection" ,
33
41
description : "Please select both a difficulty level and a topic" ,
34
42
variant : "destructive" ,
35
43
} ) ;
44
+ return ;
45
+ }
46
+
47
+ if ( ! auth || ! auth . token ) {
48
+ toast ( {
49
+ title : "Access denied" ,
50
+ description : "No authentication token found" ,
51
+ variant : "destructive" ,
52
+ } ) ;
53
+ return ;
54
+ }
55
+
56
+ if ( ! auth . user ) {
57
+ toast ( {
58
+ title : "Access denied" ,
59
+ description : "Not logged in" ,
60
+ variant : "destructive" ,
61
+ } ) ;
62
+ return ;
63
+ }
64
+
65
+ const response = await joinMatchQueue (
66
+ auth . token ,
67
+ auth ?. user ?. id ,
68
+ selectedTopic ,
69
+ selectedDifficulty
70
+ ) ;
71
+ switch ( response . status ) {
72
+ case 201 :
73
+ toast ( {
74
+ title : "Matched" ,
75
+ description : "Successfully matched" ,
76
+ variant : "success" ,
77
+ } ) ;
78
+ return ;
79
+ case 202 :
80
+ case 304 :
81
+ setIsSearching ( true ) ;
82
+ const ws = await subscribeMatch (
83
+ auth ?. user . id ,
84
+ selectedTopic ,
85
+ selectedDifficulty
86
+ ) ;
87
+ const queueTimeout = setTimeout ( ( ) => {
88
+ handleCancel ( true ) ;
89
+ } , waitTimeout ) ;
90
+ ws . onmessage = ( ) => {
91
+ setIsSearching ( false ) ;
92
+ clearTimeout ( queueTimeout ) ;
93
+ toast ( {
94
+ title : "Matched" ,
95
+ description : "Successfully matched" ,
96
+ variant : "success" ,
97
+ } ) ;
98
+ ws . onclose = ( ) => null ;
99
+ } ;
100
+ ws . onclose = ( ) => {
101
+ setIsSearching ( false ) ;
102
+ clearTimeout ( queueTimeout ) ;
103
+ toast ( {
104
+ title : "Matching Stopped" ,
105
+ description : "Matching has been stopped" ,
106
+ variant : "destructive" ,
107
+ } ) ;
108
+ } ;
109
+ return ;
110
+ default :
111
+ toast ( {
112
+ title : "Unknown Error" ,
113
+ description : "An unexpected error has occured" ,
114
+ variant : "destructive" ,
115
+ } ) ;
116
+ return ;
36
117
}
37
118
} ;
38
119
39
- const handleCancel = ( ) => {
40
- setIsSearching ( false ) ;
41
- setWaitTime ( 0 ) ;
120
+ const handleCancel = async ( timedOut : boolean ) => {
121
+ if ( ! selectedDifficulty || ! selectedTopic ) {
122
+ toast ( {
123
+ title : "Invalid Selection" ,
124
+ description : "Please select both a difficulty level and a topic" ,
125
+ variant : "destructive" ,
126
+ } ) ;
127
+ return ;
128
+ }
129
+
130
+ if ( ! auth || ! auth . token ) {
131
+ toast ( {
132
+ title : "Access denied" ,
133
+ description : "No authentication token found" ,
134
+ variant : "destructive" ,
135
+ } ) ;
136
+ return ;
137
+ }
138
+
139
+ if ( ! auth . user ) {
140
+ toast ( {
141
+ title : "Access denied" ,
142
+ description : "Not logged in" ,
143
+ variant : "destructive" ,
144
+ } ) ;
145
+ return ;
146
+ }
147
+
148
+ const response = await leaveMatchQueue (
149
+ auth . token ,
150
+ auth . user ?. id ,
151
+ selectedTopic ,
152
+ selectedDifficulty
153
+ ) ;
154
+ switch ( response . status ) {
155
+ case 200 :
156
+ setIsSearching ( false ) ;
157
+ setWaitTime ( 0 ) ;
158
+ if ( timedOut ) {
159
+ toast ( {
160
+ title : "Timed Out" ,
161
+ description : "Matching has been stopped" ,
162
+ variant : "destructive" ,
163
+ } ) ;
164
+ } else {
165
+ toast ( {
166
+ title : "Matching Stopped" ,
167
+ description : "Matching has been stopped" ,
168
+ variant : "destructive" ,
169
+ } ) ;
170
+ }
171
+ return ;
172
+ default :
173
+ toast ( {
174
+ title : "Unknown Error" ,
175
+ description : "An unexpected error has occured" ,
176
+ variant : "destructive" ,
177
+ } ) ;
178
+ return ;
179
+ }
42
180
} ;
43
181
44
182
return (
@@ -50,7 +188,7 @@ export default function FindMatch() {
50
188
setSelectedTopic = { setSelectedTopic }
51
189
handleSearch = { handleSearch }
52
190
isSearching = { isSearching }
53
- handleCancel = { handleCancel }
191
+ handleCancel = { ( ) => handleCancel ( false ) }
54
192
/>
55
193
56
194
{ isSearching && < SearchProgress waitTime = { waitTime } /> }
0 commit comments