feat: support outlook for calendar plus minor fixes

This commit is contained in:
2026-06-27 15:07:10 +09:30
parent 2163f06de9
commit d34333ca38
31 changed files with 1791 additions and 231 deletions
+65
View File
@@ -0,0 +1,65 @@
import {
GOOGLE_CALENDAR_SYNC_WEEKS_DEFAULT,
GOOGLE_CALENDAR_SYNC_WEEKS_MAX,
GOOGLE_CALENDAR_SYNC_WEEKS_MIN,
} from "@/config/googleCalendar";
import { readOutlookCalendarState } from "@/seqta/utils/outlookCalendar/storage";
import { readGoogleCalendarState } from "@/seqta/utils/googleCalendar/storage";
import {
readSharedCalendarSyncSettings,
WEEKLY_SYNC_INTERVAL_MS,
writeSharedCalendarSyncSettings,
} from "./sharedSettings";
export { CALENDAR_WEEKLY_ALARM, WEEKLY_SYNC_INTERVAL_MS } from "./sharedSettings";
export function clampSyncWeeks(weeks: number): number {
if (!Number.isFinite(weeks)) return GOOGLE_CALENDAR_SYNC_WEEKS_DEFAULT;
return Math.min(
GOOGLE_CALENDAR_SYNC_WEEKS_MAX,
Math.max(GOOGLE_CALENDAR_SYNC_WEEKS_MIN, Math.round(weeks)),
);
}
export async function getSyncWeeksAhead(): Promise<number> {
const settings = await readSharedCalendarSyncSettings();
return clampSyncWeeks(settings.syncWeeksAhead ?? GOOGLE_CALENDAR_SYNC_WEEKS_DEFAULT);
}
export async function getAutoSyncWeekly(): Promise<boolean> {
const settings = await readSharedCalendarSyncSettings();
return settings.autoSyncWeekly !== false;
}
async function isAnyCalendarConnected(): Promise<boolean> {
const [google, outlook] = await Promise.all([
readGoogleCalendarState(),
readOutlookCalendarState(),
]);
return !!(
google.refreshToken ||
google.accessToken ||
outlook.refreshToken ||
outlook.accessToken
);
}
export async function shouldRunWeeklySync(): Promise<boolean> {
const settings = await readSharedCalendarSyncSettings();
if (settings.autoSyncWeekly === false) return false;
if (!(await isAnyCalendarConnected())) return false;
if (settings.pendingWeeklySync) return true;
const last = settings.lastWeeklySyncAt ?? 0;
return Date.now() - last >= WEEKLY_SYNC_INTERVAL_MS;
}
export async function markWeeklySyncComplete(): Promise<void> {
await writeSharedCalendarSyncSettings({
lastWeeklySyncAt: Date.now(),
pendingWeeklySync: false,
});
}
export async function markWeeklySyncPending(): Promise<void> {
await writeSharedCalendarSyncSettings({ pendingWeeklySync: true });
}
@@ -0,0 +1,48 @@
import browser from "webextension-polyfill";
import {
GOOGLE_CALENDAR_SYNC_WEEKS_DEFAULT,
} from "@/config/googleCalendar";
import { readGoogleCalendarState } from "@/seqta/utils/googleCalendar/storage";
export const BSPLUS_CALENDAR_SYNC_SETTINGS_KEY = "bsplus_calendar_sync_settings";
export const CALENDAR_WEEKLY_ALARM = "bsplus_calendar_weekly";
export const WEEKLY_SYNC_INTERVAL_MS = 7 * 24 * 60 * 60 * 1000;
export interface SharedCalendarSyncSettings {
syncWeeksAhead?: number;
autoSyncWeekly?: boolean;
lastWeeklySyncAt?: number;
pendingWeeklySync?: boolean;
}
export async function readSharedCalendarSyncSettings(): Promise<SharedCalendarSyncSettings> {
const got = await browser.storage.local.get(BSPLUS_CALENDAR_SYNC_SETTINGS_KEY);
const raw = got[BSPLUS_CALENDAR_SYNC_SETTINGS_KEY];
const shared =
raw && typeof raw === "object" && !Array.isArray(raw)
? (raw as SharedCalendarSyncSettings)
: {};
if (Object.keys(shared).length > 0) return shared;
const legacy = await readGoogleCalendarState();
return {
syncWeeksAhead: legacy.syncWeeksAhead,
autoSyncWeekly: legacy.autoSyncWeekly,
lastWeeklySyncAt: legacy.lastWeeklySyncAt,
pendingWeeklySync: legacy.pendingWeeklySync,
};
}
export async function writeSharedCalendarSyncSettings(
patch: Partial<SharedCalendarSyncSettings>,
): Promise<SharedCalendarSyncSettings> {
const current = await readSharedCalendarSyncSettings();
const next = { ...current, ...patch };
await browser.storage.local.set({ [BSPLUS_CALENDAR_SYNC_SETTINGS_KEY]: next });
return next;
}
export function defaultSyncWeeksAhead(): number {
return GOOGLE_CALENDAR_SYNC_WEEKS_DEFAULT;
}