266 lines
7.4 KiB
TypeScript
266 lines
7.4 KiB
TypeScript
import { Router } from "express";
|
|
import type { Request, Response } from "express";
|
|
import { storage } from "../storage";
|
|
import {
|
|
AppointmentUncheckedCreateInputObjectSchema,
|
|
PatientUncheckedCreateInputObjectSchema,
|
|
} from "@repo/db/usedSchemas";
|
|
import { z } from "zod";
|
|
|
|
const router = Router();
|
|
|
|
//creating types out of schema auto generated.
|
|
type Appointment = z.infer<typeof AppointmentUncheckedCreateInputObjectSchema>;
|
|
|
|
const insertAppointmentSchema = (
|
|
AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
|
).omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
type InsertAppointment = z.infer<typeof insertAppointmentSchema>;
|
|
|
|
const updateAppointmentSchema = (
|
|
AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
|
)
|
|
.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
})
|
|
.partial();
|
|
type UpdateAppointment = z.infer<typeof updateAppointmentSchema>;
|
|
|
|
const PatientSchema = (
|
|
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
|
).omit({
|
|
appointments: true,
|
|
});
|
|
type Patient = z.infer<typeof PatientSchema>;
|
|
|
|
const insertPatientSchema = (
|
|
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
|
).omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
type InsertPatient = z.infer<typeof insertPatientSchema>;
|
|
|
|
const updatePatientSchema = (
|
|
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
|
)
|
|
.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
userId: true,
|
|
})
|
|
.partial();
|
|
|
|
type UpdatePatient = z.infer<typeof updatePatientSchema>;
|
|
|
|
// Patient Routes
|
|
// Get all patients for the logged-in user
|
|
router.get("/", async (req, res) => {
|
|
try {
|
|
const patients = await storage.getPatientsByUserId(req.user!.id);
|
|
res.json(patients);
|
|
} catch (error) {
|
|
res.status(500).json({ message: "Failed to retrieve patients" });
|
|
}
|
|
});
|
|
|
|
// Get a single patient by ID
|
|
router.get(
|
|
"/:id",
|
|
|
|
async (req: Request, res: Response): Promise<any> => {
|
|
try {
|
|
const patientIdParam = req.params.id;
|
|
|
|
// Ensure that patientIdParam exists and is a valid number
|
|
if (!patientIdParam) {
|
|
return res.status(400).json({ message: "Patient ID is required" });
|
|
}
|
|
|
|
const patientId = parseInt(patientIdParam);
|
|
|
|
const patient = await storage.getPatient(patientId);
|
|
|
|
if (!patient) {
|
|
return res.status(404).json({ message: "Patient not found" });
|
|
}
|
|
|
|
// Ensure the patient belongs to the logged-in user
|
|
if (patient.userId !== req.user!.id) {
|
|
return res.status(403).json({ message: "Forbidden" });
|
|
}
|
|
|
|
res.json(patient);
|
|
} catch (error) {
|
|
res.status(500).json({ message: "Failed to retrieve patient" });
|
|
}
|
|
}
|
|
);
|
|
|
|
// Create a new patient
|
|
router.post("/", async (req: Request, res: Response): Promise<any> => {
|
|
try {
|
|
// Validate request body
|
|
const patientData = insertPatientSchema.parse({
|
|
...req.body,
|
|
userId: req.user!.id,
|
|
});
|
|
|
|
// Create patient
|
|
const patient = await storage.createPatient(patientData);
|
|
res.status(201).json(patient);
|
|
} catch (error) {
|
|
if (error instanceof z.ZodError) {
|
|
return res.status(400).json({
|
|
message: "Validation error",
|
|
errors: error.format(),
|
|
});
|
|
}
|
|
res.status(500).json({ message: "Failed to create patient" });
|
|
}
|
|
});
|
|
|
|
// Update an existing patient
|
|
router.put(
|
|
"/:id",
|
|
|
|
async (req: Request, res: Response): Promise<any> => {
|
|
try {
|
|
const patientIdParam = req.params.id;
|
|
|
|
// Ensure that patientIdParam exists and is a valid number
|
|
if (!patientIdParam) {
|
|
return res.status(400).json({ message: "Patient ID is required" });
|
|
}
|
|
|
|
const patientId = parseInt(patientIdParam);
|
|
|
|
// Check if patient exists and belongs to user
|
|
const existingPatient = await storage.getPatient(patientId);
|
|
if (!existingPatient) {
|
|
return res.status(404).json({ message: "Patient not found" });
|
|
}
|
|
|
|
if (existingPatient.userId !== req.user!.id) {
|
|
return res.status(403).json({ message: "Forbidden" });
|
|
}
|
|
|
|
// Validate request body
|
|
const patientData = updatePatientSchema.parse(req.body);
|
|
|
|
// Update patient
|
|
const updatedPatient = await storage.updatePatient(
|
|
patientId,
|
|
patientData
|
|
);
|
|
res.json(updatedPatient);
|
|
} catch (error) {
|
|
if (error instanceof z.ZodError) {
|
|
return res.status(400).json({
|
|
message: "Validation error",
|
|
errors: error.format(),
|
|
});
|
|
}
|
|
res.status(500).json({ message: "Failed to update patient" });
|
|
}
|
|
}
|
|
);
|
|
|
|
// Delete a patient
|
|
router.delete(
|
|
"/:id",
|
|
|
|
async (req: Request, res: Response): Promise<any> => {
|
|
try {
|
|
const patientIdParam = req.params.id;
|
|
|
|
// Ensure that patientIdParam exists and is a valid number
|
|
if (!patientIdParam) {
|
|
return res.status(400).json({ message: "Patient ID is required" });
|
|
}
|
|
|
|
const patientId = parseInt(patientIdParam);
|
|
|
|
// Check if patient exists and belongs to user
|
|
const existingPatient = await storage.getPatient(patientId);
|
|
if (!existingPatient) {
|
|
return res.status(404).json({ message: "Patient not found" });
|
|
}
|
|
|
|
if (existingPatient.userId !== req.user!.id) {
|
|
console.warn(
|
|
`User ${req.user!.id} tried to delete patient ${patientId} owned by ${existingPatient.userId}`
|
|
);
|
|
return res
|
|
.status(403)
|
|
.json({ message: "Forbidden: Patient belongs to a different user" });
|
|
}
|
|
|
|
const appointments = await storage.getAppointmentsByPatientId(patientId);
|
|
console.log(appointments)
|
|
if (appointments.length > 0) {
|
|
throw new Error(`Cannot delete patient with ID ${patientId} because they have appointments`);
|
|
}
|
|
// Delete patient
|
|
await storage.deletePatient(patientId);
|
|
res.status(204).send();
|
|
} catch (error:any) {
|
|
if (error.message.includes("have appointments")) {
|
|
return res.status(400).json({ message: error.message });
|
|
}
|
|
console.error("Delete patient error:", error);
|
|
res.status(500).json({ message: "Failed to delete patient" });
|
|
}
|
|
}
|
|
);
|
|
|
|
// Appointment Routes
|
|
// Get all appointments for the logged-in user
|
|
router.get("/appointments", async (req, res) => {
|
|
try {
|
|
const appointments = await storage.getAppointmentsByUserId(req.user!.id);
|
|
res.json(appointments);
|
|
} catch (error) {
|
|
res.status(500).json({ message: "Failed to retrieve appointments" });
|
|
}
|
|
});
|
|
|
|
// Get appointments for a specific patient
|
|
router.get(
|
|
"/:patientId/appointments",
|
|
|
|
async (req: Request, res: Response): Promise<any> => {
|
|
try {
|
|
const patientIdParam = req.params.id;
|
|
|
|
// Ensure that patientIdParam exists and is a valid number
|
|
if (!patientIdParam) {
|
|
return res.status(400).json({ message: "Patient ID is required" });
|
|
}
|
|
|
|
const patientId = parseInt(patientIdParam);
|
|
|
|
// Check if patient exists and belongs to user
|
|
const patient = await storage.getPatient(patientId);
|
|
if (!patient) {
|
|
return res.status(404).json({ message: "Patient not found" });
|
|
}
|
|
|
|
if (patient.userId !== req.user!.id) {
|
|
return res.status(403).json({ message: "Forbidden" });
|
|
}
|
|
|
|
const appointments = await storage.getAppointmentsByPatientId(patientId);
|
|
res.json(appointments);
|
|
} catch (error) {
|
|
res.status(500).json({ message: "Failed to retrieve appointments" });
|
|
}
|
|
}
|
|
);
|
|
|
|
export default router;
|