major functionalities are fixed
This commit is contained in:
36
apps/Backend/src/app.ts
Normal file
36
apps/Backend/src/app.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import express from 'express';
|
||||
import cors from "cors";
|
||||
import routes from './routes';
|
||||
import { errorHandler } from './middlewares/error.middleware';
|
||||
import { apiLogger } from './middlewares/logger.middleware';
|
||||
import authRoutes from './routes/auth'
|
||||
import { authenticateJWT } from './middlewares/auth.middleware';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
const FRONTEND_URL = process.env.FRONTEND_URL;
|
||||
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true })); // For form data
|
||||
app.use(apiLogger);
|
||||
|
||||
|
||||
console.log(FRONTEND_URL);
|
||||
|
||||
app.use(cors({
|
||||
origin: FRONTEND_URL, // Make sure this matches the frontend URL
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // Allow these HTTP methods
|
||||
allowedHeaders: ['Content-Type', 'Authorization'], // Allow necessary headers
|
||||
credentials: true,
|
||||
}));
|
||||
|
||||
|
||||
app.use('/api/auth', authRoutes);
|
||||
app.use('/api', authenticateJWT, routes);
|
||||
|
||||
app.use(errorHandler);
|
||||
|
||||
export default app;
|
||||
11
apps/Backend/src/index.ts
Normal file
11
apps/Backend/src/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import app from './app';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const HOST = process.env.HOST;
|
||||
const PORT = process.env.PORT;
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running at http://${HOST}:${PORT}`);
|
||||
});
|
||||
26
apps/Backend/src/middlewares/auth.middleware.ts
Normal file
26
apps/Backend/src/middlewares/auth.middleware.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret'; // Secret used for signing JWTs
|
||||
|
||||
export function authenticateJWT(req: Request, res: Response, next: NextFunction): void{
|
||||
|
||||
// Check the Authorization header for the Bearer token
|
||||
const token = req.header('Authorization')?.split(' ')[1]; // Extract token from Authorization header
|
||||
|
||||
if (!token) {
|
||||
res.status(401).send("Access denied. No token provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify JWT
|
||||
jwt.verify(token, JWT_SECRET, (err, decoded) => {
|
||||
if (err) {
|
||||
return res.status(403).send("Forbidden. Invalid token.");
|
||||
}
|
||||
|
||||
// Attach the decoded user data to the request object
|
||||
req.user = decoded as Express.User;
|
||||
next(); // Proceed to the next middleware or route handler
|
||||
});
|
||||
}
|
||||
6
apps/Backend/src/middlewares/error.middleware.ts
Normal file
6
apps/Backend/src/middlewares/error.middleware.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
|
||||
export const errorHandler = (err: any, _req: Request, res: Response, _next: NextFunction) => {
|
||||
console.error(err);
|
||||
res.status(err.status || 500).json({ message: err.message || 'Internal Server Error' });
|
||||
};
|
||||
33
apps/Backend/src/middlewares/logger.middleware.ts
Normal file
33
apps/Backend/src/middlewares/logger.middleware.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
|
||||
function log(message: string) {
|
||||
console.log(`[${new Date().toISOString()}] ${message}`);
|
||||
}
|
||||
|
||||
export function apiLogger(req: Request, res: Response, next: NextFunction) {
|
||||
const start = Date.now();
|
||||
const path = req.path;
|
||||
let capturedJsonResponse: Record<string, any> | undefined = undefined;
|
||||
|
||||
const originalResJson = res.json;
|
||||
res.json = function (bodyJson, ...args) {
|
||||
capturedJsonResponse = bodyJson;
|
||||
return originalResJson.apply(res, [bodyJson, ...args]);
|
||||
};
|
||||
|
||||
res.on("finish", () => {
|
||||
const duration = Date.now() - start;
|
||||
if (path.startsWith("/api")) {
|
||||
let logLine = `${req.method} ${path} ${res.statusCode} in ${duration}ms`;
|
||||
if (capturedJsonResponse) {
|
||||
logLine += ` :: ${JSON.stringify(capturedJsonResponse)}`;
|
||||
}
|
||||
if (logLine.length > 80) {
|
||||
logLine = logLine.slice(0, 79) + "…";
|
||||
}
|
||||
log(logLine);
|
||||
}
|
||||
});
|
||||
|
||||
next();
|
||||
}
|
||||
351
apps/Backend/src/routes/appointements.ts
Normal file
351
apps/Backend/src/routes/appointements.ts
Normal file
@@ -0,0 +1,351 @@
|
||||
import { Router } from "express";
|
||||
import type { Request, Response } from "express";
|
||||
import { storage } from "../storage";
|
||||
import {
|
||||
AppointmentUncheckedCreateInputObjectSchema,
|
||||
PatientUncheckedCreateInputObjectSchema,
|
||||
} from "@repo/db/shared/schemas";
|
||||
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>;
|
||||
|
||||
|
||||
|
||||
|
||||
// Get all appointments
|
||||
router.get("/all", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const appointments = await storage.getAllAppointments();
|
||||
|
||||
res.json(appointments);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: "Failed to retrieve all appointments" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get a single appointment by ID
|
||||
router.get(
|
||||
"/:id",
|
||||
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const appointmentIdParam = req.params.id;
|
||||
|
||||
// Ensure that patientIdParam exists and is a valid number
|
||||
if (!appointmentIdParam) {
|
||||
return res.status(400).json({ message: "Appointment ID is required" });
|
||||
}
|
||||
|
||||
const appointmentId = parseInt(appointmentIdParam);
|
||||
|
||||
const appointment = await storage.getAppointment(appointmentId);
|
||||
|
||||
if (!appointment) {
|
||||
return res.status(404).json({ message: "Appointment not found" });
|
||||
}
|
||||
|
||||
// Ensure the appointment belongs to the logged-in user
|
||||
if (appointment.userId !== req.user!.id) {
|
||||
return res.status(403).json({ message: "Forbidden" });
|
||||
}
|
||||
|
||||
res.json(appointment);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: "Failed to retrieve appointment" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// Create a new appointment
|
||||
router.post(
|
||||
"/",
|
||||
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
console.log("Appointment creation request body:", req.body);
|
||||
|
||||
// Validate request body
|
||||
const appointmentData = insertAppointmentSchema.parse({
|
||||
...req.body,
|
||||
userId: req.user!.id,
|
||||
});
|
||||
|
||||
console.log("Validated appointment data:", appointmentData);
|
||||
|
||||
// Verify patient exists and belongs to user
|
||||
const patient = await storage.getPatient(appointmentData.patientId);
|
||||
if (!patient) {
|
||||
console.log("Patient not found:", appointmentData.patientId);
|
||||
return res.status(404).json({ message: "Patient not found" });
|
||||
}
|
||||
|
||||
if (patient.userId !== req.user!.id) {
|
||||
console.log(
|
||||
"Patient belongs to another user. Patient userId:",
|
||||
patient.userId,
|
||||
"Request userId:",
|
||||
req.user!.id
|
||||
);
|
||||
return res.status(403).json({ message: "Forbidden" });
|
||||
}
|
||||
|
||||
// Check if there's already an appointment at this time slot
|
||||
const existingAppointments = await storage.getAppointmentsByUserId(
|
||||
req.user!.id
|
||||
);
|
||||
const conflictingAppointment = existingAppointments.find(
|
||||
(apt) =>
|
||||
apt.date === appointmentData.date &&
|
||||
apt.startTime === appointmentData.startTime &&
|
||||
apt.notes?.includes(
|
||||
appointmentData.notes.split("Appointment with ")[1]
|
||||
)
|
||||
);
|
||||
|
||||
if (conflictingAppointment) {
|
||||
console.log(
|
||||
"Time slot already booked:",
|
||||
appointmentData.date,
|
||||
appointmentData.startTime
|
||||
);
|
||||
return res.status(409).json({
|
||||
message:
|
||||
"This time slot is already booked. Please select another time or staff member.",
|
||||
});
|
||||
}
|
||||
|
||||
// Create appointment
|
||||
const appointment = await storage.createAppointment(appointmentData);
|
||||
console.log("Appointment created successfully:", appointment);
|
||||
res.status(201).json(appointment);
|
||||
} catch (error) {
|
||||
console.error("Error creating appointment:", error);
|
||||
|
||||
if (error instanceof z.ZodError) {
|
||||
console.log(
|
||||
"Validation error details:",
|
||||
JSON.stringify(error.format(), null, 2)
|
||||
);
|
||||
return res.status(400).json({
|
||||
message: "Validation error",
|
||||
errors: error.format(),
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
message: "Failed to create appointment",
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Update an existing appointment
|
||||
router.put(
|
||||
"/:id",
|
||||
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const appointmentIdParam = req.params.id;
|
||||
if (!appointmentIdParam) {
|
||||
return res.status(400).json({ message: "Appointment ID is required" });
|
||||
}
|
||||
const appointmentId = parseInt(appointmentIdParam);
|
||||
|
||||
console.log(
|
||||
"Update appointment request. ID:",
|
||||
appointmentId,
|
||||
"Body:",
|
||||
req.body
|
||||
);
|
||||
|
||||
// Check if appointment exists and belongs to user
|
||||
const existingAppointment = await storage.getAppointment(appointmentId);
|
||||
if (!existingAppointment) {
|
||||
console.log("Appointment not found:", appointmentId);
|
||||
return res.status(404).json({ message: "Appointment not found" });
|
||||
}
|
||||
|
||||
if (existingAppointment.userId !== req.user!.id) {
|
||||
console.log(
|
||||
"Appointment belongs to another user. Appointment userId:",
|
||||
existingAppointment.userId,
|
||||
"Request userId:",
|
||||
req.user!.id
|
||||
);
|
||||
return res.status(403).json({ message: "Forbidden" });
|
||||
}
|
||||
|
||||
// Validate request body
|
||||
const appointmentData = updateAppointmentSchema.parse(req.body);
|
||||
console.log("Validated appointment update data:", appointmentData);
|
||||
|
||||
// If patient ID is being updated, verify the new patient belongs to user
|
||||
if (
|
||||
appointmentData.patientId &&
|
||||
appointmentData.patientId !== existingAppointment.patientId
|
||||
) {
|
||||
const patient = await storage.getPatient(appointmentData.patientId);
|
||||
if (!patient) {
|
||||
console.log("New patient not found:", appointmentData.patientId);
|
||||
return res.status(404).json({ message: "Patient not found" });
|
||||
}
|
||||
|
||||
if (patient.userId !== req.user!.id) {
|
||||
console.log(
|
||||
"New patient belongs to another user. Patient userId:",
|
||||
patient.userId,
|
||||
"Request userId:",
|
||||
req.user!.id
|
||||
);
|
||||
return res.status(403).json({ message: "Forbidden" });
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there's already an appointment at this time slot (if time is being changed)
|
||||
if (
|
||||
appointmentData.date &&
|
||||
appointmentData.startTime &&
|
||||
(appointmentData.date !== existingAppointment.date ||
|
||||
appointmentData.startTime !== existingAppointment.startTime)
|
||||
) {
|
||||
// Extract staff name from notes
|
||||
const staffInfo =
|
||||
appointmentData.notes?.split("Appointment with ")[1] ||
|
||||
existingAppointment.notes?.split("Appointment with ")[1];
|
||||
|
||||
const existingAppointments = await storage.getAppointmentsByUserId(
|
||||
req.user!.id
|
||||
);
|
||||
const conflictingAppointment = existingAppointments.find(
|
||||
(apt) =>
|
||||
apt.id !== appointmentId && // Don't match with itself
|
||||
apt.date === (appointmentData.date || existingAppointment.date) &&
|
||||
apt.startTime ===
|
||||
(appointmentData.startTime || existingAppointment.startTime) &&
|
||||
apt.notes?.includes(staffInfo)
|
||||
);
|
||||
|
||||
if (conflictingAppointment) {
|
||||
console.log(
|
||||
"Time slot already booked:",
|
||||
appointmentData.date,
|
||||
appointmentData.startTime
|
||||
);
|
||||
return res.status(409).json({
|
||||
message:
|
||||
"This time slot is already booked. Please select another time or staff member.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update appointment
|
||||
const updatedAppointment = await storage.updateAppointment(
|
||||
appointmentId,
|
||||
appointmentData
|
||||
);
|
||||
console.log("Appointment updated successfully:", updatedAppointment);
|
||||
res.json(updatedAppointment);
|
||||
} catch (error) {
|
||||
console.error("Error updating appointment:", error);
|
||||
|
||||
if (error instanceof z.ZodError) {
|
||||
console.log(
|
||||
"Validation error details:",
|
||||
JSON.stringify(error.format(), null, 2)
|
||||
);
|
||||
return res.status(400).json({
|
||||
message: "Validation error",
|
||||
errors: error.format(),
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
message: "Failed to update appointment",
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Delete an appointment
|
||||
router.delete(
|
||||
"/:id",
|
||||
|
||||
async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const appointmentIdParam = req.params.id;
|
||||
if (!appointmentIdParam) {
|
||||
return res.status(400).json({ message: "Appointment ID is required" });
|
||||
}
|
||||
const appointmentId = parseInt(appointmentIdParam);
|
||||
|
||||
// Check if appointment exists and belongs to user
|
||||
const existingAppointment = await storage.getAppointment(appointmentId);
|
||||
if (!existingAppointment) {
|
||||
return res.status(404).json({ message: "Appointment not found" });
|
||||
}
|
||||
|
||||
if (existingAppointment.userId !== req.user!.id) {
|
||||
return res.status(403).json({ message: "Forbidden" });
|
||||
}
|
||||
|
||||
// Delete appointment
|
||||
await storage.deleteAppointment(appointmentId);
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: "Failed to delete appointment" });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default router;
|
||||
87
apps/Backend/src/routes/auth.ts
Normal file
87
apps/Backend/src/routes/auth.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import express, { Request, Response, NextFunction } from 'express';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { storage } from '../storage';
|
||||
import { UserUncheckedCreateInputObjectSchema } from '@repo/db/shared/schemas';
|
||||
import { z } from 'zod';
|
||||
|
||||
type SelectUser = z.infer<typeof UserUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'your-jwt-secret';
|
||||
const JWT_EXPIRATION = '24h'; // JWT expiration time (1 day)
|
||||
|
||||
// Function to hash password using bcrypt
|
||||
async function hashPassword(password: string) {
|
||||
const saltRounds = 10; // Salt rounds for bcrypt
|
||||
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||||
return hashedPassword;
|
||||
}
|
||||
|
||||
// Function to compare passwords using bcrypt
|
||||
async function comparePasswords(supplied: string, stored: string) {
|
||||
const isMatch = await bcrypt.compare(supplied, stored);
|
||||
return isMatch;
|
||||
}
|
||||
|
||||
// Function to generate JWT
|
||||
function generateToken(user: SelectUser) {
|
||||
return jwt.sign({ id: user.id, username: user.username }, JWT_SECRET, {
|
||||
expiresIn: JWT_EXPIRATION,
|
||||
});
|
||||
}
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
||||
// User registration route
|
||||
router.post("/register", async (req: Request, res: Response, next: NextFunction): Promise<any> => {
|
||||
|
||||
try {
|
||||
const existingUser = await storage.getUserByUsername(req.body.username);
|
||||
if (existingUser) {
|
||||
return res.status(400).send("Username already exists");
|
||||
}
|
||||
|
||||
const hashedPassword = await hashPassword(req.body.password);
|
||||
const user = await storage.createUser({
|
||||
...req.body,
|
||||
password: hashedPassword,
|
||||
});
|
||||
|
||||
// Generate a JWT token for the user after successful registration
|
||||
const token = generateToken(user);
|
||||
|
||||
const { password, ...safeUser } = user;
|
||||
return res.status(201).json({ user: safeUser, token });
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
// User login route
|
||||
router.post("/login", async (req: Request, res: Response, next: NextFunction): Promise<any> => {
|
||||
try {
|
||||
const user = await storage.getUserByUsername(req.body.username);
|
||||
if (!user || !(await comparePasswords(req.body.password, user.password))) {
|
||||
return res.status(401).send("Invalid username or password");
|
||||
}
|
||||
|
||||
// Generate a JWT token for the user after successful login
|
||||
const token = generateToken(user);
|
||||
const { password, ...safeUser } = user;
|
||||
return res.status(200).json({ user: safeUser, token });
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
// Logout route (client-side action to remove the token)
|
||||
router.post("/logout", (req: Request, res: Response) => {
|
||||
// For JWT-based auth, logout is handled on the client (by removing token)
|
||||
res.status(200).send("Logged out successfully");
|
||||
});
|
||||
|
||||
|
||||
export default router;
|
||||
14
apps/Backend/src/routes/index.ts
Normal file
14
apps/Backend/src/routes/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Router } from 'express';
|
||||
import patientRoutes from './patients';
|
||||
import appointmentRoutes from './appointements'
|
||||
import userRoutes from './users'
|
||||
import staffRoutes from './staffs'
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.use('/patients', patientRoutes);
|
||||
router.use('/appointments', appointmentRoutes);
|
||||
router.use('/users', userRoutes);
|
||||
router.use('/staffs', staffRoutes);
|
||||
|
||||
export default router;
|
||||
252
apps/Backend/src/routes/patients.ts
Normal file
252
apps/Backend/src/routes/patients.ts
Normal file
@@ -0,0 +1,252 @@
|
||||
import { Router } from "express";
|
||||
import type { Request, Response } from "express";
|
||||
import { storage } from "../storage";
|
||||
import {
|
||||
AppointmentUncheckedCreateInputObjectSchema,
|
||||
PatientUncheckedCreateInputObjectSchema,
|
||||
} from "@repo/db/shared/schemas";
|
||||
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) {
|
||||
return res.status(403).json({ message: "Forbidden" });
|
||||
}
|
||||
|
||||
// Delete patient
|
||||
await storage.deletePatient(patientId);
|
||||
res.status(204).send();
|
||||
} catch (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;
|
||||
77
apps/Backend/src/routes/staffs.ts
Normal file
77
apps/Backend/src/routes/staffs.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Router } from "express";
|
||||
import type { Request, Response } from "express";
|
||||
import { storage } from "../storage";
|
||||
import { z } from "zod";
|
||||
import { StaffUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
|
||||
type Staff = z.infer<typeof StaffUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const staffCreateSchema = StaffUncheckedCreateInputObjectSchema;
|
||||
const staffUpdateSchema = (
|
||||
StaffUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
||||
).partial();
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post("/", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const validatedData = staffCreateSchema.parse(req.body);
|
||||
const newStaff = await storage.createStaff(validatedData);
|
||||
res.status(201).json(newStaff);
|
||||
} catch (error) {
|
||||
console.error("Failed to create staff:", error);
|
||||
res.status(500).send("Failed to create staff");
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const staff = await storage.getAllStaff();
|
||||
if (!staff) return res.status(404).send("Staff not found");
|
||||
|
||||
res.status(201).json(staff);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch staff:", error);
|
||||
res.status(500).send("Failed to fetch staff");
|
||||
}
|
||||
});
|
||||
|
||||
router.put("/:id", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const parsedStaffId = Number(req.params.id);
|
||||
if (isNaN(parsedStaffId)) {
|
||||
return res.status(400).send("Invalid staff ID");
|
||||
}
|
||||
|
||||
const validatedData = staffUpdateSchema.parse(req.body);
|
||||
const updatedStaff = await storage.updateStaff(
|
||||
parsedStaffId,
|
||||
validatedData
|
||||
);
|
||||
if (!updatedStaff) return res.status(404).send("Staff not found");
|
||||
|
||||
res.json(updatedStaff);
|
||||
} catch (error) {
|
||||
console.error("Failed to update staff:", error);
|
||||
res.status(500).send("Failed to update staff");
|
||||
}
|
||||
});
|
||||
|
||||
router.delete("/:id", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const parsedStaffId = Number(req.params.id);
|
||||
if (isNaN(parsedStaffId)) {
|
||||
return res.status(400).send("Invalid staff ID");
|
||||
}
|
||||
|
||||
const deleted = await storage.deleteStaff(parsedStaffId);
|
||||
if (!deleted) return res.status(404).send("Staff not found");
|
||||
|
||||
res.status(200).send("Staff deleted successfully");
|
||||
} catch (error) {
|
||||
console.error("Failed to delete staff:", error);
|
||||
res.status(500).send("Failed to delete staff");
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
108
apps/Backend/src/routes/users.ts
Normal file
108
apps/Backend/src/routes/users.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { Router } from "express";
|
||||
import type { Request, Response } from "express";
|
||||
import { storage } from "../storage";
|
||||
import { z } from "zod";
|
||||
import { UserUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
|
||||
const router = Router();
|
||||
|
||||
// Type based on shared schema
|
||||
type SelectUser = z.infer<typeof UserUncheckedCreateInputObjectSchema>;
|
||||
|
||||
// Zod validation
|
||||
const userCreateSchema = UserUncheckedCreateInputObjectSchema;
|
||||
const userUpdateSchema = (UserUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).partial();
|
||||
|
||||
|
||||
router.get("/", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const userId = req.user?.id;
|
||||
if (!userId) return res.status(401).send("Unauthorized UserId");
|
||||
|
||||
const user = await storage.getUser(userId);
|
||||
if (!user) return res.status(404).send("User not found");
|
||||
|
||||
|
||||
const { password, ...safeUser } = user;
|
||||
res.json(safeUser);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send("Failed to fetch user");
|
||||
}
|
||||
});
|
||||
|
||||
// GET: User by ID
|
||||
router.get("/:id", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) return res.status(400).send("User ID is required");
|
||||
|
||||
const id = parseInt(idParam);
|
||||
if (isNaN(id)) return res.status(400).send("Invalid user ID");
|
||||
|
||||
const user = await storage.getUser(id);
|
||||
if (!user) return res.status(404).send("User not found");
|
||||
|
||||
const { password, ...safeUser } = user;
|
||||
res.json(safeUser);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send("Failed to fetch user");
|
||||
}
|
||||
});
|
||||
|
||||
// POST: Create new user
|
||||
router.post("/", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const input = userCreateSchema.parse(req.body);
|
||||
const newUser = await storage.createUser(input);
|
||||
const { password, ...safeUser } = newUser;
|
||||
res.status(201).json(safeUser);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(400).json({ error: "Invalid user data", details: err });
|
||||
}
|
||||
});
|
||||
|
||||
// PUT: Update user
|
||||
router.put("/:id", async (req: Request, res: Response):Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) return res.status(400).send("User ID is required");
|
||||
|
||||
const id = parseInt(idParam);
|
||||
if (isNaN(id)) return res.status(400).send("Invalid user ID");
|
||||
|
||||
|
||||
const updates = userUpdateSchema.parse(req.body);
|
||||
const updatedUser = await storage.updateUser(id, updates);
|
||||
if (!updatedUser) return res.status(404).send("User not found");
|
||||
|
||||
const { password, ...safeUser } = updatedUser;
|
||||
res.json(safeUser);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(400).json({ error: "Invalid update data", details: err });
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE: Delete user
|
||||
router.delete("/:id", async (req: Request, res: Response):Promise<any> => {
|
||||
try {
|
||||
const idParam = req.params.id;
|
||||
if (!idParam) return res.status(400).send("User ID is required");
|
||||
|
||||
const id = parseInt(idParam);
|
||||
if (isNaN(id)) return res.status(400).send("Invalid user ID");
|
||||
|
||||
const success = await storage.deleteUser(id);
|
||||
if (!success) return res.status(404).send("User not found");
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
res.status(500).send("Failed to delete user");
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
284
apps/Backend/src/storage/index.ts
Normal file
284
apps/Backend/src/storage/index.ts
Normal file
@@ -0,0 +1,284 @@
|
||||
import { prisma as db } from "@repo/db/client";
|
||||
import {
|
||||
AppointmentUncheckedCreateInputObjectSchema,
|
||||
PatientUncheckedCreateInputObjectSchema,
|
||||
UserUncheckedCreateInputObjectSchema,
|
||||
StaffUncheckedCreateInputObjectSchema,
|
||||
} from "@repo/db/shared/schemas";
|
||||
import { z } from "zod";
|
||||
|
||||
//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>;
|
||||
|
||||
//patient types
|
||||
const PatientSchema = (
|
||||
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
||||
).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientUncheckedCreateInputObjectSchema>;
|
||||
type Patient2 = 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>;
|
||||
|
||||
//user types
|
||||
type User = z.infer<typeof UserUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const insertUserSchema = (
|
||||
UserUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
||||
).pick({
|
||||
username: true,
|
||||
password: true,
|
||||
});
|
||||
|
||||
const loginSchema = (insertUserSchema as unknown as z.ZodObject<any>).extend({
|
||||
rememberMe: z.boolean().optional(),
|
||||
});
|
||||
|
||||
const registerSchema = (insertUserSchema as unknown as z.ZodObject<any>)
|
||||
.extend({
|
||||
confirmPassword: z.string().min(6, {
|
||||
message: "Password must be at least 6 characters long",
|
||||
}),
|
||||
agreeTerms: z.literal(true, {
|
||||
errorMap: () => ({
|
||||
message: "You must agree to the terms and conditions",
|
||||
}),
|
||||
}),
|
||||
})
|
||||
.refine((data: any) => data.password === data.confirmPassword, {
|
||||
message: "Passwords don't match",
|
||||
path: ["confirmPassword"],
|
||||
});
|
||||
|
||||
type InsertUser = z.infer<typeof insertUserSchema>;
|
||||
type LoginFormValues = z.infer<typeof loginSchema>;
|
||||
type RegisterFormValues = z.infer<typeof registerSchema>;
|
||||
|
||||
// staff types:
|
||||
type Staff = z.infer<typeof StaffUncheckedCreateInputObjectSchema>;
|
||||
|
||||
export interface IStorage {
|
||||
// User methods
|
||||
getUser(id: number): Promise<User | undefined>;
|
||||
getUserByUsername(username: string): Promise<User | undefined>;
|
||||
createUser(user: InsertUser): Promise<User>;
|
||||
updateUser(id: number, updates: Partial<User>): Promise<User | undefined>;
|
||||
deleteUser(id: number): Promise<boolean>;
|
||||
|
||||
// Patient methods
|
||||
getPatient(id: number): Promise<Patient | undefined>;
|
||||
getPatientsByUserId(userId: number): Promise<Patient[]>;
|
||||
createPatient(patient: InsertPatient): Promise<Patient>;
|
||||
updatePatient(id: number, patient: UpdatePatient): Promise<Patient>;
|
||||
deletePatient(id: number): Promise<void>;
|
||||
|
||||
// Appointment methods
|
||||
getAppointment(id: number): Promise<Appointment | undefined>;
|
||||
getAllAppointments(): Promise<Appointment[]>;
|
||||
getAppointmentsByUserId(userId: number): Promise<Appointment[]>;
|
||||
getAppointmentsByPatientId(patientId: number): Promise<Appointment[]>;
|
||||
createAppointment(appointment: InsertAppointment): Promise<Appointment>;
|
||||
updateAppointment(
|
||||
id: number,
|
||||
appointment: UpdateAppointment
|
||||
): Promise<Appointment>;
|
||||
deleteAppointment(id: number): Promise<void>;
|
||||
|
||||
// Staff methods
|
||||
getStaff(id: number): Promise<Staff | undefined>;
|
||||
getAllStaff(): Promise<Staff[]>;
|
||||
createStaff(staff: Staff): Promise<Staff>;
|
||||
updateStaff(id: number, updates: Partial<Staff>): Promise<Staff | undefined>;
|
||||
deleteStaff(id: number): Promise<boolean>;
|
||||
}
|
||||
|
||||
export const storage: IStorage = {
|
||||
// User methods
|
||||
async getUser(id: number): Promise<User | undefined> {
|
||||
const user = await db.user.findUnique({ where: { id } });
|
||||
return user ?? undefined;
|
||||
},
|
||||
|
||||
async getUserByUsername(username: string): Promise<User | undefined> {
|
||||
const user = await db.user.findUnique({ where: { username } });
|
||||
return user ?? undefined;
|
||||
},
|
||||
|
||||
async createUser(user: InsertUser): Promise<User> {
|
||||
return await db.user.create({ data: user as User });
|
||||
},
|
||||
|
||||
async updateUser(
|
||||
id: number,
|
||||
updates: Partial<User>
|
||||
): Promise<User | undefined> {
|
||||
try {
|
||||
return await db.user.update({ where: { id }, data: updates });
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
|
||||
async deleteUser(id: number): Promise<boolean> {
|
||||
try {
|
||||
await db.user.delete({ where: { id } });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// Patient methods
|
||||
async getPatient(id: number): Promise<Patient | undefined> {
|
||||
const patient = await db.patient.findUnique({ where: { id } });
|
||||
return patient ?? undefined;
|
||||
},
|
||||
|
||||
async getPatientsByUserId(userId: number): Promise<Patient[]> {
|
||||
return await db.patient.findMany({ where: { userId } });
|
||||
},
|
||||
|
||||
async createPatient(patient: InsertPatient): Promise<Patient> {
|
||||
return await db.patient.create({ data: patient as Patient });
|
||||
},
|
||||
|
||||
async updatePatient(id: number, updateData: UpdatePatient): Promise<Patient> {
|
||||
try {
|
||||
return await db.patient.update({
|
||||
where: { id },
|
||||
data: updateData,
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error(`Patient with ID ${id} not found`);
|
||||
}
|
||||
},
|
||||
|
||||
async deletePatient(id: number): Promise<void> {
|
||||
try {
|
||||
await db.patient.delete({ where: { id } });
|
||||
} catch (err) {
|
||||
throw new Error(`Patient with ID ${id} not found`);
|
||||
}
|
||||
},
|
||||
|
||||
// Appointment methods
|
||||
async getAppointment(id: number): Promise<Appointment | undefined> {
|
||||
const appointment = await db.appointment.findUnique({ where: { id } });
|
||||
return appointment ?? undefined;
|
||||
},
|
||||
|
||||
async getAllAppointments(): Promise<Appointment[]> {
|
||||
return await db.appointment.findMany();
|
||||
},
|
||||
|
||||
async getAppointmentsByUserId(userId: number): Promise<Appointment[]> {
|
||||
return await db.appointment.findMany({ where: { userId } });
|
||||
},
|
||||
|
||||
async getAppointmentsByPatientId(patientId: number): Promise<Appointment[]> {
|
||||
return await db.appointment.findMany({ where: { patientId } });
|
||||
},
|
||||
|
||||
async createAppointment(
|
||||
appointment: InsertAppointment
|
||||
): Promise<Appointment> {
|
||||
return await db.appointment.create({ data: appointment as Appointment });
|
||||
},
|
||||
|
||||
async updateAppointment(
|
||||
id: number,
|
||||
updateData: UpdateAppointment
|
||||
): Promise<Appointment> {
|
||||
try {
|
||||
return await db.appointment.update({
|
||||
where: { id },
|
||||
data: updateData,
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error(`Appointment with ID ${id} not found`);
|
||||
}
|
||||
},
|
||||
|
||||
async deleteAppointment(id: number): Promise<void> {
|
||||
try {
|
||||
await db.appointment.delete({ where: { id } });
|
||||
} catch (err) {
|
||||
throw new Error(`Appointment with ID ${id} not found`);
|
||||
}
|
||||
},
|
||||
|
||||
async getStaff(id: number): Promise<Staff | undefined> {
|
||||
const staff = await db.staff.findUnique({ where: { id } });
|
||||
return staff ?? undefined;
|
||||
},
|
||||
|
||||
async getAllStaff(): Promise<Staff[]> {
|
||||
const staff = await db.staff.findMany();
|
||||
return staff;
|
||||
},
|
||||
|
||||
async createStaff(staff: Staff): Promise<Staff> {
|
||||
const createdStaff = await db.staff.create({
|
||||
data: staff,
|
||||
});
|
||||
return createdStaff;
|
||||
},
|
||||
|
||||
async updateStaff(
|
||||
id: number,
|
||||
updates: Partial<Staff>
|
||||
): Promise<Staff | undefined> {
|
||||
const updatedStaff = await db.staff.update({
|
||||
where: { id },
|
||||
data: updates,
|
||||
});
|
||||
return updatedStaff ?? undefined;
|
||||
},
|
||||
|
||||
async deleteStaff(id: number): Promise<boolean> {
|
||||
try {
|
||||
await db.staff.delete({ where: { id } });
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error deleting staff:", error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
10
apps/Backend/src/types/express.types.d.ts
vendored
Normal file
10
apps/Backend/src/types/express.types.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { User } from "@repo/db/client";
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
interface User {
|
||||
id: number;
|
||||
// include any other properties
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user