tia/src/lib/formatting.ts
Mannu 96d28cbadc refactor: full codebase sweep — shared types, utilities, component splits
New foundations:
- src/types/index.ts — shared domain types (Child, Log, GrowthRecord, Medicine,
  Dose, Allergy, Visit, Illness, Vaccination, AIChat, ChatSession, Goal)
- src/lib/formatting.ts — calculateAge, formatAge, formatTimeAgo (eliminates
  3 duplicate implementations spread across page.tsx and growth/page.tsx)
- src/lib/api.ts — typed fetch helpers (api.get/post/patch/delete) with
  consistent error handling; replaces manual fetch boilerplate

New shared components:
- src/components/PageHeader.tsx — reusable back-link + title header
- src/components/TabBar.tsx — horizontal pill tab bar
- src/components/CalendarView.tsx — extracted from activity/page.tsx (was ~170 inline lines)
- src/components/medical/ — medical page split into 5 focused tab components:
  VaccineTab, MedicineTab, AllergyTab, VisitTab, IllnessTab

Pages updated:
- medical/page.tsx: 1029 → 42 lines (thin shell wiring the 5 tab components)
- activity/page.tsx: uses CalendarView + shared Log type + api.ts
- growth/page.tsx: uses shared GrowthRecord/Goal types + formatAge; fixes
  `any` catch clauses; fixes undefined → null in Chart.js dataset values
- page.tsx (home): uses shared Log/AIChat/ChatSession types + formatTimeAgo/
  calculateAge from formatting.ts; removes inline type definitions
- ai/page.tsx: uses shared AIChat/ChatSession types
- FamilyProvider.tsx: uses shared Child type; fixes `c: any` mapping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 21:37:39 +05:30

42 lines
1.7 KiB
TypeScript

export function calculateAge(birthDate: string): string {
if (!birthDate) return "";
const birth = new Date(birthDate);
const now = new Date();
let years = now.getFullYear() - birth.getFullYear();
let months = now.getMonth() - birth.getMonth();
let days = now.getDate() - birth.getDate();
if (days < 0) {
months--;
days += new Date(now.getFullYear(), now.getMonth(), 0).getDate();
}
if (months < 0) { years--; months += 12; }
const parts: string[] = [];
if (years > 0) parts.push(`${years} year${years > 1 ? "s" : ""}`);
if (months > 0) parts.push(`${months} month${months > 1 ? "s" : ""}`);
if (days > 0) parts.push(`${days} day${days > 1 ? "s" : ""}`);
return parts.length > 0 ? parts.join(", ") : "Newborn";
}
export function formatAge(birthDate: string, measurementDate?: string): string {
const birth = new Date(birthDate);
const ref = measurementDate ? new Date(measurementDate) : new Date();
const totalDays = (ref.getTime() - birth.getTime()) / (1000 * 60 * 60 * 24);
const years = Math.floor(totalDays / 365);
const months = Math.floor((totalDays % 365) / 30);
if (years > 0 && months > 0) return `${years}y ${months}mo`;
if (years > 0) return `${years}y`;
if (months > 0) return `${months}mo`;
return "Newborn";
}
export function formatTimeAgo(dateStr: string | null | undefined): string | null {
if (!dateStr) return null;
const diffMs = Date.now() - new Date(dateStr).getTime();
const mins = Math.floor(diffMs / 60_000);
const hours = Math.floor(mins / 60);
const days = Math.floor(hours / 24);
if (mins < 1) return "just now";
if (mins < 60) return `${mins}m ago`;
if (hours < 24) return `${hours}h ago`;
return `${days}d ago`;
}