@@ -4,7 +4,7 @@ import { useForm } from "react-hook-form";
44import { zodResolver } from "@hookform/resolvers/zod" ;
55import { format } from "date-fns" ;
66import { CalendarIcon , Save , X } from "lucide-react" ;
7- import { z } from "zod " ;
7+ import { useTranslations } from "next-intl " ;
88import { Button } from "@/components/ui/Button" ;
99import { Input } from "@/components/ui/Input" ;
1010import { Card , CardContent } from "@/components/ui/Card" ;
@@ -15,32 +15,11 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
1515import { Switch } from "@/components/ui/Switch" ;
1616import TextEditor from "@/components/common/TextEditor/TextEditor" ;
1717import { cn , generateSlug } from "@/lib/utils" ;
18-
18+ import { createEventFormSchema , EventFormType } from "@/domains/Events" ;
19+ import { eventTypes } from "../constants" ;
1920import { useState , useEffect } from "react" ;
2021import Badge from "@/components/ui/Badge" ;
2122
22- const eventFormSchema = z . object ( {
23- title : z . string ( ) . min ( 1 , "Title is required" ) ,
24- description : z . string ( ) . min ( 1 , "Description is required" ) ,
25- file_name : z . string ( ) . optional ( ) ,
26- slug : z . string ( ) . min ( 1 , "Slug is required" ) ,
27- is_online : z . boolean ( ) ,
28- date : z . string ( ) . min ( 1 , "Event date is required" ) ,
29- type : z . string ( ) . min ( 1 , "Event type is required" ) ,
30- location : z . string ( ) . min ( 1 , "Location is required" ) ,
31- duration : z . string ( ) . min ( 1 , "Duration is required" ) ,
32- status : z . string ( ) . min ( 1 , "Status is required" ) ,
33- capacity : z . number ( ) . min ( 1 , "Capacity must be at least 1" ) ,
34- price : z . number ( ) . min ( 0 , "Price must be 0 or greater" ) ,
35- registration_link : z . string ( ) . url ( "Must be a valid URL" ) ,
36- tags : z . array ( z . string ( ) ) ,
37- speakers : z . array ( z . string ( ) ) ,
38- reservation_start_date : z . string ( ) . min ( 1 , "Reservation start date is required" ) ,
39- reservation_end_date : z . string ( ) . min ( 1 , "Reservation end date is required" ) ,
40- } ) ;
41-
42- type EventFormType = z . infer < typeof eventFormSchema > ;
43-
4423interface EventFormProps {
4524 onSubmit : ( data : EventFormType ) => void ;
4625 isLoading ?: boolean ;
@@ -49,6 +28,8 @@ interface EventFormProps {
4928}
5029
5130const EventForm = ( { onSubmit, isLoading = false , initialData, mode = "create" } : EventFormProps ) => {
31+ const t = useTranslations ( "EventForm" ) ;
32+ const eventFormSchema = createEventFormSchema ( t ) ;
5233 const [ tagInput , setTagInput ] = useState ( "" ) ;
5334 const [ speakerInput , setSpeakerInput ] = useState ( "" ) ;
5435 const [ isSlugEdited , setIsSlugEdited ] = useState ( false ) ;
@@ -133,9 +114,9 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
133114 name = "title"
134115 render = { ( { field } ) => (
135116 < FormItem >
136- < FormLabel > Event Title </ FormLabel >
117+ < FormLabel aria-required > { t ( "labels.title" ) } </ FormLabel >
137118 < FormControl >
138- < Input placeholder = "Enter event title" { ...field } />
119+ < Input placeholder = { t ( "placeholders. title") } { ...field } />
139120 </ FormControl >
140121 < FormMessage />
141122 </ FormItem >
@@ -147,10 +128,10 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
147128 name = "slug"
148129 render = { ( { field } ) => (
149130 < FormItem >
150- < FormLabel aria-required > Slug </ FormLabel >
131+ < FormLabel aria-required > { t ( "labels.slug" ) } </ FormLabel >
151132 < FormControl >
152133 < Input
153- placeholder = "Enter event slug"
134+ placeholder = { t ( "placeholders. slug") }
154135 { ...field }
155136 onChange = { ( e ) => {
156137 setIsSlugEdited ( true ) ;
@@ -169,7 +150,7 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
169150 name = "description"
170151 render = { ( { field } ) => (
171152 < FormItem >
172- < FormLabel aria-required > Description </ FormLabel >
153+ < FormLabel aria-required > { t ( "labels.description" ) } </ FormLabel >
173154 < FormControl >
174155 < TextEditor value = { field . value } onChange = { field . onChange } />
175156 </ FormControl >
@@ -184,19 +165,19 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
184165 name = "type"
185166 render = { ( { field } ) => (
186167 < FormItem >
187- < FormLabel aria-required > Event Type </ FormLabel >
168+ < FormLabel aria-required > { t ( "labels.type" ) } </ FormLabel >
188169 < Select onValueChange = { field . onChange } defaultValue = { field . value } >
189170 < FormControl >
190171 < SelectTrigger >
191- < SelectValue placeholder = "Select event type" />
172+ < SelectValue placeholder = { t ( "placeholders. type") } />
192173 </ SelectTrigger >
193174 </ FormControl >
194175 < SelectContent >
195- < SelectItem value = "Tech Talk" > Tech Talk </ SelectItem >
196- < SelectItem value = "Workshop" > Workshop </ SelectItem >
197- < SelectItem value = "Seminar" > Seminar </ SelectItem >
198- < SelectItem value = "Conference" > Conference </ SelectItem >
199- < SelectItem value = "Bootcamp" > Bootcamp </ SelectItem >
176+ { eventTypes . map ( ( type ) => (
177+ < SelectItem key = { type . value } value = { type . value } >
178+ { type . label }
179+ </ SelectItem >
180+ ) ) }
200181 </ SelectContent >
201182 </ Select >
202183 < FormMessage />
@@ -209,18 +190,18 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
209190 name = "status"
210191 render = { ( { field } ) => (
211192 < FormItem >
212- < FormLabel aria-required > Status </ FormLabel >
193+ < FormLabel aria-required > { t ( "labels.status" ) } </ FormLabel >
213194 < Select onValueChange = { field . onChange } defaultValue = { field . value } >
214195 < FormControl >
215196 < SelectTrigger >
216- < SelectValue placeholder = "Select status" />
197+ < SelectValue placeholder = { t ( "placeholders. status") } />
217198 </ SelectTrigger >
218199 </ FormControl >
219200 < SelectContent >
220- < SelectItem value = "coming soon" > Coming Soon </ SelectItem >
221- < SelectItem value = "open" > Open </ SelectItem >
222- < SelectItem value = "closed" > Closed </ SelectItem >
223- < SelectItem value = "cancelled" > Cancelled </ SelectItem >
201+ < SelectItem value = "coming soon" > { t ( "options.status.coming-soon" ) } </ SelectItem >
202+ < SelectItem value = "open" > { t ( "options.status.open" ) } </ SelectItem >
203+ < SelectItem value = "closed" > { t ( "options.status.closed" ) } </ SelectItem >
204+ < SelectItem value = "cancelled" > { t ( "options.status.cancelled" ) } </ SelectItem >
224205 </ SelectContent >
225206 </ Select >
226207 < FormMessage />
@@ -234,9 +215,9 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
234215 name = "location"
235216 render = { ( { field } ) => (
236217 < FormItem >
237- < FormLabel aria-required > Location </ FormLabel >
218+ < FormLabel aria-required > { t ( "labels.location" ) } </ FormLabel >
238219 < FormControl >
239- < Input placeholder = "Enter event location" { ...field } />
220+ < Input placeholder = { t ( "placeholders. location") } { ...field } />
240221 </ FormControl >
241222 < FormMessage />
242223 </ FormItem >
@@ -248,15 +229,15 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
248229 name = "date"
249230 render = { ( { field } ) => (
250231 < FormItem className = "flex flex-col" >
251- < FormLabel aria-required > Event Date </ FormLabel >
232+ < FormLabel aria-required > { t ( "labels.date" ) } </ FormLabel >
252233 < Popover >
253234 < PopoverTrigger asChild >
254235 < FormControl >
255236 < Button
256237 variant = "outline"
257238 className = { cn ( "w-full pl-3 text-left font-normal" , ! field . value && "text-muted-foreground" ) }
258239 >
259- { field . value ? format ( new Date ( field . value ) , "PPP" ) : < span > Pick a date</ span > }
240+ { field . value ? format ( new Date ( field . value ) , "PPP" ) : < span > { t ( "placeholders. date" ) } </ span > }
260241 < CalendarIcon className = "ml-auto h-4 w-4 opacity-50" />
261242 </ Button >
262243 </ FormControl >
@@ -281,15 +262,15 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
281262 name = "reservation_start_date"
282263 render = { ( { field } ) => (
283264 < FormItem className = "flex flex-col" >
284- < FormLabel aria-required > Reservation Start Date </ FormLabel >
265+ < FormLabel aria-required > { t ( "labels.reservation-start" ) } </ FormLabel >
285266 < Popover >
286267 < PopoverTrigger asChild >
287268 < FormControl >
288269 < Button
289270 variant = "outline"
290271 className = { cn ( "w-full pl-3 text-left font-normal" , ! field . value && "text-muted-foreground" ) }
291272 >
292- { field . value ? format ( new Date ( field . value ) , "PPP" ) : < span > Pick a date</ span > }
273+ { field . value ? format ( new Date ( field . value ) , "PPP" ) : < span > { t ( "placeholders. date" ) } </ span > }
293274 < CalendarIcon className = "ml-auto h-4 w-4 opacity-50" />
294275 </ Button >
295276 </ FormControl >
@@ -313,15 +294,15 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
313294 name = "reservation_end_date"
314295 render = { ( { field } ) => (
315296 < FormItem className = "flex flex-col" >
316- < FormLabel aria-required > Reservation End Date </ FormLabel >
297+ < FormLabel aria-required > { t ( "labels.reservation-end" ) } </ FormLabel >
317298 < Popover >
318299 < PopoverTrigger asChild >
319300 < FormControl >
320301 < Button
321302 variant = "outline"
322303 className = { cn ( "w-full pl-3 text-left font-normal" , ! field . value && "text-muted-foreground" ) }
323304 >
324- { field . value ? format ( new Date ( field . value ) , "PPP" ) : < span > Pick a date</ span > }
305+ { field . value ? format ( new Date ( field . value ) , "PPP" ) : < span > { t ( "placeholders. date" ) } </ span > }
325306 < CalendarIcon className = "ml-auto h-4 w-4 opacity-50" />
326307 </ Button >
327308 </ FormControl >
@@ -347,9 +328,9 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
347328 name = "duration"
348329 render = { ( { field } ) => (
349330 < FormItem >
350- < FormLabel aria-required > Duration </ FormLabel >
331+ < FormLabel aria-required > { t ( "labels.duration" ) } </ FormLabel >
351332 < FormControl >
352- < Input placeholder = "e.g. 2 hours" { ...field } />
333+ < Input placeholder = { t ( "placeholders.duration" ) } { ...field } />
353334 </ FormControl >
354335 < FormMessage />
355336 </ FormItem >
@@ -361,11 +342,11 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
361342 name = "capacity"
362343 render = { ( { field } ) => (
363344 < FormItem >
364- < FormLabel aria-required > Capacity </ FormLabel >
345+ < FormLabel aria-required > { t ( "labels.capacity" ) } </ FormLabel >
365346 < FormControl >
366347 < Input
367348 type = "number"
368- placeholder = "Enter capacity"
349+ placeholder = { t ( "placeholders. capacity") }
369350 { ...field }
370351 onChange = { ( e ) => field . onChange ( parseInt ( e . target . value ) || 0 ) }
371352 />
@@ -380,11 +361,11 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
380361 name = "price"
381362 render = { ( { field } ) => (
382363 < FormItem >
383- < FormLabel aria-required > Price </ FormLabel >
364+ < FormLabel aria-required > { t ( "labels.price" ) } </ FormLabel >
384365 < FormControl >
385366 < Input
386367 type = "number"
387- placeholder = "Enter price"
368+ placeholder = { t ( "placeholders. price") }
388369 { ...field }
389370 onChange = { ( e ) => field . onChange ( parseInt ( e . target . value ) || 0 ) }
390371 />
@@ -400,9 +381,9 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
400381 name = "registration_link"
401382 render = { ( { field } ) => (
402383 < FormItem >
403- < FormLabel aria-required > Registration Link </ FormLabel >
384+ < FormLabel aria-required > { t ( "labels.registration-link" ) } </ FormLabel >
404385 < FormControl >
405- < Input placeholder = "https://example.com/register" { ...field } />
386+ < Input placeholder = { t ( "placeholders.registration-link" ) } { ...field } />
406387 </ FormControl >
407388 < FormMessage />
408389 </ FormItem >
@@ -414,11 +395,11 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
414395 name = "tags"
415396 render = { ( { field } ) => (
416397 < FormItem >
417- < FormLabel > Tags </ FormLabel >
398+ < FormLabel > { t ( "labels.tags" ) } </ FormLabel >
418399 < div className = "space-y-2" >
419400 < div className = "flex gap-2" >
420401 < Input
421- placeholder = "Add a tag"
402+ placeholder = { t ( "placeholders.tags" ) }
422403 value = { tagInput }
423404 onChange = { ( e ) => setTagInput ( e . target . value ) }
424405 onKeyDown = { ( e ) => {
@@ -429,7 +410,7 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
429410 } }
430411 />
431412 < Button type = "button" onClick = { addTag } variant = "outline" >
432- Add
413+ { t ( "buttons.add" ) }
433414 </ Button >
434415 </ div >
435416 < div className = "flex flex-wrap gap-2" >
@@ -451,11 +432,11 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
451432 name = "speakers"
452433 render = { ( { field } ) => (
453434 < FormItem >
454- < FormLabel > Speakers </ FormLabel >
435+ < FormLabel > { t ( "labels.speakers" ) } </ FormLabel >
455436 < div className = "space-y-2" >
456437 < div className = "flex gap-2" >
457438 < Input
458- placeholder = "Add a speaker"
439+ placeholder = { t ( "placeholders.speakers" ) }
459440 value = { speakerInput }
460441 onChange = { ( e ) => setSpeakerInput ( e . target . value ) }
461442 onKeyDown = { ( e ) => {
@@ -466,7 +447,7 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
466447 } }
467448 />
468449 < Button type = "button" onClick = { addSpeaker } variant = "outline" >
469- Add
450+ { t ( "buttons.add" ) }
470451 </ Button >
471452 </ div >
472453 < div className = "flex flex-wrap gap-2" >
@@ -489,8 +470,8 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
489470 render = { ( { field } ) => (
490471 < FormItem className = "flex flex-row items-center justify-between rounded-lg border p-4" >
491472 < div className = "space-y-0.5" >
492- < FormLabel className = "text-base" > Online Event </ FormLabel >
493- < div className = "text-muted-foreground text-sm" > Is this an online event? </ div >
473+ < FormLabel className = "text-base" > { t ( "labels.online-event" ) } </ FormLabel >
474+ < div className = "text-muted-foreground text-sm" > { t ( "labels. online-description" ) } </ div >
494475 </ div >
495476 < FormControl >
496477 < Switch checked = { field . value } onCheckedChange = { field . onChange } />
@@ -504,15 +485,15 @@ const EventForm = ({ onSubmit, isLoading = false, initialData, mode = "create" }
504485 < Save className = "mr-2 h-4 w-4" />
505486 { isLoading
506487 ? mode === "create"
507- ? "Creating..."
508- : "Updating..."
488+ ? t ( "buttons.creating" )
489+ : t ( "buttons.updating" )
509490 : mode === "create"
510- ? "Create Event"
511- : "Update Event" }
491+ ? t ( "buttons.create" )
492+ : t ( "buttons.update" ) }
512493 </ Button >
513494
514495 < Button type = "button" variant = "outline" >
515- Cancel
496+ { t ( "buttons.cancel" ) }
516497 </ Button >
517498 </ div >
518499 </ form >
0 commit comments