Skip to content

Commit 6f511ba

Browse files
committed
fix: address PR review feedback from TyHil
- Use date-fns format matching EventTitle.tsx (start + duration style) - Parallelize async calls with Promise.all in OG image - Remove opacity on location text - Match UTD Clubs logo to 40x40 (consistent with club preview) - Add approved filter to club OG image query
1 parent 08eaaac commit 6f511ba

File tree

3 files changed

+94
-50
lines changed

3 files changed

+94
-50
lines changed

src/app/directory/[slug]/opengraph-image.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { eq } from 'drizzle-orm';
1+
import { and, eq } from 'drizzle-orm';
22
import { ImageResponse } from 'next/og';
33
import { UTDClubsLogoStandalone } from '@src/icons/UTDClubsLogo';
44
import { db } from '@src/server/db';
@@ -20,7 +20,7 @@ export default async function Image({ params }: { params: { slug: string } }) {
2020
interBuffer,
2121
] = await Promise.all([
2222
db.query.club.findFirst({
23-
where: (club) => eq(club.slug, slug),
23+
where: (club) => and(eq(club.slug, slug), eq(club.approved, 'approved')),
2424
with: {
2525
userMetadataToClubs: {
2626
columns: { userId: true },

src/app/events/[id]/opengraph-image.tsx

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
import {
2+
format,
3+
formatDuration,
4+
intervalToDuration,
5+
isSameDay,
6+
type FormatDistanceToken,
7+
} from 'date-fns';
18
import { and, eq } from 'drizzle-orm';
29
import { ImageResponse } from 'next/og';
310
import { UTDClubsLogoStandalone } from '@src/icons/UTDClubsLogo';
@@ -9,48 +16,62 @@ export const alt = 'Event Details';
916
export const size = { width: 1200, height: 630 };
1017
export const contentType = 'image/png';
1118

12-
function formatEventDate(startTime: Date, endTime: Date): string {
13-
const dateOptions: Intl.DateTimeFormatOptions = {
14-
weekday: 'short',
15-
month: 'short',
16-
day: 'numeric',
17-
};
18-
const timeOptions: Intl.DateTimeFormatOptions = {
19-
hour: 'numeric',
20-
minute: '2-digit',
21-
hour12: true,
22-
};
19+
const distanceTokenUnits: Partial<Record<FormatDistanceToken, string>> = {
20+
xSeconds: 's',
21+
xMinutes: 'm',
22+
xHours: 'h',
23+
xDays: 'd',
24+
xMonths: 'mo',
25+
xYears: 'y',
26+
};
2327

24-
const startDate = startTime.toLocaleDateString('en-US', dateOptions);
25-
const startTimeStr = startTime.toLocaleTimeString('en-US', timeOptions);
26-
const endTimeStr = endTime.toLocaleTimeString('en-US', timeOptions);
28+
function formatEventDate(startTime: Date, endTime: Date): string {
29+
const dateStr = format(startTime, 'EEE, LLLL d, yyyy @ h:mm a');
2730

28-
const sameDay = startTime.toDateString() === endTime.toDateString();
29-
if (sameDay) {
30-
return `${startDate}, ${startTimeStr} - ${endTimeStr}`;
31+
if (startTime.getTime() === endTime.getTime()) {
32+
return dateStr;
3133
}
32-
const endDate = endTime.toLocaleDateString('en-US', dateOptions);
33-
return `${startDate}, ${startTimeStr} - ${endDate}, ${endTimeStr}`;
34-
}
3534

36-
export default async function Image({ params }: { params: { id: string } }) {
37-
const id = (await params).id;
38-
39-
const eventData = await db.query.events.findFirst({
40-
where: (events) => and(eq(events.id, id), eq(events.status, 'approved')),
41-
with: {
42-
club: {
43-
columns: { name: true, profileImage: true, updatedAt: true },
35+
const duration = formatDuration(
36+
intervalToDuration({ start: startTime, end: endTime }),
37+
{
38+
locale: {
39+
formatDistance: (token, count) =>
40+
`${count}${distanceTokenUnits[token] ?? ''}`,
4441
},
4542
},
46-
});
43+
);
44+
45+
const endStr = isSameDay(startTime, endTime)
46+
? format(endTime, 'h:mm a')
47+
: format(endTime, 'EEE, LLLL d, yyyy @ h:mm a');
48+
49+
return `${dateStr} · ${duration} (till ${endStr})`;
50+
}
4751

48-
const gradientBuffer = await fetch(
49-
new URL('../../../../public/images/landingGradient.png', import.meta.url),
50-
).then((res) => res.arrayBuffer());
52+
export default async function Image({ params }: { params: { id: string } }) {
53+
const { id } = await params;
5154

52-
const baiJamjureeBuffer = await loadGoogleFont('Bai Jamjuree', 700);
53-
const interBuffer = await loadGoogleFont('Inter', 600);
55+
const [eventData, gradientBuffer, baiJamjureeBuffer, interBuffer] =
56+
await Promise.all([
57+
db.query.events.findFirst({
58+
where: (events) =>
59+
and(eq(events.id, id), eq(events.status, 'approved')),
60+
with: {
61+
club: {
62+
columns: { name: true, profileImage: true, updatedAt: true },
63+
},
64+
},
65+
}),
66+
fetch(
67+
new URL(
68+
'../../../../public/images/landingGradient.png',
69+
import.meta.url,
70+
),
71+
).then((res) => res.arrayBuffer()),
72+
loadGoogleFont('Bai Jamjuree', 700),
73+
loadGoogleFont('Inter', 600),
74+
]);
5475

5576
const background = (
5677
<img
@@ -194,7 +215,6 @@ export default async function Image({ params }: { params: { id: string } }) {
194215
fontSize: '22px',
195216
margin: '0 0 16px 0',
196217
textShadow: '0 0 4px rgba(0,0,0,0.4)',
197-
opacity: 0.9,
198218
maxWidth: hasImage ? '55%' : '90%',
199219
textAlign: hasImage ? 'left' : 'center',
200220
}}
@@ -271,8 +291,8 @@ export default async function Image({ params }: { params: { id: string } }) {
271291
display: 'flex',
272292
alignItems: 'center',
273293
justifyContent: 'center',
274-
width: 36,
275-
height: 36,
294+
width: 40,
295+
height: 40,
276296
}}
277297
>
278298
<UTDClubsLogoStandalone

src/app/events/[id]/page.tsx

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
import {
2+
format,
3+
formatDuration,
4+
intervalToDuration,
5+
isSameDay,
6+
type FormatDistanceToken,
7+
} from 'date-fns';
18
import { type Metadata } from 'next';
29
import ClubEventHeader from '@src/components/club/listing/ClubEventHeader';
310
import EventBody from '@src/components/events/listing/EventBody';
@@ -6,6 +13,15 @@ import { EventHeader } from '@src/components/header/Header';
613
import { api } from '@src/trpc/server';
714
import { convertMarkdownToPlaintext } from '@src/utils/markdown';
815

16+
const distanceTokenUnits: Partial<Record<FormatDistanceToken, string>> = {
17+
xSeconds: 's',
18+
xMinutes: 'm',
19+
xHours: 'h',
20+
xDays: 'd',
21+
xMonths: 'mo',
22+
xYears: 'y',
23+
};
24+
925
type Params = { params: Promise<{ id: string }> };
1026

1127
export default async function EventsPage(props: Params) {
@@ -38,16 +54,24 @@ export async function generateMetadata(props: {
3854
description: 'Event not found',
3955
};
4056

41-
const dateOptions: Intl.DateTimeFormatOptions = {
42-
weekday: 'short',
43-
month: 'short',
44-
day: 'numeric',
45-
hour: 'numeric',
46-
minute: '2-digit',
47-
hour12: true,
48-
};
49-
const startStr = event.startTime.toLocaleString('en-US', dateOptions);
50-
const endStr = event.endTime.toLocaleString('en-US', dateOptions);
57+
const startStr = format(event.startTime, 'EEE, LLLL d, yyyy @ h:mm a');
58+
59+
let durationStr = '';
60+
if (event.startTime.getTime() !== event.endTime.getTime()) {
61+
const duration = formatDuration(
62+
intervalToDuration({ start: event.startTime, end: event.endTime }),
63+
{
64+
locale: {
65+
formatDistance: (token, count) =>
66+
`${count}${distanceTokenUnits[token] ?? ''}`,
67+
},
68+
},
69+
);
70+
const endStr = isSameDay(event.startTime, event.endTime)
71+
? format(event.endTime, 'h:mm a')
72+
: format(event.endTime, 'EEE, LLLL d, yyyy @ h:mm a');
73+
durationStr = ` · ${duration} (till ${endStr})`;
74+
}
5175

5276
let cleanDescription = `${event.name} from ${event.club.name} on UTD Clubs`;
5377
const textDescription = event.description.replace(/^#+.*$/gm, '');
@@ -64,7 +88,7 @@ export async function generateMetadata(props: {
6488
}
6589
}
6690

67-
const timeDescription = `${startStr} - ${endStr}${event.location ? ` | ${event.location}` : ''}`;
91+
const timeDescription = `${startStr}${durationStr}${event.location ? ` | ${event.location}` : ''}`;
6892

6993
return {
7094
title: event.name,

0 commit comments

Comments
 (0)