feat(planning): ship holiday-aware planning and assistant upgrades
This commit is contained in:
@@ -113,6 +113,16 @@ export type VacationEntry = {
|
||||
halfDayPart?: string | null;
|
||||
};
|
||||
|
||||
export type HolidayOverlayEntry = {
|
||||
id: string;
|
||||
resourceId: string;
|
||||
type: string;
|
||||
status: string;
|
||||
startDate: Date | string;
|
||||
endDate: Date | string;
|
||||
note?: string | null;
|
||||
};
|
||||
|
||||
// ─── Context shape ──────────────────────────────────────────────────────────
|
||||
|
||||
export interface TimelineContextValue {
|
||||
@@ -314,9 +324,43 @@ export function TimelineProvider({
|
||||
{ placeholderData: (prev) => prev, refetchOnWindowFocus: false, staleTime: 90_000 },
|
||||
);
|
||||
|
||||
const { data: holidayOverlayEntries = [] } = trpc.timeline.getHolidayOverlays.useQuery(
|
||||
{
|
||||
startDate: viewStart,
|
||||
endDate: viewEnd,
|
||||
...(filters.clientIds.length > 0 ? { clientIds: filters.clientIds } : {}),
|
||||
...(filters.projectIds.length > 0 ? { projectIds: filters.projectIds } : {}),
|
||||
...(filters.chapters.length > 0 ? { chapters: filters.chapters } : {}),
|
||||
...(filters.eids.length > 0 ? { eids: filters.eids } : {}),
|
||||
...(filters.countryCodes.length > 0 ? { countryCodes: filters.countryCodes } : {}),
|
||||
},
|
||||
{ placeholderData: (prev) => prev, refetchOnWindowFocus: false, staleTime: 90_000 },
|
||||
);
|
||||
|
||||
const vacationsByResource = useMemo(() => {
|
||||
const map = new Map<string, VacationEntry[]>();
|
||||
for (const vacation of vacationEntries as VacationEntry[]) {
|
||||
const mergedEntries = [...(vacationEntries as VacationEntry[])];
|
||||
const existingKeys = new Set(
|
||||
mergedEntries.map((vacation) => {
|
||||
const start = new Date(vacation.startDate).toISOString().slice(0, 10);
|
||||
const end = new Date(vacation.endDate).toISOString().slice(0, 10);
|
||||
return `${vacation.resourceId}:${vacation.type}:${start}:${end}`;
|
||||
}),
|
||||
);
|
||||
|
||||
for (const holiday of holidayOverlayEntries as HolidayOverlayEntry[]) {
|
||||
const start = new Date(holiday.startDate).toISOString().slice(0, 10);
|
||||
const end = new Date(holiday.endDate).toISOString().slice(0, 10);
|
||||
const key = `${holiday.resourceId}:${holiday.type}:${start}:${end}`;
|
||||
if (existingKeys.has(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
existingKeys.add(key);
|
||||
mergedEntries.push(holiday as VacationEntry);
|
||||
}
|
||||
|
||||
for (const vacation of mergedEntries) {
|
||||
const existing = map.get(vacation.resourceId);
|
||||
if (existing) {
|
||||
existing.push(vacation);
|
||||
@@ -325,7 +369,7 @@ export function TimelineProvider({
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}, [vacationEntries]);
|
||||
}, [holidayOverlayEntries, vacationEntries]);
|
||||
|
||||
// When EID filter is active, explicitly fetch those resources.
|
||||
const { data: eidFilterData } = trpc.resource.list.useQuery(
|
||||
|
||||
Reference in New Issue
Block a user