From 42ec34be21b82e5a564e030de741d85b143a9c0f Mon Sep 17 00:00:00 2001
From: Linus Rath <139418639+rathlinus@users.noreply.github.com>
Date: Mon, 25 May 2026 16:28:03 +0200
Subject: [PATCH] fix: show end date in event popover for multi-day events #318
---
components/calendar/event-detail-popover.tsx | 58 ++++++++--
components/calendar/event-modal.tsx | 106 +++++++++++++++----
2 files changed, 133 insertions(+), 31 deletions(-)
diff --git a/components/calendar/event-detail-popover.tsx b/components/calendar/event-detail-popover.tsx
index 78de3c28..1f0e4f67 100644
--- a/components/calendar/event-detail-popover.tsx
+++ b/components/calendar/event-detail-popover.tsx
@@ -8,11 +8,11 @@ import {
X, Clock, MapPin, Video, Users, Repeat, Bell, AlignLeft,
Pencil, Trash2, Copy, Send, Check,
} from "lucide-react";
-import { format, parseISO } from "date-fns";
+import { format, isSameDay, parseISO } from "date-fns";
import { cn } from "@/lib/utils";
import type { CalendarEvent, Calendar, CalendarParticipant } from "@/lib/jmap/types";
import { parseDuration, getEventColor } from "./event-card";
-import { getEventEndDate, getEventStartDate } from "@/lib/calendar-utils";
+import { getEventDisplayEndDate, getEventEndDate, getEventStartDate } from "@/lib/calendar-utils";
import {
isOrganizer,
getUserParticipantId,
@@ -143,6 +143,8 @@ export function EventDetailPopover({
const startDate = getEventStartDate(event);
const durationMinutes = parseDuration(event.duration);
const endDate = getEventEndDate(event);
+ const displayEndDate = getEventDisplayEndDate(event);
+ const isMultiDay = !isSameDay(startDate, displayEndDate);
const locationName = useMemo(() => {
if (!event.locations) return null;
@@ -331,16 +333,50 @@ export function EventDetailPopover({
-
- {formatEventDate(startDate)}
-
- {event.showWithoutTime ? (
-
{t("events.all_day")}
+ {isMultiDay ? (
+ event.showWithoutTime ? (
+ <>
+
+ {formatEventDate(startDate)} –
+
+
+ {formatEventDate(displayEndDate)}
+
+
{t("events.all_day")}
+ >
+ ) : (
+ <>
+
+ {formatEventDate(startDate)}
+
+ {formatTime(startDate)}
+
+
+
+ {formatEventDate(endDate)}
+
+ {formatTime(endDate)}
+
+
+
+ ({formatDurationDisplay(durationMinutes)})
+
+ >
+ )
) : (
-
- {formatTime(startDate)} – {formatTime(endDate)}
- ({formatDurationDisplay(durationMinutes)})
-
+ <>
+
+ {formatEventDate(startDate)}
+
+ {event.showWithoutTime ? (
+
{t("events.all_day")}
+ ) : (
+
+ {formatTime(startDate)} – {formatTime(endDate)}
+ ({formatDurationDisplay(durationMinutes)})
+
+ )}
+ >
)}
diff --git a/components/calendar/event-modal.tsx b/components/calendar/event-modal.tsx
index 1d815207..c0d7c87a 100644
--- a/components/calendar/event-modal.tsx
+++ b/components/calendar/event-modal.tsx
@@ -5,7 +5,7 @@ import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { X, Trash2, Check, Users, CalendarDays, Copy, Pencil, Clock, MapPin, Video, Repeat, Bell, AlignLeft, Plus } from "lucide-react";
-import { format, parseISO, addHours, addDays } from "date-fns";
+import { format, parseISO, addHours, addDays, isSameDay } from "date-fns";
import type { CalendarEvent, Calendar, CalendarParticipant, CalendarEventAlert } from "@/lib/jmap/types";
import { parseDuration, getEventColor } from "./event-card";
import { buildAllDayDuration, getEventDisplayEndDate, getEventEndDate, getEventStartDate, getPrimaryCalendarId } from "@/lib/calendar-utils";
@@ -621,14 +621,42 @@ export function EventModal({
-
- {formatEventDate(startD)}
- {!event.showWithoutTime && (
-
- {format(startD, timeDisplayFmt)} – {format(endD, timeDisplayFmt)}
-
- )}
-
+ {(() => {
+ const displayEnd = getEventDisplayEndDate(event);
+ const multiDay = !isSameDay(startD, displayEnd);
+ if (multiDay && event.showWithoutTime) {
+ return (
+
+
{formatEventDate(startD)} –
+
{formatEventDate(displayEnd)}
+
+ );
+ }
+ if (multiDay) {
+ return (
+
+
+ {formatEventDate(startD)}
+ {format(startD, timeDisplayFmt)}
+
+
+ {formatEventDate(endD)}
+ {format(endD, timeDisplayFmt)}
+
+
+ );
+ }
+ return (
+
+ {formatEventDate(startD)}
+ {!event.showWithoutTime && (
+
+ {format(startD, timeDisplayFmt)} – {format(endD, timeDisplayFmt)}
+
+ )}
+
+ );
+ })()}
{event.description && (
{event.description}
@@ -742,17 +770,55 @@ export function EventModal({
-
- {formatEventDate(startD)}
-
- {event.showWithoutTime ? (
-
{t("events.all_day")}
- ) : (
-
- {format(startD, timeDisplayFmt)} – {format(endD, timeDisplayFmt)}
- ({formatDurationDisplay(durMin)})
-
- )}
+ {(() => {
+ const displayEnd = getEventDisplayEndDate(event);
+ const multiDay = !isSameDay(startD, displayEnd);
+ if (multiDay && event.showWithoutTime) {
+ return (
+ <>
+
{formatEventDate(startD)} –
+
{formatEventDate(displayEnd)}
+
{t("events.all_day")}
+ >
+ );
+ }
+ if (multiDay) {
+ return (
+ <>
+
+ {formatEventDate(startD)}
+
+ {format(startD, timeDisplayFmt)}
+
+
+
+ {formatEventDate(endD)}
+
+ {format(endD, timeDisplayFmt)}
+
+
+
+ ({formatDurationDisplay(durMin)})
+
+ >
+ );
+ }
+ return (
+ <>
+
+ {formatEventDate(startD)}
+
+ {event.showWithoutTime ? (
+
{t("events.all_day")}
+ ) : (
+
+ {format(startD, timeDisplayFmt)} – {format(endD, timeDisplayFmt)}
+ ({formatDurationDisplay(durMin)})
+
+ )}
+ >
+ );
+ })()}