Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support start/end timezones for Google provider #609

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ ics(event); // standard ICS file based on https://icalendar.org
| `busy` | Mark on calendar as busy? | Boolean |
| `guests` | Emails of other guests | Array of emails (String) |
| `url` | Calendar document URL | String |
| `startTimeZone` | Start timezone | String <br />**NOTE:** Only supported by `google` |
| `endTimeZone` | End timezone | String <br />**NOTE:** Only supported by `google` |

#### Notes

Expand Down
18 changes: 18 additions & 0 deletions src/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

exports[`aol service generate a aol link 1`] = `"https://calendar.aol.com/?dur=false&et=20191229T020000Z&st=20191229T000000Z&title=Birthday%20party&v=60"`;

exports[`aol service generate a aol link different timezones 1`] = `"https://calendar.aol.com/?dur=false&et=20180405T160000Z&st=20180404T160000Z&title=Flight&v=60"`;

exports[`aol service generate a aol link with description 1`] = `"https://calendar.aol.com/?desc=Bring%20gifts%21&dur=false&et=20191229T020000Z&st=20191229T000000Z&title=Birthday%20party&v=60"`;

exports[`aol service generate a aol link with guests 1`] = `"https://calendar.aol.com/?dur=false&et=20191229T020000Z&st=20191229T000000Z&title=Birthday%20party&v=60"`;
Expand All @@ -16,6 +18,8 @@ exports[`aol service generate an all day aol link 1`] = `"https://calendar.aol.c

exports[`google service generate a google link 1`] = `"https://calendar.google.com/calendar/render?action=TEMPLATE&dates=20191229T000000Z%2F20191229T020000Z&text=Birthday%20party"`;

exports[`google service generate a google link different timezones 1`] = `"https://calendar.google.com/calendar/render?action=TEMPLATE&dates=20180404T160000Z%2F20180405T160000Z&etz=America%2FNew_York&stz=Europe%2FMadrid&text=Flight"`;

exports[`google service generate a google link with description 1`] = `"https://calendar.google.com/calendar/render?action=TEMPLATE&dates=20191229T000000Z%2F20191229T020000Z&details=Bring%20gifts%21&text=Birthday%20party"`;

exports[`google service generate a google link with guests 1`] = `"https://calendar.google.com/calendar/render?action=TEMPLATE&add=hello%40example.com%2Canother%40example.com&dates=20191229T000000Z%2F20191229T020000Z&text=Birthday%20party"`;
Expand All @@ -30,6 +34,8 @@ exports[`google service generate an all day google link 1`] = `"https://calendar

exports[`ics service generate a ics link 1`] = `"data:text/calendar;charset=utf8,BEGIN:VCALENDAR%0D%0AVERSION:2.0%0D%0APRODID:Birthday%20party%0D%0ABEGIN:VEVENT%0D%0ADTSTART:20191229T000000Z%0D%0ADTEND:20191229T020000Z%0D%0ADTSTAMP:20191228T120000Z%0D%0ASUMMARY:Birthday%20party%0D%0AUID:12345%0D%0AEND:VEVENT%0D%0AEND:VCALENDAR%0D%0A"`;

exports[`ics service generate a ics link different timezones 1`] = `"data:text/calendar;charset=utf8,BEGIN:VCALENDAR%0D%0AVERSION:2.0%0D%0APRODID:Flight%0D%0ABEGIN:VEVENT%0D%0ADTSTART:20180404T160000Z%0D%0ADTEND:20180405T160000Z%0D%0ADTSTAMP:20191228T120000Z%0D%0ASUMMARY:Flight%0D%0AUID:12345%0D%0AEND:VEVENT%0D%0AEND:VCALENDAR%0D%0A"`;

