feat(calendar): show regional holidays and observances
This commit is contained in:
1 parent
87276a051e
commit
533ca2d3a4
23 files changed
+563
-29
No files matched your search
@@ -15,6 +15,33 @@ async function bingMetadata() {
|
||||
function headers(type, cache = "public, max-age=3600") { return { "content-type": type, "cache-control": cache }; }
|
||||
function userId(request) { return request.headers.get("oai-authenticated-user-id"); }
|
||||
|
||||
async function holidayFeed(url) {
|
||||
const country = url.searchParams.get('country') || '';
|
||||
const year = Number(url.searchParams.get('year'));
|
||||
if (!/^[A-Z]{2}$/.test(country) || !Number.isInteger(year) || year < 2024 || year > 2030) return Response.json({ error: 'Unsupported holiday country or year' }, { status: 400 });
|
||||
try {
|
||||
const response = await fetch(`https://openworkdays.com/api/v1/${country.toLowerCase()}/${year}.json`);
|
||||
if (!response.ok) throw new Error(`Holiday source returned ${response.status}`);
|
||||
const data = await response.json();
|
||||
if (data.code !== country || data.year !== year || !Array.isArray(data.holidays)) throw new Error('Unexpected holiday data');
|
||||
const validDate = value => typeof value === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value) && value.startsWith(`${year}-`);
|
||||
const holidays = data.holidays.filter(item => validDate(item.date) && typeof item.name === 'string').map(item => ({ date: item.date, name: item.name.slice(0, 160), observed: item.observed === true, estimated: item.estimated === true }));
|
||||
const workingDays = (data.working_weekend_days || []).filter(validDate);
|
||||
return Response.json({ country, year, holidays, workingDays, source: 'OpenWorkdays' }, { headers: { 'cache-control': 'public, max-age=43200' } });
|
||||
} catch { return Response.json({ error: 'Holiday source unavailable' }, { status: 502, headers: { 'cache-control': 'no-store' } }); }
|
||||
}
|
||||
|
||||
async function holidayCountries() {
|
||||
try {
|
||||
const response = await fetch('https://openworkdays.com/api/v1/countries.json');
|
||||
if (!response.ok) throw new Error(`Holiday source returned ${response.status}`);
|
||||
const data = await response.json();
|
||||
const countries = (data.countries || []).filter(item => /^[A-Z]{2}$/.test(item.code) && typeof item.name === 'string').map(item => ({ code: item.code, name: item.name.slice(0, 100) }));
|
||||
if (!countries.length) throw new Error('No countries available');
|
||||
return Response.json({ countries }, { headers: { 'cache-control': 'public, max-age=86400' } });
|
||||
} catch { return Response.json({ error: 'Holiday country list unavailable' }, { status: 502, headers: { 'cache-control': 'no-store' } }); }
|
||||
}
|
||||
|
||||
function loginPage(request) {
|
||||
const preferred = (request.headers.get("accept-language") || "en").split(",").map(part => part.split(";")[0].trim().toLowerCase());
|
||||
const code = preferred.map(value => {
|
||||
@@ -34,6 +61,8 @@ export default {
|
||||
async fetch(request, env) {
|
||||
const url = new URL(request.url);
|
||||
const id = userId(request);
|
||||
if (url.pathname === '/api/holidays') return holidayFeed(url);
|
||||
if (url.pathname === '/api/holiday-countries') return holidayCountries();
|
||||
if (["/api/lifeos-state", "/api/lifeos-initialize", "/api/lifeos-sync"].includes(url.pathname)) return cloudApi(request, env, id, url.pathname);
|
||||
if (url.pathname.startsWith("/api/db-admin/")) return dbAdminApi(request, env, id, url.pathname);
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user