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

fix: timezone #15

Merged
merged 1 commit into from
Feb 13, 2025
Merged
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
3 changes: 2 additions & 1 deletion packages/core/src/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('Config', () => {
GOOGLE_AUTH_SUBJECT: '[email protected]',
CALENDAR_IDS: 'calendar1,calendar2',
PRIVATE_CALENDAR_IDS: 'calendar3,calendar4',
TIMEZONE: 'Asia/Tokyo',
REMINDER_SETTINGS: JSON.stringify([
{ minutesBefore: 10, notificationType: 'email' },
{ hour: 9, minute: 0, notificationType: 'sms', target: '+1234567890' },
Expand All @@ -27,7 +28,7 @@ describe('Config', () => {
GOOGLE_AUTH_SUBJECT: '[email protected]',
CALENDAR_IDS: ['calendar1', 'calendar2'],
PRIVATE_CALENDAR_IDS: ['calendar3', 'calendar4'],
TIMEZONE: 'UTC',
TIMEZONE: 'Asia/Tokyo',
REMINDER_SETTINGS: [
{ minutesBefore: 10, notificationType: 'email' },
{ hour: 9, minute: 0, notificationType: 'sms', target: '+1234567890' },
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export function parseConfig(env: NodeJS.ProcessEnv): Config {
REMINDER_TEMPLATE: env.REMINDER_TEMPLATE,
AUTH_PROVIDER: env.AUTH_PROVIDER,
WEBHOOK_URL: env.WEBHOOK_URL,
TIMEZONE: env.TIMEZONE,
GROUP_PROVIDER: env.GROUP_PROVIDER,
GROUP_CUSTOMER_ID: env.GROUP_CUSTOMER_ID,
})
Expand Down
113 changes: 102 additions & 11 deletions packages/usecase/src/process_reminders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ describe('processReminders', () => {
})

it('should send notifications for day before at specific hour', async () => {
const baseTime = parseISO('2023-06-01T19:00:00Z') // UTC 19:00
const eventStart = parseISO('2023-06-02T10:00:00Z')
const baseTime = parseISO('2023-06-01T10:00:00Z') // UTC 10:00 = 19:00 JST
const eventStart = parseISO('2023-06-02T01:00:00Z') // UTC 01:00 = 10:00 JST

vi.mocked(mockCalendarRepository.getEvents).mockResolvedValue([
{
id: '1',
start: eventStart.toISOString(),
end: parseISO('2023-06-02T11:00:00Z').toISOString(),
end: parseISO('2023-06-02T02:00:00Z').toISOString(),
title: 'Event 1',
people: [{ email: '[email protected]', organizer: false }],
},
Expand Down Expand Up @@ -162,14 +162,14 @@ describe('processReminders', () => {
})

it('should handle multiple attendees for the same event', async () => {
const baseTime = parseISO('2023-06-01T19:00:00Z')
const eventStart = parseISO('2023-06-02T10:10:00Z')
const baseTime = parseISO('2023-06-01T10:00:00Z') // UTC 10:00 = 19:00 JST
const eventStart = parseISO('2023-06-02T01:00:00Z') // UTC 01:00 = 10:00 JST

vi.mocked(mockCalendarRepository.getEvents).mockResolvedValue([
{
id: '1',
start: eventStart.toISOString(),
end: parseISO('2023-06-02T11:10:00Z').toISOString(),
end: parseISO('2023-06-02T02:00:00Z').toISOString(),
title: 'Event 1',
people: [
{ email: '[email protected]', organizer: false },
Expand Down Expand Up @@ -209,22 +209,22 @@ describe('processReminders', () => {
})

it('should handle multiple reminder settings for the same user', async () => {
const baseTime = parseISO('2023-06-01T19:00:00Z')
const event1Start = parseISO('2023-06-01T19:10:00Z') // For minutesBefore
const event2Start = parseISO('2023-06-02T10:10:00Z') // For hour/minute
const baseTime = parseISO('2023-06-01T10:00:00Z') // UTC 10:00 = 19:00 JST
const event1Start = parseISO('2023-06-01T10:10:00Z') // For minutesBefore
const event2Start = parseISO('2023-06-02T01:00:00Z') // UTC 01:00 = 10:00 JST next day

vi.mocked(mockCalendarRepository.getEvents).mockResolvedValue([
{
id: '1',
start: event1Start.toISOString(),
end: parseISO('2023-06-01T20:10:00Z').toISOString(),
end: parseISO('2023-06-01T11:10:00Z').toISOString(),
title: 'Event 1',
people: [{ email: '[email protected]', organizer: false }],
},
{
id: '2',
start: event2Start.toISOString(),
end: parseISO('2023-06-02T11:10:00Z').toISOString(),
end: parseISO('2023-06-02T02:00:00Z').toISOString(),
title: 'Event 2',
people: [{ email: '[email protected]', organizer: false }],
},
Expand Down Expand Up @@ -310,4 +310,95 @@ describe('processReminders', () => {
expect(mockConsoleNotificationRepository.notify).not.toHaveBeenCalled()
expect(mockWebhookNotificationRepository.notify).not.toHaveBeenCalled()
})

describe('with Asia/Tokyo timezone', () => {
beforeEach(() => {
vi.resetModules()
vi.mock('@synk-cal/core', () => ({
config: {
REMINDER_TEMPLATE:
'Custom reminder: <%= it.title %> <%= it.minutesBefore ? `in ${it.minutesBefore} minutes` : `tomorrow at ${String(it.hour).padStart(2, "0")}:${String(it.minute).padStart(2, "0")}` %>.',
TIMEZONE: 'Asia/Tokyo',
},
}))
})

it('should send notifications for day before at specific hour in JST', async () => {
// JST 19:00 = UTC 10:00
const baseTime = parseISO('2023-06-01T10:00:00Z')
const eventStart = parseISO('2023-06-02T01:00:00Z') // JST 10:00

vi.mocked(mockCalendarRepository.getEvents).mockResolvedValue([
{
id: '1',
start: eventStart.toISOString(),
end: parseISO('2023-06-02T02:00:00Z').toISOString(),
title: 'Event 1',
people: [{ email: '[email protected]', organizer: false }],
},
])

const reminderSettingsMap: Record<string, ReminderSetting[]> = {
'[email protected]': [{ hour: 19, minute: 0, notificationType: 'console' }],
}

vi.mocked(mockReminderSettingsRepository.getReminderSettings).mockImplementation(async (userKey) => {
return reminderSettingsMap[userKey] ?? []
})

await processReminders({
baseTime,
calendarRepositories: [mockCalendarRepository],
groupRepository: undefined,
notificationRepositories: {
console: mockConsoleNotificationRepository,
},
reminderSettingsRepository: mockReminderSettingsRepository,
})

expect(mockConsoleNotificationRepository.notify).toHaveBeenCalledWith(
'[email protected]',
'Custom reminder: Event 1 tomorrow at 19:00.',
)
})

it('should handle date boundary cases in JST', async () => {
// JST 00:00 = UTC 15:00 previous day
const baseTime = parseISO('2023-06-01T15:00:00Z')
const eventStart = parseISO('2023-06-02T15:00:00Z') // JST 00:00 next day

vi.mocked(mockCalendarRepository.getEvents).mockResolvedValue([
{
id: '1',
start: eventStart.toISOString(),
end: parseISO('2023-06-02T16:00:00Z').toISOString(),
title: 'Event 1',
people: [{ email: '[email protected]', organizer: false }],
},
])

const reminderSettingsMap: Record<string, ReminderSetting[]> = {
'[email protected]': [{ hour: 0, minute: 0, notificationType: 'console' }],
}

vi.mocked(mockReminderSettingsRepository.getReminderSettings).mockImplementation(async (userKey) => {
return reminderSettingsMap[userKey] ?? []
})

await processReminders({
baseTime,
calendarRepositories: [mockCalendarRepository],
groupRepository: undefined,
notificationRepositories: {
console: mockConsoleNotificationRepository,
},
reminderSettingsRepository: mockReminderSettingsRepository,
})

expect(mockConsoleNotificationRepository.notify).toHaveBeenCalledWith(
'[email protected]',
'Custom reminder: Event 1 tomorrow at 00:00.',
)
})
})
})