Activity dateDisplay: detail double-renders same-day; cards omit end time #67

Open
opened 2026-05-23 13:56:19 +00:00 by padreug · 0 comments
Owner

Two adjacent dateDisplay rendering bugs in the activities module. Bundling them since the fix shape is shared (sameDay-aware compaction).


(1) Detail page double-renders same-day events

Repro

Create a date-based activity (no start/end time, just dates). The form auto-mirrors the end date to the start date for single-day events (see CreateEventDialog.vue end-date auto-mirror watcher), so a one-day event is published with both start and end set to the same date.

On the activity detail page (/activities/<id>), the "When" block reads:

Tuesday, May 26, 2026 — Tuesday, May 26, 2026

Expected: a single-day event should render the date once, e.g. Tuesday, May 26, 2026.

Root cause

src/modules/activities/views/ActivityDetailPage.vue:64-87dateDisplay has a sameDay collapse for the time-based branch but not for the date-based branch:

if (a.type === 'date') {
  const start = format(a.startDate, 'EEEE, MMMM d, yyyy', opts)
  if (a.endDate) {
    return `${start}${format(a.endDate, 'EEEE, MMMM d, yyyy', opts)}`
  }
  return start
}
// Time-based event. If start and end share the same calendar day,
// show end as time-only ("19:00 — 21:45"). ...
const FULL = 'EEEE, MMMM d, yyyy \u2022 HH:mm'
const start = format(a.startDate, FULL, opts)
if (!a.endDate) return start
const sameDay =
  a.startDate.getFullYear() === a.endDate.getFullYear() &&
  a.startDate.getMonth() === a.endDate.getMonth() &&
  a.startDate.getDate() === a.endDate.getDate()
return `${start}${format(a.endDate, sameDay ? 'HH:mm' : FULL, opts)}`

The date-based branch unconditionally appends — <end> whenever endDate is present, even when it equals the start.

Proposed fix

Add the same sameDay check to the date-based branch and skip the — <end> suffix when start and end are the same calendar day. Multi-day date events (e.g. May 26 — May 28) still render the range as before.


(2) Card omits end time entirely on time-based events

Repro

Create a time-based activity with both a start time and an end time (e.g. start 11:00, end 14:00). On the activities feed, the card's date row reads only:

Fri, May 22 • 11:00

The end time is dropped — the viewer can't tell whether the event runs 30 min or 6 hours without opening the detail page. The card has room to fit it.

Root cause

src/modules/activities/components/ActivityCard.vue:23-37dateDisplay never references endDate:

const dateDisplay = computed(() => {
  const a = props.activity
  if (!a.startDate || isNaN(a.startDate.getTime())) return ''
  try {
    const opts = { locale: dateLocale.value }
    if (a.type === 'date') {
      return format(a.startDate, 'EEE, MMM d', opts)
    }
    const date = format(a.startDate, 'EEE, MMM d', opts)
    const time = format(a.startDate, 'HH:mm', opts)
    return `${date} \u2022 ${time}`
  } catch {
    return ''
  }
})

Proposed fix

Mirror the detail-page logic with the card's shorter format strings, sameDay-aware:

  • date-based, same day: Fri, May 22
  • date-based, multi-day: Fri, May 22 — Sun, May 24
  • time-based, no end: Fri, May 22 • 11:00
  • time-based, same day + end: Fri, May 22 • 11:00 — 14:00
  • time-based, multi-day + end: Fri, May 22 • 11:00 — Sat, May 23 • 14:00

The card's date row has class="truncate" so on very narrow viewports the multi-day time form may ellipsize — acceptable, and the detail page always has the full string.


The other surfaces that render activity dates probably want the same treatment — worth a quick audit while touching this:

  • ActivityCalendarView.vue
  • ActivitySearchOverlay.vue
  • EventsPage.vue (Events list)

🤖 Generated with Claude Code

Two adjacent `dateDisplay` rendering bugs in the activities module. Bundling them since the fix shape is shared (sameDay-aware compaction). --- ## (1) Detail page double-renders same-day events ### Repro Create a date-based activity (no start/end *time*, just dates). The form auto-mirrors the end date to the start date for single-day events (see `CreateEventDialog.vue` end-date auto-mirror watcher), so a one-day event is published with both `start` and `end` set to the same date. On the activity detail page (`/activities/<id>`), the "When" block reads: > Tuesday, May 26, 2026 — Tuesday, May 26, 2026 Expected: a single-day event should render the date once, e.g. `Tuesday, May 26, 2026`. ### Root cause `src/modules/activities/views/ActivityDetailPage.vue:64-87` — `dateDisplay` has a `sameDay` collapse for the time-based branch but not for the date-based branch: ```ts if (a.type === 'date') { const start = format(a.startDate, 'EEEE, MMMM d, yyyy', opts) if (a.endDate) { return `${start} — ${format(a.endDate, 'EEEE, MMMM d, yyyy', opts)}` } return start } // Time-based event. If start and end share the same calendar day, // show end as time-only ("19:00 — 21:45"). ... const FULL = 'EEEE, MMMM d, yyyy \u2022 HH:mm' const start = format(a.startDate, FULL, opts) if (!a.endDate) return start const sameDay = a.startDate.getFullYear() === a.endDate.getFullYear() && a.startDate.getMonth() === a.endDate.getMonth() && a.startDate.getDate() === a.endDate.getDate() return `${start} — ${format(a.endDate, sameDay ? 'HH:mm' : FULL, opts)}` ``` The date-based branch unconditionally appends `— <end>` whenever `endDate` is present, even when it equals the start. ### Proposed fix Add the same `sameDay` check to the date-based branch and skip the `— <end>` suffix when start and end are the same calendar day. Multi-day date events (e.g. May 26 — May 28) still render the range as before. --- ## (2) Card omits end time entirely on time-based events ### Repro Create a time-based activity with both a start time and an end time (e.g. start 11:00, end 14:00). On the activities feed, the card's date row reads only: > Fri, May 22 • 11:00 The end time is dropped — the viewer can't tell whether the event runs 30 min or 6 hours without opening the detail page. The card has room to fit it. ### Root cause `src/modules/activities/components/ActivityCard.vue:23-37` — `dateDisplay` never references `endDate`: ```ts const dateDisplay = computed(() => { const a = props.activity if (!a.startDate || isNaN(a.startDate.getTime())) return '' try { const opts = { locale: dateLocale.value } if (a.type === 'date') { return format(a.startDate, 'EEE, MMM d', opts) } const date = format(a.startDate, 'EEE, MMM d', opts) const time = format(a.startDate, 'HH:mm', opts) return `${date} \u2022 ${time}` } catch { return '' } }) ``` ### Proposed fix Mirror the detail-page logic with the card's shorter format strings, sameDay-aware: - date-based, same day: `Fri, May 22` - date-based, multi-day: `Fri, May 22 — Sun, May 24` - time-based, no end: `Fri, May 22 • 11:00` - time-based, same day + end: `Fri, May 22 • 11:00 — 14:00` - time-based, multi-day + end: `Fri, May 22 • 11:00 — Sat, May 23 • 14:00` The card's date row has `class="truncate"` so on very narrow viewports the multi-day time form may ellipsize — acceptable, and the detail page always has the full string. --- ## Related The other surfaces that render activity dates probably want the same treatment — worth a quick audit while touching this: - `ActivityCalendarView.vue` - `ActivitySearchOverlay.vue` - `EventsPage.vue` (Events list) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
padreug changed title from Activity detail shows date twice when start and end fall on the same day to Activity dateDisplay: detail double-renders same-day; cards omit end time 2026-05-23 14:13:29 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/webapp#67
No description provided.