Modified by www.SourceFiles.app
This commit is contained in:
@@ -1,116 +0,0 @@
|
|||||||
import type { Database } from "@/integrations/supabase/types";
|
|
||||||
|
|
||||||
export type PlanType = Database["public"]["Enums"]["plan_type"];
|
|
||||||
export type PlanStatus = Database["public"]["Enums"]["plan_status"];
|
|
||||||
export type GoalStatus = Database["public"]["Enums"]["plan_goal_status"];
|
|
||||||
export type MeetingType = Database["public"]["Enums"]["plan_meeting_type"];
|
|
||||||
|
|
||||||
export const PLAN_TYPE_LABEL: Record<PlanType, string> = {
|
|
||||||
iep: "IEP",
|
|
||||||
section_504: "504 Plan",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PLAN_STATUS_LABEL: Record<PlanStatus, string> = {
|
|
||||||
draft: "Draft",
|
|
||||||
active: "Active",
|
|
||||||
archived: "Archived",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GOAL_STATUS_LABEL: Record<GoalStatus, string> = {
|
|
||||||
not_started: "Not started",
|
|
||||||
in_progress: "In progress",
|
|
||||||
met: "Met",
|
|
||||||
not_met: "Not met",
|
|
||||||
discontinued: "Discontinued",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const MEETING_TYPE_LABEL: Record<MeetingType, string> = {
|
|
||||||
initial: "Initial",
|
|
||||||
annual_review: "Annual review",
|
|
||||||
reevaluation: "Re-evaluation",
|
|
||||||
eligibility: "Eligibility",
|
|
||||||
amendment: "Amendment",
|
|
||||||
other: "Other",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ACCOMMODATION_CATEGORIES = [
|
|
||||||
{ value: "instructional", label: "Instructional" },
|
|
||||||
{ value: "environmental", label: "Environmental" },
|
|
||||||
{ value: "assessment", label: "Assessment / testing" },
|
|
||||||
{ value: "behavioral", label: "Behavioral" },
|
|
||||||
{ value: "other", label: "Other" },
|
|
||||||
];
|
|
||||||
export const accommodationLabel = (v: string) =>
|
|
||||||
ACCOMMODATION_CATEGORIES.find((c) => c.value === v)?.label ?? v;
|
|
||||||
|
|
||||||
// ── Compliance clocks ───────────────────────────────────────────────────────
|
|
||||||
// A date within this many days counts as "due soon" rather than merely upcoming.
|
|
||||||
export const DUE_SOON_DAYS = 30;
|
|
||||||
|
|
||||||
export type ComplianceState = "none" | "ok" | "due_soon" | "overdue";
|
|
||||||
|
|
||||||
// "YYYY-MM-DD" through `new Date()` parses as UTC midnight, which lands on the
|
|
||||||
// previous day for anyone west of Greenwich. Build a local date instead.
|
|
||||||
function parseISODate(d: string): Date {
|
|
||||||
const [y, m, day] = d.split("-").map(Number);
|
|
||||||
return new Date(y, m - 1, day);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function daysUntil(date: string | null | undefined, today = new Date()): number | null {
|
|
||||||
if (!date) return null;
|
|
||||||
const midnight = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
|
||||||
return Math.round((parseISODate(date).getTime() - midnight.getTime()) / 86_400_000);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function complianceState(
|
|
||||||
date: string | null | undefined,
|
|
||||||
today = new Date(),
|
|
||||||
): ComplianceState {
|
|
||||||
const d = daysUntil(date, today);
|
|
||||||
if (d === null) return "none";
|
|
||||||
if (d < 0) return "overdue";
|
|
||||||
if (d <= DUE_SOON_DAYS) return "due_soon";
|
|
||||||
return "ok";
|
|
||||||
}
|
|
||||||
|
|
||||||
// EmbraceIEP shows overdue dates in red italics; due-soon gets an amber warning.
|
|
||||||
export const COMPLIANCE_CLASS: Record<ComplianceState, string> = {
|
|
||||||
none: "text-muted-foreground",
|
|
||||||
ok: "text-foreground",
|
|
||||||
due_soon: "text-amber-600 font-medium",
|
|
||||||
overdue: "text-destructive font-semibold italic",
|
|
||||||
};
|
|
||||||
|
|
||||||
export function complianceLabel(state: ComplianceState, days: number | null): string {
|
|
||||||
switch (state) {
|
|
||||||
case "overdue":
|
|
||||||
return `${Math.abs(days ?? 0)} day${Math.abs(days ?? 0) === 1 ? "" : "s"} overdue`;
|
|
||||||
case "due_soon":
|
|
||||||
return days === 0 ? "Due today" : `Due in ${days} day${days === 1 ? "" : "s"}`;
|
|
||||||
case "ok":
|
|
||||||
return "On track";
|
|
||||||
default:
|
|
||||||
return "Not set";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const formatDate = (d: string | null | undefined) =>
|
|
||||||
d ? parseISODate(d).toLocaleDateString() : "—";
|
|
||||||
|
|
||||||
// Default compliance clocks when a plan takes effect: annual review at +1 year,
|
|
||||||
// re-evaluation at +3 years (the IDEA triennial). Both are editable afterwards.
|
|
||||||
export function defaultReviewDates(effective: string): { annual: string; reeval: string } {
|
|
||||||
const iso = (dt: Date) =>
|
|
||||||
`${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, "0")}-${String(dt.getDate()).padStart(2, "0")}`;
|
|
||||||
const base = parseISODate(effective);
|
|
||||||
const annual = new Date(base);
|
|
||||||
annual.setFullYear(annual.getFullYear() + 1);
|
|
||||||
const reeval = new Date(base);
|
|
||||||
reeval.setFullYear(reeval.getFullYear() + 3);
|
|
||||||
return { annual: iso(annual), reeval: iso(reeval) };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const todayISO = () => {
|
|
||||||
const t = new Date();
|
|
||||||
return `${t.getFullYear()}-${String(t.getMonth() + 1).padStart(2, "0")}-${String(t.getDate()).padStart(2, "0")}`;
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user