158 lines
4.5 KiB
TypeScript
158 lines
4.5 KiB
TypeScript
"use client"
|
||
|
||
import { useEffect, useState } from "react"
|
||
import { format } from "date-fns"
|
||
import { fr } from "date-fns/locale"
|
||
import { toast } from "sonner"
|
||
import { X } from "lucide-react"
|
||
import { AgendaFloatingCard, type AnchorRect } from "@/components/agenda/agenda-floating-card"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Input } from "@/components/ui/input"
|
||
import {
|
||
Select,
|
||
SelectContent,
|
||
SelectItem,
|
||
SelectTrigger,
|
||
SelectValue,
|
||
} from "@/components/ui/select"
|
||
import {
|
||
draftToApiEvent,
|
||
useCreateAgendaEvent,
|
||
} from "@/lib/api/hooks/use-calendar-mutations"
|
||
import { formatEventTime } from "@/lib/agenda/agenda-date"
|
||
import { calendarColor } from "@/lib/agenda/agenda-events"
|
||
import type {
|
||
AgendaCalendar,
|
||
AgendaEventDraft,
|
||
} from "@/lib/agenda/agenda-types"
|
||
|
||
export interface AgendaQuickCreateState {
|
||
start: Date
|
||
end: Date
|
||
allDay: boolean
|
||
anchor: AnchorRect
|
||
}
|
||
|
||
export function AgendaQuickCreate({
|
||
state,
|
||
calendars,
|
||
defaultCalendarId,
|
||
userEmail,
|
||
onClose,
|
||
onMoreOptions,
|
||
}: {
|
||
state: AgendaQuickCreateState | null
|
||
calendars: AgendaCalendar[]
|
||
defaultCalendarId: string
|
||
userEmail?: string
|
||
onClose: () => void
|
||
onMoreOptions: (draft: AgendaEventDraft) => void
|
||
}) {
|
||
const [title, setTitle] = useState("")
|
||
const [calendarId, setCalendarId] = useState(defaultCalendarId)
|
||
const createMutation = useCreateAgendaEvent()
|
||
|
||
useEffect(() => {
|
||
if (state) {
|
||
setTitle("")
|
||
setCalendarId(defaultCalendarId)
|
||
}
|
||
}, [state, defaultCalendarId])
|
||
|
||
if (!state) return null
|
||
|
||
const draft: AgendaEventDraft = {
|
||
title,
|
||
start: state.start,
|
||
end: state.end,
|
||
allDay: state.allDay,
|
||
calendarId,
|
||
}
|
||
|
||
const dateLabel = format(state.start, "EEEE d MMMM", { locale: fr }).replace(
|
||
/^./,
|
||
(c) => c.toUpperCase(),
|
||
)
|
||
const timeLabel = state.allDay
|
||
? "Toute la journée"
|
||
: `${formatEventTime(state.start)} – ${formatEventTime(state.end)}`
|
||
|
||
const save = async () => {
|
||
try {
|
||
const apiEvent = draftToApiEvent(draft)
|
||
if (userEmail) apiEvent.organizer = userEmail
|
||
await createMutation.mutateAsync({ calendarId, event: apiEvent })
|
||
toast.success("Événement créé")
|
||
onClose()
|
||
} catch {
|
||
toast.error("Impossible de créer l'événement")
|
||
}
|
||
}
|
||
|
||
return (
|
||
<AgendaFloatingCard anchor={state.anchor} onClose={onClose} width={400}>
|
||
<div className="flex items-center justify-end px-2 pt-2">
|
||
<Button
|
||
variant="ghost"
|
||
size="icon"
|
||
className="size-8 rounded-full text-muted-foreground"
|
||
aria-label="Fermer"
|
||
onClick={onClose}
|
||
>
|
||
<X className="size-4" />
|
||
</Button>
|
||
</div>
|
||
<div className="flex flex-col gap-4 px-5 pb-5">
|
||
<Input
|
||
value={title}
|
||
autoFocus
|
||
placeholder="Ajouter un titre"
|
||
onChange={(e) => setTitle(e.target.value)}
|
||
onKeyDown={(e) => {
|
||
if (e.key === "Enter") void save()
|
||
}}
|
||
className="h-11 rounded-none border-0 border-b-2 border-border/60 !bg-transparent px-1 !text-lg shadow-none focus-visible:border-primary focus-visible:ring-0"
|
||
/>
|
||
<div className="flex flex-col gap-1 text-sm text-foreground/85">
|
||
<span>{dateLabel}</span>
|
||
<span className="text-muted-foreground">{timeLabel}</span>
|
||
</div>
|
||
<Select value={calendarId} onValueChange={setCalendarId}>
|
||
<SelectTrigger className="h-9 w-fit min-w-44 border-0 bg-muted/60 shadow-none">
|
||
<SelectValue placeholder="Agenda" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
{calendars.map((cal) => (
|
||
<SelectItem key={cal.id} value={cal.id}>
|
||
<span className="flex items-center gap-2">
|
||
<span
|
||
className="size-3 rounded-full"
|
||
style={{ backgroundColor: calendarColor(cal) }}
|
||
/>
|
||
{cal.display_name}
|
||
</span>
|
||
</SelectItem>
|
||
))}
|
||
</SelectContent>
|
||
</Select>
|
||
<div className="flex items-center justify-end gap-2">
|
||
<Button
|
||
variant="ghost"
|
||
className="rounded-full"
|
||
onClick={() => onMoreOptions(draft)}
|
||
>
|
||
Autres options
|
||
</Button>
|
||
<Button
|
||
className="rounded-full px-5"
|
||
disabled={createMutation.isPending || !calendarId}
|
||
onClick={() => void save()}
|
||
>
|
||
Enregistrer
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</AgendaFloatingCard>
|
||
)
|
||
}
|