2023-02-15 22:20:14 +08:00
|
|
|
import Airtable from "airtable";
|
2020-04-12 18:58:33 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
import {
|
|
|
|
CommunityEvent,
|
|
|
|
CommunityEventType,
|
|
|
|
COMMUNITY_EVENT_TYPES,
|
|
|
|
COMMUNITY_EVENT_TYPE_OPTIONS,
|
2023-06-22 17:14:03 +08:00
|
|
|
WorldRegion,
|
2023-02-15 22:20:14 +08:00
|
|
|
WORLD_REGIONS,
|
|
|
|
} from "../types/events";
|
2023-02-08 18:29:01 +08:00
|
|
|
import {
|
|
|
|
AirtableRecords,
|
|
|
|
getImageUrl,
|
2023-02-15 22:20:14 +08:00
|
|
|
findImageAttachment,
|
|
|
|
} from "./airtable-conversion-utils";
|
2023-02-08 18:29:01 +08:00
|
|
|
|
|
|
|
// TODO: Understand why this import worked with '../' and not with '~/'
|
|
|
|
// The types has been moved outside the store, check if this works as expected
|
2020-11-12 19:20:53 +08:00
|
|
|
|
2023-01-24 00:16:01 +08:00
|
|
|
export type SeminarSeriesEvent = {
|
2023-02-15 22:20:14 +08:00
|
|
|
date: string;
|
|
|
|
startDate: string;
|
|
|
|
endDate: string;
|
|
|
|
startDateAndTime?: string | null;
|
|
|
|
image: string;
|
|
|
|
institution: string;
|
|
|
|
location: string;
|
|
|
|
speaker: string;
|
|
|
|
title: string;
|
|
|
|
to: string;
|
|
|
|
};
|
2021-02-10 17:33:08 +08:00
|
|
|
|
2023-07-24 17:38:07 +08:00
|
|
|
export const RECORD_FIELDS_IDS = Object.freeze({
|
2023-02-15 22:20:14 +08:00
|
|
|
name: "fldTqTxKr3ZzUhzKT",
|
|
|
|
startDate: "fldPGzoUf9wxsBDYJ",
|
|
|
|
endDate: "fldeFv42sqOY7oMy0",
|
|
|
|
startDateAndTime: "fldF2COMbzANgkOh8",
|
|
|
|
types: "fldarZoYRJvETevow",
|
|
|
|
website: "fldBPq3LMa5aZDBZm",
|
|
|
|
location: "fldSjeniJtud6M5j3",
|
|
|
|
regions: "fldBCXzoxvcoxsKIK",
|
|
|
|
image: "fldco5xB6dy9MG7y8",
|
|
|
|
institution: "fldLVMuuhZVGwh4qZ",
|
|
|
|
showOnEventsPage: "fldi1ThdDnUQakxWo",
|
|
|
|
showOnSeminarSeriesPage: "fldl6in6TPajnxPMs",
|
|
|
|
speaker: "fldyeOkGwMbfMRvPu",
|
2023-04-06 21:16:04 +08:00
|
|
|
abstract: "fldBqkIigePRu4oZd",
|
2023-02-15 22:20:14 +08:00
|
|
|
} as const);
|
|
|
|
|
|
|
|
const AIRTABLE_BASE_ID = "appYREKB18uC7y8ul";
|
2023-01-24 00:16:01 +08:00
|
|
|
class EventsAirtableRecords extends AirtableRecords {
|
2023-02-15 22:20:14 +08:00
|
|
|
constructor(
|
|
|
|
apiKey: string,
|
|
|
|
view: string,
|
|
|
|
recordFields?: Record<string, any>
|
|
|
|
) {
|
|
|
|
super(
|
|
|
|
apiKey,
|
|
|
|
AIRTABLE_BASE_ID,
|
|
|
|
"Event Calendar",
|
|
|
|
view,
|
|
|
|
undefined,
|
|
|
|
recordFields
|
|
|
|
);
|
2023-07-24 17:38:07 +08:00
|
|
|
this.airtableBase = new Airtable({ apiKey: this.apiKey }).base(
|
|
|
|
AIRTABLE_BASE_ID
|
|
|
|
);
|
2022-04-01 17:32:48 +08:00
|
|
|
}
|
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Sort the events by their start date.
|
|
|
|
* @param events The events to sort.
|
|
|
|
* @param direction The direction to sort the events in.
|
|
|
|
* @returns The sorted events.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
private sortEventsByStartDate<T extends CommunityEvent | SeminarSeriesEvent>(
|
|
|
|
events: T[],
|
|
|
|
direction: "asc" | "desc"
|
|
|
|
): T[] {
|
2023-02-07 21:44:40 +08:00
|
|
|
return events.sort((a, b) => {
|
2023-02-15 22:20:14 +08:00
|
|
|
const aDate = new Date(a.startDate);
|
|
|
|
const bDate = new Date(b.startDate);
|
2023-02-07 21:44:40 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
if (direction === "asc") {
|
|
|
|
return aDate.getTime() - bDate.getTime();
|
2023-02-07 21:44:40 +08:00
|
|
|
} else {
|
2023-02-15 22:20:14 +08:00
|
|
|
return bDate.getTime() - aDate.getTime();
|
2023-02-07 21:44:40 +08:00
|
|
|
}
|
2023-02-15 22:20:14 +08:00
|
|
|
});
|
2023-02-07 21:44:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the Airtable query for the events.
|
|
|
|
* @param filterFormula The Airtable filter formula to use.
|
|
|
|
* @returns The Airtable query.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
getEventsQuery(filterFormula: string): Airtable.Query<{}> {
|
2023-07-24 17:38:07 +08:00
|
|
|
return this.airtableBase("Event Calendar").select({
|
2023-02-15 22:20:14 +08:00
|
|
|
filterByFormula: filterFormula,
|
|
|
|
});
|
2022-04-01 17:32:48 +08:00
|
|
|
}
|
|
|
|
|
2023-01-24 00:16:01 +08:00
|
|
|
/**
|
|
|
|
* Check whether an event happens within a predetermined number of days before
|
|
|
|
* or after today.
|
|
|
|
* If the "days" parameter is positive, the event must happen in the future,
|
|
|
|
* between today and the given number of days after today.
|
|
|
|
* If the "days" parameter is negative, the event must happen in the past,
|
|
|
|
* between today and the given number of days before today.
|
|
|
|
* @param event The event to check.
|
|
|
|
* @param days The number of days before and after today.
|
|
|
|
* @returns Whether the event happens within the specified range.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
isEventInDateRange(
|
2023-01-24 00:16:01 +08:00
|
|
|
event: CommunityEvent | SeminarSeriesEvent,
|
|
|
|
days: number
|
|
|
|
): boolean {
|
2023-02-15 22:20:14 +08:00
|
|
|
const { startDate, endDate } = event;
|
|
|
|
const today: Date = new Date();
|
2023-05-08 16:49:29 +08:00
|
|
|
today.setUTCHours(0, 0, 0, 0);
|
2023-02-15 22:20:14 +08:00
|
|
|
const eventStartDate: Date = new Date(startDate);
|
|
|
|
const eventEndDate: Date = new Date(endDate);
|
|
|
|
const isFutureRange: boolean = days >= 0;
|
|
|
|
const isOngoingEvent: boolean =
|
|
|
|
eventStartDate <= today && today <= eventEndDate;
|
|
|
|
const isToday: boolean =
|
|
|
|
eventStartDate.getDate() === today.getDate() &&
|
|
|
|
eventStartDate.getMonth() === today.getMonth() &&
|
|
|
|
eventStartDate.getFullYear() === today.getFullYear();
|
|
|
|
let eventDateToCheck: Date;
|
2023-01-24 00:16:01 +08:00
|
|
|
|
|
|
|
// Determine which date to check based on the days parameter and checking if
|
|
|
|
// the event's dates are valid.
|
|
|
|
if (isFutureRange && isOngoingEvent) {
|
2023-02-15 22:20:14 +08:00
|
|
|
return true;
|
2023-01-24 00:16:01 +08:00
|
|
|
} else if (isFutureRange && isToday) {
|
2023-02-15 22:20:14 +08:00
|
|
|
return true;
|
2023-01-24 00:16:01 +08:00
|
|
|
} else if (!isFutureRange && isToday) {
|
2023-02-15 22:20:14 +08:00
|
|
|
return false;
|
2023-01-24 00:16:01 +08:00
|
|
|
} else if (!isFutureRange && !isNaN(eventEndDate.getTime())) {
|
2023-02-15 22:20:14 +08:00
|
|
|
eventDateToCheck = eventEndDate;
|
2023-01-24 00:16:01 +08:00
|
|
|
} else if (!isNaN(eventStartDate.getTime())) {
|
2023-02-15 22:20:14 +08:00
|
|
|
eventDateToCheck = eventStartDate;
|
2023-01-24 00:16:01 +08:00
|
|
|
} else {
|
2023-02-15 22:20:14 +08:00
|
|
|
return false;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2022-04-01 17:32:48 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
let rangeStart: Date;
|
|
|
|
let rangeEnd: Date;
|
2021-02-10 17:33:08 +08:00
|
|
|
|
2023-01-24 00:16:01 +08:00
|
|
|
// Determine the range of dates to check.
|
|
|
|
if (isFutureRange) {
|
2023-02-15 22:20:14 +08:00
|
|
|
rangeStart = new Date(today);
|
|
|
|
rangeEnd = new Date(today.getTime() + days * 24 * 60 * 60 * 1000);
|
2023-01-24 00:16:01 +08:00
|
|
|
} else {
|
2023-02-15 22:20:14 +08:00
|
|
|
rangeStart = new Date(today.getTime() + days * 24 * 60 * 60 * 1000);
|
|
|
|
rangeEnd = new Date(today);
|
2020-04-08 15:48:46 +08:00
|
|
|
}
|
2021-02-10 17:33:08 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
return eventDateToCheck >= rangeStart && eventDateToCheck <= rangeEnd;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Fetch the community events from Airtable, convert them to the
|
|
|
|
* CommunityEvent type, and return them sorted by their start date.
|
|
|
|
* @param days The number of days before and after today to fetch events for.
|
|
|
|
* @returns The community events.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
async fetchCommunityEvents(days: number): Promise<CommunityEvent[]> {
|
2023-01-24 00:16:01 +08:00
|
|
|
if (!this.recordFields) {
|
2023-02-15 22:20:14 +08:00
|
|
|
this.recordFields = await this.getAllFieldNames(RECORD_FIELDS_IDS);
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2021-02-10 17:33:08 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
const communityEvents: CommunityEvent[] = [];
|
|
|
|
const filterFormula = `{${this.recordFields.showOnEventsPage}}`;
|
2021-03-02 23:38:44 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
await this.getEventsQuery(filterFormula).eachPage(
|
|
|
|
async (records, nextPage) => {
|
|
|
|
for (const record of records) {
|
|
|
|
this.id = record.id;
|
|
|
|
const communityEvent = await this.convertToCommunityEvent(record);
|
|
|
|
if (this.isEventInDateRange(communityEvent, days)) {
|
|
|
|
communityEvents.push(communityEvent);
|
|
|
|
}
|
2022-04-01 17:32:48 +08:00
|
|
|
}
|
2023-02-15 22:20:14 +08:00
|
|
|
nextPage();
|
2021-03-02 23:38:44 +08:00
|
|
|
}
|
2023-02-15 22:20:14 +08:00
|
|
|
);
|
2023-01-24 00:16:01 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
const sortedCommunityEvents = this.sortEventsByStartDate(
|
|
|
|
communityEvents,
|
|
|
|
days > 0 ? "asc" : "desc"
|
|
|
|
);
|
|
|
|
return Promise.resolve(sortedCommunityEvents);
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Fetch the seminar series events from Airtable, convert them to the
|
|
|
|
* SeminarSeriesEvent type, and return them sorted by their start date.
|
|
|
|
* @param days The number of days before and after today to fetch events for.
|
|
|
|
* @returns The seminar series events.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
async fetchSeminarSeriesEvents(days: number): Promise<SeminarSeriesEvent[]> {
|
2023-01-24 00:16:01 +08:00
|
|
|
if (!this.recordFields) {
|
2023-02-15 22:20:14 +08:00
|
|
|
this.recordFields = await this.getAllFieldNames(RECORD_FIELDS_IDS);
|
2021-02-10 17:33:08 +08:00
|
|
|
}
|
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
const seminarSeriesEvents: SeminarSeriesEvent[] = [];
|
|
|
|
const filterFormula = `{${this.recordFields.showOnSeminarSeriesPage}}`;
|
|
|
|
|
|
|
|
await this.getEventsQuery(filterFormula).eachPage(
|
|
|
|
async (records, nextPage) => {
|
|
|
|
for (const record of records) {
|
|
|
|
this.id = record.id;
|
|
|
|
const seminarSeriesEvent = await this.convertToSeminarSeriesEvent(
|
|
|
|
record
|
|
|
|
);
|
|
|
|
|
|
|
|
if (typeof seminarSeriesEvent.to !== "undefined") {
|
|
|
|
if (this.isEventInDateRange(seminarSeriesEvent, days)) {
|
|
|
|
seminarSeriesEvents.push(seminarSeriesEvent);
|
|
|
|
}
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
|
|
|
}
|
2023-02-15 22:20:14 +08:00
|
|
|
nextPage();
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2023-02-15 22:20:14 +08:00
|
|
|
);
|
2021-02-10 17:33:08 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
const sortedSeminarSeriesEvents = this.sortEventsByStartDate(
|
|
|
|
seminarSeriesEvents,
|
|
|
|
days > 0 ? "asc" : "desc"
|
|
|
|
);
|
|
|
|
return Promise.resolve(sortedSeminarSeriesEvents);
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2021-02-10 17:33:08 +08:00
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Convert an Airtable record to a CommunityEvent.
|
|
|
|
* @param record The Airtable record to convert.
|
|
|
|
* @returns The converted CommunityEvent.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
async convertToCommunityEvent(
|
|
|
|
record: Record<string, any>
|
|
|
|
): Promise<CommunityEvent> {
|
2023-01-25 21:40:44 +08:00
|
|
|
const event = {
|
2023-03-29 22:24:57 +08:00
|
|
|
endDate: (record.get(this.recordFields!.endDate) as string) || "",
|
|
|
|
location:
|
|
|
|
(record.get(this.recordFields!.location) as string) ||
|
|
|
|
WORLD_REGIONS.tbd,
|
|
|
|
regions: (record.get(this.recordFields!.regions) as WorldRegion[]) || [
|
|
|
|
WORLD_REGIONS.tbd,
|
|
|
|
],
|
2023-06-01 22:22:05 +08:00
|
|
|
speaker: (record.get(this.recordFields!.speaker) as string) || "",
|
2023-03-29 22:24:57 +08:00
|
|
|
title: (record.get(this.recordFields!.name) as string) || "",
|
|
|
|
to: (record.get(this.recordFields!.website) as string) || "",
|
2023-04-06 21:16:04 +08:00
|
|
|
abstract: record.get(this.recordFields!.abstract) || "",
|
2023-02-07 21:44:40 +08:00
|
|
|
|
2023-01-24 00:16:01 +08:00
|
|
|
date: this.formatDates(...this.getDates(record)),
|
2023-02-07 21:44:40 +08:00
|
|
|
image: await this.getImage(record),
|
2023-01-24 00:16:01 +08:00
|
|
|
startDate: this.getStartDate(record),
|
2023-02-15 22:20:14 +08:00
|
|
|
startDateAndTime: this.formatTime(
|
|
|
|
record.get(this.recordFields!.startDateAndTime) || null
|
|
|
|
),
|
|
|
|
types: this.getEventTypes(record),
|
|
|
|
};
|
|
|
|
return event;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2020-04-08 15:48:46 +08:00
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Convert an Airtable record to a SeminarSeriesEvent.
|
|
|
|
* @param record The Airtable record to convert.
|
|
|
|
* @returns The converted SeminarSeriesEvent.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
async convertToSeminarSeriesEvent(
|
|
|
|
record: Record<string, any>
|
|
|
|
): Promise<SeminarSeriesEvent> {
|
2023-01-25 21:40:44 +08:00
|
|
|
const event = {
|
2023-02-15 22:20:14 +08:00
|
|
|
endDate: record.get(this.recordFields!.endDate) || "",
|
|
|
|
institution: record.get(this.recordFields!.institution) || "",
|
2023-02-07 21:44:40 +08:00
|
|
|
location: record.get(this.recordFields!.location) || WORLD_REGIONS.tbd,
|
2023-02-15 22:20:14 +08:00
|
|
|
speaker: record.get(this.recordFields!.speaker) || "",
|
|
|
|
title: record.get(this.recordFields!.name) || "",
|
|
|
|
to: record.get(this.recordFields!.website) || "",
|
2023-04-06 21:16:04 +08:00
|
|
|
abstract: record.get(this.recordFields!.abstract) || "",
|
2023-02-07 21:44:40 +08:00
|
|
|
|
2023-01-24 00:16:01 +08:00
|
|
|
date: this.formatDates(...this.getDates(record)),
|
2023-01-25 21:40:44 +08:00
|
|
|
image: await this.getImage(record),
|
2023-02-15 22:20:14 +08:00
|
|
|
startDate: this.getStartDate(record),
|
|
|
|
};
|
|
|
|
return event;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2021-02-10 17:33:08 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
dateParts(date: Date): [string, string, string] {
|
2023-05-08 16:49:29 +08:00
|
|
|
const year = new Intl.DateTimeFormat("en-US", {
|
|
|
|
year: "numeric",
|
|
|
|
timeZone: "UTC",
|
|
|
|
}).format(date);
|
|
|
|
const month = new Intl.DateTimeFormat("en-US", {
|
|
|
|
month: "long",
|
|
|
|
timeZone: "UTC",
|
|
|
|
}).format(date);
|
|
|
|
const day = new Intl.DateTimeFormat("en-US", {
|
|
|
|
day: "numeric",
|
|
|
|
timeZone: "UTC",
|
|
|
|
}).format(date);
|
2023-02-15 22:20:14 +08:00
|
|
|
return [year, month, day];
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2020-04-15 17:37:30 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
filterWithWhitelist<W>(list: any[], whitelist: readonly W[]): W[] {
|
|
|
|
return list.filter((type): type is W => whitelist.includes(type));
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2020-04-08 15:48:46 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
formatDates(startDate?: Date, endDate?: Date): string {
|
|
|
|
if (!startDate) {
|
|
|
|
return "TBD";
|
|
|
|
}
|
2020-04-14 00:01:17 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
const [startYear, startMonth, startDay] = this.dateParts(startDate);
|
2023-01-24 00:16:01 +08:00
|
|
|
if (!endDate || startDate.getTime() === endDate.getTime()) {
|
2023-02-15 22:20:14 +08:00
|
|
|
return `${startMonth} ${startDay}, ${startYear}`;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2020-04-08 15:48:46 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
const [endYear, endMonth, endDay] = this.dateParts(endDate);
|
2023-01-24 00:16:01 +08:00
|
|
|
if (startYear !== endYear) {
|
2023-02-15 22:20:14 +08:00
|
|
|
return `${startMonth} ${startDay}, ${startYear} - ${endMonth} ${endDay}, ${endYear}`;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
|
|
|
if (startMonth !== endMonth) {
|
2023-02-15 22:20:14 +08:00
|
|
|
return `${startMonth} ${startDay} - ${endMonth} ${endDay}, ${startYear}`;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
|
|
|
if (startDay !== endDay) {
|
2023-02-15 22:20:14 +08:00
|
|
|
return `${startMonth} ${startDay}-${endDay}, ${startYear}`;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2023-07-24 17:38:07 +08:00
|
|
|
throw new Error("Unreachable: should have been covered by a case.");
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2020-04-08 15:48:46 +08:00
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Format a date and time to a string with only the time in UTC.
|
|
|
|
* @param startDateAndTime The date and time to format.
|
|
|
|
* @returns The formatted time.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
formatTime(startDateAndTime: string | null): string | null {
|
|
|
|
if (!startDateAndTime) {
|
|
|
|
return null;
|
|
|
|
}
|
2022-04-01 17:32:48 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
const formattedStartDateAndTime = new Date(startDateAndTime);
|
2022-04-01 17:32:48 +08:00
|
|
|
|
2023-05-08 16:49:29 +08:00
|
|
|
return new Intl.DateTimeFormat("en-US", {
|
2023-02-15 22:20:14 +08:00
|
|
|
hour: "numeric",
|
|
|
|
minute: "numeric",
|
|
|
|
timeZone: "UTC",
|
|
|
|
timeZoneName: "short",
|
2023-05-08 16:49:29 +08:00
|
|
|
}).format(formattedStartDateAndTime);
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2020-04-08 15:48:46 +08:00
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Get the event's types.
|
|
|
|
* @param record The event's record.
|
|
|
|
* @returns The event's types.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
private getEventTypes(record: Record<string, any>): CommunityEventType[] {
|
|
|
|
const value = record.get(this.recordFields!.types) || [];
|
|
|
|
const valueList = (Array.isArray(value) ? value : [value]) as string[];
|
|
|
|
const communityEventTypes = this.filterWithWhitelist(
|
|
|
|
valueList,
|
|
|
|
COMMUNITY_EVENT_TYPE_OPTIONS
|
|
|
|
);
|
|
|
|
const noTypes = communityEventTypes.length === 0;
|
|
|
|
return noTypes ? [COMMUNITY_EVENT_TYPES.talks] : communityEventTypes;
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2020-04-08 15:48:46 +08:00
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Get the event's image.
|
|
|
|
* @param record The event's record.
|
|
|
|
* @returns Promise resolving to the event's image URL.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
public async getImage(record: Record<string, any>): Promise<string> {
|
|
|
|
const fallbackImage = "/images/events/no-picture.jpg";
|
|
|
|
const attachments = record.get(this.recordFields!.image);
|
|
|
|
const imageAttachment = attachments && findImageAttachment(attachments);
|
|
|
|
const imageUrl = imageAttachment && getImageUrl(imageAttachment);
|
2023-01-25 21:40:44 +08:00
|
|
|
|
|
|
|
if (!imageUrl) {
|
2023-02-15 22:20:14 +08:00
|
|
|
return fallbackImage;
|
2023-01-25 21:40:44 +08:00
|
|
|
}
|
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
const imagePublicPath = `/images/events/downloaded/${this.id}.jpg`;
|
2023-01-25 21:40:44 +08:00
|
|
|
|
2023-02-23 21:46:19 +08:00
|
|
|
return await this.storeImage(imageUrl, `public/${imagePublicPath}`)
|
2023-01-25 21:40:44 +08:00
|
|
|
.then(() => imagePublicPath)
|
2023-02-15 22:20:14 +08:00
|
|
|
.catch(() => fallbackImage);
|
2020-04-08 15:48:46 +08:00
|
|
|
}
|
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Get the event's start date.
|
|
|
|
* @param record The event's record.
|
|
|
|
* @returns The event's start date.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
public getStartDate(record: Record<string, any>): string {
|
2023-02-07 21:44:40 +08:00
|
|
|
if (record.get(this.recordFields!.startDateAndTime)) {
|
2023-02-15 22:20:14 +08:00
|
|
|
const startDateAndTime = record.get(this.recordFields!.startDateAndTime);
|
|
|
|
const startDate = new Date(startDateAndTime);
|
|
|
|
return startDate.toISOString().split("T")[0];
|
2023-02-07 21:44:40 +08:00
|
|
|
}
|
2023-01-24 00:16:01 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
return record.get(this.recordFields!.startDate) || "";
|
2020-04-08 15:48:46 +08:00
|
|
|
}
|
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
/**
|
|
|
|
* Get the event's start and end dates.
|
|
|
|
* @param record The event's record.
|
|
|
|
* @returns The event's start and end dates.
|
|
|
|
*/
|
2023-02-15 22:20:14 +08:00
|
|
|
public getDates(
|
|
|
|
record: Record<string, any>
|
|
|
|
): [Date | undefined, Date | undefined] {
|
|
|
|
const recordStartDate = this.getStartDate(record);
|
|
|
|
const recordEndDate = record.get(this.recordFields!.endDate) as
|
|
|
|
| string
|
|
|
|
| undefined;
|
2020-04-08 15:48:46 +08:00
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
let startDate: Date | undefined;
|
|
|
|
let endDate: Date | undefined;
|
2023-02-07 21:44:40 +08:00
|
|
|
|
|
|
|
if (recordStartDate) {
|
2023-02-15 22:20:14 +08:00
|
|
|
startDate = new Date(recordStartDate);
|
2023-02-07 21:44:40 +08:00
|
|
|
}
|
2020-04-08 15:48:46 +08:00
|
|
|
|
2023-02-07 21:44:40 +08:00
|
|
|
if (recordEndDate) {
|
2023-02-15 22:20:14 +08:00
|
|
|
endDate = new Date(recordEndDate);
|
2023-02-07 21:44:40 +08:00
|
|
|
}
|
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
return [startDate, endDate];
|
2023-01-24 00:16:01 +08:00
|
|
|
}
|
2020-04-08 15:48:46 +08:00
|
|
|
}
|
|
|
|
|
2023-02-15 22:20:14 +08:00
|
|
|
export default EventsAirtableRecords;
|