ultisuite-client/components/gmail/calendar-invitation-preview.tsx
2026-05-15 17:40:17 +02:00

157 lines
5.2 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 { Icon } from "@iconify/react"
import { ThumbsDown, ThumbsUp, Users, MoreVertical } from "lucide-react"
import {
VIDEO_CONFERENCE_LOGOS,
formatInvitationAttendeeLine,
formatInvitationTimeChip,
type ParsedCalendarInvitation,
} from "@/lib/calendar-invitation"
import { ensureVcLogosCollection } from "@/lib/register-vc-logos"
import { cn } from "@/lib/utils"
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-[#dadce0] bg-[#e8f0fe] px-4 py-2 text-sm font-medium text-[#1a73e8] transition-colors hover:bg-[#d2e3fc]"
export function CalendarInvitationPreview({
invitation,
className,
}: {
invitation: ParsedCalendarInvitation
className?: string
}) {
ensureVcLogosCollection()
const timeChip = useMemo(
() => formatInvitationTimeChip(invitation.start, invitation.end),
[invitation.start, invitation.end]
)
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(
"mx-6 mb-4 rounded-xl border border-[#dadce0] bg-[#e8f0fe]/90 px-4 py-3 shadow-sm",
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-[#5f6368]">
<Icon icon={confIcon} className="size-5 shrink-0" aria-hidden />
<span>{timeChip}</span>
</div>
<h2 className="text-xl font-normal leading-snug text-[#202124]">
{invitation.summary}
</h2>
{organizerLine && (
<p className="text-sm text-[#3c4043]">{organizerLine}</p>
)}
{othersLine && (
<p className="flex flex-wrap items-start gap-1.5 text-sm text-[#3c4043]">
<Users className="mt-0.5 size-4 shrink-0 text-[#5f6368]" 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-[#dadce0] bg-white 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-[#5f6368]">
<p className="font-medium text-[#3c4043]">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>
<button
type="button"
className="ml-auto flex size-10 items-center justify-center rounded-full border border-[#dadce0] bg-[#e8f0fe] text-[#5f6368] hover:bg-[#d2e3fc] 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-[#dadce0]/60 pt-3 text-xs text-[#5f6368]">
<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>
)
}