@@ -25,14 +25,21 @@ import { useApi } from "@ui/util/api";
2525import { AllOrganizationList as orgList } from "@acm-uiuc/js-shared" ;
2626import { AppRoles } from "@common/roles" ;
2727import { EVENT_CACHED_DURATION } from "@common/config" ;
28- import { IconInfoCircle , IconPlus , IconTrash } from "@tabler/icons-react" ;
28+ import {
29+ IconAlertCircle ,
30+ IconInfoCircle ,
31+ IconPlus ,
32+ IconTrash ,
33+ } from "@tabler/icons-react" ;
2934import {
3035 MAX_METADATA_KEYS ,
3136 MAX_KEY_LENGTH ,
3237 MAX_VALUE_LENGTH ,
3338 metadataSchema ,
3439} from "@common/types/events" ;
3540import { zod4Resolver as zodResolver } from "mantine-form-zod-resolver" ;
41+ import FullScreenLoader from "@ui/components/AuthContext/LoadingScreen" ;
42+ import { X } from "vitest/dist/chunks/reporters.d.BFLkQcL6" ;
3643
3744export function capitalizeFirstLetter ( string : string ) {
3845 return string . charAt ( 0 ) . toUpperCase ( ) + string . slice ( 1 ) ;
@@ -75,9 +82,11 @@ const baseBodySchema = z.object({
7582
7683const requestBodySchema = baseBodySchema
7784 . extend ( {
85+ start : z . coerce . date ( ) ,
86+ end : z . coerce . date ( ) ,
7887 repeats : z . optional ( z . enum ( repeatOptions ) ) . nullable ( ) ,
7988 repeatEnds : z . date ( ) . optional ( ) ,
80- repeatExcludes : z . array ( z . date ( ) ) . max ( 100 ) . optional ( ) ,
89+ repeatExcludes : z . array ( z . coerce . date ( ) ) . max ( 100 ) . optional ( ) ,
8190 } )
8291 . refine ( ( data ) => ( data . repeatEnds ? data . repeats !== undefined : true ) , {
8392 message : "Repeat frequency is required when Repeat End is specified." ,
@@ -95,6 +104,7 @@ type EventPostRequest = z.infer<typeof requestBodySchema>;
95104
96105export const ManageEventPage : React . FC = ( ) => {
97106 const [ isSubmitting , setIsSubmitting ] = useState < boolean > ( false ) ;
107+ const [ isLoading , setIsLoading ] = useState < boolean > ( true ) ;
98108 const navigate = useNavigate ( ) ;
99109 const api = useApi ( "core" ) ;
100110
@@ -104,6 +114,7 @@ export const ManageEventPage: React.FC = () => {
104114
105115 useEffect ( ( ) => {
106116 if ( ! isEditing ) {
117+ setIsLoading ( false ) ;
107118 return ;
108119 }
109120 const getEvent = async ( ) => {
@@ -136,10 +147,14 @@ export const ManageEventPage: React.FC = () => {
136147 metadata : eventData . metadata || { } ,
137148 } ;
138149 form . setValues ( formValues ) ;
150+ setIsLoading ( false ) ;
139151 } catch ( error ) {
140152 console . error ( "Error fetching event data:" , error ) ;
141153 notifications . show ( {
142- message : "Failed to fetch event data, please try again." ,
154+ title : "Failed to fetch event data" ,
155+ message : "Please try again or contact support." ,
156+ color : "red" ,
157+ icon : < IconAlertCircle size = { 16 } /> ,
143158 } ) ;
144159 }
145160 } ;
@@ -176,12 +191,21 @@ export const ManageEventPage: React.FC = () => {
176191 if ( form . values . locationLink === "" ) {
177192 form . setFieldValue ( "locationLink" , undefined ) ;
178193 }
179- if ( form . values . repeatExcludes ?. length === 0 ) {
180- form . setFieldValue ( "repeatExcludes" , undefined ) ;
181- }
182- } , [ form . values . locationLink , form . values . repeatExcludes ] ) ;
194+ } , [ form . values . locationLink ] ) ;
183195
184- const handleSubmit = async ( values : EventPostRequest ) => {
196+ const handleSubmit = async ( ) => {
197+ const result = form . validate ( ) ;
198+ if ( result . hasErrors ) {
199+ console . warn ( result . errors ) ;
200+ notifications . show ( {
201+ title : "Validation failed" ,
202+ message : "Please review the errors and try again." ,
203+ color : "red" ,
204+ icon : < IconAlertCircle size = { 16 } /> ,
205+ } ) ;
206+ return ;
207+ }
208+ const values = form . values ;
185209 try {
186210 setIsSubmitting ( true ) ;
187211
@@ -195,9 +219,10 @@ export const ManageEventPage: React.FC = () => {
195219 values . repeatEnds && values . repeats
196220 ? dayjs ( values . repeatEnds ) . format ( "YYYY-MM-DD[T]HH:mm:00" )
197221 : undefined ,
198- repeatExcludes : values . repeatExcludes
199- ? values . repeatExcludes . map ( ( x ) => dayjs ( x ) . format ( "YYYY-MM-DD" ) )
200- : undefined ,
222+ repeatExcludes :
223+ values . repeatExcludes && values . repeatExcludes . length > 0
224+ ? values . repeatExcludes . map ( ( x ) => dayjs ( x ) . format ( "YYYY-MM-DD" ) )
225+ : [ ] ,
201226 repeats : values . repeats ? values . repeats : undefined ,
202227 metadata :
203228 Object . keys ( values . metadata || { } ) . length > 0
@@ -301,7 +326,9 @@ export const ManageEventPage: React.FC = () => {
301326
302327 setMetadataKeys ( newMetadataKeys ) ;
303328 } , [ Object . keys ( form . values . metadata || { } ) . length ] ) ;
304-
329+ if ( isLoading ) {
330+ return < FullScreenLoader /> ;
331+ }
305332 return (
306333 < AuthGuard
307334 resourceDef = { { service : "core" , validRoles : [ AppRoles . EVENTS_MANAGER ] } }
@@ -328,7 +355,7 @@ export const ManageEventPage: React.FC = () => {
328355 </ Alert >
329356 ) }
330357
331- < form onSubmit = { form . onSubmit ( handleSubmit ) } >
358+ < form >
332359 < TextInput
333360 label = "Event Title"
334361 withAsterisk
@@ -501,7 +528,12 @@ export const ManageEventPage: React.FC = () => {
501528 ) }
502529 </ Box >
503530
504- < Button type = "submit" mt = "md" >
531+ < Button
532+ mt = "md"
533+ onClick = { ( ) => {
534+ handleSubmit ( ) ;
535+ } }
536+ >
505537 { isSubmitting ? (
506538 < >
507539 < Loader size = { 16 } color = "white" />
0 commit comments