feat: appointment card colors by status, MassHealth badge, date nav controls
- Default card color: light (bg-slate-100 / dark text) - Blue card when procedures selected, gray when claim has a number - Status badge: green/red from appointment or patient-level MassHealth status - Solid dot badge (removed ring), overflow-visible to prevent corner clipping - Date nav: << < [today circle] > >> for week/day jumps Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,7 +56,20 @@ router.get("/day", async (req: Request, res: Response): Promise<any> => {
|
||||
? await storage.getPatientsByIds(patientIds)
|
||||
: [];
|
||||
|
||||
return res.json({ appointments, patients });
|
||||
// Enrich each appointment with procedure / claim status flags
|
||||
const appointmentIds = appointments.map((a) => a.id).filter((id): id is number => id != null);
|
||||
const [idsWithProcedures, idsWithClaimNumbers] = await Promise.all([
|
||||
storage.getAppointmentIdsWithProcedures(appointmentIds),
|
||||
storage.getAppointmentIdsWithClaimNumbers(appointmentIds),
|
||||
]);
|
||||
|
||||
const enrichedAppointments = appointments.map((a) => ({
|
||||
...a,
|
||||
hasProcedures: a.id != null && idsWithProcedures.has(a.id),
|
||||
hasClaimWithNumber: a.id != null && idsWithClaimNumbers.has(a.id),
|
||||
}));
|
||||
|
||||
return res.json({ appointments: enrichedAppointments, patients });
|
||||
} catch (err) {
|
||||
console.error("Error in /api/appointments/day:", err);
|
||||
res.status(500).json({ message: "Failed to load appointments for date" });
|
||||
|
||||
@@ -37,6 +37,7 @@ export interface IAppointmentProceduresStorage {
|
||||
): Promise<AppointmentProcedure>;
|
||||
deleteProcedure(id: number): Promise<void>;
|
||||
clearByAppointmentId(appointmentId: number): Promise<void>;
|
||||
getAppointmentIdsWithProcedures(ids: number[]): Promise<Set<number>>;
|
||||
}
|
||||
|
||||
export const appointmentProceduresStorage: IAppointmentProceduresStorage = {
|
||||
@@ -130,4 +131,14 @@ export const appointmentProceduresStorage: IAppointmentProceduresStorage = {
|
||||
where: { appointmentId },
|
||||
});
|
||||
},
|
||||
|
||||
async getAppointmentIdsWithProcedures(ids: number[]): Promise<Set<number>> {
|
||||
if (!ids.length) return new Set();
|
||||
const rows = await db.appointmentProcedure.findMany({
|
||||
where: { appointmentId: { in: ids } },
|
||||
select: { appointmentId: true },
|
||||
distinct: ["appointmentId"],
|
||||
});
|
||||
return new Set(rows.map((r) => r.appointmentId));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface IStorage {
|
||||
updateClaim(id: number, updates: UpdateClaim): Promise<Claim>;
|
||||
updateClaimStatus(id: number, status: ClaimStatus): Promise<Claim>;
|
||||
deleteClaim(id: number): Promise<void>;
|
||||
getAppointmentIdsWithClaimNumbers(ids: number[]): Promise<Set<number>>;
|
||||
}
|
||||
|
||||
export const claimsStorage: IStorage = {
|
||||
@@ -120,4 +121,14 @@ export const claimsStorage: IStorage = {
|
||||
throw new Error(`Claim with ID ${id} not found`);
|
||||
}
|
||||
},
|
||||
|
||||
async getAppointmentIdsWithClaimNumbers(ids: number[]): Promise<Set<number>> {
|
||||
if (!ids.length) return new Set();
|
||||
const rows = await db.claim.findMany({
|
||||
where: { appointmentId: { in: ids }, claimNumber: { not: null } },
|
||||
select: { appointmentId: true },
|
||||
distinct: ["appointmentId"],
|
||||
});
|
||||
return new Set(rows.map((r) => r.appointmentId));
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user