1df208dbcc
Allocation bars that have active optimistic overrides (post-drag, awaiting server confirmation) now pulse subtly via animate-pulse. The pending set is derived from the existing optimisticAllocations map keys, requiring no additional state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
import type { WeekdayAvailability } from "../types/resource.js";
|
|
|
|
export * from "./germanStates.js";
|
|
export * from "./publicHolidays.js";
|
|
|
|
export const MILLISECONDS_PER_DAY = 86_400_000;
|
|
|
|
export function toIsoDate(value: Date | string): string {
|
|
if (typeof value === "string") return value.slice(0, 10);
|
|
return value.toISOString().slice(0, 10);
|
|
}
|
|
|
|
export function toIsoDateOrNull(value: Date | string | null | undefined): string | null {
|
|
if (!value) return null;
|
|
return toIsoDate(value);
|
|
}
|
|
|
|
export function round1(value: number): number {
|
|
return Math.round(value * 10) / 10;
|
|
}
|
|
|
|
export function averagePerWorkingDay(totalHours: number, workingDays: number): number {
|
|
if (workingDays <= 0) return 0;
|
|
return round1(totalHours / workingDays);
|
|
}
|
|
|
|
export const DAY_KEYS: readonly (keyof WeekdayAvailability)[] = [
|
|
"sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday",
|
|
] as const;
|
|
|
|
export function normalizeCityName(cityName?: string | null): string | null {
|
|
const normalized = cityName?.trim().toLowerCase();
|
|
return normalized && normalized.length > 0 ? normalized : null;
|
|
}
|
|
|
|
export function normalizeStateCode(stateCode?: string | null): string | null {
|
|
const normalized = stateCode?.trim().toUpperCase();
|
|
return normalized && normalized.length > 0 ? normalized : null;
|
|
}
|
|
export * from "./columns.js";
|
|
export * from "./dispo-import.js";
|
|
export * from "./data-classification.js";
|
|
export * from "./comment-entities.js";
|
|
|
|
export const BUDGET_WARNING_THRESHOLDS = {
|
|
INFO: 70,
|
|
WARNING: 85,
|
|
CRITICAL: 95,
|
|
} as const;
|
|
|
|
export const DEFAULT_WORKING_HOURS_PER_DAY = 8;
|
|
export const DEFAULT_OPENAI_MODEL = "gpt-5.4";
|
|
|
|
export const DEFAULT_AVAILABILITY = {
|
|
monday: 8,
|
|
tuesday: 8,
|
|
wednesday: 8,
|
|
thursday: 8,
|
|
friday: 8,
|
|
} as const;
|
|
|
|
export const VALUE_SCORE_WEIGHTS = {
|
|
SKILL_DEPTH: 0.30,
|
|
SKILL_BREADTH: 0.15,
|
|
COST_EFFICIENCY: 0.25,
|
|
CHARGEABILITY: 0.15,
|
|
EXPERIENCE: 0.15,
|
|
} as const;
|
|
|
|
export const SCORE_WEIGHTS = {
|
|
SKILL: 0.4,
|
|
AVAILABILITY: 0.3,
|
|
COST: 0.2,
|
|
UTILIZATION: 0.1,
|
|
} as const;
|
|
|
|
export const PAGINATION_DEFAULTS = {
|
|
PAGE: 1,
|
|
LIMIT: 50,
|
|
MAX_LIMIT: 500,
|
|
} as const;
|
|
|
|
export const SSE_EVENT_TYPES = {
|
|
ALLOCATION_CREATED: "allocation.created",
|
|
ALLOCATION_UPDATED: "allocation.updated",
|
|
ALLOCATION_DELETED: "allocation.deleted",
|
|
PROJECT_SHIFTED: "project.shifted",
|
|
BUDGET_WARNING: "budget.warning",
|
|
VACATION_CREATED: "vacation.created",
|
|
VACATION_UPDATED: "vacation.updated",
|
|
VACATION_DELETED: "vacation.deleted",
|
|
ROLE_CREATED: "role.created",
|
|
ROLE_UPDATED: "role.updated",
|
|
ROLE_DELETED: "role.deleted",
|
|
NOTIFICATION_CREATED: "notification:created",
|
|
TASK_ASSIGNED: "task.assigned",
|
|
TASK_COMPLETED: "task.completed",
|
|
TASK_STATUS_CHANGED: "task.status_changed",
|
|
REMINDER_DUE: "reminder.due",
|
|
PING: "ping",
|
|
} as const;
|
|
|
|
export type SseEventType = (typeof SSE_EVENT_TYPES)[keyof typeof SSE_EVENT_TYPES];
|
|
|
|
export const SSE_NOTIFICATION_CREATED = SSE_EVENT_TYPES.NOTIFICATION_CREATED;
|