diff --git a/apps/Frontend/src/components/claims/claim-edit-modal.tsx b/apps/Frontend/src/components/claims/claim-edit-modal.tsx index 0a5c665..aa4bb2f 100644 --- a/apps/Frontend/src/components/claims/claim-edit-modal.tsx +++ b/apps/Frontend/src/components/claims/claim-edit-modal.tsx @@ -16,6 +16,12 @@ import { import { formatDateToHumanReadable } from "@/utils/dateUtils"; import React, { useState } from "react"; import { ClaimStatus, ClaimWithServiceLines } from "@repo/db/types"; +import { + safeParseMissingTeeth, + splitTeeth, + ToothChip, + toStatusLabel, +} from "./tooth-ui"; type ClaimEditModalProps = { isOpen: boolean; @@ -223,6 +229,65 @@ export default function ClaimEditModal({ + {/* Missing Teeth */} +
+

Missing Teeth

+ +

+ Status:{" "} + {toStatusLabel((claim as any).missingTeethStatus)} +

+ + {/* Only show details when the user chose "Specify Missing" */} + {(claim as any).missingTeethStatus === "Yes_missing" && + (() => { + const map = safeParseMissingTeeth((claim as any).missingTeeth); + const { permanent, primary } = splitTeeth(map); + const hasAny = permanent.length > 0 || primary.length > 0; + + if (!hasAny) { + return ( +

+ No specific teeth marked as missing. +

+ ); + } + + return ( +
+ {permanent.length > 0 && ( +
+
+ Permanent +
+
+ {permanent.map((t) => ( + + ))} +
+
+ )} + {primary.length > 0 && ( +
+
+ Primary +
+
+ {primary.map((t) => ( + + ))} +
+
+ )} +
+ ); + })()} + + {(claim as any).missingTeethStatus === "endentulous" && ( +

Patient is edentulous.

+ )} +
+ {/* Actions */}
+ {/* Missing Teeth */} +
+

Missing Teeth

+ +

+ Status:{" "} + {toStatusLabel((claim as any).missingTeethStatus)} +

+ + {/* Only show details when the user chose "Specify Missing" */} + {(claim as any).missingTeethStatus === "Yes_missing" && + (() => { + const map = safeParseMissingTeeth( + (claim as any).missingTeeth + ); + const { permanent, primary } = splitTeeth(map); + const hasAny = permanent.length > 0 || primary.length > 0; + + if (!hasAny) { + return ( +

+ No specific teeth marked as missing. +

+ ); + } + + return ( +
+ {permanent.length > 0 && ( +
+
+ Permanent +
+
+ {permanent.map((t) => ( + + ))} +
+
+ )} + {primary.length > 0 && ( +
+
+ Primary +
+
+ {primary.map((t) => ( + + ))} +
+
+ )} +
+ ); + })()} + + {(claim as any).missingTeethStatus === "endentulous" && ( +

Patient is edentulous.

+ )} +
+ {/* Claim Files (metadata) */}

diff --git a/apps/Frontend/src/components/claims/tooth-ui.tsx b/apps/Frontend/src/components/claims/tooth-ui.tsx index d0d84ab..34f54f5 100644 --- a/apps/Frontend/src/components/claims/tooth-ui.tsx +++ b/apps/Frontend/src/components/claims/tooth-ui.tsx @@ -99,3 +99,57 @@ export function TeethGrid({

); } + + +// ——— Missing Teeth helpers for claim-view and edit modal——— +type MissingMap = Record; + +export function toStatusLabel(s?: string) { + if (!s) return "Unknown"; + if (s === "No_missing") return "No Missing"; + if (s === "endentulous") return "Edentulous"; + if (s === "Yes_missing") return "Specify Missing"; + // best-effort prettify + return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase(); +} + +export function safeParseMissingTeeth(raw: unknown): MissingMap { + if (!raw) return {}; + if (typeof raw === "string") { + try { + const parsed = JSON.parse(raw); + if (parsed && typeof parsed === "object") return parsed as MissingMap; + } catch {} + return {}; + } + if (typeof raw === "object") return raw as MissingMap; + return {}; +} + +const PERM = new Set(Array.from({ length: 32 }, (_, i) => `T_${i + 1}`)); +const PRIM = new Set(Array.from("ABCDEFGHIJKLMNOPQRST").map((ch) => `T_${ch}`)); + +export function splitTeeth(map: MissingMap) { + const permanent: Array<{ name: string; v: ToothVal }> = []; + const primary: Array<{ name: string; v: ToothVal }> = []; + for (const [k, v] of Object.entries(map)) { + if (!v) continue; + if (PERM.has(k)) permanent.push({ name: k, v }); + else if (PRIM.has(k)) primary.push({ name: k, v }); + } + // stable, human-ish order + permanent.sort((a, b) => Number(a.name.slice(2)) - Number(b.name.slice(2))); + primary.sort((a, b) => a.name.localeCompare(b.name)); + return { permanent, primary }; +} + +export function ToothChip({ name, v }: { name: string; v: ToothVal }) { + return ( + + {name.replace("T_", "")} + + {v} + + + ); +}