@@ -141,6 +141,12 @@ function AdminUsersPage() {
141141 const handleFileChange = async ( e : React . ChangeEvent < HTMLInputElement > ) => {
142142 const file = e . target . files ?. [ 0 ] ;
143143 if ( file ) {
144+ // Check if the file is an image
145+ if ( ! file . type . startsWith ( 'image/' ) ) {
146+ setError ( 'Please select an image file (JPEG, PNG, GIF, etc.)' ) ;
147+ return ;
148+ }
149+
144150 // Convert file to base64 data URL
145151 const reader = new FileReader ( ) ;
146152 reader . onload = ( event ) => {
@@ -159,70 +165,73 @@ function AdminUsersPage() {
159165 e . preventDefault ( ) ;
160166 setLoading ( true ) ;
161167 setError ( null ) ;
168+ setSuccess ( null ) ;
162169
163- try {
164- // Create user first
165- const userPayload = {
166- firstName : formState . firstName ,
167- lastName : formState . lastName ,
168- email : formState . email ,
169- password : 'tempPassword123!' , // This will be changed by the user
170- role : 'speaker' ,
171- } ;
170+ // Validate required fields
171+ if ( ! formState . industryFocuses || formState . industryFocuses . length === 0 ) {
172+ setError ( 'Please select at least one industry focus.' ) ;
173+ setLoading ( false ) ;
174+ return ;
175+ }
172176
173- console . log ( 'Creating user with payload:' , userPayload ) ;
174- const userResponse = await postData ( 'auth/register' , userPayload ) ;
175- if ( userResponse . error ) {
176- throw new Error ( userResponse . error . message ) ;
177- }
178- console . log ( 'User created:' , userResponse . data ) ;
177+ if ( ! formState . gradeSpecialties || formState . gradeSpecialties . length === 0 ) {
178+ setError ( 'Please select at least one age/grade specialty.' ) ;
179+ setLoading ( false ) ;
180+ return ;
181+ }
182+
183+ if ( ! formState . speakingFormats || formState . speakingFormats . length === 0 ) {
184+ setError ( 'Please select at least one speaking format.' ) ;
185+ setLoading ( false ) ;
186+ return ;
187+ }
188+
189+ try {
190+ // Map speaking formats to boolean values
191+ const inperson = formState . speakingFormats . includes ( 'In-Person' ) ;
192+ const virtual = formState . speakingFormats . includes ( 'Virtual' ) ;
179193
180194 // Map grade specialties to the expected format
181- const mappedGrades = formState . gradeSpecialties . map ( grade => {
195+ const mappedGrades = formState . gradeSpecialties . map ( ( grade ) => {
182196 switch ( grade ) {
183- case 'Elementary School ' :
197+ case 'elementary ' :
184198 return 'Elementary' ;
185- case 'Middle School ' :
199+ case 'middle ' :
186200 return 'Middle School' ;
187- case 'High School ' :
201+ case 'high school ' :
188202 return 'High School' ;
203+ case 'all grades' :
204+ return 'All Grades' ;
189205 default :
190206 return grade ;
191207 }
192208 } ) ;
193209
194- // Map speaking formats to inperson/virtual booleans
195- const inperson = formState . speakingFormats . includes ( 'In-Person' ) ;
196- const virtual = formState . speakingFormats . includes ( 'Virtual' ) ;
197-
210+ // Create payload for the new admin endpoint
198211 const speakerPayload = {
199- userId : userResponse . data . _id ,
212+ email : formState . email ,
213+ firstName : formState . firstName ,
214+ lastName : formState . lastName ,
200215 organization : formState . organization || 'Unknown' ,
201216 bio : formState . bio || 'No bio provided' ,
202217 city : formState . city || 'Unknown' ,
203- state : formState . state || 'Unknown ' ,
218+ state : formState . state || '' ,
204219 country : formState . country || undefined ,
205- inperson,
206- virtual,
207- imageUrl : formState . picture || undefined ,
208- industry :
209- formState . industryFocuses . length > 0
210- ? formState . industryFocuses
211- : [ 'Other' ] ,
220+ industry : formState . industryFocuses ,
212221 grades : mappedGrades ,
213222 languages : formState . languages . length > 0 ? formState . languages : [ 'English' ] ,
214223 } ;
215224
216225 console . log ( 'Creating speaker with payload:' , speakerPayload ) ;
217- const speakerResponse = await postData ( 'speaker /create' , speakerPayload ) ;
226+ const speakerResponse = await postData ( 'admin /create-speaker ' , speakerPayload ) ;
218227 if ( speakerResponse . error ) {
219228 throw new Error ( speakerResponse . error . message ) ;
220229 }
221230 console . log ( 'Speaker created:' , speakerResponse . data ) ;
222231
223232 // Reset form after successful submission
224233 setFormState ( initialFormState ) ;
225- setSuccess ( 'Speaker created successfully!' ) ;
234+ setSuccess ( 'Speaker created successfully! The speaker account is now visible and a password reset email has been sent to their email address. ' ) ;
226235 } catch ( error ) {
227236 console . error ( 'Error creating speaker:' , error ) ;
228237 setError (
@@ -243,7 +252,10 @@ function AdminUsersPage() {
243252 { /* Main Content Area */ }
244253 < Box className = "main-window" >
245254 < Typography variant = "h4" gutterBottom >
246- Speaker Submission Form
255+ Create Speaker Account
256+ </ Typography >
257+ < Typography variant = "body1" sx = { { mb : 3 , color : 'text.secondary' } } >
258+ Create a speaker account that will be immediately visible. A password reset email will be sent to the speaker.
247259 </ Typography >
248260
249261 { error && (
@@ -252,16 +264,6 @@ function AdminUsersPage() {
252264 </ Alert >
253265 ) }
254266
255- { success && (
256- < Alert
257- severity = "success"
258- sx = { { mb : 2 } }
259- onClose = { ( ) => setSuccess ( null ) }
260- >
261- { success }
262- </ Alert >
263- ) }
264-
265267 < Box
266268 component = "form"
267269 onSubmit = { handleSubmit }
@@ -294,13 +296,13 @@ function AdminUsersPage() {
294296 required
295297 />
296298 < TextField
297- label = "Job Title (optional) "
299+ label = "Job Title"
298300 name = "jobTitle"
299301 value = { formState . jobTitle }
300302 onChange = { handleChange }
301303 />
302304 < TextField
303- label = "LinkedIn/Website (optional) "
305+ label = "LinkedIn/Website"
304306 name = "website"
305307 value = { formState . website }
306308 onChange = { handleChange }
@@ -313,13 +315,14 @@ function AdminUsersPage() {
313315 required
314316 />
315317 < TextField
316- label = "Bio (optional) "
318+ label = "Bio"
317319 name = "bio"
318320 multiline
319321 rows = { 3 }
320322 variant = "outlined"
321323 value = { formState . bio }
322324 onChange = { handleChange }
325+ required
323326 />
324327 < Box sx = { { display : 'flex' , gap : 2 } } >
325328 < TextField
@@ -336,14 +339,14 @@ function AdminUsersPage() {
336339 value = { formState . state }
337340 onChange = { handleChange }
338341 sx = { { flex : 1 } }
339- required
340342 />
341343 < TextField
342- label = "Country (optional) "
344+ label = "Country"
343345 name = "country"
344346 value = { formState . country }
345347 onChange = { handleChange }
346348 sx = { { flex : 1 } }
349+ required
347350 />
348351 </ Box >
349352 < MultiSelect
@@ -377,8 +380,8 @@ function AdminUsersPage() {
377380 </ FormControl >
378381
379382 < FormControl component = "fieldset" >
380- < FormLabel component = "legend" >
381- Preferred Speaking Format (optional)
383+ < FormLabel component = "legend" required >
384+ Preferred Speaking Format
382385 </ FormLabel >
383386 < Box sx = { { display : 'flex' , flexDirection : 'column' } } >
384387 { speakingFormatOptions . map ( ( format ) => (
@@ -397,8 +400,8 @@ function AdminUsersPage() {
397400 </ FormControl >
398401
399402 < FormControl component = "fieldset" >
400- < FormLabel component = "legend" >
401- Age/Grade Specialty (optional)
403+ < FormLabel component = "legend" required >
404+ Age/Grade Specialty
402405 </ FormLabel >
403406 < Box sx = { { display : 'flex' , flexDirection : 'column' } } >
404407 { gradeOptions . map ( ( grade ) => (
@@ -416,7 +419,7 @@ function AdminUsersPage() {
416419 </ Box >
417420 </ FormControl >
418421 < Typography variant = "subtitle1" > Profile Picture</ Typography >
419- < input type = "file" onChange = { handleFileChange } name = "picture" />
422+ < input type = "file" accept = "image/*" onChange = { handleFileChange } name = "picture" />
420423 < Button
421424 variant = "contained"
422425 color = "primary"
@@ -426,6 +429,16 @@ function AdminUsersPage() {
426429 >
427430 { loading ? 'Creating Speaker...' : 'Submit' }
428431 </ Button >
432+
433+ { success && (
434+ < Alert
435+ severity = "success"
436+ sx = { { mt : 2 } }
437+ onClose = { ( ) => setSuccess ( null ) }
438+ >
439+ { success }
440+ </ Alert >
441+ ) }
429442 </ Box >
430443 </ Box >
431444 </ div >
0 commit comments