Skip to content

Commit add340f

Browse files
committed
feat: enhance conference scheduling logic and SEO metadata
- Introduced new functions to calculate event end times and resolve conference event dates, improving scheduling accuracy. - Updated the JSON-LD structure to reflect the resolved start and end dates for conferences, enhancing SEO performance. - Refactored the buildScheduleSubEvents function to utilize the new scheduling logic, ensuring better event representation. - Improved overall clarity and consistency in the conference SEO metadata.
1 parent 17cda42 commit add340f

2 files changed

Lines changed: 105 additions & 14 deletions

File tree

‎src/lib/seo/conferenceSeo.ts‎

Lines changed: 104 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,81 @@ export const scheduleTimeToIso = (
4444
return `${date}T${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:00+03:30`;
4545
};
4646

47+
const addMinutesToIso = (iso: string, minutes: number): string | undefined => {
48+
const match = iso.match(
49+
/^(\d{4}-\d{2}-\d{2})T(\d{2}):(\d{2}):(\d{2})\+03:30$/
50+
);
51+
if (!match) return undefined;
52+
53+
const totalMinutes = Number(match[2]) * 60 + Number(match[3]) + minutes;
54+
const minutesInDay = ((totalMinutes % (24 * 60)) + 24 * 60) % (24 * 60);
55+
const hours = Math.floor(minutesInDay / 60);
56+
const mins = minutesInDay % 60;
57+
58+
return `${match[1]}T${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}:${match[4]}+03:30`;
59+
};
60+
61+
const resolveScheduleEndDate = (
62+
schedule: ScheduleEvent[],
63+
scheduleIndex: number,
64+
eventDate: string,
65+
conference: ConferenceProfile
66+
): string | undefined => {
67+
const event = schedule[scheduleIndex];
68+
69+
if (event.endTime) {
70+
return scheduleTimeToIso(eventDate, event.endTime);
71+
}
72+
73+
const next = schedule[scheduleIndex + 1];
74+
if (next) {
75+
const nextDate = next.date ?? eventDate;
76+
return scheduleTimeToIso(nextDate, next.time);
77+
}
78+
79+
const startDate = scheduleTimeToIso(eventDate, event.time);
80+
if (startDate) {
81+
return addMinutesToIso(startDate, 30);
82+
}
83+
84+
if (conference.endDate?.includes('T')) {
85+
return conference.endDate;
86+
}
87+
88+
return undefined;
89+
};
90+
91+
const resolveConferenceEventDates = (conference: ConferenceProfile) => {
92+
const schedule = conference.schedule ?? [];
93+
let startDate = conference.startDate;
94+
let endDate = conference.endDate;
95+
96+
if (!startDate.includes('T') && schedule.length > 0) {
97+
const first = schedule[0];
98+
const firstDate = first.date ?? conference.startDate;
99+
startDate =
100+
scheduleTimeToIso(firstDate, first.time) ?? conference.startDate;
101+
}
102+
103+
if (schedule.length > 0) {
104+
const lastIndex = schedule.length - 1;
105+
const last = schedule[lastIndex];
106+
const lastDate = last.date ?? conference.endDate ?? conference.startDate;
107+
const resolvedEnd = resolveScheduleEndDate(
108+
schedule,
109+
lastIndex,
110+
lastDate,
111+
conference
112+
);
113+
114+
if (resolvedEnd) {
115+
endDate = resolvedEnd;
116+
}
117+
}
118+
119+
return { startDate, endDate };
120+
};
121+
47122
export const parseConferenceLocation = (locationName: string) => {
48123
const [localityPart, venuePart] = locationName
49124
.split('—')
@@ -313,17 +388,25 @@ const buildScheduleSubEvents = (
313388
): Record<string, unknown>[] => {
314389
if (!conference.schedule?.length) return [];
315390

316-
return conference.schedule
317-
.filter((event) =>
391+
const schedule = conference.schedule;
392+
let sessionIndex = 0;
393+
394+
return schedule
395+
.map((event, scheduleIndex) => ({ event, scheduleIndex }))
396+
.filter(({ event }) =>
318397
['talk', 'panel', 'competition', 'workshop'].includes(event.type)
319398
)
320-
.map((event: ScheduleEvent, index) => {
399+
.map(({ event, scheduleIndex }) => {
400+
sessionIndex += 1;
321401
const eventDate = event.date ?? conference.startDate;
322402
const startDate = scheduleTimeToIso(eventDate, event.time);
323-
const endDate = event.endTime
324-
? scheduleTimeToIso(eventDate, event.endTime)
325-
: undefined;
326-
const sessionUrl = `${eventUrl}#session-${index + 1}`;
403+
const endDate = resolveScheduleEndDate(
404+
schedule,
405+
scheduleIndex,
406+
eventDate,
407+
conference
408+
);
409+
const sessionUrl = `${eventUrl}#session-${sessionIndex}`;
327410
const sessionStartDate = startDate ?? conference.startDate;
328411

329412
return {
@@ -364,7 +447,13 @@ const buildScheduleSubEvents = (
364447
name: speaker.name,
365448
})),
366449
}
367-
: {}),
450+
: event.type === 'competition'
451+
? {
452+
performer: {
453+
'@id': organizationId,
454+
},
455+
}
456+
: {}),
368457
superEvent: {
369458
'@id': `${eventUrl}#event`,
370459
},
@@ -374,7 +463,9 @@ const buildScheduleSubEvents = (
374463

375464
export const buildConferenceJsonLd = (conference: ConferenceProfile) => {
376465
const eventUrl = `${SITE_URL}${conferencePath(conference.slug)}`;
377-
const isPastEvent = new Date(conference.startDate).getTime() < Date.now();
466+
const { startDate: eventStartDate, endDate: eventEndDate } =
467+
resolveConferenceEventDates(conference);
468+
const isPastEvent = new Date(eventStartDate).getTime() < Date.now();
378469
const { locality, region, venue } = parseConferenceLocation(
379470
conference.locationName
380471
);
@@ -448,8 +539,8 @@ export const buildConferenceJsonLd = (conference: ConferenceProfile) => {
448539
name: pageName,
449540
alternateName: [`همایش فرانت‌چپتر ${conference.year}`, conference.title],
450541
description: plainifySync(conference.description),
451-
startDate: conference.startDate,
452-
...(conference.endDate ? { endDate: conference.endDate } : {}),
542+
startDate: eventStartDate,
543+
...(eventEndDate ? { endDate: eventEndDate } : {}),
453544
eventAttendanceMode: 'https://schema.org/OfflineEventAttendanceMode',
454545
eventStatus: 'https://schema.org/EventScheduled',
455546
inLanguage: 'fa-IR',
@@ -464,8 +555,8 @@ export const buildConferenceJsonLd = (conference: ConferenceProfile) => {
464555
...(attendeeCount ? { maximumAttendeeCapacity: attendeeCount } : {}),
465556
offers: buildEventOffers(
466557
eventUrl,
467-
conference.startDate,
468-
conference.endDate,
558+
eventStartDate,
559+
eventEndDate,
469560
isPastEvent
470561
),
471562
...(subEvents.length ? { subEvent: subEvents } : {}),

‎tsconfig.tsbuildinfo‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)