diff --git a/client/src/components/EventCard.tsx b/client/src/components/EventCard.tsx index 7d3e35bb..856874a9 100644 --- a/client/src/components/EventCard.tsx +++ b/client/src/components/EventCard.tsx @@ -147,6 +147,7 @@ export interface EventCardProps { vendors?: Vendor[]; price?: number; showActions?: boolean; + showShareButton?: boolean; showDetailedView?: boolean; showAttendees?: boolean; showRegisterButton?: boolean; @@ -196,6 +197,7 @@ export default function EventCard({ registrationDeadline, vendors = [], showActions = true, + showShareButton = true, showDetailedView = false, showAttendees = true, showRegisterButton = true, @@ -1685,7 +1687,7 @@ export default function EventCard({ )} - {inlineShareButton && ( + {showShareButton && inlineShareButton && (
@@ -1742,7 +1744,7 @@ export default function EventCard({ )} - {!inlineShareButton && ( + {showShareButton && !inlineShareButton && (
diff --git a/client/src/components/EventsDetailsDialog.tsx b/client/src/components/EventsDetailsDialog.tsx index 97653b66..2896f78b 100644 --- a/client/src/components/EventsDetailsDialog.tsx +++ b/client/src/components/EventsDetailsDialog.tsx @@ -94,20 +94,40 @@ export default function EventDetailsDialog({ const startTime = formatStringTime(event.startTime) || - (event.startDate - ? new Date(event.startDate).toLocaleTimeString("en-US", { - hour: "2-digit", - minute: "2-digit", - }) - : null); + (() => { + if (!event.startDate) return null; + const date = new Date(event.startDate); + if ( + date.getHours() === 0 && + date.getMinutes() === 0 && + date.getSeconds() === 0 + ) { + return null; + } + return date.toLocaleTimeString("en-US", { + hour: "2-digit", + minute: "2-digit", + hour12: true, + }); + })(); const endTime = formatStringTime(event.endTime) || - (event.endDate - ? new Date(event.endDate).toLocaleTimeString("en-US", { - hour: "2-digit", - minute: "2-digit", - }) - : null); + (() => { + if (!event.endDate) return null; + const date = new Date(event.endDate); + if ( + date.getHours() === 0 && + date.getMinutes() === 0 && + date.getSeconds() === 0 + ) { + return null; + } + return date.toLocaleTimeString("en-US", { + hour: "2-digit", + minute: "2-digit", + hour12: true, + }); + })(); const startDateStr = formatDate(event.startDate); const endDateStr = formatDate(event.endDate); diff --git a/client/src/lib/favoritesApi.ts b/client/src/lib/favoritesApi.ts index ea7a7e97..3efcd7b4 100644 --- a/client/src/lib/favoritesApi.ts +++ b/client/src/lib/favoritesApi.ts @@ -8,6 +8,8 @@ export interface FavoriteEvent { location: string; startDate: string; endDate: string; + startTime?: string; + endTime?: string; bannerImage?: string; status: string; eventType?: string; diff --git a/client/src/pages/FavoritesPage.tsx b/client/src/pages/FavoritesPage.tsx index 1cadd474..cef56530 100644 --- a/client/src/pages/FavoritesPage.tsx +++ b/client/src/pages/FavoritesPage.tsx @@ -83,6 +83,47 @@ export default function FavoritesPage() { }); }; + // Convert a stored 24-hour time string (e.g. "14:05") to 12-hour ("2:05 PM") + const formatStringTime = (timeStr?: string) => { + if (!timeStr) return null; + if (/^\d{1,2}:\d{2}$/.test(timeStr)) { + const [hoursStr, minutesStr] = timeStr.split(":"); + let hours = parseInt(hoursStr, 10); + const suffix = hours >= 12 ? "PM" : "AM"; + hours = hours % 12; + hours = hours ? hours : 12; + return `${hours}:${minutesStr} ${suffix}`; + } + return timeStr; + }; + + const getEventTimeLabel = (event: any) => { + const start = formatStringTime(event?.startTime); + const end = formatStringTime(event?.endTime); + + // If we don't have explicit times, only derive a time from Date fields + // when the Date actually contains a non-midnight time component. + const deriveTimeFromDateIfMeaningful = (dateString?: string) => { + if (!dateString) return null; + const date = new Date(dateString); + if ( + date.getHours() === 0 && + date.getMinutes() === 0 && + date.getSeconds() === 0 + ) { + return null; + } + return formatEventTime(dateString); + }; + + const startLabel = + start || deriveTimeFromDateIfMeaningful(event?.startDate); + const endLabel = end || deriveTimeFromDateIfMeaningful(event?.endDate); + + if (startLabel && endLabel) return `${startLabel} - ${endLabel}`; + return startLabel || ""; + }; + const formatBoothDate = (event: any) => { // If platform booth has startDate and endDate, show dates if (event.startDate && event.endDate) { @@ -211,7 +252,7 @@ export default function FavoritesPage() { time={ isBoothEvent && !event.startDate ? "" - : formatEventTime(event.startDate) + : getEventTimeLabel(event) } location={ event.location || @@ -225,6 +266,8 @@ export default function FavoritesPage() { description={event.description} startDate={event.startDate} endDate={event.endDate} + dbStartTime={event.startTime} + dbEndTime={event.endTime} durationWeeks={event.durationWeeks} showActions={true} showDetailedView={false} diff --git a/client/src/pages/MyEvents.tsx b/client/src/pages/MyEvents.tsx index 6b2dced1..b319a232 100644 --- a/client/src/pages/MyEvents.tsx +++ b/client/src/pages/MyEvents.tsx @@ -204,6 +204,7 @@ export default function MyEvents() { endDate={event.endDate} durationWeeks={event.durationWeeks} showActions={true} + showShareButton={false} isRegistered={true} hideRegisterButton={ userRole === "student" || diff --git a/server/src/features/facilities/facility.service.js b/server/src/features/facilities/facility.service.js index 283344a2..666ceafd 100644 --- a/server/src/features/facilities/facility.service.js +++ b/server/src/features/facilities/facility.service.js @@ -33,8 +33,6 @@ class FacilitiesServiceClass { if (bookingDate < today) throw new Error("Cannot book a past date"); - const formattedDate = this.getLocalDateString(bookingDate); - // Check availability directly const existingBooking = await CourtBooking.findOne({ courtType, diff --git a/server/src/features/users/user.service.js b/server/src/features/users/user.service.js index 41a3aed5..d4874b88 100644 --- a/server/src/features/users/user.service.js +++ b/server/src/features/users/user.service.js @@ -284,7 +284,7 @@ class UserService { .populate({ path: "favoriteEvents", select: - "name description location locationPreference startDate endDate bannerImage status eventType type category durationWeeks attendees attendeesCount application archivedAt", // Added archivedAt + "name description location locationPreference startDate endDate startTime endTime bannerImage status eventType type category durationWeeks attendees attendeesCount application archivedAt", // Added archivedAt match: { deletedAt: null, archivedAt: null, // ✅ Exclude archived events