Skip to content

Commit

Permalink
Feat/meeting ical template (#221)
Browse files Browse the repository at this point in the history
* feat: new ical template for scheduled meeting

* feat: add migration

* chore update drizzle data into latest version
  • Loading branch information
ghaniswara authored May 16, 2024
1 parent 7d781a6 commit 71fb3b7
Show file tree
Hide file tree
Showing 34 changed files with 1,442 additions and 759 deletions.
2 changes: 1 addition & 1 deletion app/(server)/_features/event/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const statusEnum = pgEnum('event_status_enum', [
// Event Table
export const events = pgTable('events', {
id: serial('id').primaryKey(),
uuid: uuid('uuid').defaultRandom(),
uuid: uuid('uuid').defaultRandom().notNull(),
slug: text('slug').notNull().unique(),
name: text('name').notNull(),
startTime: timestamp('start_time').notNull(),
Expand Down
38 changes: 34 additions & 4 deletions app/(server)/_shared/mailer/mailer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ export async function SendEventInvitationEmail(
timeZone: 'Asia/Jakarta',
}).format(event.startTime);

const icalString = GenerateIcal(event, 'Asia/Jakarta', host, participant);
const icalString = GenerateIcal(
{ ...event },
'meeting',
'Asia/Jakarta',
host,
{
...participant,
}
);
const iCalendarBuffer = Buffer.from(icalString, 'utf-8');
const roomURL = `${PUBLIC_URL}/rooms/${event.roomId}?clientID=${participant.clientId}`;
const res = await mailer.messages.create(MAILER_DOMAIN, {
Expand Down Expand Up @@ -122,7 +130,15 @@ export async function SendEventCancelledEmail(
timeZone: 'Asia/Jakarta',
}).format(event.startTime);

const icalString = GenerateIcal(event, 'Asia/Jakarta', host, participant);
const icalString = GenerateIcal(
{ ...event },
'meeting',
'Asia/Jakarta',
host,
{
...participant,
}
);
const iCalendarBuffer = Buffer.from(icalString, 'utf-8');

const res = await mailer.messages.create(MAILER_DOMAIN, {
Expand Down Expand Up @@ -211,7 +227,15 @@ export async function SendEventRescheduledEmail(
timeZone: 'Asia/Jakarta',
}).format(newEvent.startTime);

const icalString = GenerateIcal(newEvent, 'Asia/Jakarta', host, participant);
const icalString = GenerateIcal(
{ ...newEvent },
'meeting',
'Asia/Jakarta',
host,
{
...participant,
}
);
const iCalendarBuffer = Buffer.from(icalString, 'utf-8');

const res = await mailer.messages.create(MAILER_DOMAIN, {
Expand Down Expand Up @@ -317,7 +341,13 @@ export async function SendScheduledMeetinEmail(
username: 'api',
});

const icalString = GenerateIcal(event, 'Asia/Jakarta', host, participant);
const icalString = GenerateIcal(
{ ...event },
'meeting',
'Asia/Jakarta',
host,
participant
);
const iCalendarBuffer = Buffer.from(icalString, 'utf-8');

const html = render(
Expand Down
151 changes: 116 additions & 35 deletions app/(server)/api/events/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
import {
selectEvent,
selectParticipant,
} from '@/(server)/_features/event/schema';
import { EventType } from '@/_shared/types/event';

const PUBLIC_URL = process.env.NEXT_PUBLIC_APP_ORIGIN || '';

// reference: https://www.rfc-editor.org/rfc/rfc5545
export function GenerateIcal(
event: selectEvent,
event: {
uuid: string;
name: string;
slug: string;
roomId?: string | null;
startTime: Date;
endTime: Date;
status: string;
},
type: 'webinar' | 'meeting',
timezone: string,
host: EventType.Host,
participant: selectParticipant
host: {
name: string;
email: string;
},
participant: {
clientId: string;
firstName: string;
lastName: string;
email: string;
updateCount: number;
}
) {
const { eventDate, eventTime, DTSTAMP, DTSTART, DTEND } = generateDateTime(
event,
timezone
);
const { eventDate, eventStartTime, eventEndTime, DTSTAMP, DTSTART, DTEND } =
generateDateTime(
{
start: event.startTime,
end: event.endTime,
},
timezone
);

const roomURL = `${PUBLIC_URL}/rooms/${event.roomId}?clientID=${participant.clientId}`;

Expand All @@ -28,19 +44,32 @@ export function GenerateIcal(
eventMethod = 'CANCEL';
}

const eventDesc = `Hi there!\\n
Thanks for registering for our upcoming webinar!\\n
We're excited to have you join us to learn more about\\n
\\n
${event.name}\\n
Hosted by ${host.name}\\n
\\n
${eventDate} - ${eventTime}\\n
\\n
Don't forget to mark your calendar on that date, see you there!\\n
\\n
About event : ${PUBLIC_URL}/events/${event.slug}\\n
Join the event : ${roomURL}`;
let eventDesc = '';

switch (type) {
case 'meeting':
eventDesc = createMeetingDesc({
eventDate,
eventStartTime,
eventEndTime,
roomURL,
host: host.name,
});
break;
case 'webinar':
eventDesc = createWebinarDesc({
name: event.name,
eventDate,
eventStartTime,
roomURL,
slug: event.slug,
host: host.name,
});
break;

default:
break;
}

// eslint-disable-next-line prettier/prettier
return `BEGIN:VCALENDAR
Expand Down Expand Up @@ -77,24 +106,35 @@ END:VEVENT
END:VCALENDAR`;
}

function generateDateTime(event: selectEvent, timezone: string) {
function generateDateTime(
time: {
start: Date;
end: Date;
},
timezone: string
) {
const eventDate = Intl.DateTimeFormat('en-GB', {
dateStyle: 'full',
timeZone: timezone,
}).format(event.startTime);
}).format(time.start);

const eventTime = Intl.DateTimeFormat('en-GB', {
const eventStartTime = Intl.DateTimeFormat('en-GB', {
timeStyle: 'long',
timeZone: timezone,
}).format(event.startTime);
}).format(time.start);

const eventEndTime = Intl.DateTimeFormat('en-GB', {
timeStyle: 'long',
timeZone: timezone,
}).format(time.end);

const icalStartDate = Intl.DateTimeFormat('fr-CA', {
timeZone: timezone,
month: '2-digit',
day: '2-digit',
year: 'numeric',
})
.format(event.startTime)
.format(time.start)
.replaceAll('-', '');

const icalStartTime = Intl.DateTimeFormat('en-GB', {
Expand All @@ -103,7 +143,7 @@ function generateDateTime(event: selectEvent, timezone: string) {
second: '2-digit',
timeZone: timezone,
})
.format(event.startTime)
.format(time.start)
.replaceAll(':', '');

const icalEndDate = Intl.DateTimeFormat('fr-CA', {
Expand All @@ -112,7 +152,7 @@ function generateDateTime(event: selectEvent, timezone: string) {
day: '2-digit',
year: 'numeric',
})
.format(event.endTime)
.format(time.end)
.replaceAll('-', '');

const icalEndTime = Intl.DateTimeFormat('en-GB', {
Expand All @@ -121,11 +161,52 @@ function generateDateTime(event: selectEvent, timezone: string) {
second: '2-digit',
timeZone: timezone,
})
.format(event.endTime)
.format(time.end)
.replaceAll(':', '');

const DTSTAMP = `${icalStartDate}T${icalStartTime}`;
const DTSTART = `${icalStartDate}T${icalStartTime}`;
const DTEND = `${icalEndDate}T${icalEndTime}`;
return { eventDate, eventTime, DTSTAMP, DTSTART, DTEND };
return { eventDate, eventStartTime, eventEndTime, DTSTAMP, DTSTART, DTEND };
}

function createWebinarDesc(meta: {
name: string;
eventDate: string;
eventStartTime: string;
roomURL: string;
slug: string;
host: string;
}) {
return `Hi there!\\n
Thanks for registering for our upcoming webinar!\\n
We're excited to have you join us to learn more about\\n
\\n
${meta.name}\\n
Hosted by ${meta.host}\\n
\\n
${meta.eventDate} - ${meta.eventStartTime}\\n
\\n
Don't forget to mark your calendar on that date, see you there!\\n
\\n
About event : ${PUBLIC_URL}/events/${meta.slug}\\n
Join the event : ${meta.roomURL}`;
}

function createMeetingDesc(meta: {
eventDate: string;
eventStartTime: string;
eventEndTime: string;
roomURL: string;
host: string;
}) {
return `
Hi there! \\n
${meta.host} has scheduled a meeting with you. \\n
${meta.eventDate}
${meta.eventStartTime} - ${meta.eventEndTime} \\n
Join the meeting : ${meta.roomURL} \\n
`;
}
1 change: 1 addition & 0 deletions migrations/0027_fix_event_uuid_not_null.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "events" ALTER COLUMN "uuid" SET NOT NULL;
12 changes: 6 additions & 6 deletions migrations/meta/0000_snapshot.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
{
"version": "5",
"dialect": "pg",
"id": "6dbd156f-51db-4e8d-b0d1-87e8ff835a75",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "6",
"dialect": "postgresql",
"tables": {
"rooms": {
"public.rooms": {
"name": "rooms",
"schema": "",
"columns": {
Expand Down Expand Up @@ -45,5 +43,7 @@
"schemas": {},
"tables": {},
"columns": {}
}
},
"id": "6dbd156f-51db-4e8d-b0d1-87e8ff835a75",
"prevId": "00000000-0000-0000-0000-000000000000"
}
20 changes: 10 additions & 10 deletions migrations/meta/0001_snapshot.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
{
"version": "5",
"dialect": "pg",
"id": "a465116c-b371-4618-aa6c-75f5bb785713",
"prevId": "6dbd156f-51db-4e8d-b0d1-87e8ff835a75",
"version": "6",
"dialect": "postgresql",
"tables": {
"participants": {
"public.participants": {
"name": "participants",
"schema": "",
"columns": {
Expand Down Expand Up @@ -32,21 +30,21 @@
"participants_room_id_rooms_id_fk": {
"name": "participants_room_id_rooms_id_fk",
"tableFrom": "participants",
"tableTo": "rooms",
"columnsFrom": [
"room_id"
],
"tableTo": "rooms",
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
"onUpdate": "no action",
"onDelete": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"rooms": {
"public.rooms": {
"name": "rooms",
"schema": "",
"columns": {
Expand Down Expand Up @@ -87,5 +85,7 @@
"schemas": {},
"tables": {},
"columns": {}
}
},
"id": "a465116c-b371-4618-aa6c-75f5bb785713",
"prevId": "6dbd156f-51db-4e8d-b0d1-87e8ff835a75"
}
Loading

0 comments on commit 71fb3b7

Please sign in to comment.