From b3463a307b0b1d3086cb4d4e5be9925cfc73b654 Mon Sep 17 00:00:00 2001 From: Adam Eivy Date: Sun, 24 May 2026 09:48:56 -0700 Subject: [PATCH 1/5] refactor([migrate-two-remaining-local-formatters]): consolidate EventDetail/TaskItem formatters into shared utils MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace EventDetail's local formatDateTime (which shadowed the shared export with a weekday-led, event-specific shape) with a new shared formatEventDateTime(dateStr, { allDay }) — the all-day branch reuses the existing formatDateFull. Replace TaskItem's local formatDurationMin (every output ~-prefixed) by extending shared formatDurationMin with an { approximate } option. Visual semantics preserved exactly; add formatters.test.js covering both. --- .../src/components/calendar/EventDetail.jsx | 12 ++-- client/src/components/cos/tabs/TaskItem.jsx | 13 +---- client/src/utils/formatters.js | 32 +++++++++-- client/src/utils/formatters.test.js | 55 +++++++++++++++++++ 4 files changed, 89 insertions(+), 23 deletions(-) create mode 100644 client/src/utils/formatters.test.js diff --git a/client/src/components/calendar/EventDetail.jsx b/client/src/components/calendar/EventDetail.jsx index aab1ae11d..ca64b8539 100644 --- a/client/src/components/calendar/EventDetail.jsx +++ b/client/src/components/calendar/EventDetail.jsx @@ -1,4 +1,5 @@ import { X, MapPin, Clock, Users, Repeat, CalendarDays } from 'lucide-react'; +import { formatEventDateTime } from '../../utils/formatters'; const RSVP_STYLES = { accepted: 'bg-port-success/20 text-port-success', @@ -7,11 +8,6 @@ const RSVP_STYLES = { none: 'bg-gray-700 text-gray-400' }; -function formatDateTime(dateStr, isAllDay) { - if (isAllDay) return new Date(dateStr).toLocaleDateString([], { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }); - return new Date(dateStr).toLocaleString([], { weekday: 'short', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }); -} - export default function EventDetail({ event, onClose }) { return (
@@ -47,13 +43,13 @@ export default function EventDetail({ event, onClose }) {
) : ( <> -
{formatDateTime(event.startTime, false)}
+
{formatEventDateTime(event.startTime)}
to
-
{formatDateTime(event.endTime, false)}
+
{formatEventDateTime(event.endTime)}
)} {event.isAllDay && ( -
{formatDateTime(event.startTime, true)}
+
{formatEventDateTime(event.startTime, { allDay: true })}
)} diff --git a/client/src/components/cos/tabs/TaskItem.jsx b/client/src/components/cos/tabs/TaskItem.jsx index c65fea962..fc5904fdd 100644 --- a/client/src/components/cos/tabs/TaskItem.jsx +++ b/client/src/components/cos/tabs/TaskItem.jsx @@ -20,6 +20,7 @@ import { import toast from '../../ui/Toast'; import * as api from '../../../services/api'; import { filterSelectableModels } from '../../../utils/providers'; +import { formatDurationMin } from '../../../utils/formatters'; const statusIcons = { pending: