feat(events): pipe displayTimezone through list and sidebar formatters

Sidebar (EventsMiniSidebar), public events list, member dashboard
"Upcoming" block, and EventTicketPurchase all formatted dates in
viewer-local TZ. Switch each formatter to accept the event (or an
eventTimezone prop) and pass it to Intl.DateTimeFormat so the
displayed wall-clock matches the event's intended zone.
This commit is contained in:
Jennie Robinson Faber 2026-05-19 10:46:44 +01:00
parent acbd3c0737
commit 9dd007657a
5 changed files with 40 additions and 25 deletions

View file

@ -231,6 +231,10 @@ const props = defineProps({
type: String, type: String,
required: true, required: true,
}, },
eventTimezone: {
type: String,
default: "America/Toronto",
},
userEmail: { userEmail: {
type: String, type: String,
default: null, default: null,
@ -415,6 +419,7 @@ const formatEventDate = (date) => {
month: "long", month: "long",
day: "numeric", day: "numeric",
year: "numeric", year: "numeric",
timeZone: props.eventTimezone || "America/Toronto",
}); });
}; };
</script> </script>

View file

@ -6,7 +6,7 @@
<div v-if="events?.length" class="em-rows"> <div v-if="events?.length" class="em-rows">
<div v-for="event in events" :key="event._id" class="em-item"> <div v-for="event in events" :key="event._id" class="em-item">
<div class="em-inset em-item-body"> <div class="em-inset em-item-body">
<span class="em-date">{{ formatDate(event.startDate) }}</span> <span class="em-date">{{ formatDate(event) }}</span>
<NuxtLink <NuxtLink
:to="`/events/${event.slug || event._id}`" :to="`/events/${event.slug || event._id}`"
class="em-title" class="em-title"
@ -37,10 +37,13 @@ defineProps({
events: { type: Array, default: () => [] }, events: { type: Array, default: () => [] },
}); });
const formatDate = (dateStr) => { const formatDate = (event) => {
if (!dateStr) return ""; if (!event?.startDate) return "";
const d = new Date(dateStr); return new Date(event.startDate).toLocaleDateString("en-US", {
return d.toLocaleDateString("en-US", { month: "short", day: "numeric" }); month: "short",
day: "numeric",
timeZone: event.displayTimezone || "America/Toronto",
});
}; };
</script> </script>

View file

@ -131,6 +131,7 @@
:event-id="event._id || event.id" :event-id="event._id || event.id"
:event-start-date="event.startDate" :event-start-date="event.startDate"
:event-title="event.title" :event-title="event.title"
:event-timezone="eventTimeZone"
:user-email="memberData?.email" :user-email="memberData?.email"
:user-name="memberData?.name" :user-name="memberData?.name"
@success="handleTicketSuccess" @success="handleTicketSuccess"

View file

@ -34,8 +34,8 @@
:class="{ 'is-cancelled': event.isCancelled }" :class="{ 'is-cancelled': event.isCancelled }"
> >
<div class="event-date-col"> <div class="event-date-col">
<span class="event-date">{{ formatDate(event.startDate) }}</span> <span class="event-date">{{ formatDate(event) }}</span>
<span class="event-time">{{ formatTime(event.startDate) }}</span> <span class="event-time">{{ formatTime(event) }}</span>
</div> </div>
<div class="event-info"> <div class="event-info">
<div class="event-title"> <div class="event-title">
@ -152,18 +152,24 @@ const activeSeries = computed(() => {
); );
}); });
const formatDate = (dateStr) => { const formatDate = (event) => {
if (!dateStr) return ""; if (!event?.startDate) return "";
const d = new Date(dateStr); const tz = event.displayTimezone || "America/Toronto";
const opts = { month: "short", day: "numeric" }; const d = new Date(event.startDate);
if (d.getFullYear() !== new Date().getFullYear()) opts.year = "numeric"; const opts = { month: "short", day: "numeric", timeZone: tz };
const dYear = d.toLocaleDateString("en-US", { year: "numeric", timeZone: tz });
const nowYear = new Date().toLocaleDateString("en-US", { year: "numeric", timeZone: tz });
if (dYear !== nowYear) opts.year = "numeric";
return d.toLocaleDateString("en-US", opts); return d.toLocaleDateString("en-US", opts);
}; };
const formatTime = (dateStr) => { const formatTime = (event) => {
if (!dateStr) return ""; if (!event?.startDate) return "";
const d = new Date(dateStr); return new Date(event.startDate).toLocaleTimeString("en-US", {
return d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" }); hour: "numeric",
minute: "2-digit",
timeZone: event.displayTimezone || "America/Toronto",
});
}; };
const formatLocation = (event) => { const formatLocation = (event) => {

View file

@ -60,9 +60,7 @@
:to="`/events/${evt.slug || evt._id}`" :to="`/events/${evt.slug || evt._id}`"
class="event-item" class="event-item"
> >
<span class="event-date">{{ <span class="event-date">{{ formatEventDate(evt) }}</span>
formatEventDate(evt.startDate)
}}</span>
<span class="event-title">{{ evt.title }}</span> <span class="event-title">{{ evt.title }}</span>
<CircleBadge v-if="evt.circle" :circle="evt.circle" /> <CircleBadge v-if="evt.circle" :circle="evt.circle" />
</NuxtLink> </NuxtLink>
@ -365,20 +363,22 @@ const getEventImageUrl = (featureImage) => {
return ""; return "";
}; };
const formatEventDate = (dateString) => { const formatEventDate = (event) => {
const date = new Date(dateString); if (!event?.startDate) return "";
return new Intl.DateTimeFormat("en-US", { return new Intl.DateTimeFormat("en-US", {
month: "short", month: "short",
day: "numeric", day: "numeric",
}).format(date); timeZone: event.displayTimezone || "America/Toronto",
}).format(new Date(event.startDate));
}; };
const formatEventTime = (dateString) => { const formatEventTime = (event) => {
const date = new Date(dateString); if (!event?.startDate) return "";
return new Intl.DateTimeFormat("en-US", { return new Intl.DateTimeFormat("en-US", {
hour: "numeric", hour: "numeric",
minute: "2-digit", minute: "2-digit",
}).format(date); timeZone: event.displayTimezone || "America/Toronto",
}).format(new Date(event.startDate));
}; };
const formatMemberSince = (dateString) => { const formatMemberSince = (dateString) => {