exports[`ics service generate a ics link with description 1`] = `"data:text/calendar;charset=utf8,BEGIN:VCALENDAR%0D%0AVERSION:2.0%0D%0APRODID:Birthday%20party%0D%0ABEGIN:VEVENT%0D%0ADTSTART:20191229T000000Z%0D%0ADTEND:20191229T020000Z%0D%0ADTSTAMP:20191228T120000Z%0D%0ASUMMARY:Birthday%20party%0D%0ADESCRIPTION:Bring%20gifts!%0D%0AUID:12345%0D%0AEND:VEVENT%0D%0AEND:VCALENDAR%0D%0A"`;

exports[`ics service generate a ics link with guests 1`] = `"data:text/calendar;charset=utf8,BEGIN:VCALENDAR%0D%0AVERSION:2.0%0D%0APRODID:Birthday%20party%0D%0ABEGIN:VEVENT%0D%0ADTSTART:20191229T000000Z%0D%0ADTEND:20191229T020000Z%0D%0ADTSTAMP:20191228T120000Z%0D%0ASUMMARY:Birthday%20party%0D%0AUID:12345%0D%0AEND:VEVENT%0D%0AEND:VCALENDAR%0D%0A"`;
Expand All @@ -44,6 +50,8 @@ exports[`ics service generate an all day ics link 1`] = `"data:text/calendar;cha

exports[`msTeams service generate a msTeams link 1`] = `"https://teams.microsoft.com/l/meeting/new?endTime=2019-12-29T02%3A00%3A00.000Z&startTime=2019-12-29T00%3A00%3A00.000Z&subject=Birthday%20party"`;

exports[`msTeams service generate a msTeams link different timezones 1`] = `"https://teams.microsoft.com/l/meeting/new?endTime=2018-04-05T16%3A00%3A00.000Z&startTime=2018-04-04T16%3A00%3A00.000Z&subject=Flight"`;

exports[`msTeams service generate a msTeams link with description 1`] = `"https://teams.microsoft.com/l/meeting/new?content=Bring%20gifts%21&endTime=2019-12-29T02%3A00%3A00.000Z&startTime=2019-12-29T00%3A00%3A00.000Z&subject=Birthday%20party"`;

exports[`msTeams service generate a msTeams link with guests 1`] = `"https://teams.microsoft.com/l/meeting/new?attendees=hello%40example.com%2Canother%40example.com&endTime=2019-12-29T02%3A00%3A00.000Z&startTime=2019-12-29T00%3A00%3A00.000Z&subject=Birthday%20party"`;
Expand All @@ -60,6 +68,8 @@ exports[`office365 service generate a multi day office365 link 1`] = `"https://o

exports[`office365 service generate a office365 link 1`] = `"https://outlook.office.com/calendar/0/action/compose?allday=false&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;

exports[`office365 service generate a office365 link different timezones 1`] = `"https://outlook.office.com/calendar/0/action/compose?allday=false&enddt=2018-04-05T16%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2018-04-04T16%3A00%3A00&subject=Flight"`;

exports[`office365 service generate a office365 link with description 1`] = `"https://outlook.office.com/calendar/0/action/compose?allday=false&body=Bring%20gifts%21&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;

exports[`office365 service generate a office365 link with guests 1`] = `"https://outlook.office.com/calendar/0/action/compose?allday=false&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;
Expand All @@ -74,6 +84,8 @@ exports[`office365Mobile service generate a multi day office365Mobile link 1`] =

exports[`office365Mobile service generate a office365Mobile link 1`] = `"https://outlook.office.com/calendar/0/deeplink/compose?allday=false&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;

exports[`office365Mobile service generate a office365Mobile link different timezones 1`] = `"https://outlook.office.com/calendar/0/deeplink/compose?allday=false&enddt=2018-04-05T16%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2018-04-04T16%3A00%3A00&subject=Flight"`;

exports[`office365Mobile service generate a office365Mobile link with description 1`] = `"https://outlook.office.com/calendar/0/deeplink/compose?allday=false&body=Bring%20gifts%21&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;

exports[`office365Mobile service generate a office365Mobile link with guests 1`] = `"https://outlook.office.com/calendar/0/deeplink/compose?allday=false&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;
Expand All @@ -88,6 +100,8 @@ exports[`outlook service generate a multi day outlook link 1`] = `"https://outlo

exports[`outlook service generate a outlook link 1`] = `"https://outlook.live.com/calendar/0/action/compose?allday=false&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;

