123 lines
3.5 KiB
TypeScript
123 lines
3.5 KiB
TypeScript
import type { Prisma } from "@capakraken/db";
|
|
import { fmtDate } from "./timeline-read-shared.js";
|
|
|
|
export interface TimelineHolidayOverlayRecord {
|
|
id: string;
|
|
resourceId: string;
|
|
startDate: Date;
|
|
endDate: Date;
|
|
note?: string | null;
|
|
scope?: string | null;
|
|
calendarName?: string | null;
|
|
sourceType?: string | null;
|
|
countryCode?: string | null;
|
|
countryName?: string | null;
|
|
federalState?: string | null;
|
|
metroCityName?: string | null;
|
|
}
|
|
|
|
export function formatTimelineHolidayOverlays(overlays: TimelineHolidayOverlayRecord[]) {
|
|
return overlays.map((overlay) => ({
|
|
id: overlay.id,
|
|
resourceId: overlay.resourceId,
|
|
startDate: fmtDate(overlay.startDate),
|
|
endDate: fmtDate(overlay.endDate),
|
|
note: overlay.note ?? null,
|
|
scope: overlay.scope ?? null,
|
|
calendarName: overlay.calendarName ?? null,
|
|
sourceType: overlay.sourceType ?? null,
|
|
countryCode: overlay.countryCode ?? null,
|
|
countryName: overlay.countryName ?? null,
|
|
federalState: overlay.federalState ?? null,
|
|
metroCityName: overlay.metroCityName ?? null,
|
|
}));
|
|
}
|
|
|
|
export function summarizeTimelineHolidayOverlays(
|
|
overlays: ReturnType<typeof formatTimelineHolidayOverlays>,
|
|
) {
|
|
const resourceIds = new Set<string>();
|
|
const byScope = new Map<string, number>();
|
|
|
|
for (const overlay of overlays) {
|
|
resourceIds.add(overlay.resourceId);
|
|
const scope = overlay.scope ?? "UNKNOWN";
|
|
byScope.set(scope, (byScope.get(scope) ?? 0) + 1);
|
|
}
|
|
|
|
return {
|
|
overlayCount: overlays.length,
|
|
holidayResourceCount: resourceIds.size,
|
|
byScope: [...byScope.entries()]
|
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
.map(([scope, count]) => ({ scope, count })),
|
|
};
|
|
}
|
|
|
|
export function buildTimelineHolidayResourceWhere(input: {
|
|
chapters?: string[] | undefined;
|
|
eids?: string[] | undefined;
|
|
countryCodes?: string[] | undefined;
|
|
}): Prisma.ResourceWhereInput | null {
|
|
const andConditions: Prisma.ResourceWhereInput[] = [];
|
|
|
|
if (input.chapters && input.chapters.length > 0) {
|
|
andConditions.push({ chapter: { in: input.chapters } });
|
|
}
|
|
if (input.eids && input.eids.length > 0) {
|
|
andConditions.push({ eid: { in: input.eids } });
|
|
}
|
|
if (input.countryCodes && input.countryCodes.length > 0) {
|
|
andConditions.push({ country: { code: { in: input.countryCodes } } });
|
|
}
|
|
|
|
if (andConditions.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return andConditions.length === 1 ? andConditions[0]! : { AND: andConditions };
|
|
}
|
|
|
|
export function buildTimelineHolidayResourceIds(input: {
|
|
assignmentResourceIds: Array<string | null>;
|
|
requestedResourceIds?: string[] | undefined;
|
|
matchingFilterResourceIds?: string[] | undefined;
|
|
}) {
|
|
const resourceIds = new Set(
|
|
input.assignmentResourceIds.filter(
|
|
(resourceId): resourceId is string => typeof resourceId === "string" && resourceId.length > 0,
|
|
),
|
|
);
|
|
|
|
for (const resourceId of input.requestedResourceIds ?? []) {
|
|
if (resourceId) {
|
|
resourceIds.add(resourceId);
|
|
}
|
|
}
|
|
|
|
for (const resourceId of input.matchingFilterResourceIds ?? []) {
|
|
if (resourceId) {
|
|
resourceIds.add(resourceId);
|
|
}
|
|
}
|
|
|
|
return [...resourceIds];
|
|
}
|
|
|
|
export function buildTimelineHolidayOverlayDetailResponse(input: {
|
|
startDate: Date;
|
|
endDate: Date;
|
|
filters: Record<string, unknown>;
|
|
overlays: ReturnType<typeof formatTimelineHolidayOverlays>;
|
|
}) {
|
|
return {
|
|
period: {
|
|
startDate: fmtDate(input.startDate),
|
|
endDate: fmtDate(input.endDate),
|
|
},
|
|
filters: input.filters,
|
|
summary: summarizeTimelineHolidayOverlays(input.overlays),
|
|
overlays: input.overlays,
|
|
};
|
|
}
|