diff --git a/app/routes.ts b/app/routes.ts index 47ab806..715c844 100644 --- a/app/routes.ts +++ b/app/routes.ts @@ -1,3 +1,3 @@ import { type RouteConfig, index } from "@react-router/dev/routes"; -export default [index("routes/starter.tsx")] satisfies RouteConfig; +export default [index("routes/_index.tsx")] satisfies RouteConfig; diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx new file mode 100644 index 0000000..df2928b --- /dev/null +++ b/app/routes/_index.tsx @@ -0,0 +1,332 @@ +//This is the home page +import React, { useMemo, useState } from "react"; +import { ChevronDown, ChevronUp, Search } from "lucide-react"; + +// --- Temporary JSON data --- +type Status = "Active" | "Follow-up" | "Pending"; +type SortKey = "name" | "socialWorker" | "lastContact" | "status"; + +type Patient = { + id: string; + name: string; + socialWorker: string; + lastContact: string; // ISO date (international standard) + status: Status; +}; + +// Sample patient data +const PATIENTS: Patient[] = [ + { + id: "1", + name: "David Thompson", + socialWorker: "Emily Chen", + lastContact: "2025-10-18", + status: "Active", + }, + { + id: "2", + name: "James Brown", + socialWorker: "Jake Morrison", + lastContact: "2025-10-17", + status: "Follow-up", + }, + { + id: "3", + name: "Jennifer Wilson", + socialWorker: "Emily Chen", + lastContact: "2025-10-19", + status: "Follow-up", + }, + { + id: "4", + name: "Linda Anderson", + socialWorker: "Jake Morrison", + lastContact: "2025-10-21", + status: "Pending", + }, + { + id: "5", + name: "Maria Garcia", + socialWorker: "Sarah Thompson", + lastContact: "2025-10-24", + status: "Active", + }, +]; + +// --- Utilities --- +function formatDate(iso: string) { + const d = new Date(iso); + return d.toLocaleDateString("en-US", { + month: "short", + day: "2-digit", + year: "numeric", + }); +} + +function statusStyles(status: Status) { + // recommended by someone on Figma document + switch (status) { + case "Active": + return "bg-green-50 text-green-700 ring-1 ring-green-200"; + case "Follow-up": + return "bg-yellow-50 text-yellow-800 ring-1 ring-yellow-200"; + case "Pending": + return "bg-gray-100 text-gray-700 ring-1 ring-gray-200"; + } +} + +// --- Component --- +export default function HomePage() { + const [query, setQuery] = useState(""); + const [sortKey, setSortKey] = useState("name"); + const [sortDir, setSortDir] = useState<"asc" | "desc">("asc"); + + // Compute totals + const totals = useMemo(() => { + const total = PATIENTS.length; + const active = PATIENTS.filter((p) => p.status === "Active").length; + const followUps = PATIENTS.filter( + (p) => p.status === "Follow-up" + ).length; + return { total, active, followUps }; + }, []); + + // Filtered patients + const filtered = useMemo(() => { + if (!query.trim()) return PATIENTS; + const q = query.toLowerCase(); + return PATIENTS.filter( + (p) => + p.name.toLowerCase().includes(q) || + p.socialWorker.toLowerCase().includes(q) + ); + }, [query]); + + // Sorted patients + const sorted = useMemo(() => { + const copy = [...filtered]; + + const statusOrder: Record = { + Active: 0, + "Follow-up": 1, + Pending: 2, + }; + + // Function to get the value to sort by + const val = (p: Patient, key: SortKey): string | number => { + switch (key) { + case "lastContact": + return new Date(p.lastContact).getTime(); + case "status": + return statusOrder[p.status]; + case "name": + return p.name.toLowerCase(); + case "socialWorker": + return p.socialWorker.toLowerCase(); + } + }; + + copy.sort((a, b) => { + const av = val(a, sortKey); + const bv = val(b, sortKey); + if (av < bv) return sortDir === "asc" ? -1 : 1; + if (av > bv) return sortDir === "asc" ? 1 : -1; + return 0; + }); + + return copy; + }, [filtered, sortDir, sortKey]); + + // Toggle sort direction + function toggleSort(key: SortKey) { + if (sortKey === key) setSortDir((d) => (d === "asc" ? "desc" : "asc")); + else { + setSortKey(key); + setSortDir("asc"); + } + } + + // Sort Icon Component (uses lucide icons for up/down arrows) + const SortIcon = ({ active }: { active: boolean }) => + active ? ( + sortDir === "asc" ? ( + + ) : ( + + ) + ) : ( + + ); + + return ( +
+ {/* Top Bar */} +
+
+ {/* Logo (Implement later!!!) */} +
+
+ CancerLINC +
+
+ + {/* Search */} +
+ + setQuery(e.target.value)} + placeholder="Search patients or social workers..." + className="w-full rounded-2xl border border-gray-200 bg-white py-2.5 pl-10 pr-4 text-sm text-gray-900 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-green-600" + /> +
+ + {/* Welcome / Logout */} +
+ Welcome, Emily {/* User's name */} + + Logout + +
+
+
+ + {/* Main */} +
+

+ Patient Dashboard +

+

+ Manage and view all patients and their assigned social + workers. Click on any patient name to view their detailed + profile. +

+ + {/* Stat Cards */} +
+ + + +
+ + {/* Table */} +
+
+ + + + + + + + + + + + {sorted.map((p) => ( + + + + + + + + ))} + +
+ + + + + + + Status + + Actions +
+ + + {p.socialWorker} + + {formatDate(p.lastContact)} + + + {p.status} + + + +
+
+
+
+
+ ); +} + +// --- Small components --- +function StatCard({ label, value }: { label: string; value: number }) { + return ( +
+
{label}
+
+ {value} +
+
+ ); +} diff --git a/package-lock.json b/package-lock.json index 33c37bd..1f70cb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "@react-router/node": "^7.7.1", "@react-router/serve": "^7.7.1", "isbot": "^5.1.27", + "lucide-react": "^0.552.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-icons": "^5.5.0", @@ -5533,6 +5534,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "0.552.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.552.0.tgz", + "integrity": "sha512-g9WCjmfwqbexSnZE+2cl21PCfXOcqnGeWeMTNAOGEfpPbm/ZF4YIq77Z8qWrxbu660EKuLB4nSLggoKnCb+isw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.19", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", diff --git a/package.json b/package.json index 7466851..43be4c5 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@react-router/node": "^7.7.1", "@react-router/serve": "^7.7.1", "isbot": "^5.1.27", + "lucide-react": "^0.552.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-icons": "^5.5.0",