feat: add collapsible details to calendar invitation banner and update sanitization config for iframe rendering

This commit is contained in:
Linus Rath
2026-04-21 21:21:42 +02:00
parent f032758303
commit 9a44babcf1
4 changed files with 49 additions and 7 deletions
@@ -15,6 +15,7 @@ import {
X,
AlertCircle,
ChevronDown,
ChevronUp,
} from 'lucide-react';
import { useTranslations, useFormatter } from 'next-intl';
import { useRouter } from '@/i18n/navigation';
@@ -372,6 +373,7 @@ export function CalendarInvitationBanner({ email }: CalendarInvitationBannerProp
const [showCalendarPicker, setShowCalendarPicker] = useState(false);
const [selectedCalendarId, setSelectedCalendarId] = useState<string>('');
const [rawIcsMethod, setRawIcsMethod] = useState<InvitationMethod>('unknown');
const [isCollapsed, setIsCollapsed] = useState(true);
const attachment = findCalendarAttachment(email);
@@ -442,6 +444,8 @@ export function CalendarInvitationBanner({ email }: CalendarInvitationBannerProp
const summary = parsedEvent ? formatEventSummary(parsedEvent) : null;
const isCancellation = method === 'cancel';
const isResponseOnly = method === 'reply' || method === 'refresh' || method === 'counter' || method === 'declinecounter';
const canCollapse = method === 'reply';
const showDetails = !canCollapse || !isCollapsed;
const allowsRsvp = method === 'request';
const allowsImport = method === 'request' || method === 'publish' || method === 'add' || method === 'unknown';
@@ -750,9 +754,22 @@ export function CalendarInvitationBanner({ email }: CalendarInvitationBannerProp
)}
<span className="text-sm font-medium text-foreground truncate">{bannerTitle}</span>
</div>
{canCollapse && (
<button
type="button"
onClick={() => setIsCollapsed((prev) => !prev)}
aria-expanded={!isCollapsed}
aria-label={isCollapsed ? t('expand') : t('collapse')}
title={isCollapsed ? t('expand') : t('collapse')}
className="p-1 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors flex-shrink-0"
>
{isCollapsed ? <ChevronDown className="w-4 h-4" /> : <ChevronUp className="w-4 h-4" />}
</button>
)}
</div>
{/* Content */}
{showDetails && (
<div className="px-4 py-3 space-y-2.5">
<div className="lg:flex lg:gap-6">
{/* Left: Event info */}
@@ -894,8 +911,10 @@ export function CalendarInvitationBanner({ email }: CalendarInvitationBannerProp
</div>
)}
</div>
)}
{/* Actions */}
{showDetails && (
<div className="px-4 py-2.5 border-t border-border bg-muted/20 flex items-center gap-2 flex-wrap">
{canRespond && (
<>
@@ -1020,6 +1039,7 @@ export function CalendarInvitationBanner({ email }: CalendarInvitationBannerProp
<Loader2 className="w-4 h-4 animate-spin text-muted-foreground ml-auto" />
)}
</div>
)}
</div>
);
}