Skip to content

Commit fa78162

Browse files
committed
chore: adjust translation, and schema
1 parent b8969c0 commit fa78162

File tree

5 files changed

+215
-71
lines changed

5 files changed

+215
-71
lines changed

src/domains/Events.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,26 @@ export const userEventSchema = z.object({
7979
});
8080

8181
export type UserEventType = z.infer<typeof userEventSchema>;
82+
83+
export const createEventFormSchema = (t: (key: string) => string) =>
84+
z.object({
85+
title: z.string().min(1, t("validation.title-required")),
86+
description: z.string().min(1, t("validation.description-required")),
87+
file_name: z.string().optional(),
88+
slug: z.string().min(1, t("validation.slug-required")),
89+
is_online: z.boolean(),
90+
date: z.string().min(1, t("validation.date-required")),
91+
type: z.string().min(1, t("validation.type-required")),
92+
location: z.string().min(1, t("validation.location-required")),
93+
duration: z.string().min(1, t("validation.duration-required")),
94+
status: z.string().min(1, t("validation.status-required")),
95+
capacity: z.number().min(1, t("validation.capacity-min")),
96+
price: z.number().min(0, t("validation.price-min")),
97+
registration_link: z.string().url(t("validation.registration-url")),
98+
tags: z.array(z.string()),
99+
speakers: z.array(z.string()),
100+
reservation_start_date: z.string().min(1, t("validation.reservation-start-required")),
101+
reservation_end_date: z.string().min(1, t("validation.reservation-end-required")),
102+
});
103+
104+
export type EventFormType = z.infer<ReturnType<typeof createEventFormSchema>>;

src/features/events/components/EventForm.tsx

Lines changed: 52 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useForm } from "react-hook-form";
44
import { zodResolver } from "@hookform/resolvers/zod";
55
import { format } from "date-fns";
66
import { CalendarIcon, Save, X } from "lucide-react";
7-
import { z } from "zod";
7+
import { useTranslations } from "next-intl";
88
import { Button } from "@/components/ui/Button";
99
import { Input } from "@/components/ui/Input";
1010
import { Card, CardContent } from "@/components/ui/Card";
@@ -15,32 +15,11 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
1515
import { Switch } from "@/components/ui/Switch";
1616
import TextEditor from "@/components/common/TextEditor/TextEditor";
1717
import { cn, generateSlug } from "@/lib/utils";
18-
18+
import { createEventFormSchema, EventFormType } from "@/domains/Events";
19+
import { eventTypes } from "../constants";
1920
import { useState, useEffect } from "react";
2021
import 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-
4423
interface EventFormProps {
4524
onSubmit: (data: EventFormType) => void;
4625
isLoading?: boolean;
@@ -49,6 +28,8 @@ interface EventFormProps {
4928
}
5029

5130
const 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>

src/features/events/constants.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ export const mockEvents: TechEvent[] = [
112112
},
113113
];
114114

115+
export const eventTypes = [
116+
{ value: "Tech Talk", label: "Tech Talk" },
117+
{ value: "Workshop", label: "Workshop" },
118+
{ value: "Seminar", label: "Seminar" },
119+
{ value: "Conference", label: "Conference" },
120+
{ value: "Bootcamp", label: "Bootcamp" },
121+
];
122+
115123
export const eventsInfo: EventInfoType[] = [
116124
{
117125
id: 1,

0 commit comments

Comments
 (0)