1- import React , { useState } from 'react' ;
1+ import React , { useState , useEffect } from 'react' ;
22import { useUser } from '@/context/UserContext' ;
33import { useWorkshopContext } from '@/context/WorkshopContext' ;
44import { UsersService } from '@/client' ;
@@ -7,12 +7,41 @@ import { Input } from '@/components/ui/input';
77import { Label } from '@/components/ui/label' ;
88import { Card , CardContent , CardDescription , CardHeader , CardTitle } from '@/components/ui/card' ;
99import { Alert , AlertDescription } from '@/components/ui/alert' ;
10+ import { Select , SelectContent , SelectItem , SelectTrigger , SelectValue } from '@/components/ui/select' ;
11+ import { Loader2 , Plus } from 'lucide-react' ;
12+ import type { Workshop } from '@/client' ;
1013
1114export const ProductionLogin : React . FC = ( ) => {
1215 const { setUser } = useUser ( ) ;
13- const { workshopId } = useWorkshopContext ( ) ;
16+ const { workshopId, setWorkshopId } = useWorkshopContext ( ) ;
1417 const [ isLoading , setIsLoading ] = useState ( false ) ;
1518 const [ error , setError ] = useState < string | null > ( null ) ;
19+ const [ workshops , setWorkshops ] = useState < Workshop [ ] > ( [ ] ) ;
20+ const [ isLoadingWorkshops , setIsLoadingWorkshops ] = useState ( true ) ;
21+ const [ selectedWorkshopId , setSelectedWorkshopId ] = useState < string > ( workshopId || '' ) ;
22+ const [ createNewWorkshop , setCreateNewWorkshop ] = useState ( false ) ;
23+
24+ // Fetch available workshops on mount
25+ useEffect ( ( ) => {
26+ const fetchWorkshops = async ( ) => {
27+ try {
28+ const response = await fetch ( '/workshops/' ) ;
29+ if ( response . ok ) {
30+ const data = await response . json ( ) ;
31+ setWorkshops ( data ) ;
32+ // If there's only one workshop, auto-select it
33+ if ( data . length === 1 && ! workshopId ) {
34+ setSelectedWorkshopId ( data [ 0 ] . id ) ;
35+ }
36+ }
37+ } catch ( err ) {
38+ console . error ( 'Failed to fetch workshops:' , err ) ;
39+ } finally {
40+ setIsLoadingWorkshops ( false ) ;
41+ }
42+ } ;
43+ fetchWorkshops ( ) ;
44+ } , [ workshopId ] ) ;
1645
1746 // Login form state
1847 const [ loginData , setLoginData ] = useState ( {
@@ -25,12 +54,33 @@ export const ProductionLogin: React.FC = () => {
2554 setIsLoading ( true ) ;
2655 setError ( null ) ;
2756
57+ // Validate workshop selection for non-facilitators
58+ if ( ! selectedWorkshopId && ! loginData . password ) {
59+ setError ( 'Please select a workshop to join.' ) ;
60+ setIsLoading ( false ) ;
61+ return ;
62+ }
63+
2864 try {
2965 const response = await UsersService . loginUsersAuthLoginPost ( {
3066 email : loginData . email ,
3167 password : loginData . password
3268 } ) ;
3369
70+ // Handle facilitator creating new workshop
71+ if ( loginData . password && createNewWorkshop ) {
72+ // Clear workshop ID to go to workshop creation page
73+ setWorkshopId ( null ) ;
74+ localStorage . removeItem ( 'workshop_id' ) ;
75+ window . history . replaceState ( { } , '' , '/' ) ;
76+ }
77+ // Set workshop ID if selected (for existing workshops)
78+ else if ( selectedWorkshopId && ! response . user . workshop_id ) {
79+ // Update the workshop context
80+ setWorkshopId ( selectedWorkshopId ) ;
81+ window . history . pushState ( { } , '' , `?workshop=${ selectedWorkshopId } ` ) ;
82+ }
83+
3484 // Set the user in context
3585 await setUser ( response . user ) ;
3686 } catch ( error : any ) {
@@ -81,14 +131,116 @@ export const ProductionLogin: React.FC = () => {
81131 />
82132 </ div >
83133
134+ { /* Workshop Selection for Participants/SMEs */ }
135+ { ! loginData . password && (
136+ < div className = "space-y-2" >
137+ < Label htmlFor = "workshop" > Select Workshop</ Label >
138+ { isLoadingWorkshops ? (
139+ < div className = "flex items-center justify-center py-2" >
140+ < Loader2 className = "h-4 w-4 animate-spin mr-2" />
141+ < span className = "text-sm text-gray-500" > Loading workshops...</ span >
142+ </ div >
143+ ) : workshops . length === 0 ? (
144+ < div className = "text-sm text-amber-600 bg-amber-50 p-3 rounded-lg" >
145+ No workshops available. Please wait for a facilitator to create one.
146+ </ div >
147+ ) : (
148+ < Select
149+ value = { selectedWorkshopId }
150+ onValueChange = { setSelectedWorkshopId }
151+ >
152+ < SelectTrigger >
153+ < SelectValue placeholder = "Select a workshop to join" />
154+ </ SelectTrigger >
155+ < SelectContent >
156+ { workshops . map ( ( workshop ) => (
157+ < SelectItem key = { workshop . id } value = { workshop . id } >
158+ { workshop . name }
159+ </ SelectItem >
160+ ) ) }
161+ </ SelectContent >
162+ </ Select >
163+ ) }
164+ </ div >
165+ ) }
166+
167+ { /* Workshop Selection for Facilitators */ }
168+ { loginData . password && (
169+ < div className = "space-y-3" >
170+ < Label > Workshop</ Label >
171+
172+ { /* Toggle between existing and new */ }
173+ < div className = "flex gap-2" >
174+ < Button
175+ type = "button"
176+ variant = { ! createNewWorkshop ? "default" : "outline" }
177+ size = "sm"
178+ className = "flex-1"
179+ onClick = { ( ) => setCreateNewWorkshop ( false ) }
180+ >
181+ Join Existing
182+ </ Button >
183+ < Button
184+ type = "button"
185+ variant = { createNewWorkshop ? "default" : "outline" }
186+ size = "sm"
187+ className = "flex-1"
188+ onClick = { ( ) => setCreateNewWorkshop ( true ) }
189+ >
190+ < Plus className = "h-4 w-4 mr-1" />
191+ Create New
192+ </ Button >
193+ </ div >
194+
195+ { ! createNewWorkshop ? (
196+ // Existing workshop selection
197+ isLoadingWorkshops ? (
198+ < div className = "flex items-center justify-center py-2" >
199+ < Loader2 className = "h-4 w-4 animate-spin mr-2" />
200+ < span className = "text-sm text-gray-500" > Loading workshops...</ span >
201+ </ div >
202+ ) : workshops . length === 0 ? (
203+ < div className = "text-sm text-blue-600 bg-blue-50 p-3 rounded-lg" >
204+ No existing workshops. Click "Create New" to start a new workshop.
205+ </ div >
206+ ) : (
207+ < Select
208+ value = { selectedWorkshopId }
209+ onValueChange = { setSelectedWorkshopId }
210+ >
211+ < SelectTrigger >
212+ < SelectValue placeholder = "Select a workshop" />
213+ </ SelectTrigger >
214+ < SelectContent >
215+ { workshops . map ( ( workshop ) => (
216+ < SelectItem key = { workshop . id } value = { workshop . id } >
217+ { workshop . name }
218+ </ SelectItem >
219+ ) ) }
220+ </ SelectContent >
221+ </ Select >
222+ )
223+ ) : (
224+ // New workshop indicator
225+ < div className = "text-sm text-green-600 bg-green-50 p-3 rounded-lg" >
226+ A new workshop will be created after you sign in.
227+ </ div >
228+ ) }
229+ </ div >
230+ ) }
231+
84232 { error && (
85233 < Alert variant = "destructive" >
86234 < AlertDescription > { error } </ AlertDescription >
87235 </ Alert >
88236 ) }
89237
90- < Button type = "submit" className = "w-full" disabled = { isLoading } >
91- { isLoading ? 'Signing in...' : 'Sign In' }
238+ < Button
239+ type = "submit"
240+ className = "w-full"
241+ disabled = { isLoading || ( ! loginData . password && ! selectedWorkshopId ) || ( loginData . password && ! createNewWorkshop && ! selectedWorkshopId && workshops . length > 0 ) }
242+ >
243+ { isLoading ? 'Signing in...' : createNewWorkshop ? 'Sign In & Create Workshop' : 'Sign In' }
92244 </ Button >
93245 </ form >
94246
0 commit comments