fix: implement useTranslations for start date on event modal
This commit is contained in:
committed by
Linus Rath
parent
a4bb8e0c28
commit
f0967f90eb
+115
-106
@@ -130,6 +130,15 @@ export function EventModal({
|
|||||||
const timeFormat = useSettingsStore((s) => s.timeFormat);
|
const timeFormat = useSettingsStore((s) => s.timeFormat);
|
||||||
const timeDisplayFmt = timeFormat === "12h" ? "h:mm a" : "HH:mm";
|
const timeDisplayFmt = timeFormat === "12h" ? "h:mm a" : "HH:mm";
|
||||||
const isEdit = !!event;
|
const isEdit = !!event;
|
||||||
|
|
||||||
|
const formatEventDate = useCallback((startD: Date): string => {
|
||||||
|
const dayOfWeek = format(startD, "EEE").toLowerCase();
|
||||||
|
const month = format(startD, "MMM").toLowerCase();
|
||||||
|
const day = format(startD, "d");
|
||||||
|
const year = format(startD, "yyyy");
|
||||||
|
return `${t(`days.${dayOfWeek}`)}, ${t(`months.${month}`)} ${day}, ${year}`;
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
const [mode, setMode] = useState<"view" | "edit">(isEdit ? "view" : "edit");
|
const [mode, setMode] = useState<"view" | "edit">(isEdit ? "view" : "edit");
|
||||||
|
|
||||||
const userIsOrganizer = useMemo(() => {
|
const userIsOrganizer = useMemo(() => {
|
||||||
@@ -495,14 +504,14 @@ export function EventModal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={modalRef} role="dialog" aria-modal={isMobile || undefined} aria-label={event.title || t("events.no_title")} className={isMobile ? "fixed inset-0 z-50 flex flex-col bg-background" : "flex flex-col h-full bg-background"}>
|
<div ref={modalRef} role="dialog" aria-modal={isMobile || undefined} aria-label={event.title || t("events.no_title")} className={isMobile ? "fixed inset-0 z-50 flex flex-col bg-background" : "flex flex-col h-full bg-background"}>
|
||||||
<div className="flex items-center justify-between px-6 py-4 border-b border-border flex-shrink-0">
|
<div className="flex items-center justify-between px-6 py-4 border-b border-border flex-shrink-0">
|
||||||
<h2 className="text-lg font-semibold truncate">{event.title || t("events.no_title")}</h2>
|
<h2 className="text-lg font-semibold truncate">{event.title || t("events.no_title")}</h2>
|
||||||
<button onClick={onClose} className="p-1.5 rounded-md hover:bg-muted transition-colors duration-150 text-muted-foreground hover:text-foreground" aria-label={t("form.cancel")}>
|
<button onClick={onClose} className="p-1.5 rounded-md hover:bg-muted transition-colors duration-150 text-muted-foreground hover:text-foreground" aria-label={t("form.cancel")}>
|
||||||
<X className="w-5 h-5" />
|
<X className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto">
|
||||||
<div className="px-6 py-4 space-y-3">
|
<div className="px-6 py-4 space-y-3">
|
||||||
<div className="flex items-start gap-3 rounded-lg border border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-950/50 px-4 py-3">
|
<div className="flex items-start gap-3 rounded-lg border border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-950/50 px-4 py-3">
|
||||||
<CalendarDays className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" />
|
<CalendarDays className="w-5 h-5 text-blue-600 dark:text-blue-400 mt-0.5 flex-shrink-0" />
|
||||||
@@ -517,7 +526,7 @@ export function EventModal({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-sm">
|
<div className="text-sm">
|
||||||
<span className="font-medium">{format(startD, "EEE, MMM d, yyyy")}</span>
|
<span className="font-medium">{formatEventDate(startD)}</span>
|
||||||
{!event.showWithoutTime && (
|
{!event.showWithoutTime && (
|
||||||
<span className="text-muted-foreground ml-2">
|
<span className="text-muted-foreground ml-2">
|
||||||
{format(startD, timeDisplayFmt)} – {format(endD, timeDisplayFmt)}
|
{format(startD, timeDisplayFmt)} – {format(endD, timeDisplayFmt)}
|
||||||
@@ -550,48 +559,48 @@ export function EventModal({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="px-6 py-4 border-t border-border flex-shrink-0">
|
<div className="px-6 py-4 border-t border-border flex-shrink-0">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm font-medium">{t("participants.rsvp_label")}</span>
|
<span className="text-sm font-medium">{t("participants.rsvp_label")}</span>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={userCurrentStatus === "accepted" ? "default" : "outline"}
|
variant={userCurrentStatus === "accepted" ? "default" : "outline"}
|
||||||
onClick={() => handleRsvp("accepted")}
|
onClick={() => handleRsvp("accepted")}
|
||||||
className={userCurrentStatus === "accepted"
|
className={userCurrentStatus === "accepted"
|
||||||
? "bg-success hover:bg-success/80 text-success-foreground"
|
? "bg-success hover:bg-success/80 text-success-foreground"
|
||||||
: "text-success border-success/30 hover:bg-success/10"}
|
: "text-success border-success/30 hover:bg-success/10"}
|
||||||
>
|
>
|
||||||
{userCurrentStatus === "accepted" && <Check className="w-4 h-4 mr-1" />}
|
{userCurrentStatus === "accepted" && <Check className="w-4 h-4 mr-1" />}
|
||||||
{t("participants.accepted")}
|
{t("participants.accepted")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={userCurrentStatus === "tentative" ? "default" : "outline"}
|
variant={userCurrentStatus === "tentative" ? "default" : "outline"}
|
||||||
onClick={() => handleRsvp("tentative")}
|
onClick={() => handleRsvp("tentative")}
|
||||||
className={userCurrentStatus === "tentative"
|
className={userCurrentStatus === "tentative"
|
||||||
? "bg-warning hover:bg-warning/80 text-warning-foreground"
|
? "bg-warning hover:bg-warning/80 text-warning-foreground"
|
||||||
: "border border-warning/30 text-warning hover:bg-warning/10"}
|
: "border border-warning/30 text-warning hover:bg-warning/10"}
|
||||||
>
|
>
|
||||||
{userCurrentStatus === "tentative" && <Check className="w-4 h-4 mr-1" />}
|
{userCurrentStatus === "tentative" && <Check className="w-4 h-4 mr-1" />}
|
||||||
{t("participants.tentative")}
|
{t("participants.tentative")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={userCurrentStatus === "declined" ? "default" : "ghost"}
|
variant={userCurrentStatus === "declined" ? "default" : "ghost"}
|
||||||
onClick={() => handleRsvp("declined")}
|
onClick={() => handleRsvp("declined")}
|
||||||
className={userCurrentStatus === "declined"
|
className={userCurrentStatus === "declined"
|
||||||
? "bg-destructive hover:bg-destructive/80 text-destructive-foreground"
|
? "bg-destructive hover:bg-destructive/80 text-destructive-foreground"
|
||||||
: "text-destructive hover:bg-destructive/10"}
|
: "text-destructive hover:bg-destructive/10"}
|
||||||
>
|
>
|
||||||
{userCurrentStatus === "declined" && <Check className="w-4 h-4 mr-1" />}
|
{userCurrentStatus === "declined" && <Check className="w-4 h-4 mr-1" />}
|
||||||
{t("participants.declined")}
|
{t("participants.declined")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -638,7 +647,7 @@ export function EventModal({
|
|||||||
<Clock className="w-4 h-4 text-muted-foreground mt-0.5 flex-shrink-0" />
|
<Clock className="w-4 h-4 text-muted-foreground mt-0.5 flex-shrink-0" />
|
||||||
<div className="text-sm">
|
<div className="text-sm">
|
||||||
<span className="font-medium text-foreground">
|
<span className="font-medium text-foreground">
|
||||||
{format(startD, "EEE, MMM d, yyyy")}
|
{formatEventDate(startD)}
|
||||||
</span>
|
</span>
|
||||||
{event.showWithoutTime ? (
|
{event.showWithoutTime ? (
|
||||||
<span className="text-muted-foreground ml-1.5">{t("events.all_day")}</span>
|
<span className="text-muted-foreground ml-1.5">{t("events.all_day")}</span>
|
||||||
@@ -767,16 +776,16 @@ export function EventModal({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={modalRef} role="dialog" aria-modal={isMobile || undefined} aria-label={isEdit ? t("events.edit") : t("events.create")} data-tour="event-modal" className={isMobile ? "fixed inset-0 z-50 flex flex-col bg-background" : "flex flex-col h-full bg-background"}>
|
<div ref={modalRef} role="dialog" aria-modal={isMobile || undefined} aria-label={isEdit ? t("events.edit") : t("events.create")} data-tour="event-modal" className={isMobile ? "fixed inset-0 z-50 flex flex-col bg-background" : "flex flex-col h-full bg-background"}>
|
||||||
<div className="flex items-center justify-between px-6 py-4 border-b border-border flex-shrink-0">
|
<div className="flex items-center justify-between px-6 py-4 border-b border-border flex-shrink-0">
|
||||||
<h2 className="text-lg font-semibold">
|
<h2 className="text-lg font-semibold">
|
||||||
{isEdit ? t("events.edit") : t("events.create")}
|
{isEdit ? t("events.edit") : t("events.create")}
|
||||||
</h2>
|
</h2>
|
||||||
<button onClick={onClose} className="p-1.5 rounded-md hover:bg-muted transition-colors duration-150 text-muted-foreground hover:text-foreground" aria-label={t("form.cancel")}>
|
<button onClick={onClose} className="p-1.5 rounded-md hover:bg-muted transition-colors duration-150 text-muted-foreground hover:text-foreground" aria-label={t("form.cancel")}>
|
||||||
<X className="w-5 h-5" />
|
<X className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto">
|
||||||
<div className="px-6 py-4 space-y-4">
|
<div className="px-6 py-4 space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium mb-1 block">{t("form.title")}</label>
|
<label className="text-sm font-medium mb-1 block">{t("form.title")}</label>
|
||||||
@@ -986,69 +995,69 @@ export function EventModal({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-between px-6 py-4 border-t border-border flex-shrink-0">
|
<div className="flex items-center justify-between px-6 py-4 border-t border-border flex-shrink-0">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
{isEdit && onDelete && (
|
{isEdit && onDelete && (
|
||||||
showDeleteConfirm ? (
|
showDeleteConfirm ? (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div>
|
<div>
|
||||||
<span className="text-sm text-red-600 dark:text-red-400">
|
<span className="text-sm text-red-600 dark:text-red-400">
|
||||||
{t("form.delete_confirm")}
|
{t("form.delete_confirm")}
|
||||||
</span>
|
</span>
|
||||||
{hasParticipants && (
|
{hasParticipants && (
|
||||||
<p className="text-xs text-muted-foreground mt-0.5">
|
<p className="text-xs text-muted-foreground mt-0.5">
|
||||||
{t("participants.cancel_notification")}
|
{t("participants.cancel_notification")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
onClick={() => { onDelete(event!.id, hasParticipants || undefined); onClose(); }}
|
|
||||||
className="text-red-600 dark:text-red-400 border-red-300 dark:border-red-700"
|
|
||||||
>
|
|
||||||
{t("events.delete")}
|
|
||||||
</Button>
|
|
||||||
<Button variant="ghost" size="sm" onClick={() => setShowDeleteConfirm(false)}>
|
|
||||||
{t("form.cancel")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => setShowDeleteConfirm(true)}
|
onClick={() => { onDelete(event!.id, hasParticipants || undefined); onClose(); }}
|
||||||
className="text-red-600 dark:text-red-400"
|
className="text-red-600 dark:text-red-400 border-red-300 dark:border-red-700"
|
||||||
>
|
>
|
||||||
<Trash2 className="w-4 h-4 mr-1" />
|
|
||||||
{t("events.delete")}
|
{t("events.delete")}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
<Button variant="ghost" size="sm" onClick={() => setShowDeleteConfirm(false)}>
|
||||||
)}
|
{t("form.cancel")}
|
||||||
{isEdit && onDuplicate && !showDeleteConfirm && (
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={handleDuplicate}
|
onClick={() => setShowDeleteConfirm(true)}
|
||||||
aria-label={t("events.duplicate")}
|
className="text-red-600 dark:text-red-400"
|
||||||
>
|
>
|
||||||
<Copy className="w-4 h-4 mr-1" />
|
<Trash2 className="w-4 h-4 mr-1" />
|
||||||
{t("events.duplicate")}
|
{t("events.delete")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)
|
||||||
</div>
|
)}
|
||||||
|
{isEdit && onDuplicate && !showDeleteConfirm && (
|
||||||
<div className="flex gap-2">
|
<Button
|
||||||
<Button variant="outline" onClick={isEdit ? () => setMode("view") : onClose}>
|
variant="ghost"
|
||||||
{t("form.cancel")}
|
size="sm"
|
||||||
|
onClick={handleDuplicate}
|
||||||
|
aria-label={t("events.duplicate")}
|
||||||
|
>
|
||||||
|
<Copy className="w-4 h-4 mr-1" />
|
||||||
|
{t("events.duplicate")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleSave} disabled={!title.trim() || isSaving}>
|
)}
|
||||||
{t("form.save")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Button variant="outline" onClick={isEdit ? () => setMode("view") : onClose}>
|
||||||
|
{t("form.cancel")}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleSave} disabled={!title.trim() || isSaving}>
|
||||||
|
{t("form.save")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-1
@@ -2272,6 +2272,20 @@
|
|||||||
"sat": "Sat",
|
"sat": "Sat",
|
||||||
"sun": "Sun"
|
"sun": "Sun"
|
||||||
},
|
},
|
||||||
|
"months": {
|
||||||
|
"jan": "Jan",
|
||||||
|
"feb": "Feb",
|
||||||
|
"mar": "Mar",
|
||||||
|
"apr": "Apr",
|
||||||
|
"may": "May",
|
||||||
|
"jun": "Jun",
|
||||||
|
"jul": "Jul",
|
||||||
|
"aug": "Aug",
|
||||||
|
"sep": "Sep",
|
||||||
|
"oct": "Oct",
|
||||||
|
"nov": "Nov",
|
||||||
|
"dec": "Dez"
|
||||||
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"event_created": "Event created",
|
"event_created": "Event created",
|
||||||
"event_updated": "Event updated",
|
"event_updated": "Event updated",
|
||||||
@@ -2749,4 +2763,4 @@
|
|||||||
"unified_mailbox": {
|
"unified_mailbox": {
|
||||||
"search_unavailable": "Search is not available in the unified view"
|
"search_unavailable": "Search is not available in the unified view"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+15
-1
@@ -2261,6 +2261,20 @@
|
|||||||
"sat": "Sam",
|
"sat": "Sam",
|
||||||
"sun": "Dim"
|
"sun": "Dim"
|
||||||
},
|
},
|
||||||
|
"months": {
|
||||||
|
"jan": "Jan",
|
||||||
|
"feb": "Fév",
|
||||||
|
"mar": "Mar",
|
||||||
|
"apr": "Avr",
|
||||||
|
"may": "Mai",
|
||||||
|
"jun": "Juin",
|
||||||
|
"jul": "Juil",
|
||||||
|
"aug": "Aoû",
|
||||||
|
"sep": "Sep",
|
||||||
|
"oct": "Oct",
|
||||||
|
"nov": "Nov",
|
||||||
|
"dec": "Déc"
|
||||||
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"event_created": "Événement créé",
|
"event_created": "Événement créé",
|
||||||
"event_updated": "Événement mis à jour",
|
"event_updated": "Événement mis à jour",
|
||||||
@@ -2738,4 +2752,4 @@
|
|||||||
"custom": "Personnalisé"
|
"custom": "Personnalisé"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2261,6 +2261,20 @@
|
|||||||
"sat": "Sáb",
|
"sat": "Sáb",
|
||||||
"sun": "Dom"
|
"sun": "Dom"
|
||||||
},
|
},
|
||||||
|
"months": {
|
||||||
|
"jan": "Jan",
|
||||||
|
"feb": "Fev",
|
||||||
|
"mar": "Mar",
|
||||||
|
"apr": "Abr",
|
||||||
|
"may": "Mai",
|
||||||
|
"jun": "Jun",
|
||||||
|
"jul": "Jul",
|
||||||
|
"aug": "Ago",
|
||||||
|
"sep": "Set",
|
||||||
|
"oct": "Out",
|
||||||
|
"nov": "Nov",
|
||||||
|
"dec": "Dez"
|
||||||
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"event_created": "Evento criado",
|
"event_created": "Evento criado",
|
||||||
"event_updated": "Evento atualizado",
|
"event_updated": "Evento atualizado",
|
||||||
|
|||||||
Reference in New Issue
Block a user