ultisuite-client/components/gmail/calendar-invitation-preview.tsx
R3D347HR4Y 3bbf3691b0
Some checks failed
E2E / Playwright e2e (push) Has been cancelled
bordel c'est beau
2026-06-11 10:10:39 +02:00

163 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useMemo, useState } from "react"
import { format } from "date-fns"
import { InvitationTimeChipText } from "@/components/gmail/invitation-time-chip-text"
import { Icon } from "@iconify/react"
import { ThumbsDown, ThumbsUp, Users, MoreVertical } from "lucide-react"
import {
VIDEO_CONFERENCE_LOGOS,
formatInvitationAttendeeLine,
type ParsedCalendarInvitation,
} from "@/lib/calendar-invitation"
import { ensureVcLogosCollection } from "@/lib/register-vc-logos"
import { cn } from "@/lib/utils"
import { MAIL_INVITATION_CARD_CLASS } from "@/lib/mail-chrome-classes"
function attendeeDisplayList(inv: ParsedCalendarInvitation): {
organizerLine?: string
othersLine?: string
} {
const orgEmail = inv.organizer?.email
const organizerLine =
orgEmail || inv.organizer?.name
? `${orgEmail ?? inv.organizer?.name} Organisateur`
: undefined
const others = inv.attendees.filter((a) => {
const e = a.email?.toLowerCase()
return e && e !== orgEmail?.toLowerCase()
})
const line = formatInvitationAttendeeLine(
others.length > 0 ? others : inv.attendees,
4
)
return {
organizerLine,
othersLine: line || undefined,
}
}
const RSVP_BTN =
"rounded-full bg-[#1a73e8] px-4 py-2 text-sm font-medium text-white shadow-sm transition-colors hover:bg-[#1557b0]"
const RSVP_SECONDARY =
"rounded-full border border-border bg-mail-surface px-4 py-2 text-sm font-medium text-primary transition-colors hover:bg-accent"
export function CalendarInvitationPreview({
invitation,
className,
}: {
invitation: ParsedCalendarInvitation
className?: string
}) {
ensureVcLogosCollection()
const { organizerLine, othersLine } = useMemo(
() => attendeeDisplayList(invitation),
[invitation]
)
const confIcon = VIDEO_CONFERENCE_LOGOS[invitation.conferenceProvider]
const [rsvp, setRsvp] = useState<string | null>(null)
return (
<div
className={cn(
MAIL_INVITATION_CARD_CLASS,
className
)}
>
<div className="flex flex-col gap-3 md:flex-row md:items-start md:justify-between md:gap-4">
<div className="min-w-0 flex-1 space-y-2">
<div className="flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
<Icon icon={confIcon} className="size-5 shrink-0" aria-hidden />
<InvitationTimeChipText
start={invitation.start}
end={invitation.end}
/>
</div>
<h2 className="text-xl font-normal leading-snug text-foreground">
{invitation.summary}
</h2>
{organizerLine && (
<p className="text-sm text-foreground/90">{organizerLine}</p>
)}
{othersLine && (
<p className="flex flex-wrap items-start gap-1.5 text-sm text-foreground/90">
<Users className="mt-0.5 size-4 shrink-0 text-muted-foreground" aria-hidden />
<span>{othersLine}</span>
</p>
)}
</div>
<div className="flex shrink-0 flex-row items-start gap-3 md:flex-col md:items-end">
<div className="flex size-12 shrink-0 items-center justify-center rounded-lg border border-border bg-mail-surface shadow-sm">
<img
src="/agenda-mark.svg"
alt=""
className="size-9 object-contain"
aria-hidden
/>
</div>
<div className="min-w-0 text-right text-sm leading-snug text-muted-foreground">
<p className="font-medium text-foreground">Dans votre agenda</p>
<p className="mt-0.5">Aucun autre événement à cette date</p>
</div>
</div>
</div>
<div className="mt-4 flex flex-wrap items-center gap-2">
{(["Oui", "Non", "Peut-être"] as const).map((label) => (
<button
key={label}
type="button"
className={cn(RSVP_BTN, rsvp === label && "ring-2 ring-[#202124]/30")}
onClick={() => setRsvp(label)}
>
{label}
</button>
))}
<button type="button" className={RSVP_SECONDARY}>
Proposer un autre horaire
</button>
<a
href={`/agenda/day/${format(invitation.start, "yyyy-MM-dd")}`}
className={RSVP_SECONDARY}
>
Ouvrir dans Agenda
</a>
<button
type="button"
className="ml-auto flex size-10 items-center justify-center rounded-full border border-border bg-mail-surface text-muted-foreground hover:bg-accent md:ml-0"
aria-label="Plus doptions"
>
<MoreVertical className="size-[18px]" strokeWidth={1.5} />
</button>
</div>
<div className="mt-4 flex flex-wrap items-center justify-between gap-2 border-t border-border/60 pt-3 text-xs text-muted-foreground">
<span>Daprès cet e-mail</span>
<div className="flex items-center gap-2">
<span>Correct ?</span>
<button
type="button"
className="rounded p-1 text-[#5f6368] hover:bg-black/5"
aria-label="Oui, correct"
>
<ThumbsUp className="size-4" strokeWidth={1.5} />
</button>
<button
type="button"
className="rounded p-1 text-[#5f6368] hover:bg-black/5"
aria-label="Non, incorrect"
>
<ThumbsDown className="size-4" strokeWidth={1.5} />
</button>
</div>
</div>
</div>
)
}