Function bodies 1,383 total
formatDateISO function · typescript · L53-L58 (6 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function formatDateISO(d: Date): string {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}defaultStartDate function · typescript · L60-L64 (5 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function defaultStartDate(): string {
const d = new Date();
d.setDate(d.getDate() - 30);
return formatDateISO(d);
}defaultEndDate function · typescript · L66-L68 (3 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function defaultEndDate(): string {
return formatDateISO(new Date());
}loadTemplates function · typescript · L72-L80 (9 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function loadTemplates(): ReportTemplate[] {
if (typeof window === "undefined") return [];
try {
const stored = localStorage.getItem(STORAGE_KEY);
return stored ? (JSON.parse(stored) as ReportTemplate[]) : [];
} catch {
return [];
}
}saveTemplates function · typescript · L82-L85 (4 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function saveTemplates(templates: ReportTemplate[]) {
if (typeof window === "undefined") return;
localStorage.setItem(STORAGE_KEY, JSON.stringify(templates));
}getApiBaseUrl function · typescript · L87-L89 (3 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function getApiBaseUrl(): string {
return process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000";
}loadOptions function · typescript · L185-L198 (14 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
async function loadOptions() {
try {
const staffData = await api<StaffOption[]>("/api/v1/staff");
setStaffOptions(staffData);
} catch {
setStaffOptions([]);
}
try {
const zoneData = await api<ZoneOption[]>("/api/v1/zones");
setZoneOptions(zoneData);
} catch {
setZoneOptions([]);
}
}Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
handleExport function · typescript · L243-L255 (13 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function handleExport(format: "csv" | "pdf") {
const params = new URLSearchParams({
start: startDate,
end: endDate,
format,
});
if (zoneId) params.set("zone_id", zoneId);
if (staffId) params.set("staff_id", staffId);
if (patientSearch) params.set("patient_id", patientSearch);
const url = `${getApiBaseUrl()}/api/v1/reports/${reportType}?${params.toString()}`;
window.open(url, "_blank");
}handleSaveTemplate function · typescript · L261-L282 (22 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function handleSaveTemplate() {
if (!templateName.trim()) return;
const template: ReportTemplate = {
id: Date.now().toString(),
name: templateName.trim(),
reportType,
startDate,
endDate,
zoneId,
staffId,
patientSearch,
groupBy,
savedAt: new Date().toISOString(),
};
const updated = [...templates, template];
setTemplates(updated);
saveTemplates(updated);
setTemplateName("");
setShowSaveDialog(false);
}handleLoadTemplate function · typescript · L284-L293 (10 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function handleLoadTemplate(template: ReportTemplate) {
setReportType(template.reportType);
setStartDate(template.startDate);
setEndDate(template.endDate);
setZoneId(template.zoneId);
setStaffId(template.staffId);
setPatientSearch(template.patientSearch);
setGroupBy(template.groupBy);
setShowLoadDialog(false);
}handleDeleteTemplate function · typescript · L295-L299 (5 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function handleDeleteTemplate(id: string) {
const updated = templates.filter((t) => t.id !== id);
setTemplates(updated);
saveTemplates(updated);
}formatCellValue function · typescript · L305-L320 (16 LOC)admin/src/app/(authenticated)/analytics/builder/page.tsx
function formatCellValue(key: string, value: unknown): string {
if (value === null || value === undefined) return "--";
if (key === "total_cost") {
return new Intl.NumberFormat("en-CA", {
style: "currency",
currency: "CAD",
}).format(Number(value));
}
if (key.includes("pct") || key.includes("rate")) {
return `${Number(value).toFixed(1)}%`;
}
if (key.includes("hours") || key.includes("duration") || key === "avg_duration") {
return Number(value).toFixed(1);
}
return String(value);
}formatDateISO function · typescript · L116-L121 (6 LOC)admin/src/app/(authenticated)/analytics/financial/page.tsx
function formatDateISO(d: Date): string {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}formatCurrency function · typescript · L123-L128 (6 LOC)admin/src/app/(authenticated)/analytics/financial/page.tsx
function formatCurrency(amount: number): string {
return new Intl.NumberFormat("en-CA", {
style: "currency",
currency: "CAD",
}).format(amount);
}serviceLabel function · typescript · L130-L132 (3 LOC)admin/src/app/(authenticated)/analytics/financial/page.tsx
function serviceLabel(type: string): string {
return SERVICE_TYPE_LABELS[type] || type.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
}Open data scored by Repobility · https://repobility.com
getApiBaseUrl function · typescript · L134-L136 (3 LOC)admin/src/app/(authenticated)/analytics/financial/page.tsx
function getApiBaseUrl(): string {
return process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000";
}handleSort function · typescript · L247-L254 (8 LOC)admin/src/app/(authenticated)/analytics/financial/page.tsx
function handleSort(field: keyof FinancialReportRow) {
if (sortField === field) {
setSortAsc(!sortAsc);
} else {
setSortField(field);
setSortAsc(true);
}
}handleExport function · typescript · L256-L260 (5 LOC)admin/src/app/(authenticated)/analytics/financial/page.tsx
function handleExport(format: "csv" | "pdf") {
const { start, end } = dateRange;
const url = `${getApiBaseUrl()}/api/v1/reports/financial?start=${start}&end=${end}&format=${format}`;
window.open(url, "_blank");
}AnalyticsLayout function · typescript · L15-L62 (48 LOC)admin/src/app/(authenticated)/analytics/layout.tsx
export default function AnalyticsLayout({
children,
}: {
children: React.ReactNode;
}) {
const pathname = usePathname();
return (
<div>
{/* Page header */}
<div className="mb-6">
<h1 className="text-2xl font-bold text-gray-900">Analytics</h1>
<p className="mt-1 text-sm text-gray-500">
Monitor key performance indicators and trends
</p>
</div>
{/* Sub-navigation tabs */}
<div className="mb-6 border-b border-gray-200">
<nav className="-mb-px flex gap-6" aria-label="Analytics tabs">
{tabs.map((tab) => {
const isActive =
tab.href === "/analytics"
? pathname === "/analytics"
: pathname.startsWith(tab.href);
return (
<Link
key={tab.href}
href={tab.href}
className={`whitespace-nowrap border-b-2 px-1 pb-3 text-sm font-medium transition-colors ${
isActiformatDateISO function · typescript · L77-L82 (6 LOC)admin/src/app/(authenticated)/analytics/page.tsx
function formatDateISO(d: Date): string {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}formatDateLabel function · typescript · L84-L91 (8 LOC)admin/src/app/(authenticated)/analytics/page.tsx
function formatDateLabel(iso: string): string {
const d = new Date(iso + "T00:00:00");
return d.toLocaleDateString("en-CA", {
month: "short",
day: "numeric",
timeZone: "America/Toronto",
});
}getPreviousPeriod function · typescript · L93-L96 (4 LOC)admin/src/app/(authenticated)/analytics/page.tsx
function getPreviousPeriod(
start: string,
end: string
): { start: string; end: string } {TrendIndicator function · typescript · L109-L145 (37 LOC)admin/src/app/(authenticated)/analytics/page.tsx
function TrendIndicator({
current,
previous,
higherIsBetter = true,
}: {
current: number;
previous: number | null;
higherIsBetter?: boolean;
}) {
if (previous === null || previous === 0) {
return <span className="text-xs text-gray-400">--</span>;
}
const diff = current - previous;
const pctChange = ((diff / previous) * 100).toFixed(1);
if (Math.abs(diff) < 0.01) {
return (
<span className="flex items-center gap-1 text-xs text-gray-400">
<Minus className="h-3 w-3" />
No change
</span>
);
}
const isPositive = diff > 0;
const isGood = higherIsBetter ? isPositive : !isPositive;
const colorClass = isGood ? "text-green-600" : "text-red-600";
const Icon = isPositive ? ArrowUp : ArrowDown;
return (
<span className={`flex items-center gap-1 text-xs font-medium ${colorClass}`}>
<Icon className="h-3 w-3" />
{Math.abs(Number(pctChange))}%
</span>
);
}All rows above produced by Repobility · https://repobility.com
utilizationColor function · typescript · L151-L155 (5 LOC)admin/src/app/(authenticated)/analytics/page.tsx
function utilizationColor(pct: number): string {
if (pct >= 80) return "#16a34a"; // green-600
if (pct >= 50) return "#ca8a04"; // yellow-600
return "#dc2626"; // red-600
}Toast function · typescript · L46-L60 (15 LOC)admin/src/app/(authenticated)/analytics/reports/page.tsx
function Toast({ message, onClose }: { message: string; onClose: () => void }) {
useEffect(() => {
const timer = setTimeout(onClose, 3000);
return () => clearTimeout(timer);
}, [onClose]);
return (
<div className="fixed bottom-6 right-6 z-50 flex items-center gap-3 rounded-lg bg-gray-900 px-5 py-3 text-sm text-white shadow-lg">
<span>{message}</span>
<button onClick={onClose} className="text-white/60 hover:text-white">
×
</button>
</div>
);
}formatDateISO function · typescript · L57-L62 (6 LOC)admin/src/app/(authenticated)/analytics/satisfaction/page.tsx
function formatDateISO(d: Date): string {
const y = d.getFullYear();
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${y}-${m}-${day}`;
}formatDateLabel function · typescript · L97-L104 (8 LOC)admin/src/app/(authenticated)/analytics/satisfaction/page.tsx
function formatDateLabel(iso: string): string {
const d = new Date(iso + "T00:00:00");
return d.toLocaleDateString("en-CA", {
month: "short",
day: "numeric",
timeZone: "America/Toronto",
});
}npsColorClass function · typescript · L110-L114 (5 LOC)admin/src/app/(authenticated)/analytics/satisfaction/page.tsx
function npsColorClass(score: number): string {
if (score > 50) return "text-green-600";
if (score >= 0) return "text-yellow-600";
return "text-red-600";
}npsBgClass function · typescript · L116-L120 (5 LOC)admin/src/app/(authenticated)/analytics/satisfaction/page.tsx
function npsBgClass(score: number): string {
if (score > 50) return "bg-green-50 border-green-200";
if (score >= 0) return "bg-yellow-50 border-yellow-200";
return "bg-red-50 border-red-200";
}RatingStars function · typescript · L126-L141 (16 LOC)admin/src/app/(authenticated)/analytics/satisfaction/page.tsx
function RatingStars({ value, max = 5 }: { value: number; max?: number }) {
const filled = Math.round(value);
return (
<div className="flex items-center gap-0.5">
{Array.from({ length: max }, (_, i) => (
<Star
key={i}
className={`h-4 w-4 ${
i < filled ? "fill-yellow-400 text-yellow-400" : "text-gray-300"
}`}
/>
))}
<span className="ml-1 text-sm text-gray-600">{value.toFixed(1)}</span>
</div>
);
}AnalyticsSatisfactionPage function · typescript · L147-L462 (316 LOC)admin/src/app/(authenticated)/analytics/satisfaction/page.tsx
export default function AnalyticsSatisfactionPage() {
const [preset, setPreset] = useState<DatePreset>("this_month");
const [customStart, setCustomStart] = useState("");
const [customEnd, setCustomEnd] = useState("");
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [data, setData] = useState<SatisfactionResponse | null>(null);
const dateRange = useMemo(() => {
if (preset === "custom" && customStart && customEnd) {
return { start: customStart, end: customEnd };
}
return getDateRange(preset);
}, [preset, customStart, customEnd]);
const fetchData = useCallback(async () => {
const { start, end } = dateRange;
try {
const result = await api<SatisfactionResponse>(
`/api/v1/analytics/satisfaction?start=${start}&end=${end}`
);
setData(result);
setError(null);
} catch (err) {
setError(err instanceof Error ? err.message : "Failed to load satisfactionRepobility · code-quality intelligence · https://repobility.com
formatDate function · typescript · L70-L72 (3 LOC)admin/src/app/(authenticated)/analytics/staff/page.tsx
function formatDate(d: Date): string {
return d.toISOString().split("T")[0];
}roleLabel function · typescript · L74-L87 (14 LOC)admin/src/app/(authenticated)/analytics/staff/page.tsx
function roleLabel(role: string): string {
const map: Record<string, string> = {
psw: "PSW",
rn: "RN",
rpn: "RPN",
pt: "PT",
ot: "OT",
social_worker: "Social Worker",
dietitian: "Dietitian",
coordinator: "Coordinator",
admin: "Admin",
};
return map[role] || role.toUpperCase();
}rateColor function · typescript · L89-L93 (5 LOC)admin/src/app/(authenticated)/analytics/staff/page.tsx
function rateColor(rate: number): string {
if (rate >= 90) return "text-green-600";
if (rate >= 75) return "text-yellow-600";
return "text-red-600";
}rateBg function · typescript · L95-L99 (5 LOC)admin/src/app/(authenticated)/analytics/staff/page.tsx
function rateBg(rate: number): string {
if (rate >= 90) return "bg-green-50 border-green-200";
if (rate >= 75) return "bg-yellow-50 border-yellow-200";
return "bg-red-50 border-red-200";
}medalEmoji function · typescript · L101-L106 (6 LOC)admin/src/app/(authenticated)/analytics/staff/page.tsx
function medalEmoji(rank: number): string {
if (rank === 1) return "1st";
if (rank === 2) return "2nd";
if (rank === 3) return "3rd";
return `${rank}th`;
}loadStaff function · typescript · L144-L152 (9 LOC)admin/src/app/(authenticated)/analytics/staff/page.tsx
async function loadStaff() {
try {
const data = await api<StaffListItem[]>("/api/v1/staff");
setStaffList(data);
} catch {
// Staff list may fail if endpoint requires auth
setStaffList([]);
}
}handleSort function · typescript · L232-L241 (10 LOC)admin/src/app/(authenticated)/analytics/staff/page.tsx
function handleSort(
field: "score" | "on_time_rate" | "completion_rate" | "total_visits"
) {
if (sortField === field) {
setSortAsc(!sortAsc);
} else {
setSortField(field);
setSortAsc(false);
}
}StepIndicator function · typescript · L32-L68 (37 LOC)admin/src/app/(authenticated)/clients/[id]/care-plan/new/page.tsx
function StepIndicator({ current }: { current: number }) {
return (
<div className="mb-8 flex items-center justify-center gap-2">
{STEPS.map((step, idx) => (
<div key={step.num} className="flex items-center gap-2">
<div
className={`flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium ${
step.num < current
? "bg-primary text-white"
: step.num === current
? "bg-primary text-white"
: "bg-gray-200 text-gray-500"
}`}
>
{step.num < current ? (
<Check className="h-4 w-4" />
) : (
step.num
)}
</div>
<span
className={`text-sm ${
step.num === current
? "font-medium text-gray-900"
: "text-gray-500"
}`}
>
{step.label}
</span>
{idx < STEPS.leGenerated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
updateForm function · typescript · L125-L127 (3 LOC)admin/src/app/(authenticated)/clients/[id]/care-plan/new/page.tsx
function updateForm(updates: Partial<CarePlanFormData>) {
setForm((prev) => ({ ...prev, ...updates }));
}handleServiceTypeChange function · typescript · L129-L139 (11 LOC)admin/src/app/(authenticated)/clients/[id]/care-plan/new/page.tsx
function handleServiceTypeChange(type: ServiceType) {
const updates: Partial<CarePlanFormData> = { service_type: type };
if (type === "psw") {
updates.nursing_visits_per_week = 0;
updates.nursing_tasks = [];
} else if (type === "nursing") {
updates.psw_visits_per_week = 0;
updates.psw_tasks = [];
}
updateForm(updates);
}applyTemplate function · typescript · L141-L156 (16 LOC)admin/src/app/(authenticated)/clients/[id]/care-plan/new/page.tsx
function applyTemplate(template: TaskTemplate) {
const updates: Partial<CarePlanFormData> = {};
if (
form.service_type === "psw" ||
form.service_type === "both"
) {
updates.psw_tasks = [...template.psw_tasks];
}
if (
form.service_type === "nursing" ||
form.service_type === "both"
) {
updates.nursing_tasks = [...template.nursing_tasks];
}
updateForm(updates);
}toggleTask function · typescript · L158-L168 (11 LOC)admin/src/app/(authenticated)/clients/[id]/care-plan/new/page.tsx
function toggleTask(
type: "psw_tasks" | "nursing_tasks",
task: string
) {
const current = form[type];
if (current.includes(task)) {
updateForm({ [type]: current.filter((t) => t !== task) });
} else {
updateForm({ [type]: [...current, task] });
}
}addCustomTask function · typescript · L170-L179 (10 LOC)admin/src/app/(authenticated)/clients/[id]/care-plan/new/page.tsx
function addCustomTask(type: "psw_tasks" | "nursing_tasks") {
const value =
type === "psw_tasks" ? customPswTask : customNursingTask;
if (!value.trim()) return;
if (!form[type].includes(value.trim())) {
updateForm({ [type]: [...form[type], value.trim()] });
}
if (type === "psw_tasks") setCustomPswTask("");
else setCustomNursingTask("");
}toggleDay function · typescript · L181-L190 (10 LOC)admin/src/app/(authenticated)/clients/[id]/care-plan/new/page.tsx
function toggleDay(day: string) {
const current = form.preferred_days;
if (current.includes(day)) {
updateForm({
preferred_days: current.filter((d) => d !== day),
});
} else {
updateForm({ preferred_days: [...current, day] });
}
}handleSubmit function · typescript · L192-L233 (42 LOC)admin/src/app/(authenticated)/clients/[id]/care-plan/new/page.tsx
async function handleSubmit() {
setSubmitting(true);
setError(null);
try {
const title =
form.title ||
`${form.service_type.toUpperCase()} Care Plan`;
const reviewDate =
form.review_date ||
(() => {
const d = new Date(form.start_date);
d.setMonth(d.getMonth() + 3);
return d.toISOString().split("T")[0];
})();
await createCarePlan({
patient_id: patientId,
title,
start_date: form.start_date,
review_date: reviewDate,
psw_visits_per_week: form.psw_visits_per_week,
nursing_visits_per_week: form.nursing_visits_per_week,
psw_visit_duration: form.psw_visit_duration,
nursing_visit_duration: form.nursing_visit_duration,
psw_tasks: JSON.stringify(form.psw_tasks),
nursing_tasks: JSON.stringify(form.nursing_tasks),
requires_two_psw: form.requires_two_psw,
requires_lift_training: form.requires_lift_trainipatientToForm function · typescript · L37-L61 (25 LOC)admin/src/app/(authenticated)/clients/[id]/edit/page.tsx
function patientToForm(p: PatientDetail): FormState {
return {
first_name: p.first_name,
last_name: p.last_name,
date_of_birth: p.date_of_birth,
gender: p.gender ?? "",
language: p.language ?? "",
health_card_number: p.health_card_number ?? "",
phone: p.phone ?? "",
email: p.email ?? "",
address: p.address ?? "",
city: p.city ?? "",
postal_code: p.postal_code ?? "",
diagnosis: p.diagnosis ?? "",
mobility_level: p.mobility_level ?? "",
fall_risk: p.fall_risk ?? "",
cognitive_status: p.cognitive_status ?? "",
special_instructions: p.special_instructions ?? "",
emergency_contact_name: p.emergency_contact_name ?? "",
emergency_contact_phone: p.emergency_contact_phone ?? "",
emergency_contact_relationship: p.emergency_contact_relationship ?? "",
poa_name: p.poa_name ?? "",
poa_phone: p.poa_phone ?? "",
};
}Open data scored by Repobility · https://repobility.com
FormSkeleton function · typescript · L92-L114 (23 LOC)admin/src/app/(authenticated)/clients/[id]/edit/page.tsx
function FormSkeleton() {
return (
<div className="mx-auto max-w-4xl px-4 py-8">
<div className="mb-6 h-8 w-48 animate-pulse rounded bg-gray-200" />
{Array.from({ length: 3 }).map((_, i) => (
<div
key={i}
className="mb-6 rounded-xl border border-gray-200 bg-white p-6 shadow-sm"
>
<div className="mb-4 h-6 w-40 animate-pulse rounded bg-gray-200" />
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{Array.from({ length: 4 }).map((_, j) => (
<div key={j}>
<div className="mb-1 h-4 w-24 animate-pulse rounded bg-gray-200" />
<div className="h-10 w-full animate-pulse rounded-lg bg-gray-200" />
</div>
))}
</div>
</div>
))}
</div>
);
}updateField function · typescript · L154-L156 (3 LOC)admin/src/app/(authenticated)/clients/[id]/edit/page.tsx
function updateField(field: keyof FormState, value: string) {
setForm((prev) => (prev ? { ...prev, [field]: value } : prev));
}handleSubmit function · typescript · L158-L211 (54 LOC)admin/src/app/(authenticated)/clients/[id]/edit/page.tsx
async function handleSubmit(e: FormEvent) {
e.preventDefault();
if (!form || !patient) return;
setError(null);
// Validate required fields
if (!form.first_name.trim() || !form.last_name.trim()) {
setError("Please fill in all required fields: First Name and Last Name.");
window.scrollTo({ top: 0, behavior: "smooth" });
return;
}
setSubmitting(true);
try {
// Build payload with only changed fields
const payload: Record<string, unknown> = {};
const original = patientToForm(patient);
for (const key of Object.keys(form) as (keyof FormState)[]) {
if (form[key] !== original[key]) {
const value = form[key].trim();
// Send null for cleared optional fields, but keep required fields as-is
if (
value === "" &&
key !== "first_name" &&
key !== "last_name"
) {
payload[key] = null;
} else {
payload[key] = vpage 1 / 28next ›