Phase 1: project foundation for Alpenwerk HR
Scaffolds the Next.js 16 / TypeScript strict / Tailwind v3 app per NEXTJS_REBUILD_SUPERPROMPT.md, and implements the Foundation slice from the Phase 1 plan: - Corrected Supabase schema (supabase/schema.sql): org units, employees, history, positions, hire drafts, saved reports, audit log, reorg scenarios, role-based profiles, salary-masking view, RLS policies, auto-derivation triggers, position-number generator. - Seed script (supabase/seed.ts): ~800 realistic Austrian employees across 9 divisions / 16 departments / 35 teams, history, 8 open positions, and hr_admin/manager test accounts. - Supabase clients (lib/supabase/*), design tokens (tailwind.config.ts), format/color helpers (lib/format.ts, lib/colors.ts). - Shared UI kit (components/ui): Avatar, StatusChip, Toast, Modal, SlideOver, SegmentedControl, Lookup. - Auth (login page, Server Actions) and proxy.ts (Next 16's replacement for middleware) guarding the authenticated route group. - Shell (Sidebar, Topbar, NewHireButton stub) and the Dashboard page, reading live data via employees_directory. Employees list/detail, hire wizard, action panels, org chart, positions, reports, and audit log are deferred to later phases per the plan.
This commit is contained in:
64
lib/format.ts
Normal file
64
lib/format.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
const dateFormatter = new Intl.DateTimeFormat("de-AT", {
|
||||
day: "2-digit",
|
||||
month: "2-digit",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
const eurFormatter = new Intl.NumberFormat("de-AT", {
|
||||
style: "currency",
|
||||
currency: "EUR",
|
||||
});
|
||||
|
||||
export function fmtDate(date: string | Date | null | undefined): string {
|
||||
if (!date) return "–";
|
||||
const d = typeof date === "string" ? new Date(date) : date;
|
||||
if (Number.isNaN(d.getTime())) return "–";
|
||||
return dateFormatter.format(d);
|
||||
}
|
||||
|
||||
export function fmtEUR(amount: number | null | undefined): string {
|
||||
if (amount === null || amount === undefined) return "••• (ausgeblendet)";
|
||||
return eurFormatter.format(amount);
|
||||
}
|
||||
|
||||
export function initials(firstName: string, lastName: string): string {
|
||||
const a = firstName.trim().charAt(0).toUpperCase();
|
||||
const b = lastName.trim().charAt(0).toUpperCase();
|
||||
return `${a}${b}`;
|
||||
}
|
||||
|
||||
export function fmtAge(birthDate: string | Date): number {
|
||||
const d = typeof birthDate === "string" ? new Date(birthDate) : birthDate;
|
||||
const today = new Date();
|
||||
let age = today.getFullYear() - d.getFullYear();
|
||||
const hasHadBirthdayThisYear =
|
||||
today.getMonth() > d.getMonth() ||
|
||||
(today.getMonth() === d.getMonth() && today.getDate() >= d.getDate());
|
||||
if (!hasHadBirthdayThisYear) age -= 1;
|
||||
return age;
|
||||
}
|
||||
|
||||
export function tenure(entryDate: string | Date, endDate?: string | Date | null): string {
|
||||
const start = typeof entryDate === "string" ? new Date(entryDate) : entryDate;
|
||||
const end = endDate ? (typeof endDate === "string" ? new Date(endDate) : endDate) : new Date();
|
||||
|
||||
let years = end.getFullYear() - start.getFullYear();
|
||||
let months = end.getMonth() - start.getMonth();
|
||||
if (end.getDate() < start.getDate()) months -= 1;
|
||||
if (months < 0) {
|
||||
years -= 1;
|
||||
months += 12;
|
||||
}
|
||||
if (years < 0) return "0 Monate";
|
||||
|
||||
const yearPart = years > 0 ? `${years} ${years === 1 ? "Jahr" : "Jahre"}` : "";
|
||||
const monthPart = months > 0 ? `${months} ${months === 1 ? "Monat" : "Monate"}` : "";
|
||||
if (yearPart && monthPart) return `${yearPart}, ${monthPart}`;
|
||||
return yearPart || monthPart || "unter 1 Monat";
|
||||
}
|
||||
|
||||
export function daysBetween(a: string | Date, b: string | Date = new Date()): number {
|
||||
const start = typeof a === "string" ? new Date(a) : a;
|
||||
const end = typeof b === "string" ? new Date(b) : b;
|
||||
return Math.round((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
Reference in New Issue
Block a user