exports[`outlook service generate a outlook link different timezones 1`] = `"https://outlook.live.com/calendar/0/action/compose?allday=false&enddt=2018-04-05T16%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2018-04-04T16%3A00%3A00&subject=Flight"`;

exports[`outlook service generate a outlook link with description 1`] = `"https://outlook.live.com/calendar/0/action/compose?allday=false&body=Bring%20gifts%21&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;

exports[`outlook service generate a outlook link with guests 1`] = `"https://outlook.live.com/calendar/0/action/compose?allday=false&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;
Expand All @@ -102,6 +116,8 @@ exports[`outlookMobile service generate a multi day outlookMobile link 1`] = `"h

exports[`outlookMobile service generate a outlookMobile link 1`] = `"https://outlook.live.com/calendar/0/deeplink/compose?allday=false&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;

exports[`outlookMobile service generate a outlookMobile link different timezones 1`] = `"https://outlook.live.com/calendar/0/deeplink/compose?allday=false&enddt=2018-04-05T16%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2018-04-04T16%3A00%3A00&subject=Flight"`;

exports[`outlookMobile service generate a outlookMobile link with description 1`] = `"https://outlook.live.com/calendar/0/deeplink/compose?allday=false&body=Bring%20gifts%21&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;

exports[`outlookMobile service generate a outlookMobile link with guests 1`] = `"https://outlook.live.com/calendar/0/deeplink/compose?allday=false&enddt=2019-12-29T02%3A00%3A00&path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&startdt=2019-12-29T00%3A00%3A00&subject=Birthday%20party"`;
Expand All @@ -118,6 +134,8 @@ exports[`yahoo service generate a recurring yahoo link 1`] = `"https://calendar.

exports[`yahoo service generate a yahoo link 1`] = `"https://calendar.yahoo.com/?dur=false&et=20191229T020000Z&st=20191229T000000Z&title=Birthday%20party&v=60"`;

exports[`yahoo service generate a yahoo link different timezones 1`] = `"https://calendar.yahoo.com/?dur=false&et=20180405T160000Z&st=20180404T160000Z&title=Flight&v=60"`;

exports[`yahoo service generate a yahoo link with description 1`] = `"https://calendar.yahoo.com/?desc=Bring%20gifts%21&dur=false&et=20191229T020000Z&st=20191229T000000Z&title=Birthday%20party&v=60"`;

exports[`yahoo service generate a yahoo link with guests 1`] = `"https://calendar.yahoo.com/?dur=false&et=20191229T020000Z&st=20191229T000000Z&title=Birthday%20party&v=60"`;
Expand Down
12 changes: 12 additions & 0 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,17 @@ for (const service of [
const link = service(event);
expect(link).toMatchSnapshot();
});

test(`generate a ${service.name} link different timezones`, () => {
const event: CalendarEvent = {
title: "Flight",
start: "2018-04-04T16:00:00.000Z",
end: "2018-04-05T16:00:00.000Z",
startTimeZone: "Europe/Madrid",
endTimeZone: "America/New_York",
};
const link = service(event);
expect(link).toMatchSnapshot();
});
});
}
36 changes: 20 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function stringify(input: Record<string, any>): string {

function formatTimes(
{ startTime, endTime }: NormalizedCalendarEvent,
dateTimeFormat: keyof typeof TimeFormats
dateTimeFormat: keyof typeof TimeFormats,
): { start: string; end: string } {
const format = TimeFormats[dateTimeFormat];
return { start: startTime.format(format), end: endTime.format(format) };
Expand Down Expand Up @@ -72,6 +72,8 @@ export const google = (calendarEvent: CalendarEvent): string => {
trp: event.busy,
dates: start + "/" + end,
recur: event.rRule ? "RRULE:" + event.rRule : undefined,
stz: event.startTimeZone,
etz: event.endTimeZone,
};
if (event.guests && event.guests.length) {
details.add = event.guests.join();
Expand Down Expand Up @@ -159,18 +161,18 @@ export const yahoo = (calendarEvent: CalendarEvent): string => {
};

export const aol = (calendarEvent: CalendarEvent): string => {
const event = eventify(calendarEvent);
const { start, end } = formatTimes(event, event.allDay ? "allDay" : "dateTimeUTC");
const details: Aol = {
v: 60,
title: event.title,
st: start,
et: end,
desc: event.description,
in_loc: event.location,
dur: event.allDay ? "allday" : false,
};
return `https://calendar.aol.com/?${stringify(details)}`;
const event = eventify(calendarEvent);
const { start, end } = formatTimes(event, event.allDay ? "allDay" : "dateTimeUTC");
const details: Aol = {
v: 60,
title: event.title,
st: start,
et: end,
desc: event.description,
in_loc: event.location,
dur: event.allDay ? "allday" : false,
};
return `https://calendar.aol.com/?${stringify(details)}`;
};

// https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/build-and-test/deep-link-workflow?tabs=teamsjs-v2#configure-deep-link-manually-to-open-a-meeting-scheduling-dialog
Expand Down Expand Up @@ -217,7 +219,7 @@ export const ics = (calendarEvent: CalendarEvent): string => {
},
{
key: "PRODID",
value: event.title
value: event.title,
},
{
key: "BEGIN",
Expand Down Expand Up @@ -261,7 +263,9 @@ export const ics = (calendarEvent: CalendarEvent): string => {
},
{
key: "UID",
value: Math.floor(Math.random() * 100000).toString().replace(".", ""),
value: Math.floor(Math.random() * 100000)
.toString()
.replace(".", ""),
},
{
key: "END",
Expand All @@ -280,7 +284,7 @@ export const ics = (calendarEvent: CalendarEvent): string => {
if (chunk.key == "ORGANIZER") {
const value = chunk.value as CalendarEventOrganizer;
calendarUrl += `${chunk.key};${encodeURIComponent(
`CN=${value.name}:MAILTO:${value.email}\r\n`
`CN=${value.name}:MAILTO:${value.email}\r\n`,
)}`;
} else {
calendarUrl += `${chunk.key}:${encodeURIComponent(`${chunk.value}\r\n`)}`;
Expand Down
29 changes: 21 additions & 8 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ interface CalendarEvent {
busy?: boolean;
guests?: string[];
url?: string;
startTimeZone?: string;
endTimeZone?: string;
}

interface CalendarEventOrganizer {
Expand All @@ -36,6 +38,8 @@ interface Google extends Record<string, string | boolean | number | undefined> {
add?: string;
src?: string;
recur?: string;
stz?: string;
etz?: string;
}

interface Outlook extends Record<string, string | boolean | number | undefined> {
Expand All @@ -59,13 +63,13 @@ interface Yahoo extends Record<string, string | boolean | number | undefined> {
}

interface Aol extends Record<string, string | boolean | number | undefined> {
v: number;
title: string;
st: string;
et: string;
desc?: string;
in_loc?: string;
}
v: number;
title: string;
st: string;
et: string;
desc?: string;
in_loc?: string;
}

interface MsTeams extends Record<string, string | boolean | number | undefined> {
subject?: string;
Expand All @@ -75,4 +79,13 @@ interface MsTeams extends Record<string, string | boolean | number | undefined>
attendees?: string;
}

export { CalendarEvent, CalendarEventOrganizer, NormalizedCalendarEvent, Outlook, Yahoo, Google, Aol, MsTeams };
export {
CalendarEvent,
CalendarEventOrganizer,
NormalizedCalendarEvent,
Outlook,
Yahoo,
Google,
Aol,
MsTeams,
};