From 52e82fab139268dc9edff202946ee6461f00c3bf Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 21:02:44 +0530 Subject: [PATCH 01/41] =?UTF-8?q?chore:=20=F0=9F=94=A7=20Extend=20CI/CD=20?= =?UTF-8?q?pipeline=20for=20'fix-'=20branches=20-=20Include=20'fix-**'=20b?= =?UTF-8?q?ranches=20in=20GitHub=20Actions=20trigger=20events=20-=20Extend?= =?UTF-8?q?=20preview=20deployment=20to=20'fix-'=20branches=20-=20Maintain?= =?UTF-8?q?=20existing=20workflow=20for=20'feature/'=20branches=20and=20pr?= =?UTF-8?q?oduction=20deployment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-and-deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-and-deploy.yml b/.github/workflows/test-and-deploy.yml index b948854e..252091a5 100644 --- a/.github/workflows/test-and-deploy.yml +++ b/.github/workflows/test-and-deploy.yml @@ -2,9 +2,9 @@ name: CI/CD Pipeline For Playwright Tests and Vercel Deployment on: push: - branches: [main, "feature/**"] + branches: [main, "feature/**", "fix-**"] pull_request: - branches: [main, "feature/**"] + branches: [main, "feature/**", "fix-**"] jobs: test: @@ -43,7 +43,7 @@ jobs: deploy-preview: needs: test - if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature/')) + if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature/') || startsWith(github.ref, 'refs/heads/fix-')) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 From 80c3a27187ddbe00cc644597d605e9c3af516f2c Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:40:20 +0530 Subject: [PATCH 02/41] =?UTF-8?q?chore(admin):=20=F0=9F=9B=A0=EF=B8=8F=20i?= =?UTF-8?q?mplement=20errorHandler=20for=20consistent=20error=20responses?= =?UTF-8?q?=20and=20use=20NextResponse=20for=20API=20responses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/admin/add-admin/route.ts | 14 ++++++++------ app/api/admin/dashboard/recent-users/route.ts | 4 ++-- app/api/admin/dashboard/tiles/route.ts | 5 ++--- app/api/admin/hospitals/route.ts | 7 +++---- app/api/admin/hospitals/users/route.ts | 5 ++--- app/api/admin/route.ts | 4 ++-- app/api/admin/transactions/route.ts | 7 +++---- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/app/api/admin/add-admin/route.ts b/app/api/admin/add-admin/route.ts index 34d900e3..7474a02c 100644 --- a/app/api/admin/add-admin/route.ts +++ b/app/api/admin/add-admin/route.ts @@ -1,11 +1,13 @@ -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { NextResponse } from "next/server"; import Admin from "@models/admin"; -import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; -import hashPassword from "@utils/hashPassword"; -import { NewAdminTemplate } from "@lib/emails/templates"; +import { + dbConfig, + errorHandler, + hashPassword, + STATUS_CODES, +} from "@utils/index"; +import { authenticateUser, NewAdminTemplate, sendEmail } from "@lib/index"; import { render } from "@react-email/render"; -import sendEmail from "@lib/sendemail"; -import { NextResponse } from "next/server"; export async function POST(request: Request) { const authHeader = request.headers.get("Authorization"); diff --git a/app/api/admin/dashboard/recent-users/route.ts b/app/api/admin/dashboard/recent-users/route.ts index 1cc2f46c..5494021c 100644 --- a/app/api/admin/dashboard/recent-users/route.ts +++ b/app/api/admin/dashboard/recent-users/route.ts @@ -1,12 +1,12 @@ -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { NextResponse } from "next/server"; import mongoose from "mongoose"; +import authenticateUser from "@lib/auth/authenticateUser"; import { FormattedRecentUser, RecentUserTile, RecentUserPaginatedResponse, } from "@pft-types/admin"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; -import { NextResponse } from "next/server"; export async function GET(request: Request): Promise { const authHeader = request.headers.get("Authorization"); diff --git a/app/api/admin/dashboard/tiles/route.ts b/app/api/admin/dashboard/tiles/route.ts index 5e05ffc9..16167da7 100644 --- a/app/api/admin/dashboard/tiles/route.ts +++ b/app/api/admin/dashboard/tiles/route.ts @@ -1,8 +1,7 @@ -import dbConfig from "@utils/db"; import { Hospital, Patient, Doctor, Receptionist } from "@models/index"; -import { authenticateUser } from "@lib/auth/authenticateUser"; +import authenticateUser from "@lib/auth/authenticateUser"; import { NextResponse } from "next/server"; -import { errorHandler, STATUS_CODES } from "@utils/index"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; export async function GET(request: Request) { const authHeader = request.headers.get("Authorization"); diff --git a/app/api/admin/hospitals/route.ts b/app/api/admin/hospitals/route.ts index 233c9e27..17164ad6 100644 --- a/app/api/admin/hospitals/route.ts +++ b/app/api/admin/hospitals/route.ts @@ -1,10 +1,9 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; import Hospital from "@models/hospital"; import { HospitalDetails } from "@pft-types/admin"; import { Types } from "mongoose"; -import { NextResponse } from "next/server"; -import { errorHandler, STATUS_CODES } from "@utils/index"; -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; +import authenticateUser from "@lib/auth/authenticateUser"; export async function GET(request: Request) { try { diff --git a/app/api/admin/hospitals/users/route.ts b/app/api/admin/hospitals/users/route.ts index f46f0cae..69f2c0da 100644 --- a/app/api/admin/hospitals/users/route.ts +++ b/app/api/admin/hospitals/users/route.ts @@ -1,10 +1,9 @@ -import dbConfig from "@utils/db"; import { Patient, Receptionist, Hospital, Doctor } from "@models/index"; import { HospitalUserDetails } from "@pft-types/admin"; import { Types } from "mongoose"; import { NextResponse } from "next/server"; -import { errorHandler, STATUS_CODES } from "@utils/index"; -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; +import authenticateUser from "@lib/auth/authenticateUser"; export async function GET(request: Request) { try { diff --git a/app/api/admin/route.ts b/app/api/admin/route.ts index b704e936..ed95e328 100644 --- a/app/api/admin/route.ts +++ b/app/api/admin/route.ts @@ -1,8 +1,8 @@ -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { NextResponse } from "next/server"; +import authenticateUser from "@lib/auth/authenticateUser"; import Admin from "@models/admin"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import { Types } from "mongoose"; -import { NextResponse } from "next/server"; export async function GET(request: Request) { const authHeader = request.headers.get("Authorization"); diff --git a/app/api/admin/transactions/route.ts b/app/api/admin/transactions/route.ts index eb7f2a05..89536af5 100644 --- a/app/api/admin/transactions/route.ts +++ b/app/api/admin/transactions/route.ts @@ -1,10 +1,9 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; import { Admin, Hospital, Patient, Transaction } from "@models/index"; import { TransactionDetails } from "@pft-types/index"; import { Types } from "mongoose"; -import { NextResponse } from "next/server"; -import { errorHandler, STATUS_CODES } from "@utils/index"; -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; +import authenticateUser from "@lib/auth/authenticateUser"; export async function GET(request: Request) { try { From d82e0502201223ce406f50b8f1038dd06c9646cd Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:40:32 +0530 Subject: [PATCH 03/41] =?UTF-8?q?chore(patient):=20=E2=9A=A1=20optimize=20?= =?UTF-8?q?error=20handling=20using=20errorHandler=20and=20NextResponse=20?= =?UTF-8?q?for=20responses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/patient/appointment/pending/route.ts | 4 ++-- app/api/patient/appointment/route.ts | 14 ++++++++------ app/api/patient/medicalhistory/route.ts | 7 ++++--- app/api/patient/paymenthistory/route.ts | 7 ++++--- app/api/patient/route.ts | 7 +++---- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/app/api/patient/appointment/pending/route.ts b/app/api/patient/appointment/pending/route.ts index 4a8dbb62..40fd15b4 100644 --- a/app/api/patient/appointment/pending/route.ts +++ b/app/api/patient/appointment/pending/route.ts @@ -1,8 +1,8 @@ +import { NextResponse } from "next/server"; import { Patient, BookedAppointment } from "@models/index"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { authenticateUser } from "@lib/auth"; import { Types } from "mongoose"; -import { NextResponse } from "next/server"; export async function POST(req: Request) { try { diff --git a/app/api/patient/appointment/route.ts b/app/api/patient/appointment/route.ts index 9ba5c5e9..a1589284 100644 --- a/app/api/patient/appointment/route.ts +++ b/app/api/patient/appointment/route.ts @@ -1,13 +1,15 @@ -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { NextResponse } from "next/server"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import { Types } from "mongoose"; -import sendEmail from "@lib/sendemail"; import { render } from "@react-email/render"; -import { AppointmentBookedTemplate } from "@lib/emails/templates"; -import sendNotification from "@lib/novu"; +import { + authenticateUser, + AppointmentBookedTemplate, + sendEmail, + sendNotification, +} from "@lib/index"; import { Patient, BookedAppointment, Doctor } from "@models/index"; import { BookingAppointmentType } from "@pft-types/patient"; -import { NextResponse } from "next/server"; // getting patient's approved appointments export async function GET(request: Request) { @@ -152,7 +154,7 @@ export async function POST(req: Request) { ); return NextResponse.json( - { msg: "Appointment request added successfully" }, + { message: "Appointment request added successfully" }, { status: 200 } ); } catch (error: any) { diff --git a/app/api/patient/medicalhistory/route.ts b/app/api/patient/medicalhistory/route.ts index 2e3da3e9..410e855d 100644 --- a/app/api/patient/medicalhistory/route.ts +++ b/app/api/patient/medicalhistory/route.ts @@ -1,12 +1,13 @@ +import { NextResponse } from "next/server"; import { Patient, MedicalHistory } from "@models/index"; import { Types } from "mongoose"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; -import { NextResponse } from "next/server"; +import { authenticateUser } from "@lib/auth"; export async function GET(request: Request) { try { - const id = request.headers.get("x-user-id"); - const role = request.headers.get("x-user-role"); + const authHeader = request.headers.get("Authorization"); + const { id, role } = await authenticateUser(authHeader); if (!id || !role) { return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); diff --git a/app/api/patient/paymenthistory/route.ts b/app/api/patient/paymenthistory/route.ts index 7346e7c5..305d42aa 100644 --- a/app/api/patient/paymenthistory/route.ts +++ b/app/api/patient/paymenthistory/route.ts @@ -1,12 +1,13 @@ +import { NextResponse } from "next/server"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import { Patient, Transaction } from "@models/index"; import { Types } from "mongoose"; -import { NextResponse } from "next/server"; +import { authenticateUser } from "@lib/auth"; export async function GET(request: Request) { try { - const id = request.headers.get("x-user-id"); - const role = request.headers.get("x-user-role"); + const authHeader = request.headers.get("Authorization"); + const { id, role } = await authenticateUser(authHeader); if (!id || !role) { return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); diff --git a/app/api/patient/route.ts b/app/api/patient/route.ts index 1c5a9ff3..f705c1fc 100644 --- a/app/api/patient/route.ts +++ b/app/api/patient/route.ts @@ -1,13 +1,12 @@ +import { NextResponse } from "next/server"; import Patient from "@models/patient"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { authenticateUser } from "@lib/auth"; import { Types } from "mongoose"; -import { NextResponse } from "next/server"; export async function GET(request: Request) { - const authHeader = request.headers.get("Authorization"); - try { + const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { From fb94826ec2e671b22d49f97f499bf48f5ff6a64d Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:40:49 +0530 Subject: [PATCH 04/41] =?UTF-8?q?chore(receptionist):=20=F0=9F=A7=B9=20cle?= =?UTF-8?q?an=20up=20error=20management=20with=20errorHandler=20and=20swit?= =?UTF-8?q?ch=20to=20NextResponse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/receptionist/appointments/approve/route.ts | 11 +++++------ app/api/receptionist/appointments/pending/route.ts | 7 +++---- app/api/receptionist/route.ts | 4 ++-- app/api/receptionist/scan/route.ts | 7 +++---- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app/api/receptionist/appointments/approve/route.ts b/app/api/receptionist/appointments/approve/route.ts index 3efeb2ba..6352f84c 100644 --- a/app/api/receptionist/appointments/approve/route.ts +++ b/app/api/receptionist/appointments/approve/route.ts @@ -1,11 +1,10 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; import { BookedAppointment, Receptionist } from "@models/index"; import { Types } from "mongoose"; -import { authenticateUser } from "@lib/auth/authenticateUser"; -import { NextResponse } from "next/server"; -import { errorHandler, STATUS_CODES } from "@utils/index"; +import { authenticateUser } from "@lib/auth"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; -// Get approved appointments +// get approved appointments export async function GET(request: Request) { try { const authHeader = request.headers.get("Authorization"); @@ -39,7 +38,7 @@ export async function GET(request: Request) { } } -// Approving appointments +// approving appointments export async function POST(request: Request) { try { const { patient_id } = await request.json(); diff --git a/app/api/receptionist/appointments/pending/route.ts b/app/api/receptionist/appointments/pending/route.ts index a725183b..ca4cd4dc 100644 --- a/app/api/receptionist/appointments/pending/route.ts +++ b/app/api/receptionist/appointments/pending/route.ts @@ -1,9 +1,8 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; import { Patient, BookedAppointment, Receptionist } from "@models/index"; import { Types } from "mongoose"; -import { authenticateUser } from "@lib/auth/authenticateUser"; -import { NextResponse } from "next/server"; -import { errorHandler, STATUS_CODES } from "@utils/index"; +import { authenticateUser } from "@lib/auth"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; export async function GET(request: Request) { try { diff --git a/app/api/receptionist/route.ts b/app/api/receptionist/route.ts index 754ffb17..fb4123d7 100644 --- a/app/api/receptionist/route.ts +++ b/app/api/receptionist/route.ts @@ -1,8 +1,8 @@ -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { NextResponse } from "next/server"; +import authenticateUser from "@lib/auth/authenticateUser"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import Receptionist from "@models/receptionist"; import { Types } from "mongoose"; -import { NextResponse } from "next/server"; export async function GET(request: Request) { try { diff --git a/app/api/receptionist/scan/route.ts b/app/api/receptionist/scan/route.ts index a52fb615..fc22540e 100644 --- a/app/api/receptionist/scan/route.ts +++ b/app/api/receptionist/scan/route.ts @@ -1,9 +1,8 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; import { BookedAppointment, Patient } from "@models/index"; -import { authenticateUser } from "@lib/auth/authenticateUser"; +import { authenticateUser } from "@lib/auth"; import { Types } from "mongoose"; -import { NextResponse } from "next/server"; -import { errorHandler, STATUS_CODES } from "@utils/index"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; export async function POST(req: Request) { try { From cb943a40d37337f501f2bca95779c779babc5d7c Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:41:00 +0530 Subject: [PATCH 05/41] =?UTF-8?q?chore(hospital):=20=F0=9F=94=84=20refacto?= =?UTF-8?q?r=20error=20handling=20to=20use=20errorHandler=20and=20NextResp?= =?UTF-8?q?onse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/hospital/route.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/app/api/hospital/route.ts b/app/api/hospital/route.ts index 14c62e86..4c53feb7 100644 --- a/app/api/hospital/route.ts +++ b/app/api/hospital/route.ts @@ -1,34 +1,32 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; import Hospital from "@models/hospital"; import { Types } from "mongoose"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; +import { authenticateUser } from "@lib/auth"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); + try { - const id = request.headers.get("x-user-id"); - const role = request.headers.get("x-user-role"); + const { id, role } = await authenticateUser(authHeader); if (!id || !role) { - return Response.json( - { error: "Missing user ID or role" }, - { status: 400 } - ); + return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); } const hospital_id = new Types.ObjectId(id); await dbConfig(); - // const projection = {}; { projection } - const hospitalData = await Hospital.findById(hospital_id); if (!hospitalData) { - return Response.json({ error: "Hospital not found" }, { status: 404 }); + return errorHandler("Hospital not found", STATUS_CODES.NOT_FOUND); } - return Response.json(hospitalData); + return NextResponse.json(hospitalData, { status: 200 }); } catch (error) { console.error("Error fetching Hospital data:", error); - return Response.json({ error: "Internal Server Error" }, { status: 500 }); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } From 839bb646b7ab629df6f57a6e8c63ac3496900626 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:41:15 +0530 Subject: [PATCH 06/41] =?UTF-8?q?chore(updateprofile):=20=E2=9C=A8=20enhan?= =?UTF-8?q?ce=20error=20responses=20with=20errorHandler=20and=20adopt=20Ne?= =?UTF-8?q?xtResponse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/update-profile/address/route.ts | 37 ++++++----- app/api/update-profile/personal/route.ts | 62 +++++++++---------- app/api/update-profile/profile/route.ts | 41 +++++++----- .../update-profile/reset-password/route.ts | 59 ++++++++---------- 4 files changed, 100 insertions(+), 99 deletions(-) diff --git a/app/api/update-profile/address/route.ts b/app/api/update-profile/address/route.ts index 08bbcc87..cb571f06 100644 --- a/app/api/update-profile/address/route.ts +++ b/app/api/update-profile/address/route.ts @@ -1,39 +1,40 @@ +import { NextResponse } from "next/server"; import { AddressBody } from "@pft-types/index"; -import { dbConfig, getModelByRole } from "@utils/index"; +import { + dbConfig, + getModelByRole, + errorHandler, + STATUS_CODES, +} from "@utils/index"; import { Types } from "mongoose"; +import { authenticateUser } from "@lib/auth"; export async function PUT(req: Request) { try { - const id = req.headers.get("x-user-id"); - const role = req.headers.get("x-user-role"); + const authHeader = req.headers.get("Authorization"); + const { id, role } = await authenticateUser(authHeader); if (!id || !role) { - return Response.json( - { error: "Missing user ID or role" }, - { status: 400 } - ); + return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); } - // any user of system const user_id = new Types.ObjectId(id); - const addressData: AddressBody = await req.json(); await dbConfig(); - // removing undefined fields + // remove undefined fields Object.keys(addressData).forEach((key) => { if (addressData[key as keyof AddressBody] === undefined) { delete addressData[key as keyof AddressBody]; } }); - let UserModel = getModelByRole(role); - + const UserModel = getModelByRole(role); const user = await UserModel.findById(user_id); if (!user) { - return Response.json({ error: `${role} not found` }, { status: 404 }); + return errorHandler(`${role} not found`, STATUS_CODES.NOT_FOUND); } const updatedAddress = { @@ -47,12 +48,14 @@ export async function PUT(req: Request) { }; user.address = updatedAddress; - await user.save(); - return Response.json({ msg: "ok" }, { status: 200 }); - } catch (error) { + return NextResponse.json({ message: "ok" }, { status: 200 }); + } catch (error: any) { console.error("Error updating address:", error); - return Response.json({ error: "Error updating address" }, { status: 500 }); + return errorHandler( + error.message || "Error updating address", + STATUS_CODES.SERVER_ERROR + ); } } diff --git a/app/api/update-profile/personal/route.ts b/app/api/update-profile/personal/route.ts index 6c239237..42e07028 100644 --- a/app/api/update-profile/personal/route.ts +++ b/app/api/update-profile/personal/route.ts @@ -1,44 +1,47 @@ -import { dbConfig, getModelByRole } from "@utils/index"; +import { NextResponse } from "next/server"; +import { + dbConfig, + getModelByRole, + errorHandler, + STATUS_CODES, +} from "@utils/index"; import { PersonalInfoBody } from "@pft-types/index"; import { Types } from "mongoose"; +import { authenticateUser } from "@lib/auth"; export async function PUT(req: Request) { try { - const id = req.headers.get("x-user-id"); - const role = req.headers.get("x-user-role"); + const authHeader = req.headers.get("Authorization"); + const { id, role } = await authenticateUser(authHeader); if (!id || !role) { - return Response.json( - { error: "Missing user ID or role" }, - { status: 400 } - ); + return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); } const user_id = new Types.ObjectId(id); - const updateData: PersonalInfoBody = await req.json(); await dbConfig(); - // remove undefined fields + // Remove undefined fields Object.keys(updateData).forEach((key) => { if (updateData[key as keyof PersonalInfoBody] === undefined) { delete updateData[key as keyof PersonalInfoBody]; } }); - let UserModel = getModelByRole(role); + const UserModel = getModelByRole(role); - // check for uniqueness of username, email, and contact + // Check for uniqueness of username, email, and contact if (updateData.username) { const existingUsername = await UserModel.findOne({ username: updateData.username, _id: { $ne: user_id }, }); if (existingUsername) { - return Response.json( - { error: "Username already exists" }, - { status: 400 } + return errorHandler( + "Username already exists", + STATUS_CODES.BAD_REQUEST ); } } @@ -46,15 +49,10 @@ export async function PUT(req: Request) { if (updateData.email) { const existingEmail = await UserModel.findOne({ email: updateData.email, - _id: { - $ne: user_id, - }, + _id: { $ne: user_id }, }); if (existingEmail) { - return Response.json( - { error: "Email already exists" }, - { status: 400 } - ); + return errorHandler("Email already exists", STATUS_CODES.BAD_REQUEST); } } @@ -64,14 +62,14 @@ export async function PUT(req: Request) { _id: { $ne: user_id }, }); if (existingContact) { - return Response.json( - { error: "Contact number already exists" }, - { status: 400 } + return errorHandler( + "Contact number already exists", + STATUS_CODES.BAD_REQUEST ); } } - // update the user + // Update the user const updatedUser = await UserModel.findByIdAndUpdate( user_id, { $set: updateData }, @@ -79,18 +77,18 @@ export async function PUT(req: Request) { ); if (!updatedUser) { - return Response.json({ error: `${role} not found` }, { status: 404 }); + return errorHandler(`${role} not found`, STATUS_CODES.NOT_FOUND); } - return Response.json( - { msg: "Profile updated successfully" }, + return NextResponse.json( + { message: "Profile updated successfully" }, { status: 200 } ); - } catch (error) { + } catch (error: any) { console.error("Error updating personal information:", error); - return Response.json( - { error: "Failed to update personal information" }, - { status: 500 } + return errorHandler( + error.message || "Failed to update personal information", + STATUS_CODES.SERVER_ERROR ); } } diff --git a/app/api/update-profile/profile/route.ts b/app/api/update-profile/profile/route.ts index 42871955..887daadc 100644 --- a/app/api/update-profile/profile/route.ts +++ b/app/api/update-profile/profile/route.ts @@ -1,37 +1,46 @@ -import { dbConfig, getModelByRole } from "@utils/index"; +import { NextResponse } from "next/server"; +import { + dbConfig, + getModelByRole, + errorHandler, + STATUS_CODES, +} from "@utils/index"; import { Types } from "mongoose"; +import { authenticateUser } from "@lib/auth"; export async function PUT(request: Request) { try { const profile_pic = await request.json(); - const id = request.headers.get("x-user-id"); - const role = request.headers.get("x-user-role"); + const authHeader = request.headers.get("Authorization"); + const { id, role } = await authenticateUser(authHeader); + // check for missing user ID or role if (!id || !role) { - return Response.json( - { error: "Missing user ID or role" }, - { status: 400 } - ); + return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); } const user_id = new Types.ObjectId(id); - await dbConfig(); - let UserModel = getModelByRole(role); + const UserModel = getModelByRole(role); - const result = await UserModel.findByIdAndUpdate(user_id, { - $set: { profile: profile_pic }, - }); + const result = await UserModel.findByIdAndUpdate( + user_id, + { $set: { profile: profile_pic } }, + { new: true } + ); if (!result) { - return Response.json({ error: "Error updating profile picture" }); + return errorHandler( + "Error updating profile picture", + STATUS_CODES.NOT_FOUND + ); } - return Response.json({ msg: "ok" }); + return NextResponse.json({ message: "ok" }, { status: 200 }); } catch (error) { - console.error("Error updating profile picture :", error); - return Response.json({ error: "Internal Server Error" }, { status: 500 }); + console.error("Error updating profile picture:", error); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } diff --git a/app/api/update-profile/reset-password/route.ts b/app/api/update-profile/reset-password/route.ts index 659ee425..119650d8 100644 --- a/app/api/update-profile/reset-password/route.ts +++ b/app/api/update-profile/reset-password/route.ts @@ -1,55 +1,55 @@ -import { dbConfig, getModelByRole } from "@utils/index"; +import { NextResponse } from "next/server"; +import { + dbConfig, + getModelByRole, + errorHandler, + STATUS_CODES, + hashPassword, +} from "@utils/index"; import bcrypt from "bcrypt"; import { SecurityBody } from "@pft-types/index"; import { Types } from "mongoose"; +import { authenticateUser } from "@lib/auth"; export async function PUT(req: Request) { try { - const id = req.headers.get("x-user-id"); - const role = req.headers.get("x-user-role"); + const authHeader = req.headers.get("Authorization"); + const { id, role } = await authenticateUser(authHeader); if (!id || !role) { - return Response.json( - { error: "Missing user ID or role" }, - { status: 400 } - ); + return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); } const user_id = new Types.ObjectId(id); - const { currentPassword, newPassword }: SecurityBody = await req.json(); if (!currentPassword || !newPassword) { - return Response.json( - { error: "Current password and new password are required" }, - { status: 400 } + return errorHandler( + "Current password and new password are required", + STATUS_CODES.BAD_REQUEST ); } await dbConfig(); - - let UserModel = getModelByRole(role); + const UserModel = getModelByRole(role); const user = await UserModel.findById(user_id); - if (!user) { - return Response.json({ error: "User not found" }, { status: 404 }); + return errorHandler("User not found", STATUS_CODES.NOT_FOUND); } const isPasswordValid = await bcrypt.compare( currentPassword, user.password ); - if (!isPasswordValid) { - return Response.json( - { error: "Current password is incorrect" }, - { status: 400 } + return errorHandler( + "Current password is incorrect", + STATUS_CODES.BAD_REQUEST ); } const hashedNewPassword = await hashPassword(newPassword); - const updatedUser = await UserModel.findByIdAndUpdate( user_id, { $set: { password: hashedNewPassword } }, @@ -57,24 +57,15 @@ export async function PUT(req: Request) { ); if (!updatedUser) { - return Response.json( - { error: "Error updating password" }, - { status: 500 } - ); + return errorHandler("Error updating password", STATUS_CODES.SERVER_ERROR); } - return Response.json( - { msg: "Password updated successfully" }, + return NextResponse.json( + { message: "Password updated successfully" }, { status: 200 } ); } catch (error) { - return Response.json({ error: "Error updating password" }, { status: 500 }); + console.error("Error updating password:", error); + return errorHandler("Error updating password", STATUS_CODES.SERVER_ERROR); } } - -// hashing the password -async function hashPassword(password: string) { - const saltRounds = parseInt(process.env.BCRYPT_SALT_ROUNDS || "10"); - const hashedPassword = await bcrypt.hash(password, saltRounds); - return hashedPassword; -} From 27111a3904db06173c8fb8003896a05937169666 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:41:33 +0530 Subject: [PATCH 07/41] =?UTF-8?q?chore(auth):=20=F0=9F=94=92=20secure=20er?= =?UTF-8?q?ror=20handling=20with=20errorHandler=20and=20NextResponse=20for?= =?UTF-8?q?=20responses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/auth/login/route.ts | 62 +++++++++++++++++---------------- app/api/auth/signup/route.ts | 47 +++++++++++++------------ app/api/auth/verifyotp/route.ts | 36 ++++++++++--------- 3 files changed, 75 insertions(+), 70 deletions(-) diff --git a/app/api/auth/login/route.ts b/app/api/auth/login/route.ts index c46b0635..f95999f5 100644 --- a/app/api/auth/login/route.ts +++ b/app/api/auth/login/route.ts @@ -1,8 +1,14 @@ -import { OtpTemplate } from "@lib/emails/templates"; -import sendEmail from "@lib/sendemail"; +import { NextResponse } from "next/server"; +import { OtpTemplate, sendEmail } from "@lib/index"; import { render } from "@react-email/render"; -import { dbConfig, generateSecureOTP, getModelByRole } from "@utils/index"; -import { allowedRoles } from "@constants/index"; +import { + dbConfig, + errorHandler, + generateSecureOTP, + getModelByRole, + STATUS_CODES, + allowedRoles, +} from "@utils/index"; import bcrypt from "bcrypt"; type LoginBody = { @@ -12,31 +18,25 @@ type LoginBody = { }; export async function POST(req: Request) { - try { - const body: LoginBody = await req.json(); + const body: LoginBody = await req.json(); - if (!body || !body.usernameOrEmail || !body.password || !body.role) { - return Response.json( - { - error: - "Invalid request body. Please provide username or email, password, and role.", - }, - { status: 400 } - ); - } + if (!body || !body.usernameOrEmail || !body.password || !body.role) { + return errorHandler( + "Invalid request body. Please provide username or email, password, and role.", + STATUS_CODES.BAD_REQUEST + ); + } - if (!allowedRoles.includes(body.role)) { - return Response.json( - { error: "User role isn't valid." }, - { status: 400 } - ); - } + if (!allowedRoles.includes(body.role)) { + return errorHandler("User role isn't valid.", STATUS_CODES.BAD_REQUEST); + } + try { const result = await setOTP(body); return result; - } catch (error) { + } catch (error: any) { console.error("Error during login: ", error); - return Response.json({ error: "Internal Server Error" }, { status: 500 }); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } @@ -56,18 +56,17 @@ async function setOTP(loginBody: LoginBody) { ); if (!user || !(await bcrypt.compare(loginBody.password, user.password))) { - return Response.json( - { error: "Invalid username/email or password" }, - { status: 401 } + return errorHandler( + "Invalid username/email or password", + STATUS_CODES.UNAUTHORIZED ); } const generatedOTP = generateSecureOTP(); - user.otp = generatedOTP; await user.save(); - const mailsent = await sendEmail({ + const mailSent = await sendEmail({ to: user.email, subject: "OTP Verification", html: render(OtpTemplate(user.firstname, generatedOTP)), @@ -77,6 +76,9 @@ async function setOTP(loginBody: LoginBody) { }, }); - if (!mailsent) return Response.json({ error: "Email Sending Failed" }); - return Response.json({ message: "ok" }, { status: 201 }); + if (!mailSent) { + return errorHandler("Email Sending Failed", STATUS_CODES.SERVER_ERROR); + } + + return NextResponse.json({ message: "ok" }, { status: 201 }); } diff --git a/app/api/auth/signup/route.ts b/app/api/auth/signup/route.ts index 1dc00083..44b30f0b 100644 --- a/app/api/auth/signup/route.ts +++ b/app/api/auth/signup/route.ts @@ -1,5 +1,5 @@ -import { OtpTemplate } from "@lib/emails/templates"; -import sendEmail from "@lib/sendemail"; +import { NextResponse } from "next/server"; +import { OtpTemplate, sendEmail } from "@lib/index"; import { render } from "@react-email/render"; import { allowedRoles, @@ -13,6 +13,8 @@ import { generateSecureOTP, getModelByRole, hashPassword, + STATUS_CODES, + errorHandler, } from "@utils/index"; type SignupBody = { @@ -29,24 +31,21 @@ export async function POST(req: Request) { const body: SignupBody = await req.json(); if (checkMissingElements(body)) { - return Response.json( - { error: "Missing required fields in the request body" }, - { status: 400 } + return errorHandler( + "Missing required fields in the request body", + STATUS_CODES.BAD_REQUEST ); } if (!allowedRoles.includes(body.role)) { - return Response.json( - { error: "User role isn't valid." }, - { status: 400 } - ); + return errorHandler("User role isn't valid.", STATUS_CODES.BAD_REQUEST); } const result = await createAccount(body); return result; - } catch (error) { + } catch (error: any) { console.error("Error during signup:", error); - return Response.json({ error: "Internal Server Error" }, { status: 500 }); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } @@ -61,20 +60,15 @@ async function createAccount(signupBody: SignupBody) { if (existingUser) { if (existingUser.email === signupBody.email) { - return Response.json({ error: "Email already exists" }, { status: 409 }); + return errorHandler("Email already exists", STATUS_CODES.CONFLICT); } if (existingUser.username === signupBody.username) { - return Response.json( - { error: "Username already exists" }, - { status: 409 } - ); + return errorHandler("Username already exists", STATUS_CODES.CONFLICT); } } - // gets the additional details based on the user's role - let additionalDetails = getAdditionalDetails(signupBody.role); - + const additionalDetails = getAdditionalDetails(signupBody.role); const hashedPassword = await hashPassword(signupBody.password); const newUser = new UserModel({ @@ -84,7 +78,6 @@ async function createAccount(signupBody: SignupBody) { }); const savedUser = await newUser.save(); - const generatedOTP = generateSecureOTP(); await savedUser.updateOne( @@ -92,7 +85,7 @@ async function createAccount(signupBody: SignupBody) { { $set: { otp: generatedOTP } } ); - const mailsent = await sendEmail({ + const mailSent = await sendEmail({ to: savedUser.email, subject: "Verification of OTP for Account Creation", html: render(OtpTemplate(savedUser.firstname, generatedOTP)), @@ -102,8 +95,14 @@ async function createAccount(signupBody: SignupBody) { }, }); - if (!mailsent) return Response.json({ error: "Signup email sending failed" }); - return Response.json( + if (!mailSent) { + return errorHandler( + "Signup email sending failed", + STATUS_CODES.SERVER_ERROR + ); + } + + return NextResponse.json( { message: "Account created successfully" }, { status: 201 } ); @@ -133,5 +132,7 @@ function getAdditionalDetails(role: string) { return doctoradditionalDetails; case "hospital": return hospitaladditionalDetails; + default: + return {}; } } diff --git a/app/api/auth/verifyotp/route.ts b/app/api/auth/verifyotp/route.ts index 51dd8e82..0605a380 100644 --- a/app/api/auth/verifyotp/route.ts +++ b/app/api/auth/verifyotp/route.ts @@ -1,7 +1,13 @@ +import { NextResponse } from "next/server"; import { setSession } from "@sessions/sessionUtils"; -import { dbConfig, getModelByRole } from "@utils/index"; -import { allowedRoles } from "@constants/index"; import logUserActivity from "@lib/logs"; +import { + allowedRoles, + dbConfig, + errorHandler, + getModelByRole, + STATUS_CODES, +} from "@utils/index"; type bodyType = { usernameOrEmail: string; @@ -21,29 +27,24 @@ export async function POST(req: Request) { !body.action || !body.otp ) { - return Response.json( - { - error: - "Username/Email, OTP, action and role are required fields in the request body.", - }, - { status: 400 } + return errorHandler( + "Username/Email, OTP, action, and role are required fields in the request body.", + STATUS_CODES.BAD_REQUEST ); } if (!allowedRoles.includes(body.role)) { - return Response.json( - { error: "User role isn't valid." }, - { status: 400 } - ); + return errorHandler("User role isn't valid.", STATUS_CODES.BAD_REQUEST); } const result = await checkOTP(body, req); return result; } catch (error) { - console.error("Error during otp verification:", error); - return Response.json({ error: "Internal Server Error" }, { status: 500 }); + console.error("Error during OTP verification:", error); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } + async function checkOTP(body: bodyType, req: Request) { await dbConfig(); @@ -59,8 +60,9 @@ async function checkOTP(body: bodyType, req: Request) { { _id: 1, username: 1, firstname: 1, lastname: 1, otp: 1, email: 1 } ); - if (!user || user.otp !== body.otp) - return Response.json({ error: "OTP Verification Failed" }, { status: 401 }); + if (!user || user.otp !== body.otp) { + return errorHandler("OTP Verification Failed", STATUS_CODES.UNAUTHORIZED); + } await UserModel.updateOne({ email: user.email }, { $set: { otp: "" } }); @@ -78,5 +80,5 @@ async function checkOTP(body: bodyType, req: Request) { // storing user logs in db await logUserActivity(userlog, req); - return Response.json({ message: "ok" }, { status: 200 }); + return NextResponse.json({ message: "ok" }, { status: 200 }); } From e2c96dbef25d1e1f03776ee7286a12173a9c3538 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:41:48 +0530 Subject: [PATCH 08/41] =?UTF-8?q?chore(doctor):=20=F0=9F=93=9D=20standardi?= =?UTF-8?q?ze=20error=20handling=20using=20errorHandler=20and=20utilize=20?= =?UTF-8?q?NextResponse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/doctor/route.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/app/api/doctor/route.ts b/app/api/doctor/route.ts index d25b8c79..c450af3f 100644 --- a/app/api/doctor/route.ts +++ b/app/api/doctor/route.ts @@ -1,34 +1,32 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; import Doctor from "@models/doctor"; import { Types } from "mongoose"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; +import authenticateUser from "@lib/auth/authenticateUser"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); + try { - const id = request.headers.get("x-user-id"); - const role = request.headers.get("x-user-role"); + const { id, role } = await authenticateUser(authHeader); if (!id || !role) { - return Response.json( - { error: "Missing user ID or role" }, - { status: 400 } - ); + return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); } const doctor_id = new Types.ObjectId(id); await dbConfig(); - // const projection = {}; { projection } - const doctorData = await Doctor.findById(doctor_id); if (!doctorData) { - return Response.json({ error: "Doctor not found" }, { status: 404 }); + return NextResponse.json({ error: "Doctor not found" }, { status: 404 }); } - return Response.json(doctorData); + return NextResponse.json(doctorData); } catch (error) { console.error("Error fetching Doctor data:", error); - return Response.json({ error: "Internal Server Error" }, { status: 500 }); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } From bc5fd0101a6fcfaed93ea444c6caea8040d46c73 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:42:00 +0530 Subject: [PATCH 09/41] =?UTF-8?q?chore(transactions):=20=F0=9F=94=8D=20rev?= =?UTF-8?q?iew=20error=20management=20with=20errorHandler=20and=20implemen?= =?UTF-8?q?t=20NextResponse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/transactions/route.ts | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/app/api/transactions/route.ts b/app/api/transactions/route.ts index 3db9ef99..0153190f 100644 --- a/app/api/transactions/route.ts +++ b/app/api/transactions/route.ts @@ -1,4 +1,5 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import { Transaction as TransactionType } from "@pft-types/index"; import Transaction from "@models/transaction"; import { Types } from "mongoose"; @@ -20,10 +21,7 @@ export async function POST(req: Request) { const role = req.headers.get("x-user-role"); if (!id || !role) { - return Response.json( - { error: "Missing user ID or role" }, - { status: 400 } - ); + return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); } await dbConfig(); @@ -40,14 +38,19 @@ export async function POST(req: Request) { const res = await Transaction.create(transactionData); - if (!res) - return Response.json({ - error: "Error saving transaction details", - }); + if (!res) { + return errorHandler( + "Error saving transaction details", + STATUS_CODES.SERVER_ERROR + ); + } - return Response.json({ status: 200 }); - } catch (error) { - console.error("Error saving transaction :", error); - return Response.json({ error: "Internal Server Error" }, { status: 500 }); + return NextResponse.json({ status: 200 }); + } catch (error: any) { + console.error("Error saving transaction:", error); + return errorHandler( + error.message || "Internal Server Error", + STATUS_CODES.SERVER_ERROR + ); } } From 711542a3ea48242e1eff20c4325f37f934c9519b Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:42:13 +0530 Subject: [PATCH 10/41] =?UTF-8?q?chore(demosuer):=20=F0=9F=8E=89=20improve?= =?UTF-8?q?=20error=20handling=20with=20errorHandler=20and=20switch=20to?= =?UTF-8?q?=20NextResponse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/demouser/route.ts | 55 +++++++++++++++------------------------ 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/app/api/demouser/route.ts b/app/api/demouser/route.ts index 6c7a5baf..f14b8843 100644 --- a/app/api/demouser/route.ts +++ b/app/api/demouser/route.ts @@ -1,8 +1,13 @@ -import dbConfig from "@utils/db"; -import logUserActivity from "@lib/logs"; +import { NextResponse } from "next/server"; import DemoUser from "@models/demouser"; -import getModelByRole from "@utils/getModelByRole"; import { setSession } from "@sessions/sessionUtils"; +import logUserActivity from "@lib/logs"; +import { + dbConfig, + errorHandler, + getModelByRole, + STATUS_CODES, +} from "@utils/index"; export async function POST(req: Request) { await dbConfig(); @@ -10,14 +15,11 @@ export async function POST(req: Request) { try { const { role } = await req.json(); - // Validate the incoming body + // validate the incoming body if (!role || typeof role !== "string") { - return Response.json( - { - success: false, - error: "Invalid request body. Please provide a valid role.", - }, - { status: 400 } + return errorHandler( + "Invalid request body. Please provide a valid role.", + STATUS_CODES.BAD_REQUEST ); } @@ -25,32 +27,23 @@ export async function POST(req: Request) { const demoUser = await DemoUser.findOne({ role }); if (!demoUser) { - return Response.json( - { - success: false, - error: "Demo user not found for this role", - }, - { status: 404 } + return errorHandler( + "Demo user not found for this role", + STATUS_CODES.NOT_FOUND ); } - // get a usermodel with matching role + // get a user model with matching role const UserModel = getModelByRole(role); - // find a user which have same ObjectId as demousers + // find a user which has the same ObjectId as demo users const userData = await UserModel.findById(demoUser.referenceId); if (!userData) { - return Response.json( - { - success: false, - error: "Demo user data not found", - }, - { status: 404 } - ); + return errorHandler("Demo user data not found", STATUS_CODES.NOT_FOUND); } - // setting session for demouser (stores jwt token in cookie named session) + // setting session for demo user (stores jwt token in cookie named session) await setSession(userData._id, role); const userLog = { @@ -64,7 +57,7 @@ export async function POST(req: Request) { // log activity await logUserActivity(userLog, req); - return Response.json( + return NextResponse.json( { success: true, message: "Demo User logged in successfully.", @@ -73,12 +66,6 @@ export async function POST(req: Request) { ); } catch (error) { console.error("Error during login: ", error); - return Response.json( - { - success: false, - error: "Internal Server Error", - }, - { status: 500 } - ); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } From 83dbd2cea16015055efcbf00b825cff34a333506 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 22:44:12 +0530 Subject: [PATCH 11/41] =?UTF-8?q?chore:=20=F0=9F=9A=80=20Refactor=20error?= =?UTF-8?q?=20handling=20to=20use=20errorHandler=20-=20NextResponse=20for?= =?UTF-8?q?=20consistent=20API=20responses=20-=20Removed=20x-user-id=20and?= =?UTF-8?q?=20x-user-role=20headers=20-=20implementing=20authenticateUser?= =?UTF-8?q?=20method=20for=20authorization.=20=F0=9F=94=92=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/city/route.ts | 20 +++++++++---- app/api/cloudinary/sign-image/route.ts | 4 +-- app/api/gethospitals/disease/route.ts | 13 +++++---- app/api/gethospitals/route.ts | 31 +++++++++++--------- app/api/payment/create-order/route.ts | 4 +-- app/api/payment/verify/route.ts | 39 ++++++++++++++++---------- app/api/states/route.ts | 14 +++++---- 7 files changed, 76 insertions(+), 49 deletions(-) diff --git a/app/api/city/route.ts b/app/api/city/route.ts index a52d5e5a..eecb25cc 100644 --- a/app/api/city/route.ts +++ b/app/api/city/route.ts @@ -1,12 +1,17 @@ -import dbConfig from "@utils/db"; +import { NextResponse } from "next/server"; import CityStateHospital from "@models/citystate_hospitals"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; export async function GET(req: Request) { const { searchParams } = new URL(req.url); const state = searchParams.get("state"); + try { if (!state) { - return new Response("State parameter is missing", { status: 400 }); + return errorHandler( + "State parameter is missing", + STATUS_CODES.BAD_REQUEST + ); } await dbConfig(); @@ -15,19 +20,22 @@ export async function GET(req: Request) { }); if (!stateDocument) { - return new Response("State not found", { status: 404 }); + return errorHandler("State not found", STATUS_CODES.NOT_FOUND); } // Get the cities for the given state const cities = Object.keys(stateDocument.get(state)); if (cities.length === 0) { - return Response.json(cities, { status: 404 }); + return errorHandler( + "No cities found for the given state", + STATUS_CODES.NOT_FOUND + ); } - return Response.json(cities, { status: 201 }); + return NextResponse.json(cities, { status: 200 }); } catch (error) { console.error("Error fetching state and city data:", error); - return new Response("Internal Server Error", { status: 500 }); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } diff --git a/app/api/cloudinary/sign-image/route.ts b/app/api/cloudinary/sign-image/route.ts index 0ba41308..06dc1d39 100644 --- a/app/api/cloudinary/sign-image/route.ts +++ b/app/api/cloudinary/sign-image/route.ts @@ -1,5 +1,5 @@ +import { NextRequest, NextResponse } from "next/server"; import { v2 as cloudinary } from "cloudinary"; -import { NextRequest } from "next/server"; export async function POST(request: NextRequest) { const body = (await request.json()) as { @@ -12,5 +12,5 @@ export async function POST(request: NextRequest) { process.env.CLOUDINARY_API_SECRET as string ); - return Response.json({ signature }); + return NextResponse.json({ signature }); } diff --git a/app/api/gethospitals/disease/route.ts b/app/api/gethospitals/disease/route.ts index 5513b027..620495c3 100644 --- a/app/api/gethospitals/disease/route.ts +++ b/app/api/gethospitals/disease/route.ts @@ -1,5 +1,6 @@ +import { NextResponse } from "next/server"; import CommonDiseases from "@models/commonDisease"; -import dbConfig from "@utils/db"; +import { dbConfig, errorHandler, STATUS_CODES } from "@/utils"; export async function GET() { try { @@ -8,17 +9,17 @@ export async function GET() { const result = await CommonDiseases.findOne(); if (!result) { - return Response.json( - { error: "error no common diseases found" }, - { status: 200 } + return errorHandler( + "error no common diseases found", + STATUS_CODES.BAD_REQUEST ); } const commonDiseases = result.commonDiseases; - return Response.json(commonDiseases, { status: 200 }); + return NextResponse.json(commonDiseases, { status: 200 }); } catch (error) { console.error("Error while getting common diseases:", error); - return new Response("Internal Server Error", { status: 500 }); + return new NextResponse("Internal Server Error", { status: 500 }); } } diff --git a/app/api/gethospitals/route.ts b/app/api/gethospitals/route.ts index 56bbb83f..81d616da 100644 --- a/app/api/gethospitals/route.ts +++ b/app/api/gethospitals/route.ts @@ -1,16 +1,19 @@ +import { NextResponse } from "next/server"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import CityStateHospital from "@models/citystate_hospitals"; -import dbConfig from "@utils/db"; export async function GET(req: Request) { const { searchParams } = new URL(req.url); const state = searchParams.get("state"); const city = searchParams.get("city"); + try { if (!state || !city) { - return new Response("State or city parameter is missing", { - status: 400, - }); + return errorHandler( + "State or city parameter is missing", + STATUS_CODES.BAD_REQUEST + ); } await dbConfig(); @@ -20,25 +23,27 @@ export async function GET(req: Request) { }); if (!stateHospitals) { - return new Response("No hospitals found for the specified state", { - status: 404, - }); + return errorHandler( + "No hospitals found for the specified state", + STATUS_CODES.NOT_FOUND + ); } const cityHospitals = stateHospitals.get(state)[city]; if (!cityHospitals) { - return new Response("No hospitals found in the specified city", { - status: 404, - }); + return errorHandler( + "No hospitals found in the specified city", + STATUS_CODES.NOT_FOUND + ); } - return new Response(JSON.stringify(cityHospitals), { status: 200 }); + return NextResponse.json(cityHospitals, { status: 200 }); } catch (error) { console.error( - "Error while fetching hospitals for booking appointments : ", + "Error while fetching hospitals for booking appointments: ", error ); - return new Response("Internal Server Error", { status: 500 }); + return errorHandler("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } diff --git a/app/api/payment/create-order/route.ts b/app/api/payment/create-order/route.ts index 19261324..6ec121fe 100644 --- a/app/api/payment/create-order/route.ts +++ b/app/api/payment/create-order/route.ts @@ -1,4 +1,4 @@ -import { NextRequest } from "next/server"; +import { NextRequest, NextResponse } from "next/server"; import { razorpay } from "@lib/razorpay"; export async function POST(request: NextRequest) { @@ -13,5 +13,5 @@ export async function POST(request: NextRequest) { receipt: "rcp1", }; const order = await razorpay.orders.create(options); - return Response.json({ orderId: order.id }, { status: 200 }); + return NextResponse.json({ orderId: order.id }, { status: 200 }); } diff --git a/app/api/payment/verify/route.ts b/app/api/payment/verify/route.ts index 55f8ce62..fa5a9cf8 100644 --- a/app/api/payment/verify/route.ts +++ b/app/api/payment/verify/route.ts @@ -1,5 +1,6 @@ -import { NextRequest } from "next/server"; +import { NextRequest, NextResponse } from "next/server"; import crypto from "crypto"; +import { errorHandler, STATUS_CODES } from "@utils/index"; const generatedSignature = ( razorpayOrderId: string, @@ -11,26 +12,34 @@ const generatedSignature = ( "Razorpay key secret is not defined in environment variables." ); } - const sig = crypto + return crypto .createHmac("sha256", keySecret) - .update(razorpayOrderId + "|" + razorpayPaymentId) + .update(`${razorpayOrderId}|${razorpayPaymentId}`) .digest("hex"); - return sig; }; export async function POST(request: NextRequest) { - const { orderCreationId, razorpayPaymentId, razorpaySignature } = - await request.json(); + try { + const { orderCreationId, razorpayPaymentId, razorpaySignature } = + await request.json(); - const signature = generatedSignature(orderCreationId, razorpayPaymentId); - if (signature !== razorpaySignature) { - return Response.json( - { message: "payment verification failed", isOk: false }, - { status: 400 } + const signature = generatedSignature(orderCreationId, razorpayPaymentId); + if (signature !== razorpaySignature) { + return errorHandler( + "Payment verification failed", + STATUS_CODES.BAD_REQUEST + ); + } + + return NextResponse.json( + { message: "Payment verified successfully", isOk: true }, + { status: 200 } + ); + } catch (error: any) { + console.error("Error during payment verification:", error); + return errorHandler( + error.message || "Internal Server Error", + STATUS_CODES.SERVER_ERROR ); } - return Response.json( - { message: "payment verified successfully", isOk: true }, - { status: 200 } - ); } diff --git a/app/api/states/route.ts b/app/api/states/route.ts index ec3be141..0630a737 100644 --- a/app/api/states/route.ts +++ b/app/api/states/route.ts @@ -1,5 +1,6 @@ +import { NextResponse } from "next/server"; +import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import CityStateHospital from "@models/citystate_hospitals"; -import dbConfig from "@utils/db"; export async function GET(req: Request) { try { @@ -8,16 +9,19 @@ export async function GET(req: Request) { const statesArray = await CityStateHospital.find({}, { _id: 0 }); if (!statesArray || statesArray.length === 0) { - return Response.json("States not found", { status: 404 }); + return errorHandler("States not found", STATUS_CODES.NOT_FOUND); } const stateNames = statesArray .flatMap((state) => Object.keys(state.toObject())) .filter((key) => key !== "cities"); - return Response.json(stateNames, { status: 200 }); - } catch (error) { + return NextResponse.json(stateNames, { status: 200 }); + } catch (error: any) { console.error("Error fetching state data:", error); - return Response.json("Internal Server Error", { status: 500 }); + return errorHandler( + error.message || "Internal Server Error", + STATUS_CODES.SERVER_ERROR + ); } } From 425b04f64016c9168b5b031e31d253088e8ce6d1 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:16:14 +0530 Subject: [PATCH 12/41] =?UTF-8?q?feat(auth):=20replace=20getBaseUrl=20and?= =?UTF-8?q?=20auth=20headers=20with=20fetchHandler=20=F0=9F=9B=A0=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/auth/authenticateUser.ts | 2 +- app/lib/auth/index.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 app/lib/auth/index.ts diff --git a/app/lib/auth/authenticateUser.ts b/app/lib/auth/authenticateUser.ts index c6a84788..8296fa60 100644 --- a/app/lib/auth/authenticateUser.ts +++ b/app/lib/auth/authenticateUser.ts @@ -2,7 +2,7 @@ import { AppError, STATUS_CODES } from "@utils/index"; import { decrypt } from "@sessions/sessionUtils"; import { JWTExpired, JWTInvalid } from "jose/errors"; -export async function authenticateUser( +export default async function authenticateUser( authHeader: string | null ): Promise<{ id: string; role: string }> { if (!authHeader || !authHeader.startsWith("Bearer ")) { diff --git a/app/lib/auth/index.ts b/app/lib/auth/index.ts new file mode 100644 index 00000000..ef7c477a --- /dev/null +++ b/app/lib/auth/index.ts @@ -0,0 +1,3 @@ +import authenticateUser from "./authenticateUser"; + +export { authenticateUser }; From b81c039fcee61ade2825e8a08166eb652b881276 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:16:26 +0530 Subject: [PATCH 13/41] =?UTF-8?q?feat(demo):=20update=20to=20use=20fetchHa?= =?UTF-8?q?ndler,=20removing=20getBaseUrl=20=F0=9F=8C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/demo-user/handleDemoUserLogin.tsx | 27 +++++++++-------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/app/lib/demo-user/handleDemoUserLogin.tsx b/app/lib/demo-user/handleDemoUserLogin.tsx index 72df41e2..e29b095b 100644 --- a/app/lib/demo-user/handleDemoUserLogin.tsx +++ b/app/lib/demo-user/handleDemoUserLogin.tsx @@ -1,36 +1,29 @@ +"use server"; import toast from "react-hot-toast"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; const handleDemoUserLogin = async ( role: string, redirectDemoUser: (role: string) => void ) => { + const endpoint = "/api/demouser"; + try { toast.loading("Logging in...", { id: "demoLogin" }); - const serverUrl = getBaseUrl(); - - const response = await fetch(`${serverUrl}/api/demouser`, { + const result = await fetchHandler(endpoint, { method: "POST", - headers: { - "Content-Type": "application/json", - }, body: JSON.stringify({ role }), + cache: "no-cache", }); - const result = await response.json(); - - if (!response.ok) { - console.error("Error while demouser login:", result.error); + if (!result.success) { + console.error("Error while demo user login:", result.error); return { success: false, error: result.error }; } - if (result.success) { - toast.success("Login successful, redirecting...", { id: "demoLogin" }); - redirectDemoUser(role); - } else { - throw new Error(result.error || "Login failed"); - } + toast.success("Login successful, redirecting...", { id: "demoLogin" }); + redirectDemoUser(role); } catch (error) { console.error("Demo login error:", error); toast.error( From e06014f4d54588731dd13bb350bc4eaae8a21765 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:16:44 +0530 Subject: [PATCH 14/41] =?UTF-8?q?feat(doctor):=20refactor=20to=20use=20fet?= =?UTF-8?q?chHandler=20instead=20of=20getBaseUrl=20=F0=9F=94=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/doctor/getDoctorData.ts | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/app/lib/doctor/getDoctorData.ts b/app/lib/doctor/getDoctorData.ts index a34ecc51..1ec7ab7a 100644 --- a/app/lib/doctor/getDoctorData.ts +++ b/app/lib/doctor/getDoctorData.ts @@ -1,27 +1,13 @@ -"use server"; -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getDoctorData() { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/doctor"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const res = await fetch(`${serverUrl}/api/doctor`, { - headers, + const doctorData = await fetchHandler(endpoint, { cache: "no-cache", }); - if (!res.ok) { - console.error(`Error fetching doctor data: ${res.statusText}`); - throw new Error("fetching doctor data"); - } - - const doctorData = await res.json(); - return doctorData; } catch (error) { console.error("An error occurred while fetching doctor data:", error); From b430f72534bbc7cc7e96776ee6b320deb76be482 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:16:58 +0530 Subject: [PATCH 15/41] =?UTF-8?q?feat(hospital):=20migrate=20to=20fetchHan?= =?UTF-8?q?dler,=20eliminating=20getBaseUrl=20=F0=9F=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/hospital/getHospitalData.ts | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/app/lib/hospital/getHospitalData.ts b/app/lib/hospital/getHospitalData.ts index 2d8dbd4b..19aac2a3 100644 --- a/app/lib/hospital/getHospitalData.ts +++ b/app/lib/hospital/getHospitalData.ts @@ -1,27 +1,13 @@ -"use server"; -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getHospitalData() { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/hospital"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const res = await fetch(`${serverUrl}/api/hospital`, { - headers, + const hospitalData = await fetchHandler(endpoint, { cache: "no-cache", }); - if (!res.ok) { - console.error(`Error fetching hospital data: ${res.statusText}`); - throw new Error("fetching hospital data"); - } - - const hospitalData = await res.json(); - return hospitalData; } catch (error) { console.error("An error occurred while fetching hospital data:", error); From 330c066dcbe3e187ff685daadf4d69aca165c452 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:17:37 +0530 Subject: [PATCH 16/41] =?UTF-8?q?refactor(patient):=20switch=20to=20fetchH?= =?UTF-8?q?andler,=20removing=20base=20URL=20logic=20=F0=9F=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/patient/bookAppointment.tsx | 24 ++++++---------- app/lib/patient/getPatientData.tsx | 20 ++----------- app/lib/patient/getPatientMedicalHistory.tsx | 24 +++------------- app/lib/patient/getPaymentsHistory.tsx | 22 +++------------ app/lib/patient/getUpcomingAppointments.tsx | 25 ++++------------- app/lib/patient/misc/getCities.tsx | 17 ++++------- app/lib/patient/misc/getDiseases.tsx | 15 ++++------ app/lib/patient/misc/getHospitals.tsx | 17 ++++------- app/lib/patient/misc/getStates.tsx | 15 ++++------ app/lib/patient/pendingAppointmentsReq.tsx | 28 ++++++------------- .../patient/saveAppointmentTransaction.tsx | 16 +++-------- 11 files changed, 56 insertions(+), 167 deletions(-) diff --git a/app/lib/patient/bookAppointment.tsx b/app/lib/patient/bookAppointment.tsx index f249fd60..6b2c0f9e 100644 --- a/app/lib/patient/bookAppointment.tsx +++ b/app/lib/patient/bookAppointment.tsx @@ -1,22 +1,16 @@ -"use server"; +import fetchHandler from "@utils/fetchHandler"; import { bookingAppointment } from "@pft-types/index"; -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; export default async function bookAppointment( bookAppointmentData: bookingAppointment, transaction_id: string | null, appointment_charge: string ) { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/patient/appointment"; + try { - const response = await fetch(`${serverUrl}/api/patient/appointment`, { + const response = await fetchHandler(endpoint, { method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${session}`, - }, body: JSON.stringify({ ...bookAppointmentData, transaction_id, @@ -24,14 +18,12 @@ export default async function bookAppointment( }), }); - if (!response.ok) { - console.error(`Error booking appointments: ${response.statusText}`); - const res = await response.json(); - return { error: res.error }; + if (!response) { + console.error("Error booking appointments"); + return { error: "Failed to book appointment" }; } - const res = await response.json(); - return res; + return response; } catch (error) { console.error("Error booking appointment:", error); throw error; diff --git a/app/lib/patient/getPatientData.tsx b/app/lib/patient/getPatientData.tsx index b15b3b69..13ba9f16 100644 --- a/app/lib/patient/getPatientData.tsx +++ b/app/lib/patient/getPatientData.tsx @@ -1,27 +1,13 @@ -"use server"; -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getPatientData() { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/patient"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const res = await fetch(`${serverUrl}/api/patient`, { - headers, + const patientData = await fetchHandler(endpoint, { cache: "no-cache", }); - if (!res.ok) { - console.error(`Error fetching patient data: ${res.statusText}`); - throw new Error("fetching patient data"); - } - - const patientData = await res.json(); - return patientData; } catch (error) { console.error("An error occurred while fetching patient data:", error); diff --git a/app/lib/patient/getPatientMedicalHistory.tsx b/app/lib/patient/getPatientMedicalHistory.tsx index d21fdc13..ddb25e6a 100644 --- a/app/lib/patient/getPatientMedicalHistory.tsx +++ b/app/lib/patient/getPatientMedicalHistory.tsx @@ -1,28 +1,12 @@ -"use server"; - -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getPatientMedicalHistory() { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/patient/medicalhistory"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const response = await fetch(`${serverUrl}/api/patient/medicalhistory`, { - headers, - }); - - if (!response.ok) { - throw new Error( - `Failed to fetch patient medical history: ${response.statusText}` - ); - } + const medicalHistory = await fetchHandler(endpoint); - const res = await response.json(); - return res; + return medicalHistory; } catch (error) { console.error("Error fetching patient medical history:", error); throw error; diff --git a/app/lib/patient/getPaymentsHistory.tsx b/app/lib/patient/getPaymentsHistory.tsx index 7e695307..66e435c6 100644 --- a/app/lib/patient/getPaymentsHistory.tsx +++ b/app/lib/patient/getPaymentsHistory.tsx @@ -1,26 +1,12 @@ -"use server"; - -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getPaymentsHistory() { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/patient/paymenthistory"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const response = await fetch(`${serverUrl}/api/patient/paymenthistory`, { - headers, - }); - - if (!response.ok) { - throw new Error(`Failed to fetch payments: ${response.statusText}`); - } + const paymentsHistory = await fetchHandler(endpoint); - const res = await response.json(); - return res; + return paymentsHistory; } catch (error) { console.error("Error fetching payments:", error); throw error; diff --git a/app/lib/patient/getUpcomingAppointments.tsx b/app/lib/patient/getUpcomingAppointments.tsx index 52f3a13f..a03ff7a5 100644 --- a/app/lib/patient/getUpcomingAppointments.tsx +++ b/app/lib/patient/getUpcomingAppointments.tsx @@ -1,29 +1,14 @@ "use server"; - -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getUpcomingAppointments() { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/patient/appointment"; try { - const res = await fetch(`${serverUrl}/api/patient/appointment`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${session}`, - }, - // next: { revalidate: 10 }, - }); - - if (!res.ok) { - throw new Error( - `Failed to fetch upcoming appointments: ${res.statusText}` - ); - } + const upcomingAppointments = await fetchHandler(endpoint); + // next: { revalidate: 10 }, - return res.json(); + return upcomingAppointments; } catch (error) { console.error("Error fetching upcoming appointments:", error); throw error; diff --git a/app/lib/patient/misc/getCities.tsx b/app/lib/patient/misc/getCities.tsx index f2f2f39b..95e64a5f 100644 --- a/app/lib/patient/misc/getCities.tsx +++ b/app/lib/patient/misc/getCities.tsx @@ -1,21 +1,14 @@ -"use server"; - -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getCities(selectedState: string) { - const serverUrl = getBaseUrl(); + const endpoint = `/api/city/?state=${selectedState}`; try { - const response = await fetch( - `${serverUrl}/api/city/?state=${selectedState}` - ); - if (!response.ok) { - throw new Error("Failed to fetch cities"); - } - const data = await response.json(); + const data = await fetchHandler(endpoint); + return data; } catch (error) { - console.error("Error fetching cities :", error); + console.error("Error fetching cities:", error); throw error; } } diff --git a/app/lib/patient/misc/getDiseases.tsx b/app/lib/patient/misc/getDiseases.tsx index 82cb4bdf..8ac59b0d 100644 --- a/app/lib/patient/misc/getDiseases.tsx +++ b/app/lib/patient/misc/getDiseases.tsx @@ -1,19 +1,14 @@ -"use server"; - -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getDiseases() { - const serverUrl = getBaseUrl(); + const endpoint = `/api/gethospitals/disease/`; try { - const response = await fetch(`${serverUrl}/api/gethospitals/disease/`); - if (!response.ok) { - throw new Error("Failed to fetch diseases"); - } - const data = await response.json(); + const data = await fetchHandler(endpoint); + return data; } catch (error) { - console.error("Error fetching diseases :", error); + console.error("Error fetching diseases:", error); throw error; } } diff --git a/app/lib/patient/misc/getHospitals.tsx b/app/lib/patient/misc/getHospitals.tsx index 1e1e04c9..3d746e84 100644 --- a/app/lib/patient/misc/getHospitals.tsx +++ b/app/lib/patient/misc/getHospitals.tsx @@ -1,24 +1,17 @@ -"use server"; - -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getHospitals( selectedState: string, selectedCity: string ) { - const serverUrl = getBaseUrl(); + const endpoint = `/api/gethospitals/?state=${selectedState}&city=${selectedCity}`; try { - const response = await fetch( - `${serverUrl}/api/gethospitals/?state=${selectedState}&city=${selectedCity}` - ); - if (!response.ok) { - throw new Error("Failed to fetch hospitals"); - } - const data = await response.json(); + const data = await fetchHandler(endpoint); + return data; } catch (error) { - console.error("Error fetching hospitals :", error); + console.error("Error fetching hospitals:", error); throw error; } } diff --git a/app/lib/patient/misc/getStates.tsx b/app/lib/patient/misc/getStates.tsx index 1e1f5980..cddca474 100644 --- a/app/lib/patient/misc/getStates.tsx +++ b/app/lib/patient/misc/getStates.tsx @@ -1,19 +1,14 @@ -"use server"; - -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getStates() { - const serverUrl = getBaseUrl(); + const endpoint = "/api/states"; try { - const response = await fetch(`${serverUrl}/api/states`); - if (!response.ok) { - throw new Error("Failed to fetch states"); - } - const data = await response.json(); + const data = await fetchHandler(endpoint); + return data; } catch (error) { - console.error("Error fetching states :", error); + console.error("Error fetching states:", error); throw error; } } diff --git a/app/lib/patient/pendingAppointmentsReq.tsx b/app/lib/patient/pendingAppointmentsReq.tsx index dabec138..a904abba 100644 --- a/app/lib/patient/pendingAppointmentsReq.tsx +++ b/app/lib/patient/pendingAppointmentsReq.tsx @@ -1,32 +1,20 @@ -"use server"; - -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function pendingAppointmentsRequest(hospital_id: string) { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/patient/appointment/pending"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const res = await fetch(`${serverUrl}/api/patient/appointment/pending`, { + const data = await fetchHandler(endpoint, { method: "POST", body: JSON.stringify({ hospital_id }), - headers, }); - if (!res.ok) { - throw new Error( - `fetching pending appointment request : ${res.statusText}` - ); - } - - const data = await res.json(); - return data; } catch (error) { - console.error("An error occurred while :", error); + console.error( + "An error occurred while fetching pending appointment requests:", + error + ); + throw error; } } diff --git a/app/lib/patient/saveAppointmentTransaction.tsx b/app/lib/patient/saveAppointmentTransaction.tsx index 360371c1..a182335a 100644 --- a/app/lib/patient/saveAppointmentTransaction.tsx +++ b/app/lib/patient/saveAppointmentTransaction.tsx @@ -1,6 +1,4 @@ -"use server"; -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function saveAppointmentTransaction( transaction_id: string | null, @@ -21,20 +19,14 @@ export default async function saveAppointmentTransaction( status, }; - const session = getSessionToken(); - const serverUrl = getBaseUrl(); - - const headers = { - Authorization: `Bearer ${session}`, - }; + const endpoint = "/api/transactions"; try { - await fetch(`${serverUrl}/api/transactions`, { + await fetchHandler(endpoint, { method: "POST", body: JSON.stringify(transactionData), - headers, }); } catch (error) { - console.error("Error recording appointment transaction :", error); + console.error("Error recording appointment transaction:", error); } } From 0be267af0b57c8bd9e2caf0f2c3db8893043eec3 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:17:51 +0530 Subject: [PATCH 17/41] =?UTF-8?q?refactor(receptionist):=20utilize=20fetch?= =?UTF-8?q?Handler,=20removing=20getBaseUrl=20=F0=9F=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/receptionist/approveAppointment.tsx | 32 ++++--------------- .../receptionist/getPendingAppointments.tsx | 26 ++------------- app/lib/receptionist/getReceptionistData.tsx | 22 ++----------- app/lib/receptionist/scanQrCode.tsx | 4 +-- 4 files changed, 15 insertions(+), 69 deletions(-) diff --git a/app/lib/receptionist/approveAppointment.tsx b/app/lib/receptionist/approveAppointment.tsx index 2e3337f7..c743d919 100644 --- a/app/lib/receptionist/approveAppointment.tsx +++ b/app/lib/receptionist/approveAppointment.tsx @@ -1,33 +1,15 @@ -"use server"; - -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function approveAppointment(patientId: string) { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/receptionist/appointments/approve"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const response = await fetch( - `${serverUrl}/api/receptionist/appointments/approve`, - { - method: "POST", - headers, - body: JSON.stringify({ patient_id: patientId }), - } - ); - - if (!response.ok) { - throw new Error( - `Failed to approve appointment: ${response.status} - ${response.statusText}` - ); - } + const result = await fetchHandler(endpoint, { + method: "POST", + body: JSON.stringify({ patient_id: patientId }), + }); - const res = await response.json(); - return res; + return result; } catch (error) { console.error("Error approving appointment:", error); throw error; diff --git a/app/lib/receptionist/getPendingAppointments.tsx b/app/lib/receptionist/getPendingAppointments.tsx index 8a0bd296..45bd7209 100644 --- a/app/lib/receptionist/getPendingAppointments.tsx +++ b/app/lib/receptionist/getPendingAppointments.tsx @@ -1,30 +1,10 @@ -"use server"; - -import { getSessionToken } from "../sessions/sessionUtils"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function getPendingAppointments() { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/receptionist/appointments/pending"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const res = await fetch( - `${serverUrl}/api/receptionist/appointments/pending`, - { - headers, - } - ); - - if (!res.ok) { - throw new Error( - `Failed to fetch pending appointments: ${res.status} - ${res.statusText}` - ); - } - - const receptionistData = await res.json(); + const receptionistData = await fetchHandler(endpoint, {}); return receptionistData; } catch (error) { diff --git a/app/lib/receptionist/getReceptionistData.tsx b/app/lib/receptionist/getReceptionistData.tsx index 8f3c485d..89f3bbb3 100644 --- a/app/lib/receptionist/getReceptionistData.tsx +++ b/app/lib/receptionist/getReceptionistData.tsx @@ -1,29 +1,13 @@ -"use server"; - -import getBaseUrl from "@utils/getBaseUrl"; -import { getSessionToken } from "../sessions/sessionUtils"; +import fetchHandler from "@utils/fetchHandler"; export default async function getReceptionistData() { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/receptionist"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const res = await fetch(`${serverUrl}/api/receptionist`, { - headers, + const receptionistData = await fetchHandler(endpoint, { cache: "no-cache", }); - if (!res.ok) { - throw new Error( - `Failed to fetch receptionist data: ${res.status} - ${res.statusText}` - ); - } - - const receptionistData = await res.json(); - return receptionistData; } catch (error) { console.error("Error fetching receptionist data:", error); diff --git a/app/lib/receptionist/scanQrCode.tsx b/app/lib/receptionist/scanQrCode.tsx index 272db391..645d8a98 100644 --- a/app/lib/receptionist/scanQrCode.tsx +++ b/app/lib/receptionist/scanQrCode.tsx @@ -14,8 +14,8 @@ export default async function scanQRCode(email: string) { }, }); - const msg = await res.json(); - return msg; + const message = await res.json(); + return message; } catch (error) { console.error("Error fetching data:", error); } From eeb279a1e0174a6fd69fc7acdad4530656e22e5f Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:18:02 +0530 Subject: [PATCH 18/41] =?UTF-8?q?chore(update-profile):=20refactor=20to=20?= =?UTF-8?q?use=20fetchHandler,=20eliminating=20base=20URL=20=F0=9F=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/update-profile/index.ts | 2 -- app/lib/update-profile/reset_password.tsx | 27 ++++++------------- app/lib/update-profile/update_address.tsx | 16 +++-------- .../update-profile/update_personal_info.tsx | 16 +++-------- .../update-profile/update_profile_picture.tsx | 17 ++++-------- 5 files changed, 21 insertions(+), 57 deletions(-) diff --git a/app/lib/update-profile/index.ts b/app/lib/update-profile/index.ts index 0c4d5a3d..9a8ecb4b 100644 --- a/app/lib/update-profile/index.ts +++ b/app/lib/update-profile/index.ts @@ -1,5 +1,3 @@ -"use server"; - import updateAddress from "./update_address"; import updatePersonal from "./update_personal_info"; import resetPassword from "./reset_password"; diff --git a/app/lib/update-profile/reset_password.tsx b/app/lib/update-profile/reset_password.tsx index c95fdce5..a55dc2c4 100644 --- a/app/lib/update-profile/reset_password.tsx +++ b/app/lib/update-profile/reset_password.tsx @@ -1,31 +1,20 @@ -import getBaseUrl from "@utils/getBaseUrl"; -import { getSessionToken } from "../sessions/sessionUtils"; +import fetchHandler from "@utils/fetchHandler"; export default async function resetPassword( currentPassword: string, newPassword: string ) { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); - - const headers = { - Authorization: `Bearer ${session}`, - }; + const endpoint = "/api/update-profile/reset-password"; try { - const response = await fetch( - `${serverUrl}/api/update-profile/reset-password`, - { - method: "PUT", - headers, - body: JSON.stringify({ currentPassword, newPassword }), - } - ); - - const result = await response.json(); + const result = await fetchHandler(endpoint, { + method: "PUT", + body: JSON.stringify({ currentPassword, newPassword }), + }); return result; } catch (error) { - console.error("Error updating password :", error); + console.error("Error updating password:", error); + throw error; } } diff --git a/app/lib/update-profile/update_address.tsx b/app/lib/update-profile/update_address.tsx index 87d20c3e..a0b8c651 100644 --- a/app/lib/update-profile/update_address.tsx +++ b/app/lib/update-profile/update_address.tsx @@ -1,25 +1,17 @@ -import getBaseUrl from "@utils/getBaseUrl"; -import { getSessionToken } from "../sessions/sessionUtils"; +import fetchHandler from "@utils/fetchHandler"; export default async function updateAddress(filteredFields: any) { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); - - const headers = { - Authorization: `Bearer ${session}`, - }; + const endpoint = "/api/update-profile/address"; try { - const response = await fetch(`${serverUrl}/api/update-profile/address`, { + const result = await fetchHandler(endpoint, { method: "PUT", - headers, body: JSON.stringify(filteredFields), }); - const result = await response.json(); - return result; } catch (error) { console.error("Error updating address information:", error); + throw error; } } diff --git a/app/lib/update-profile/update_personal_info.tsx b/app/lib/update-profile/update_personal_info.tsx index 2ef27e24..5617db9c 100644 --- a/app/lib/update-profile/update_personal_info.tsx +++ b/app/lib/update-profile/update_personal_info.tsx @@ -1,25 +1,17 @@ -import getBaseUrl from "@utils/getBaseUrl"; -import { getSessionToken } from "../sessions/sessionUtils"; +import fetchHandler from "@utils/fetchHandler"; export default async function updatePersonal(filteredFields: any) { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); - - const headers = { - Authorization: `Bearer ${session}`, - }; + const endpoint = "/api/update-profile/personal"; try { - const response = await fetch(`${serverUrl}/api/update-profile/personal`, { + const result = await fetchHandler(endpoint, { method: "PUT", - headers, body: JSON.stringify(filteredFields), }); - const result = await response.json(); - return result; } catch (error) { console.error("Error updating personal information:", error); + throw error; } } diff --git a/app/lib/update-profile/update_profile_picture.tsx b/app/lib/update-profile/update_profile_picture.tsx index d4982b5c..21bb3880 100644 --- a/app/lib/update-profile/update_profile_picture.tsx +++ b/app/lib/update-profile/update_profile_picture.tsx @@ -1,25 +1,18 @@ -import getBaseUrl from "@utils/getBaseUrl"; -import { getSessionToken } from "../sessions/sessionUtils"; +import fetchHandler from "@utils/fetchHandler"; async function updateProfilePicture(profile_url: string) { - const session = getSessionToken(); - const serverUrl = getBaseUrl(); + const endpoint = "/api/update-profile/profile"; - const headers = { - Authorization: `Bearer ${session}`, - }; try { - const res = await fetch(`${serverUrl}/api/update-profile/profile`, { + const result = await fetchHandler(endpoint, { method: "PUT", - headers, body: JSON.stringify(profile_url), }); - const isProfileUpdated = await res.json(); - - return isProfileUpdated; + return result; } catch (error) { console.error("Error updating profile picture:", error); + throw error; } } From 0afb25c7f643d7bfe75ff62885d176c3f1fd57bf Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:19:10 +0530 Subject: [PATCH 19/41] =?UTF-8?q?refactor:=20replace=20'msg'=20with=20'mes?= =?UTF-8?q?sage'=20in=20various=20components=20=F0=9F=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(pages)/(auth)/signup/page.tsx | 2 +- app/(pages)/patient/components/BookAppointment/index.tsx | 2 +- app/components/ProfileSettings/index.tsx | 6 +++--- app/lib/actions.ts | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/(pages)/(auth)/signup/page.tsx b/app/(pages)/(auth)/signup/page.tsx index 31e3ff7d..29d1a2a1 100644 --- a/app/(pages)/(auth)/signup/page.tsx +++ b/app/(pages)/(auth)/signup/page.tsx @@ -99,7 +99,7 @@ export default function Signup() { toast.dismiss(); if (signUpSuccess.failure) { - toast.error(signUpSuccess.msg); + toast.error(signUpSuccess.message); } else { const userRole = formData.get("role"); diff --git a/app/(pages)/patient/components/BookAppointment/index.tsx b/app/(pages)/patient/components/BookAppointment/index.tsx index 395586e8..b31d50d4 100644 --- a/app/(pages)/patient/components/BookAppointment/index.tsx +++ b/app/(pages)/patient/components/BookAppointment/index.tsx @@ -255,7 +255,7 @@ export default function BookAppointment({ return; } clearSelected(); - toast.success(response.msg); + toast.success(response.message); } function clearSelected() { diff --git a/app/components/ProfileSettings/index.tsx b/app/components/ProfileSettings/index.tsx index 3b512d18..1e504304 100644 --- a/app/components/ProfileSettings/index.tsx +++ b/app/components/ProfileSettings/index.tsx @@ -193,7 +193,7 @@ export default function ProfileSettings({ user }: ProfileSettingsProps) { toast.dismiss(); - if (response.msg) { + if (response.message) { toast.success("Personal information updated successfully"); } else { toast.error("Failed to update personal information"); @@ -239,7 +239,7 @@ export default function ProfileSettings({ user }: ProfileSettingsProps) { toast.dismiss(); - if (response.msg) { + if (response.message) { toast.success("Address information updated successfully"); } else { toast.error("Failed to update address information"); @@ -263,7 +263,7 @@ export default function ProfileSettings({ user }: ProfileSettingsProps) { toast.dismiss(); - if (response.msg) { + if (response.message) { toast.success("Password updated successfully"); setCurrentPassword(""); setNewPassword(""); diff --git a/app/lib/actions.ts b/app/lib/actions.ts index 50868d21..6a7e933b 100644 --- a/app/lib/actions.ts +++ b/app/lib/actions.ts @@ -20,7 +20,7 @@ export async function loginAction(formData: FormData) { const userData = await response.json(); if (!response.ok) { - return { msg: userData.error, unauthorized: true }; + return { message: userData.error, unauthorized: true }; } else return userData; } catch (error) { console.error("Login failed:", error); @@ -49,7 +49,7 @@ export async function signupAction(formData: FormData) { const userData = await response.json(); if (!response.ok) { - return { msg: userData.error, failure: true }; + return { message: userData.error, failure: true }; } else return userData; } catch (error) { console.error("Signup failed:", error); From b6065527715176d27600d2189fcf6b48d8f8e28e Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:20:42 +0530 Subject: [PATCH 20/41] =?UTF-8?q?chore:=20restructure=20exports=20?= =?UTF-8?q?=F0=9F=93=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 app/lib/index.ts diff --git a/app/lib/index.ts b/app/lib/index.ts new file mode 100644 index 00000000..6d3d9330 --- /dev/null +++ b/app/lib/index.ts @@ -0,0 +1,7 @@ +import authenticateUser from "./auth/authenticateUser"; +import sendEmail from "./sendemail"; +import sendNotification from "./novu"; +import verifyOtp from "./verifyOtp"; + +export * from "./emails/templates"; +export { authenticateUser, sendEmail, sendNotification, verifyOtp }; From 3008bcf4cc2402d61c11b6766c0d37f5968e5976 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:20:58 +0530 Subject: [PATCH 21/41] =?UTF-8?q?refactor:=20replace=20fetch=20implementat?= =?UTF-8?q?ion=20in=20verifyOtp=20with=20fetchHandler=20=F0=9F=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/verifyOtp.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/app/lib/verifyOtp.ts b/app/lib/verifyOtp.ts index 31327a61..49cf99b6 100644 --- a/app/lib/verifyOtp.ts +++ b/app/lib/verifyOtp.ts @@ -1,4 +1,4 @@ -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; export default async function verifyOtp( usernameOrEmail: string, @@ -6,14 +6,11 @@ export default async function verifyOtp( action: string, otp: string ) { - const serverUrl = getBaseUrl(); + const endpoint = "/api/auth/verifyotp"; try { - const response = await fetch(`${serverUrl}/api/auth/verifyotp`, { + const result = await fetchHandler(endpoint, { method: "POST", - headers: { - "Content-Type": "application/json", - }, body: JSON.stringify({ otp, usernameOrEmail, @@ -21,9 +18,10 @@ export default async function verifyOtp( action, }), }); - const data = await response.json(); - return data; + + return result; } catch (error) { - console.error("Error:", error); + console.error("Error verifying OTP:", error); + throw error; } } From cbb5f0e8add0dd3f9ed7fd2c0f76b082c4cdecc9 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:21:33 +0530 Subject: [PATCH 22/41] =?UTF-8?q?refactor:=20replace=20'msg'=20with=20'mes?= =?UTF-8?q?sage'=20in=20various=20components=20=F0=9F=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/logs/index.tsx | 7 ++++--- app/lib/novu/index.tsx | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/lib/logs/index.tsx b/app/lib/logs/index.tsx index 9c21f8a5..f3e1a26d 100644 --- a/app/lib/logs/index.tsx +++ b/app/lib/logs/index.tsx @@ -1,7 +1,6 @@ import dbConfig from "@utils/db"; -import sendEmail from "../sendemail"; import { render } from "@react-email/render"; -import { UserActivityTemplate } from "../emails/templates"; +import { sendEmail, UserActivityTemplate } from "../index"; import { UserLog } from "@models/index"; import { userAgent } from "next/server"; @@ -47,7 +46,9 @@ async function logUserActivity(userlog: userlogType, req: Request) { }, }); } catch (error: any) { - console.error(`While logging user activities got an error : ${error.msg}`); + console.error( + `While logging user activities got an error : ${error.message}` + ); } } diff --git a/app/lib/novu/index.tsx b/app/lib/novu/index.tsx index e82a0029..57acf9bf 100644 --- a/app/lib/novu/index.tsx +++ b/app/lib/novu/index.tsx @@ -2,7 +2,7 @@ import { Novu } from "@novu/node"; export default async function sendNotification( subscriberId: string, - msg: string, + message: string, type: string ) { try { @@ -15,7 +15,7 @@ export default async function sendNotification( subscriberId, }, payload: { - msg, + message, type, }, }); From 19af0c25f9d628b88e6638d6a48032c77b4c7435 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Mon, 23 Sep 2024 23:21:50 +0530 Subject: [PATCH 23/41] remove createOrderId --- app/lib/razorpay/createOrderId.ts | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 app/lib/razorpay/createOrderId.ts diff --git a/app/lib/razorpay/createOrderId.ts b/app/lib/razorpay/createOrderId.ts deleted file mode 100644 index 4d6d4013..00000000 --- a/app/lib/razorpay/createOrderId.ts +++ /dev/null @@ -1,25 +0,0 @@ -// const createOrderId = async (amount: string) => { -// try { -// const response = await fetch("/api/payment/create-order", { -// method: "POST", -// headers: { -// "Content-Type": "application/json", -// }, -// body: JSON.stringify({ -// amount: parseFloat(amount) * 100, -// currency: "INR", -// }), -// }); - -// if (!response.ok) { -// throw new Error("Network response was not ok"); -// } - -// const data = await response.json(); -// return data.orderId; -// } catch (error) { -// console.error("There was a problem with your fetch operation:", error); -// } -// }; - -// export default createOrderId; From efc7129dab516e97436a8b5267b841e8d047adb2 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:31:24 +0530 Subject: [PATCH 24/41] =?UTF-8?q?feat(session-expired):=20add=20suspense?= =?UTF-8?q?=20fallback=20for=20session=20expired=20page=20=E2=9A=A0?= =?UTF-8?q?=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(pages)/session-expired/page.tsx | 85 ++++++++++++++++------------ 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/app/(pages)/session-expired/page.tsx b/app/(pages)/session-expired/page.tsx index 62d86211..9603fa2e 100644 --- a/app/(pages)/session-expired/page.tsx +++ b/app/(pages)/session-expired/page.tsx @@ -1,15 +1,30 @@ "use client"; -import React, { useState, useEffect, Suspense } from "react"; -import { useRouter, useSearchParams } from "next/navigation"; -import { Image } from "@nextui-org/react"; +import React, { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import Image from "next/image"; +import { Suspense } from "react"; import SpinnerLoader from "@components/SpinnerLoader"; export default function SessionExpired() { + return ( + }> + + + ); +} + +function SessionExpiredContent() { const router = useRouter(); - const searchParams = useSearchParams(); const [secondsRemaining, setSecondsRemaining] = useState(5); - const role = searchParams.get("role"); + const [role, setRole] = useState(null); + + useEffect(() => { + // fetch the role from URL parameters + const params = new URLSearchParams(window.location.search); + const roleParam = params.get("role"); + setRole(roleParam); + }, []); useEffect(() => { if (secondsRemaining <= 0) { @@ -30,36 +45,36 @@ export default function SessionExpired() { }; return ( - }> -
-
- error-image -
-
-

SESSION EXPIRED

-

- {secondsRemaining > 0 ? ( - <> - You will be redirected to the login page in {secondsRemaining}{" "} - second{secondsRemaining !== 1 ? "s" : ""}.{" "} - - ) : ( - "Redirecting to login page... " - )} - {" "} - if not redirected. -

-
+
+
+ error-image
- +
+

SESSION EXPIRED

+

+ {secondsRemaining > 0 ? ( + <> + You will be redirected to the login page in {secondsRemaining}{" "} + second{secondsRemaining !== 1 ? "s" : ""}.{" "} + + ) : ( + "Redirecting to login page... " + )} + {" "} + if not redirected. +

+
+
); } From 3a72f1277f4666fa4d20de03ff813bf81ebb5aed Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:34:16 +0530 Subject: [PATCH 25/41] =?UTF-8?q?chore:=20refactor=20types=20and=20API=20m?= =?UTF-8?q?ethods=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Moved and reorganized types and interfaces for better structure - Updated API calling methods to improve consistency across roles - Applied changes for auth, admin, doctor, patient, receptionist, and hospital modules --- app/(pages)/(auth)/login/page.tsx | 11 +++--- app/(pages)/(auth)/signup/page.tsx | 11 +++--- app/(pages)/admin/add-admin/page.tsx | 5 ++- .../admin/components/LoginForm/index.tsx | 11 +++--- app/(pages)/admin/hospitals/[id]/page.tsx | 26 +++----------- app/(pages)/admin/hospitals/page.tsx | 18 +--------- app/(pages)/admin/layout.tsx | 3 +- app/(pages)/admin/transactions/page.tsx | 3 +- app/(pages)/doctor/layout.tsx | 3 +- app/(pages)/hospital/layout.tsx | 3 +- app/(pages)/patient/appointments/page.tsx | 3 +- .../components/BookAppointment/index.tsx | 36 +++++++------------ .../components/MedicalDetails/index.tsx | 6 +--- .../components/PaymentDetails/index.tsx | 19 +--------- app/(pages)/patient/layout.tsx | 3 +- app/(pages)/patient/page.tsx | 6 ++-- app/(pages)/patient/qrcode/page.tsx | 3 +- app/(pages)/patient/settings/page.tsx | 3 +- .../components/PatientTabs/index.tsx | 6 ++-- app/(pages)/receptionist/page.tsx | 19 ++-------- 20 files changed, 58 insertions(+), 140 deletions(-) diff --git a/app/(pages)/(auth)/login/page.tsx b/app/(pages)/(auth)/login/page.tsx index e8dfaf97..02cf5760 100644 --- a/app/(pages)/(auth)/login/page.tsx +++ b/app/(pages)/(auth)/login/page.tsx @@ -85,10 +85,11 @@ export default function Login() { position: "bottom-center", }); - const isValidUser = await loginAction(formData); + const response = await loginAction(formData); toast.dismiss(); - if (isValidUser?.unauthorized) { - toast.error("Invalid username | email or password. Please try again."); + + if (response.error) { + toast.error(`${response.error.message}`); } else { const userRole = formData.get("role"); setUserData({ @@ -103,7 +104,9 @@ export default function Login() { setShowOtp(true); } } catch (error) { - toast.error("Invalid username | email or password. Please try again."); + toast.dismiss(); + console.error("Login failed:", error); + toast.error("An unexpected error occurred. Please try again later."); } } diff --git a/app/(pages)/(auth)/signup/page.tsx b/app/(pages)/(auth)/signup/page.tsx index 29d1a2a1..78371ba3 100644 --- a/app/(pages)/(auth)/signup/page.tsx +++ b/app/(pages)/(auth)/signup/page.tsx @@ -95,11 +95,11 @@ export default function Signup() { position: "bottom-center", }); - const signUpSuccess = await signupAction(formData); + const response = await signupAction(formData); toast.dismiss(); - if (signUpSuccess.failure) { - toast.error(signUpSuccess.message); + if (response.error) { + toast.error(`${response.error.message}`); } else { const userRole = formData.get("role"); @@ -119,8 +119,9 @@ export default function Signup() { setShowOtp(true); } } catch (error) { - console.error("Error signing up"); - toast.error("Error signing up. Please try again!"); + toast.dismiss(); + console.error("Signup failed:", error); + toast.error("An unexpected error occurred. Please try again later."); } } diff --git a/app/(pages)/admin/add-admin/page.tsx b/app/(pages)/admin/add-admin/page.tsx index 54440e09..edb9a4ee 100644 --- a/app/(pages)/admin/add-admin/page.tsx +++ b/app/(pages)/admin/add-admin/page.tsx @@ -66,7 +66,10 @@ export default function AddAdmin() { const result = await addAdmin(formDataToSend); if (result.error) { - toast.error(result.error, { id: toastId, position: "top-center" }); + toast.error(result.error.message, { + id: toastId, + position: "top-center", + }); } else { toast.success("Admin added successfully!", { id: toastId }); setFormData({ diff --git a/app/(pages)/admin/components/LoginForm/index.tsx b/app/(pages)/admin/components/LoginForm/index.tsx index 7a6216e7..820f9f93 100644 --- a/app/(pages)/admin/components/LoginForm/index.tsx +++ b/app/(pages)/admin/components/LoginForm/index.tsx @@ -69,11 +69,12 @@ export default function LoginForm() { try { toast.loading("Please wait ...", { position: "bottom-center" }); - const isValidUser = await loginAction(formData); + + const response = await loginAction(formData); toast.dismiss(); - if (isValidUser?.unauthorized) { - toast.error("Invalid username or email & password. Please try again."); + if (response.error) { + toast.error(`${response.error.message}`); } else { setUserData({ usernameOrEmail, @@ -86,7 +87,9 @@ export default function LoginForm() { setShowOtp(true); } } catch (error) { - toast.error("An error occurred. Please try again."); + toast.dismiss(); + console.error("Admin Login failed:", error); + toast.error("An unexpected error occurred. Please try again later."); } } diff --git a/app/(pages)/admin/hospitals/[id]/page.tsx b/app/(pages)/admin/hospitals/[id]/page.tsx index 1c90de33..337d3a31 100644 --- a/app/(pages)/admin/hospitals/[id]/page.tsx +++ b/app/(pages)/admin/hospitals/[id]/page.tsx @@ -23,35 +23,17 @@ import { AiOutlineStop as BlockIcon, } from "react-icons/ai"; import SpinnerLoader from "@components/SpinnerLoader"; -import { getHospitalDetails } from "@/lib/admin"; +import { getHospitalDetails } from "@lib/admin"; import { FaExclamationCircle } from "react-icons/fa"; - -interface UserData { - id: string; - name: string; - role: string; - username: string; - profile: string; - gender: string; - contact: string; - city: string; - state: string; -} - -interface PaginationMetadata { - currentPage: number; - pageSize: number; - totalPages: number; - totalCount: number; -} +import { HospitalUserData, PaginationMetadata } from "@pft-types/admin"; function UserManagement({ params }: { params: { id: string } }) { - const [users, setUsers] = useState([]); + const [users, setUsers] = useState([]); const [loading, setLoading] = useState(false); const [searchTerm, setSearchTerm] = useState(""); const [selectedRole, setSelectedRole] = useState("All"); - const [currentUser, setCurrentUser] = useState(null); + const [currentUser, setCurrentUser] = useState(null); const [pagination, setPagination] = useState({ currentPage: 1, pageSize: 10, diff --git a/app/(pages)/admin/hospitals/page.tsx b/app/(pages)/admin/hospitals/page.tsx index 0a64c9d5..62ba9b87 100644 --- a/app/(pages)/admin/hospitals/page.tsx +++ b/app/(pages)/admin/hospitals/page.tsx @@ -24,23 +24,7 @@ import SpinnerLoader from "@components/SpinnerLoader"; import Link from "next/link"; import { getHospitalsList } from "@lib/admin/getHospitals"; import { FaExclamationCircle } from "react-icons/fa"; - -interface HospitalData { - id: string; - name: string; - username: string; - profile: string; - contact: string; - city: string; - state: string; -} - -interface PaginationMetadata { - currentPage: number; - pageSize: number; - totalPages: number; - totalCount: number; -} +import { HospitalData, PaginationMetadata } from "@pft-types/admin"; const HospitalManagement: React.FC = () => { const [hospitals, setHospitals] = useState([]); diff --git a/app/(pages)/admin/layout.tsx b/app/(pages)/admin/layout.tsx index 7055be8b..9fc5de52 100644 --- a/app/(pages)/admin/layout.tsx +++ b/app/(pages)/admin/layout.tsx @@ -1,6 +1,5 @@ import type { Metadata } from "next"; import { Sidebar, Header } from "./components"; -import { Admin } from "@pft-types/index"; import { getAdminData } from "@lib/admin"; export const metadata: Metadata = { @@ -13,7 +12,7 @@ export default async function AdminLayout({ }: Readonly<{ children: React.ReactNode; }>) { - const admin: Admin = await getAdminData(); + const admin = await getAdminData(); return (
diff --git a/app/(pages)/admin/transactions/page.tsx b/app/(pages)/admin/transactions/page.tsx index 8d02f316..5357748f 100644 --- a/app/(pages)/admin/transactions/page.tsx +++ b/app/(pages)/admin/transactions/page.tsx @@ -1,9 +1,8 @@ -import { TransactionDetails } from "@pft-types/index"; import Transactions from "../components/Transactions"; import getTransactions from "@lib/admin/getTransactions"; export default async function TransactionsPage() { - const transactions: TransactionDetails[] = await getTransactions(); + const transactions = await getTransactions(); return ; } diff --git a/app/(pages)/doctor/layout.tsx b/app/(pages)/doctor/layout.tsx index 84b4a37c..4fffd0e5 100644 --- a/app/(pages)/doctor/layout.tsx +++ b/app/(pages)/doctor/layout.tsx @@ -1,6 +1,5 @@ import { Sidebar, Headbar } from "@components/index"; import { getDoctorData } from "@lib/doctor"; -import { Doctor } from "@pft-types/index"; import type { Metadata } from "next"; @@ -14,7 +13,7 @@ export default async function DoctorLayout({ }: Readonly<{ children: React.ReactNode; }>) { - const doctor: Doctor = await getDoctorData(); + const doctor = await getDoctorData(); return (
diff --git a/app/(pages)/hospital/layout.tsx b/app/(pages)/hospital/layout.tsx index cb1ccd73..71b8a414 100644 --- a/app/(pages)/hospital/layout.tsx +++ b/app/(pages)/hospital/layout.tsx @@ -1,6 +1,5 @@ import { Sidebar, Headbar } from "@components/index"; import { getHospitalData } from "@lib/hospital"; -import { Hospital } from "@pft-types/index"; import type { Metadata } from "next"; @@ -14,7 +13,7 @@ export default async function HospitalLayout({ }: Readonly<{ children: React.ReactNode; }>) { - const hospital: Hospital = await getHospitalData(); + const hospital = await getHospitalData(); return (
diff --git a/app/(pages)/patient/appointments/page.tsx b/app/(pages)/patient/appointments/page.tsx index 1cecaccb..ec2430eb 100644 --- a/app/(pages)/patient/appointments/page.tsx +++ b/app/(pages)/patient/appointments/page.tsx @@ -1,10 +1,9 @@ import { Card, Image } from "@nextui-org/react"; import { BookAppointment } from "../components"; -import { Patient } from "@pft-types/index"; import { getPatientData } from "@lib/patient"; export default async function Appointments() { - const patient: Patient = await getPatientData(); + const patient = await getPatientData(); const { _id, firstname, lastname, email } = patient; diff --git a/app/(pages)/patient/components/BookAppointment/index.tsx b/app/(pages)/patient/components/BookAppointment/index.tsx index b31d50d4..c4acff75 100644 --- a/app/(pages)/patient/components/BookAppointment/index.tsx +++ b/app/(pages)/patient/components/BookAppointment/index.tsx @@ -29,18 +29,10 @@ import { getHospitals, getStates, } from "@lib/patient/misc"; - -type Hospital = { - hospital_id: string; - hospital_name: string; - appointment_charge: string; -}; - -type BookAppointmentProps = { - patientId: string; - name: string; - email: string; -}; +import { + BookAppointmentHospital, + BookAppointmentProps, +} from "@pft-types/patient"; export default function BookAppointment({ patientId, @@ -51,11 +43,12 @@ export default function BookAppointment({ const [selectedState, setSelectedState] = useState(""); const [cities, setCities] = useState([]); const [selectedCity, setSelectedCity] = useState(""); - const [selectedHospital, setSelectedHospital] = useState({ - hospital_id: "", - hospital_name: "", - appointment_charge: "", - }); + const [selectedHospital, setSelectedHospital] = + useState({ + hospital_id: "", + hospital_name: "", + appointment_charge: "", + }); const [selectedDisease, setSelectedDisease] = useState(""); const [loadingStates, setLoadingStates] = useState(false); const [loadingCities, setLoadingCities] = useState(false); @@ -64,9 +57,7 @@ export default function BookAppointment({ const [isOpenPopover, setIsOpenPopover] = useState(false); const [isOpenHospitalPopover, setIsOpenHospitalPopover] = useState(false); const [isOpenDiseasePopover, setIsOpenDiseasePopover] = useState(false); - const [hospitals, setHospitals] = useState< - { hospital_id: string; hospital_name: string; appointment_charge: string }[] - >([]); + const [hospitals, setHospitals] = useState([]); const [diseases, setDiseases] = useState([]); const [additionalNote, setAdditionalNote] = useState(""); const [noteError, setNoteError] = useState(""); @@ -171,9 +162,8 @@ export default function BookAppointment({ function handleHospitalChange(e: ChangeEvent): void { const selectedId = e.target.value; - const selectedHospitalObj: Hospital | undefined = hospitals.find( - (hospital) => hospital.hospital_id === selectedId - ); + const selectedHospitalObj: BookAppointmentHospital | undefined = + hospitals.find((hospital) => hospital.hospital_id === selectedId); if (selectedHospitalObj) { setSelectedHospital({ diff --git a/app/(pages)/patient/components/MedicalDetails/index.tsx b/app/(pages)/patient/components/MedicalDetails/index.tsx index a97c5060..70e68b6a 100644 --- a/app/(pages)/patient/components/MedicalDetails/index.tsx +++ b/app/(pages)/patient/components/MedicalDetails/index.tsx @@ -1,6 +1,6 @@ "use client"; -import { MedicalHistory } from "@pft-types/index"; +import { MedicalDetailsProps } from "@pft-types/index"; import { Chip, Spinner, @@ -14,10 +14,6 @@ import { } from "@nextui-org/react"; import { getFormattedDate } from "@utils/getDate"; -type MedicalDetailsProps = { - medicalDetails: MedicalHistory[]; -}; - export default function MedicalDetails({ medicalDetails, }: MedicalDetailsProps) { diff --git a/app/(pages)/patient/components/PaymentDetails/index.tsx b/app/(pages)/patient/components/PaymentDetails/index.tsx index ef6fa83f..af76f961 100644 --- a/app/(pages)/patient/components/PaymentDetails/index.tsx +++ b/app/(pages)/patient/components/PaymentDetails/index.tsx @@ -10,24 +10,7 @@ import { TransactionsTable, } from "@components/index"; import useFilterTransaction from "@hooks/useFilterTransaction"; - -type Hospital = { - name: string; - profile: string; -}; - -type Payment = { - hospital: Hospital; - disease: string; - description: string; - date: string; - amount: number; - status: "Success" | "Failed"; -}; - -type PaymentDetailsProps = { - paymentHistory: Payment[]; -}; +import { Payment, PaymentDetailsProps } from "@pft-types/patient"; const statusColorMap: any = { Failed: "danger", diff --git a/app/(pages)/patient/layout.tsx b/app/(pages)/patient/layout.tsx index 184e38b3..236da89c 100644 --- a/app/(pages)/patient/layout.tsx +++ b/app/(pages)/patient/layout.tsx @@ -1,6 +1,5 @@ import Script from "next/script"; import { Sidebar, Headbar } from "@components/index"; -import { Patient } from "@pft-types/index"; import { getPatientData } from "@lib/patient"; import type { Metadata } from "next"; @@ -15,7 +14,7 @@ export default async function PatientLayout({ }: Readonly<{ children: React.ReactNode; }>) { - const patient: Patient = await getPatientData(); + const patient = await getPatientData(); return (
diff --git a/app/(pages)/patient/page.tsx b/app/(pages)/patient/page.tsx index 21659f56..b45f6418 100644 --- a/app/(pages)/patient/page.tsx +++ b/app/(pages)/patient/page.tsx @@ -5,14 +5,12 @@ import { MedicineDetails, HealthConditions, } from "./components"; -import { Patient, bookedAppointments } from "@pft-types/index"; import { getPatientData, getUpcomingAppointments } from "@lib/patient"; export default async function PatientPage() { - const patient: Patient = await getPatientData(); + const patient = await getPatientData(); - const upcomingAppointments: bookedAppointments = - await getUpcomingAppointments(); + const upcomingAppointments = await getUpcomingAppointments(); return (
diff --git a/app/(pages)/patient/qrcode/page.tsx b/app/(pages)/patient/qrcode/page.tsx index ba9aeae5..b86d771b 100644 --- a/app/(pages)/patient/qrcode/page.tsx +++ b/app/(pages)/patient/qrcode/page.tsx @@ -1,10 +1,9 @@ import { getPatientData } from "@lib/patient"; -import { Patient } from "@pft-types/index"; import { Card, Link, User } from "@nextui-org/react"; import { QRCode } from "../components"; export default async function QRCodePage() { - const patient: Patient = await getPatientData(); + const patient = await getPatientData(); return ( diff --git a/app/(pages)/receptionist/components/PatientTabs/index.tsx b/app/(pages)/receptionist/components/PatientTabs/index.tsx index c005fb64..dd266af0 100644 --- a/app/(pages)/receptionist/components/PatientTabs/index.tsx +++ b/app/(pages)/receptionist/components/PatientTabs/index.tsx @@ -54,11 +54,9 @@ export default function PatientTabs({ pendingAppointments }: PatientTabsProps) { try { const response = await approveAppointment(selectedPatient?._id ?? ""); - if (response.error) { - throw new Error(response.error); + if (response) { + toast.success("Appointment approved successfully"); } - - toast.success("Appointment approved successfully"); } catch (error) { console.error("Error approving appointment:", error); } diff --git a/app/(pages)/receptionist/page.tsx b/app/(pages)/receptionist/page.tsx index 67d38027..246878df 100644 --- a/app/(pages)/receptionist/page.tsx +++ b/app/(pages)/receptionist/page.tsx @@ -17,7 +17,6 @@ import { BsClock, BsCalendarCheck, } from "react-icons/bs"; -import { Receptionist } from "@pft-types/index"; import { getReceptionistData, getPendingAppointments } from "@lib/receptionist"; import { MonthlyVisitors, @@ -28,22 +27,8 @@ import { } from "./components/Graphs"; export default async function ReceptionistPage() { - interface PatientDetail { - id: string; - name: string; - appointmentTime: string; - reason: string; - contactNumber: string; - email?: string; - } - - interface PendingPatients { - patientDetails: PatientDetail[]; - totalCount: number; - } - - const receptionist: Receptionist = await getReceptionistData(); - const pendingPatients: PendingPatients = await getPendingAppointments(); + const receptionist = await getReceptionistData(); + const pendingPatients = await getPendingAppointments(); const pendingAppointments = pendingPatients.patientDetails.length; const approvedAppointments = receptionist.dailyCount.approved; From bb6edb5b1eba766ad0cac6af62a839e42aa30c76 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:35:01 +0530 Subject: [PATCH 26/41] =?UTF-8?q?chore:=20refactor=20API=20method=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/OtpSection/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/OtpSection/index.tsx b/app/components/OtpSection/index.tsx index 1d271fc6..6b144735 100644 --- a/app/components/OtpSection/index.tsx +++ b/app/components/OtpSection/index.tsx @@ -77,15 +77,15 @@ export default function OtpSection({ userData }: userDataType) { const handleSubmit = async () => { const otpString = otp.join(""); - const data = await verifyOtp( + const response = await verifyOtp( userData.usernameOrEmail, userData.role, userData.action, otpString ); - if (data.error) { - setShowError(data.error); + if (response.error) { + setShowError(response.error); resetOtpInputs(); } else { setShowError(""); From f43f0b4070aab39d9f04aae1548600d2449eb269 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:35:44 +0530 Subject: [PATCH 27/41] =?UTF-8?q?feat(types):=20add=20new=20types=20for=20?= =?UTF-8?q?better=20type=20safety=20=F0=9F=9B=A0=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/admin.d.ts | 29 +++++++++++++++++++++++++++++ types/index.ts | 2 +- types/patient.d.ts | 32 ++++++++++++++++++++++++++++++++ types/receptionist.d.ts | 4 ++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/types/admin.d.ts b/types/admin.d.ts index ea174d31..4ffd175b 100644 --- a/types/admin.d.ts +++ b/types/admin.d.ts @@ -79,3 +79,32 @@ export type RecentUserPaginatedResponse = { totalPages: number; totalItems: number; }; + +export interface HospitalData { + id: string; + name: string; + username: string; + profile: string; + contact: string; + city: string; + state: string; +} + +export interface HospitalUserData { + id: string; + name: string; + role: string; + username: string; + profile: string; + gender: string; + contact: string; + city: string; + state: string; +} + +export interface PaginationMetadata { + currentPage: number; + pageSize: number; + totalPages: number; + totalCount: number; +} diff --git a/types/index.ts b/types/index.ts index b8d627ae..1a2a451e 100644 --- a/types/index.ts +++ b/types/index.ts @@ -88,4 +88,4 @@ export type SecurityBody = { export * from "./admin"; export * from "./patient"; -// export * from "./receptionist"; +export * from "./receptionist"; diff --git a/types/patient.d.ts b/types/patient.d.ts index 16010fc4..6c4ec889 100644 --- a/types/patient.d.ts +++ b/types/patient.d.ts @@ -38,6 +38,22 @@ export type bookingAppointment = { note: string; }; +export type BookAppointmentHospital = { + hospital_id: string; + hospital_name: string; + appointment_charge: string; +}; + +export type BookAppointmentProps = { + patientId: string; + name: string; + email: string; +}; + +export type MedicalDetailsProps = { + medicalDetails: MedicalHistory[]; +}; + export interface PaymentHistory { hospital: { name: string; @@ -89,3 +105,19 @@ export type BookingAppointmentType = bookingAppointment & { transaction_id: string | null; appointment_charge: string; }; + +export type Payment = { + hospital: { + name: string; + profile: string; + }; + disease: string; + description: string; + date: string; + amount: number; + status: "Success" | "Failed"; +}; + +export type PaymentDetailsProps = { + paymentHistory: Payment[]; +}; diff --git a/types/receptionist.d.ts b/types/receptionist.d.ts index e69de29b..e9627c74 100644 --- a/types/receptionist.d.ts +++ b/types/receptionist.d.ts @@ -0,0 +1,4 @@ +export interface PendingPatients { + patientDetails: PatientDetail[]; + totalCount: number; +} From 4df5484e2410999099d0107067d7ec4247cc3da7 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:36:56 +0530 Subject: [PATCH 28/41] =?UTF-8?q?feat(utils):=20create=20custom=20fetch=20?= =?UTF-8?q?handler=20with=20enhanced=20options=20=E2=9A=99=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added etchHandler to handle API requests with customizable options - Support for headers, caching, and revalidation logic - Integrated session-based authorization using Bearer tokens - Improved error handling with detailed error structure (title, message, stackTrace) --- app/utils/fetchHandler.ts | 84 ++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/app/utils/fetchHandler.ts b/app/utils/fetchHandler.ts index 763ab1e6..cc5e1634 100644 --- a/app/utils/fetchHandler.ts +++ b/app/utils/fetchHandler.ts @@ -1,6 +1,3 @@ -"use server"; - -import { getSessionToken } from "@lib/sessions/sessionUtils"; import getBaseUrl from "@utils/getBaseUrl"; type ApiRequestOptions = Omit & { @@ -8,47 +5,68 @@ type ApiRequestOptions = Omit & { revalidate?: number | false; }; -async function fetchHandler(endpoint: string, options: ApiRequestOptions = {}) { - const session = getSessionToken(); +type FetchResult = { + data?: T; + error?: { + title: string; + message: string; + stackTrace: string | null; + }; +}; + +export default async function fetchHandler( + endpoint: string, + options: ApiRequestOptions = {}, + session?: string +): Promise> { const serverUrl = getBaseUrl(); const headers = new Headers(options.headers); - headers.set("Authorization", `Bearer ${session}`); headers.set("Content-Type", "application/json"); + if (session) headers.set("Authorization", `Bearer ${session}`); - const { cache, revalidate, ...restOptions } = options; + try { + const { cache, revalidate, ...restOptions } = options; - let cacheOption: RequestCache | undefined; - if (cache) { - cacheOption = cache; - } else if (revalidate === false) { - cacheOption = "no-store"; - } else if (typeof revalidate === "number") { - cacheOption = "force-cache"; - } + let cacheOption: RequestCache | undefined; + if (cache) { + cacheOption = cache; + } else if (revalidate === false) { + cacheOption = "no-store"; + } else if (typeof revalidate === "number") { + cacheOption = "force-cache"; + } - const fetchOptions: RequestInit = { - ...restOptions, - headers, - }; + const fetchOptions: RequestInit = { + ...restOptions, + headers, + }; - if (cacheOption) { - fetchOptions.cache = cacheOption; - } + if (cacheOption) { + fetchOptions.cache = cacheOption; + } - if (typeof revalidate === "number") { - fetchOptions.next = { revalidate }; - } + if (typeof revalidate === "number") { + fetchOptions.next = { revalidate }; + } - const response = await fetch(`${serverUrl}${endpoint}`, fetchOptions); + const response = await fetch(`${serverUrl}${endpoint}`, fetchOptions); - const result = await response.json(); + const result = await response.json(); - if (!response.ok) { - throw new Error(result.error || "An error occurred"); - } + if (!response.ok) { + return { + error: { + title: result.title || "Error", + message: result.message || "An error occurred", + stackTrace: result.stackTrace || null, + }, + }; + } - return result; + return { data: result }; + } catch (error: any) { + console.error("Error in fetchHandler:", error); + throw error; + } } - -export default fetchHandler; From 14e822855a3edc0eee4368ff1578897891b79fa6 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:38:28 +0530 Subject: [PATCH 29/41] =?UTF-8?q?fix(api):=20resolve=20dynamic=20server=20?= =?UTF-8?q?usage=20error=20by=20moving=20headers,=20searchParams,=20and=20?= =?UTF-8?q?cookies=20=F0=9F=9B=A0=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/api/admin/dashboard/recent-users/route.ts | 8 ++++---- app/api/admin/hospitals/route.ts | 15 ++++++++------- app/api/admin/hospitals/users/route.ts | 19 ++++++++++--------- app/api/admin/transactions/route.ts | 2 +- app/api/patient/appointment/pending/route.ts | 2 +- app/api/patient/appointment/route.ts | 5 +++-- app/api/patient/medicalhistory/route.ts | 2 +- app/api/patient/paymenthistory/route.ts | 2 +- app/api/patient/route.ts | 3 ++- .../appointments/approve/route.ts | 11 +++++++---- .../appointments/pending/route.ts | 2 +- app/api/receptionist/route.ts | 4 ++-- app/api/receptionist/scan/route.ts | 2 +- app/api/test/route.ts | 6 ++++++ app/api/transactions/route.ts | 5 +++-- app/api/update-profile/address/route.ts | 2 +- app/api/update-profile/personal/route.ts | 2 +- app/api/update-profile/profile/route.ts | 2 +- .../update-profile/reset-password/route.ts | 2 +- 19 files changed, 55 insertions(+), 41 deletions(-) create mode 100644 app/api/test/route.ts diff --git a/app/api/admin/dashboard/recent-users/route.ts b/app/api/admin/dashboard/recent-users/route.ts index 5494021c..779d85ab 100644 --- a/app/api/admin/dashboard/recent-users/route.ts +++ b/app/api/admin/dashboard/recent-users/route.ts @@ -11,6 +11,10 @@ import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; export async function GET(request: Request): Promise { const authHeader = request.headers.get("Authorization"); + const url = new URL(request.url); + const page = parseInt(url.searchParams.get("page") || "1"); + const limit = parseInt(url.searchParams.get("limit") || "10"); + try { const { id, role } = await authenticateUser(authHeader); @@ -18,10 +22,6 @@ export async function GET(request: Request): Promise { return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); } - const url = new URL(request.url); - const page = parseInt(url.searchParams.get("page") || "1"); - const limit = parseInt(url.searchParams.get("limit") || "10"); - await dbConfig(); const oneMonthAgo = new Date(); diff --git a/app/api/admin/hospitals/route.ts b/app/api/admin/hospitals/route.ts index 17164ad6..d674e652 100644 --- a/app/api/admin/hospitals/route.ts +++ b/app/api/admin/hospitals/route.ts @@ -6,8 +6,15 @@ import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import authenticateUser from "@lib/auth/authenticateUser"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); + + // parse query parameters for pagination + const url = new URL(request.url); + const page = parseInt(url.searchParams.get("page") || "1"); + const limit = parseInt(url.searchParams.get("limit") || "10"); + const skip = (page - 1) * limit; + try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { @@ -18,12 +25,6 @@ export async function GET(request: Request) { await dbConfig(); - // Parse query parameters for pagination - const url = new URL(request.url); - const page = parseInt(url.searchParams.get("page") || "1"); - const limit = parseInt(url.searchParams.get("limit") || "10"); - const skip = (page - 1) * limit; - // Count total hospitals before applying skip and limit const totalHospitals = await Hospital.countDocuments(); let hospitals = []; diff --git a/app/api/admin/hospitals/users/route.ts b/app/api/admin/hospitals/users/route.ts index 69f2c0da..2a9eada4 100644 --- a/app/api/admin/hospitals/users/route.ts +++ b/app/api/admin/hospitals/users/route.ts @@ -6,8 +6,17 @@ import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import authenticateUser from "@lib/auth/authenticateUser"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); + + // parse query parameters for pagination + const url = new URL(request.url); + const page = parseInt(url.searchParams.get("page") || "1"); + const limit = parseInt(url.searchParams.get("limit") || "10"); + const skip = (page - 1) * limit; + + const hospitalId = url.searchParams.get("hospitalId"); + try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { @@ -16,14 +25,6 @@ export async function GET(request: Request) { await dbConfig(); - // Parse query parameters for pagination - const url = new URL(request.url); - const page = parseInt(url.searchParams.get("page") || "1"); - const limit = parseInt(url.searchParams.get("limit") || "10"); - const skip = (page - 1) * limit; - - const hospitalId = url.searchParams.get("hospitalId"); - if (!hospitalId) { return errorHandler("hospitalId is required", STATUS_CODES.BAD_REQUEST); } diff --git a/app/api/admin/transactions/route.ts b/app/api/admin/transactions/route.ts index 89536af5..ea9bcb4e 100644 --- a/app/api/admin/transactions/route.ts +++ b/app/api/admin/transactions/route.ts @@ -6,8 +6,8 @@ import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import authenticateUser from "@lib/auth/authenticateUser"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/patient/appointment/pending/route.ts b/app/api/patient/appointment/pending/route.ts index 40fd15b4..a58700b1 100644 --- a/app/api/patient/appointment/pending/route.ts +++ b/app/api/patient/appointment/pending/route.ts @@ -5,9 +5,9 @@ import { authenticateUser } from "@lib/auth"; import { Types } from "mongoose"; export async function POST(req: Request) { + const authHeader = req.headers.get("Authorization"); try { const { hospital_id }: { hospital_id: string } = await req.json(); - const authHeader = req.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); diff --git a/app/api/patient/appointment/route.ts b/app/api/patient/appointment/route.ts index a1589284..37e895cb 100644 --- a/app/api/patient/appointment/route.ts +++ b/app/api/patient/appointment/route.ts @@ -13,8 +13,8 @@ import { BookingAppointmentType } from "@pft-types/patient"; // getting patient's approved appointments export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { @@ -68,6 +68,8 @@ export async function GET(request: Request) { // booking an appointment export async function POST(req: Request) { + const authHeader = req.headers.get("Authorization"); + try { const { state, @@ -79,7 +81,6 @@ export async function POST(req: Request) { appointment_charge, }: BookingAppointmentType = await req.json(); - const authHeader = req.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/patient/medicalhistory/route.ts b/app/api/patient/medicalhistory/route.ts index 410e855d..2a5a41a7 100644 --- a/app/api/patient/medicalhistory/route.ts +++ b/app/api/patient/medicalhistory/route.ts @@ -5,8 +5,8 @@ import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import { authenticateUser } from "@lib/auth"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/patient/paymenthistory/route.ts b/app/api/patient/paymenthistory/route.ts index 305d42aa..2f0b7303 100644 --- a/app/api/patient/paymenthistory/route.ts +++ b/app/api/patient/paymenthistory/route.ts @@ -5,8 +5,8 @@ import { Types } from "mongoose"; import { authenticateUser } from "@lib/auth"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/patient/route.ts b/app/api/patient/route.ts index f705c1fc..1b131f50 100644 --- a/app/api/patient/route.ts +++ b/app/api/patient/route.ts @@ -5,8 +5,9 @@ import { authenticateUser } from "@lib/auth"; import { Types } from "mongoose"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); + try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/receptionist/appointments/approve/route.ts b/app/api/receptionist/appointments/approve/route.ts index 6352f84c..7dd9398c 100644 --- a/app/api/receptionist/appointments/approve/route.ts +++ b/app/api/receptionist/appointments/approve/route.ts @@ -6,8 +6,12 @@ import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; // get approved appointments export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); + + const { searchParams } = new URL(request.url); + const patient_id = searchParams.get("patient_id"); + try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { @@ -15,8 +19,6 @@ export async function GET(request: Request) { } const receptionist_id = new Types.ObjectId(id); - const { searchParams } = new URL(request.url); - const patient_id = searchParams.get("patient_id"); if (!patient_id) { return errorHandler("Patient ID is required", STATUS_CODES.BAD_REQUEST); @@ -40,9 +42,10 @@ export async function GET(request: Request) { // approving appointments export async function POST(request: Request) { + const authHeader = request.headers.get("Authorization"); + try { const { patient_id } = await request.json(); - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/receptionist/appointments/pending/route.ts b/app/api/receptionist/appointments/pending/route.ts index ca4cd4dc..61f18e0c 100644 --- a/app/api/receptionist/appointments/pending/route.ts +++ b/app/api/receptionist/appointments/pending/route.ts @@ -5,8 +5,8 @@ import { authenticateUser } from "@lib/auth"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/receptionist/route.ts b/app/api/receptionist/route.ts index fb4123d7..2b0a86f2 100644 --- a/app/api/receptionist/route.ts +++ b/app/api/receptionist/route.ts @@ -5,8 +5,8 @@ import Receptionist from "@models/receptionist"; import { Types } from "mongoose"; export async function GET(request: Request) { + const authHeader = request.headers.get("Authorization"); try { - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { @@ -33,7 +33,7 @@ export async function GET(request: Request) { return NextResponse.json(receptionistData, { status: 200 }); } catch (error: any) { - console.error("Error fetching receptionist data:", error); + console.error("Error fetching receptionist data route:", error); return errorHandler( error.message || "Internal Server Error", STATUS_CODES.SERVER_ERROR diff --git a/app/api/receptionist/scan/route.ts b/app/api/receptionist/scan/route.ts index fc22540e..cd48fdca 100644 --- a/app/api/receptionist/scan/route.ts +++ b/app/api/receptionist/scan/route.ts @@ -5,8 +5,8 @@ import { Types } from "mongoose"; import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; export async function POST(req: Request) { + const authHeader = req.headers.get("Authorization"); try { - const authHeader = req.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/test/route.ts b/app/api/test/route.ts new file mode 100644 index 00000000..759dc86e --- /dev/null +++ b/app/api/test/route.ts @@ -0,0 +1,6 @@ +import { setSession } from "@/lib/sessions/sessionUtils"; + +export async function GET() { + await setSession("66b72575fc219b2351f17180", "admin"); + return Response.json("OK"); +} diff --git a/app/api/transactions/route.ts b/app/api/transactions/route.ts index 0153190f..c6d646c6 100644 --- a/app/api/transactions/route.ts +++ b/app/api/transactions/route.ts @@ -3,9 +3,11 @@ import { dbConfig, errorHandler, STATUS_CODES } from "@utils/index"; import { Transaction as TransactionType } from "@pft-types/index"; import Transaction from "@models/transaction"; import { Types } from "mongoose"; +import authenticateUser from "@lib/auth/authenticateUser"; // saving transaction details in db export async function POST(req: Request) { + const authHeader = req.headers.get("Authorization"); try { const { transaction_id, @@ -17,8 +19,7 @@ export async function POST(req: Request) { status, }: TransactionType = await req.json(); - const id = req.headers.get("x-user-id"); - const role = req.headers.get("x-user-role"); + const { id, role } = await authenticateUser(authHeader); if (!id || !role) { return errorHandler("Missing user ID or role", STATUS_CODES.BAD_REQUEST); diff --git a/app/api/update-profile/address/route.ts b/app/api/update-profile/address/route.ts index cb571f06..f9cb335a 100644 --- a/app/api/update-profile/address/route.ts +++ b/app/api/update-profile/address/route.ts @@ -10,8 +10,8 @@ import { Types } from "mongoose"; import { authenticateUser } from "@lib/auth"; export async function PUT(req: Request) { + const authHeader = req.headers.get("Authorization"); try { - const authHeader = req.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/update-profile/personal/route.ts b/app/api/update-profile/personal/route.ts index 42e07028..318dbe1e 100644 --- a/app/api/update-profile/personal/route.ts +++ b/app/api/update-profile/personal/route.ts @@ -10,8 +10,8 @@ import { Types } from "mongoose"; import { authenticateUser } from "@lib/auth"; export async function PUT(req: Request) { + const authHeader = req.headers.get("Authorization"); try { - const authHeader = req.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { diff --git a/app/api/update-profile/profile/route.ts b/app/api/update-profile/profile/route.ts index 887daadc..5d3ebd27 100644 --- a/app/api/update-profile/profile/route.ts +++ b/app/api/update-profile/profile/route.ts @@ -9,10 +9,10 @@ import { Types } from "mongoose"; import { authenticateUser } from "@lib/auth"; export async function PUT(request: Request) { + const authHeader = request.headers.get("Authorization"); try { const profile_pic = await request.json(); - const authHeader = request.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); // check for missing user ID or role diff --git a/app/api/update-profile/reset-password/route.ts b/app/api/update-profile/reset-password/route.ts index 119650d8..4e18f1e7 100644 --- a/app/api/update-profile/reset-password/route.ts +++ b/app/api/update-profile/reset-password/route.ts @@ -12,8 +12,8 @@ import { Types } from "mongoose"; import { authenticateUser } from "@lib/auth"; export async function PUT(req: Request) { + const authHeader = req.headers.get("Authorization"); try { - const authHeader = req.headers.get("Authorization"); const { id, role } = await authenticateUser(authHeader); if (!id || !role) { From ddef955ea402b36fa11fe751ac85e6e96cda40c9 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:41:20 +0530 Subject: [PATCH 30/41] =?UTF-8?q?feat(admin):=20implement=20API=20call=20f?= =?UTF-8?q?or=20fetching=20admin=20data=20with=20enhanced=20type=20safety?= =?UTF-8?q?=20=F0=9F=9B=A1=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added API method for fetching admin data using fetchHandler - Improved type safety with Admin type definition - Integrated session token for authorization and cache control --- app/lib/admin/addAdmin.tsx | 21 ++++++++----- app/lib/admin/getAdminData.tsx | 23 ++++++++++---- app/lib/admin/getDashboardData.tsx | 48 ++++++++++++++++++++++-------- app/lib/admin/getHospitals.tsx | 46 +++++++++++++++++++++++----- app/lib/admin/getTransactions.tsx | 19 ++++++++++-- 5 files changed, 122 insertions(+), 35 deletions(-) diff --git a/app/lib/admin/addAdmin.tsx b/app/lib/admin/addAdmin.tsx index cbf74554..516960e2 100644 --- a/app/lib/admin/addAdmin.tsx +++ b/app/lib/admin/addAdmin.tsx @@ -1,21 +1,28 @@ "use server"; + +import { getSessionToken } from "../sessions/sessionUtils"; import fetchHandler from "@utils/fetchHandler"; -export default async function addAdmin(formData: FormData) { +export default async function addAdmin(formData: FormData): Promise { const endpoint = "/api/admin/add-admin"; + const session = getSessionToken(); try { const formDataObject = Object.fromEntries(formData.entries()); - const result = await fetchHandler(endpoint, { - method: "POST", - body: JSON.stringify(formDataObject), - cache: "no-cache", - }); + const result = await fetchHandler( + endpoint, + { + method: "POST", + body: JSON.stringify(formDataObject), + cache: "no-cache", + }, + session! + ); return result; } catch (error) { console.error("An error occurred while adding admin:", error); - return { error: "An unexpected error occurred" }; + throw error; } } diff --git a/app/lib/admin/getAdminData.tsx b/app/lib/admin/getAdminData.tsx index d27d8cb5..d2b4b238 100644 --- a/app/lib/admin/getAdminData.tsx +++ b/app/lib/admin/getAdminData.tsx @@ -1,14 +1,27 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { Admin } from "@pft-types/index"; -export default async function getAdminData() { +export default async function getAdminData(): Promise { const endpoint = "/api/admin"; + const session = getSessionToken(); try { - const adminData = await fetchHandler(endpoint, { - cache: "no-cache", - }); + const response = await fetchHandler( + endpoint, + { + cache: "no-cache", + }, + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } - return adminData; + return response.data!; } catch (error) { console.error("An error occurred while fetching admin data:", error); throw error; diff --git a/app/lib/admin/getDashboardData.tsx b/app/lib/admin/getDashboardData.tsx index 2cc806c1..08faff3c 100644 --- a/app/lib/admin/getDashboardData.tsx +++ b/app/lib/admin/getDashboardData.tsx @@ -1,33 +1,57 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { PaginatedResponse, TilesDataType } from "@pft-types/admin"; -export async function getTilesData() { +export async function getTilesData(): Promise { const endpoint = "/api/admin/dashboard/tiles"; + const session = getSessionToken(); try { - const adminData = await fetchHandler(endpoint, { - next: { - revalidate: 5000, + const response = await fetchHandler( + endpoint, + { + next: { + revalidate: 5000, + }, }, - }); + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } - return adminData; + return response.data!; } catch (error) { console.error("An error occurred while fetching admin data:", error); throw error; } } -export async function getRecentUsersData(page: number) { +export async function getRecentUsersData( + page: number +): Promise { const endpoint = `/api/admin/dashboard/recent-users?page=${page}&limit=10`; + const session = getSessionToken(); try { - const data = await fetchHandler(endpoint, { - next: { - revalidate: 5000, + const response = await fetchHandler( + endpoint, + { + next: { + revalidate: 5000, + }, }, - }); + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } - return data; + return response.data!; } catch (error) { console.error("An error occurred while fetching admin data:", error); throw error; diff --git a/app/lib/admin/getHospitals.tsx b/app/lib/admin/getHospitals.tsx index bb590fe6..604ea3b6 100644 --- a/app/lib/admin/getHospitals.tsx +++ b/app/lib/admin/getHospitals.tsx @@ -1,17 +1,36 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { + HospitalData, + HospitalUserData, + PaginationMetadata, +} from "@pft-types/admin"; export async function getHospitalsList( currentPage: number = 1, pageSize: number = 10 -) { +): Promise<{ + hospitals: [HospitalData]; + pagination: PaginationMetadata; +}> { const endpoint = `/api/admin/hospitals?page=${currentPage}&limit=${pageSize}`; + const session = getSessionToken(); try { - const data = await fetchHandler(endpoint); + const response = await fetchHandler<{ + hospitals: [HospitalData]; + pagination: PaginationMetadata; + }>(endpoint, {}, session!); + + if (response.error) { + throw new Error(response.error.message); + } return { - hospitals: data.hospitals, - pagination: data.pagination, + hospitals: response.data!.hospitals, + pagination: response.data!.pagination, }; } catch (error) { console.error("An error occurred while fetching hospitals list:", error); @@ -23,15 +42,26 @@ export async function getHospitalDetails( hospitalId: string, currentPage: number = 1, pageSize: number = 10 -) { +): Promise<{ + users: [HospitalUserData]; + pagination: PaginationMetadata; +}> { const endpoint = `/api/admin/hospitals/users?hospitalId=${hospitalId}&page=${currentPage}&limit=${pageSize}`; + const session = getSessionToken(); try { - const data = await fetchHandler(endpoint); + const response = await fetchHandler<{ + users: [HospitalUserData]; + pagination: PaginationMetadata; + }>(endpoint, {}, session!); + + if (response.error) { + throw new Error(response.error.message); + } return { - users: data.users, - pagination: data.pagination, + users: response.data!.users, + pagination: response.data!.pagination, }; } catch (error) { console.error("An error occurred while fetching hospital details:", error); diff --git a/app/lib/admin/getTransactions.tsx b/app/lib/admin/getTransactions.tsx index 365867ad..65f2ddb4 100644 --- a/app/lib/admin/getTransactions.tsx +++ b/app/lib/admin/getTransactions.tsx @@ -1,12 +1,25 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { TransactionDetails } from "@pft-types/admin"; -export default async function getTransactions() { +export default async function getTransactions(): Promise<[TransactionDetails]> { const endpoint = "/api/admin/transactions"; + const session = getSessionToken(); try { - const transactionsData = await fetchHandler(endpoint); + const response = await fetchHandler<[TransactionDetails]>( + endpoint, + {}, + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } - return transactionsData; + return response.data!; } catch (error) { console.error("An error occurred while fetching transactions data:", error); throw error; From fec7256a00810abfac5580f0956694dfa548fbc8 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:41:37 +0530 Subject: [PATCH 31/41] =?UTF-8?q?feat(doctor):=20add=20API=20method=20for?= =?UTF-8?q?=20retrieving=20doctor=20data=20with=20improved=20session=20han?= =?UTF-8?q?dling=20=F0=9F=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added API function to retrieve doctor data using fetchHandler - Ensured type safety for doctor data structure - Included session token for authentication and used no-cache policy --- app/lib/doctor/getDoctorData.ts | 23 ++++++++++++++++++----- app/lib/doctor/index.ts | 1 - 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/app/lib/doctor/getDoctorData.ts b/app/lib/doctor/getDoctorData.ts index 1ec7ab7a..348d9107 100644 --- a/app/lib/doctor/getDoctorData.ts +++ b/app/lib/doctor/getDoctorData.ts @@ -1,14 +1,27 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { Doctor } from "@pft-types/index"; -export default async function getDoctorData() { +export default async function getDoctorData(): Promise { const endpoint = "/api/doctor"; + const session = getSessionToken(); try { - const doctorData = await fetchHandler(endpoint, { - cache: "no-cache", - }); + const response = await fetchHandler>( + endpoint, + { + cache: "no-cache", + }, + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } - return doctorData; + return response.data!; } catch (error) { console.error("An error occurred while fetching doctor data:", error); throw error; diff --git a/app/lib/doctor/index.ts b/app/lib/doctor/index.ts index 92287154..19f7c28b 100644 --- a/app/lib/doctor/index.ts +++ b/app/lib/doctor/index.ts @@ -1,3 +1,2 @@ import getDoctorData from "./getDoctorData"; - export { getDoctorData }; From a6e7b06bd0a7f13c52feeb1ca32b87e0e51bfc2f Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:41:48 +0530 Subject: [PATCH 32/41] =?UTF-8?q?feat(patient):=20implement=20patient=20da?= =?UTF-8?q?ta=20fetching=20API=20with=20better=20type=20handling=20?= =?UTF-8?q?=F0=9F=94=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added API method to fetch patient data using fetchHandler - Applied stricter type safety for patient data structure - Included session token in API calls for secure access --- app/lib/patient/bookAppointment.tsx | 31 ++++++++++--------- app/lib/patient/getPatientData.tsx | 23 +++++++++++--- app/lib/patient/getPatientMedicalHistory.tsx | 21 +++++++++++-- app/lib/patient/getPaymentsHistory.tsx | 15 +++++++-- app/lib/patient/getUpcomingAppointments.tsx | 17 ++++++++-- app/lib/patient/misc/getCities.tsx | 12 +++++-- app/lib/patient/misc/getDiseases.tsx | 10 ++++-- app/lib/patient/misc/getHospitals.tsx | 11 +++++-- app/lib/patient/misc/getStates.tsx | 9 ++++-- app/lib/patient/pendingAppointmentsReq.tsx | 22 +++++++++---- .../patient/saveAppointmentTransaction.tsx | 23 +++++++++++--- 11 files changed, 143 insertions(+), 51 deletions(-) diff --git a/app/lib/patient/bookAppointment.tsx b/app/lib/patient/bookAppointment.tsx index 6b2c0f9e..289890d7 100644 --- a/app/lib/patient/bookAppointment.tsx +++ b/app/lib/patient/bookAppointment.tsx @@ -1,27 +1,30 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; import { bookingAppointment } from "@pft-types/index"; +import { getSessionToken } from "../sessions/sessionUtils"; export default async function bookAppointment( bookAppointmentData: bookingAppointment, transaction_id: string | null, appointment_charge: string -) { +): Promise { const endpoint = "/api/patient/appointment"; + const session = getSessionToken(); try { - const response = await fetchHandler(endpoint, { - method: "POST", - body: JSON.stringify({ - ...bookAppointmentData, - transaction_id, - appointment_charge, - }), - }); - - if (!response) { - console.error("Error booking appointments"); - return { error: "Failed to book appointment" }; - } + const response = await fetchHandler( + endpoint, + { + method: "POST", + body: JSON.stringify({ + ...bookAppointmentData, + transaction_id, + appointment_charge, + }), + }, + session! + ); return response; } catch (error) { diff --git a/app/lib/patient/getPatientData.tsx b/app/lib/patient/getPatientData.tsx index 13ba9f16..e5703d5c 100644 --- a/app/lib/patient/getPatientData.tsx +++ b/app/lib/patient/getPatientData.tsx @@ -1,14 +1,27 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { Patient } from "@pft-types/index"; -export default async function getPatientData() { +export default async function getresponse(): Promise { const endpoint = "/api/patient"; + const session = getSessionToken(); try { - const patientData = await fetchHandler(endpoint, { - cache: "no-cache", - }); + const response = await fetchHandler( + endpoint, + { + cache: "no-cache", + }, + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } - return patientData; + return response.data!; } catch (error) { console.error("An error occurred while fetching patient data:", error); throw error; diff --git a/app/lib/patient/getPatientMedicalHistory.tsx b/app/lib/patient/getPatientMedicalHistory.tsx index ddb25e6a..4200f376 100644 --- a/app/lib/patient/getPatientMedicalHistory.tsx +++ b/app/lib/patient/getPatientMedicalHistory.tsx @@ -1,12 +1,27 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { MedicalHistory } from "@pft-types/patient"; -export default async function getPatientMedicalHistory() { +export default async function getPatientMedicalHistory(): Promise< + [MedicalHistory] +> { const endpoint = "/api/patient/medicalhistory"; + const session = getSessionToken(); try { - const medicalHistory = await fetchHandler(endpoint); + const response = await fetchHandler<[MedicalHistory]>( + endpoint, + {}, + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } - return medicalHistory; + return response.data!; } catch (error) { console.error("Error fetching patient medical history:", error); throw error; diff --git a/app/lib/patient/getPaymentsHistory.tsx b/app/lib/patient/getPaymentsHistory.tsx index 66e435c6..95b1ce60 100644 --- a/app/lib/patient/getPaymentsHistory.tsx +++ b/app/lib/patient/getPaymentsHistory.tsx @@ -1,12 +1,21 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { Payment } from "@pft-types/patient"; -export default async function getPaymentsHistory() { +export default async function getPaymentsHistory(): Promise<[Payment]> { const endpoint = "/api/patient/paymenthistory"; + const session = getSessionToken(); try { - const paymentsHistory = await fetchHandler(endpoint); + const response = await fetchHandler<[Payment]>(endpoint, {}, session!); + + if (response.error) { + throw new Error(response.error.message); + } - return paymentsHistory; + return response.data!; } catch (error) { console.error("Error fetching payments:", error); throw error; diff --git a/app/lib/patient/getUpcomingAppointments.tsx b/app/lib/patient/getUpcomingAppointments.tsx index a03ff7a5..8046bd92 100644 --- a/app/lib/patient/getUpcomingAppointments.tsx +++ b/app/lib/patient/getUpcomingAppointments.tsx @@ -1,14 +1,25 @@ "use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { bookedAppointments } from "@pft-types/patient"; -export default async function getUpcomingAppointments() { +export default async function getUpcomingAppointments(): Promise { const endpoint = "/api/patient/appointment"; + const session = getSessionToken(); try { - const upcomingAppointments = await fetchHandler(endpoint); + const response = await fetchHandler( + endpoint, + {}, + session! + ); // next: { revalidate: 10 }, - return upcomingAppointments; + if (response.error) { + throw new Error(response.error.message); + } + return response.data!; } catch (error) { console.error("Error fetching upcoming appointments:", error); throw error; diff --git a/app/lib/patient/misc/getCities.tsx b/app/lib/patient/misc/getCities.tsx index 95e64a5f..2ea227a5 100644 --- a/app/lib/patient/misc/getCities.tsx +++ b/app/lib/patient/misc/getCities.tsx @@ -1,12 +1,18 @@ import fetchHandler from "@utils/fetchHandler"; -export default async function getCities(selectedState: string) { +export default async function getCities( + selectedState: string +): Promise<[string]> { const endpoint = `/api/city/?state=${selectedState}`; try { - const data = await fetchHandler(endpoint); + const response = await fetchHandler<[string]>(endpoint); - return data; + if (response.error) { + throw new Error(response.error.message); + } + + return response.data!; } catch (error) { console.error("Error fetching cities:", error); throw error; diff --git a/app/lib/patient/misc/getDiseases.tsx b/app/lib/patient/misc/getDiseases.tsx index 8ac59b0d..d0972d76 100644 --- a/app/lib/patient/misc/getDiseases.tsx +++ b/app/lib/patient/misc/getDiseases.tsx @@ -1,12 +1,16 @@ import fetchHandler from "@utils/fetchHandler"; -export default async function getDiseases() { +export default async function getDiseases(): Promise<[string]> { const endpoint = `/api/gethospitals/disease/`; try { - const data = await fetchHandler(endpoint); + const response = await fetchHandler<[string]>(endpoint); - return data; + if (response.error) { + throw new Error(response.error.message); + } + + return response.data!; } catch (error) { console.error("Error fetching diseases:", error); throw error; diff --git a/app/lib/patient/misc/getHospitals.tsx b/app/lib/patient/misc/getHospitals.tsx index 3d746e84..ce475054 100644 --- a/app/lib/patient/misc/getHospitals.tsx +++ b/app/lib/patient/misc/getHospitals.tsx @@ -1,15 +1,20 @@ +import { BookAppointmentHospital } from "@pft-types/patient"; import fetchHandler from "@utils/fetchHandler"; export default async function getHospitals( selectedState: string, selectedCity: string -) { +): Promise<[BookAppointmentHospital]> { const endpoint = `/api/gethospitals/?state=${selectedState}&city=${selectedCity}`; try { - const data = await fetchHandler(endpoint); + const response = await fetchHandler<[BookAppointmentHospital]>(endpoint); - return data; + if (response.error) { + throw new Error(response.error.message); + } + + return response.data!; } catch (error) { console.error("Error fetching hospitals:", error); throw error; diff --git a/app/lib/patient/misc/getStates.tsx b/app/lib/patient/misc/getStates.tsx index cddca474..e34e1670 100644 --- a/app/lib/patient/misc/getStates.tsx +++ b/app/lib/patient/misc/getStates.tsx @@ -1,12 +1,15 @@ import fetchHandler from "@utils/fetchHandler"; -export default async function getStates() { +export default async function getStates(): Promise<[string]> { const endpoint = "/api/states"; try { - const data = await fetchHandler(endpoint); + const response = await fetchHandler<[string]>(endpoint); - return data; + if (response.error) { + throw new Error(response.error.message); + } + return response.data!; } catch (error) { console.error("Error fetching states:", error); throw error; diff --git a/app/lib/patient/pendingAppointmentsReq.tsx b/app/lib/patient/pendingAppointmentsReq.tsx index a904abba..7825e539 100644 --- a/app/lib/patient/pendingAppointmentsReq.tsx +++ b/app/lib/patient/pendingAppointmentsReq.tsx @@ -1,15 +1,25 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; -export default async function pendingAppointmentsRequest(hospital_id: string) { +export default async function pendingAppointmentsRequest( + hospital_id: string +): Promise<{ hasPendingAppointment: boolean }> { const endpoint = "/api/patient/appointment/pending"; + const session = getSessionToken(); try { - const data = await fetchHandler(endpoint, { - method: "POST", - body: JSON.stringify({ hospital_id }), - }); + const response = await fetchHandler<{ hasPendingAppointment: boolean }>( + endpoint, + { + method: "POST", + body: JSON.stringify({ hospital_id }), + }, + session! + ); - return data; + return response.data!; } catch (error) { console.error( "An error occurred while fetching pending appointment requests:", diff --git a/app/lib/patient/saveAppointmentTransaction.tsx b/app/lib/patient/saveAppointmentTransaction.tsx index a182335a..d5e74c4b 100644 --- a/app/lib/patient/saveAppointmentTransaction.tsx +++ b/app/lib/patient/saveAppointmentTransaction.tsx @@ -1,4 +1,7 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; export default async function saveAppointmentTransaction( transaction_id: string | null, @@ -8,7 +11,7 @@ export default async function saveAppointmentTransaction( description: string, amount: string, status: string -) { +): Promise { const transactionData = { transaction_id, patient_id, @@ -20,13 +23,23 @@ export default async function saveAppointmentTransaction( }; const endpoint = "/api/transactions"; + const session = getSessionToken(); try { - await fetchHandler(endpoint, { - method: "POST", - body: JSON.stringify(transactionData), - }); + const response = await fetchHandler( + endpoint, + { + method: "POST", + body: JSON.stringify(transactionData), + }, + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } } catch (error) { console.error("Error recording appointment transaction:", error); + throw error; } } From fba8ac1d2d47ff3762436f6ff66e05d0b04114dc Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:42:02 +0530 Subject: [PATCH 33/41] =?UTF-8?q?feat(receptionist):=20integrate=20recepti?= =?UTF-8?q?onist=20API=20with=20secure=20session=20token=20passing=20?= =?UTF-8?q?=F0=9F=93=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implemented API method for fetching receptionist data using fetchHandler - Improved type safety for receptionist data handling - Used session token for secure API calls and enhanced error handling --- app/lib/receptionist/approveAppointment.tsx | 24 ++++++++++++----- .../receptionist/getPendingAppointments.tsx | 17 +++++++++--- app/lib/receptionist/getReceptionistData.tsx | 21 +++++++++++---- app/lib/receptionist/scanQrCode.tsx | 27 +++++++++++-------- 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/app/lib/receptionist/approveAppointment.tsx b/app/lib/receptionist/approveAppointment.tsx index c743d919..2bc89725 100644 --- a/app/lib/receptionist/approveAppointment.tsx +++ b/app/lib/receptionist/approveAppointment.tsx @@ -1,15 +1,27 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; -export default async function approveAppointment(patientId: string) { +export default async function approveAppointment( + patientId: string +): Promise { const endpoint = "/api/receptionist/appointments/approve"; + const session = getSessionToken(); try { - const result = await fetchHandler(endpoint, { - method: "POST", - body: JSON.stringify({ patient_id: patientId }), - }); + const response = await fetchHandler( + endpoint, + { + method: "POST", + body: JSON.stringify({ patient_id: patientId }), + }, + session! + ); + + if (response.error) throw new Error(response.error.message); - return result; + return response.data!; } catch (error) { console.error("Error approving appointment:", error); throw error; diff --git a/app/lib/receptionist/getPendingAppointments.tsx b/app/lib/receptionist/getPendingAppointments.tsx index 45bd7209..12a03ba6 100644 --- a/app/lib/receptionist/getPendingAppointments.tsx +++ b/app/lib/receptionist/getPendingAppointments.tsx @@ -1,12 +1,23 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { PendingPatients } from "@pft-types/receptionist"; -export default async function getPendingAppointments() { +export default async function getPendingAppointments(): Promise { const endpoint = "/api/receptionist/appointments/pending"; + const session = getSessionToken(); try { - const receptionistData = await fetchHandler(endpoint, {}); + const response = await fetchHandler( + endpoint, + {}, + session! + ); + + if (response.error) throw new Error(response.error.message); - return receptionistData; + return response.data!; } catch (error) { console.error("Error fetching pending appointments:", error); throw error; diff --git a/app/lib/receptionist/getReceptionistData.tsx b/app/lib/receptionist/getReceptionistData.tsx index 89f3bbb3..12843ae9 100644 --- a/app/lib/receptionist/getReceptionistData.tsx +++ b/app/lib/receptionist/getReceptionistData.tsx @@ -1,14 +1,25 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { Receptionist } from "@pft-types/index"; -export default async function getReceptionistData() { +export default async function getReceptionistData(): Promise { const endpoint = "/api/receptionist"; + const session = getSessionToken(); try { - const receptionistData = await fetchHandler(endpoint, { - cache: "no-cache", - }); + const response = await fetchHandler( + endpoint, + { + cache: "no-cache", + }, + session! + ); + + if (response.error) throw new Error(response.error.message); - return receptionistData; + return response.data!; } catch (error) { console.error("Error fetching receptionist data:", error); throw error; diff --git a/app/lib/receptionist/scanQrCode.tsx b/app/lib/receptionist/scanQrCode.tsx index 645d8a98..24b80888 100644 --- a/app/lib/receptionist/scanQrCode.tsx +++ b/app/lib/receptionist/scanQrCode.tsx @@ -1,22 +1,27 @@ "use server"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; -export default async function scanQRCode(email: string) { - const serverUrl = getBaseUrl(); +export default async function scanQRCode( + email: string +): Promise<{ message: string }> { + const endpoint = "/api/receptionist/scan"; + const session = getSessionToken(); try { - const res = await fetch(`${serverUrl}/api/receptionist/scan`, { - method: "POST", - body: JSON.stringify({ email }), - headers: { - "Content-Type": "application/json", + const result = await fetchHandler<{ message: string }>( + endpoint, + { + method: "POST", + body: JSON.stringify({ email }), }, - }); + session! + ); - const message = await res.json(); - return message; + return result.data!; } catch (error) { console.error("Error fetching data:", error); + throw error; } } From 32869baa6eed442faa6a7f5696c1cc0929b43df7 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:42:20 +0530 Subject: [PATCH 34/41] =?UTF-8?q?feat(hospital):=20create=20hospital=20dat?= =?UTF-8?q?a=20fetching=20API=20with=20enhanced=20type=20and=20session=20h?= =?UTF-8?q?andling=20=F0=9F=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added API method for fetching hospital data using fetchHandler - Ensured type safety for hospital data structures - Passed session token for secure API requests and used cache control options --- app/lib/hospital/getHospitalData.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/app/lib/hospital/getHospitalData.ts b/app/lib/hospital/getHospitalData.ts index 19aac2a3..376dcfa3 100644 --- a/app/lib/hospital/getHospitalData.ts +++ b/app/lib/hospital/getHospitalData.ts @@ -1,14 +1,27 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; +import { Hospital } from "@pft-types/index"; -export default async function getHospitalData() { +export default async function getHospitalData(): Promise { const endpoint = "/api/hospital"; + const session = getSessionToken(); try { - const hospitalData = await fetchHandler(endpoint, { - cache: "no-cache", - }); + const response = await fetchHandler( + endpoint, + { + cache: "no-cache", + }, + session! + ); + + if (response.error) { + throw new Error(response.error.message); + } - return hospitalData; + return response.data!; } catch (error) { console.error("An error occurred while fetching hospital data:", error); throw error; From 9ab8cfd2b3297cf0902e5177a7950e9b6487583c Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:43:41 +0530 Subject: [PATCH 35/41] =?UTF-8?q?feat(auth):=20enhance=20user=20authentica?= =?UTF-8?q?tion=20with=20detailed=20error=20handling=20=F0=9F=94=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added error handling for expired and invalid JWT tokens - Used AppError to throw appropriate HTTP status codes for authentication errors - Improved logging for unauthorized access and token decryption failures --- app/lib/auth/authenticateUser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/auth/authenticateUser.ts b/app/lib/auth/authenticateUser.ts index 8296fa60..27b04e30 100644 --- a/app/lib/auth/authenticateUser.ts +++ b/app/lib/auth/authenticateUser.ts @@ -6,6 +6,7 @@ export default async function authenticateUser( authHeader: string | null ): Promise<{ id: string; role: string }> { if (!authHeader || !authHeader.startsWith("Bearer ")) { + console.log("Unauthorized : auth header not present"); throw new AppError("Unauthorized", STATUS_CODES.UNAUTHORIZED); } @@ -19,12 +20,11 @@ export default async function authenticateUser( }; } catch (error) { console.error("Error in authentication:", error); - if (error instanceof JWTExpired) { throw new AppError("Token expired", STATUS_CODES.UNAUTHORIZED); } else if (error instanceof JWTInvalid) { throw new AppError("Invalid token", STATUS_CODES.UNAUTHORIZED); } - throw new AppError("Internal dfdfgv Error", STATUS_CODES.SERVER_ERROR); + throw new AppError("Internal Server Error", STATUS_CODES.SERVER_ERROR); } } From c97ed5bbe666de582a512321b48524dce1d12ba5 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:43:53 +0530 Subject: [PATCH 36/41] =?UTF-8?q?feat(demo-login):=20implement=20demo=20us?= =?UTF-8?q?er=20login=20with=20fetchHandler=20and=20toast=20notifications?= =?UTF-8?q?=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added demo user login functionality using fetchHandler for API calls - Integrated toast notifications for login status (loading, success, error) - Improved error handling and user feedback for demo login process --- app/lib/demo-user/handleDemoUserLogin.tsx | 19 ++++++++----------- app/lib/demo-user/index.ts | 1 - 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/app/lib/demo-user/handleDemoUserLogin.tsx b/app/lib/demo-user/handleDemoUserLogin.tsx index e29b095b..c73753c8 100644 --- a/app/lib/demo-user/handleDemoUserLogin.tsx +++ b/app/lib/demo-user/handleDemoUserLogin.tsx @@ -1,4 +1,3 @@ -"use server"; import toast from "react-hot-toast"; import fetchHandler from "@utils/fetchHandler"; @@ -11,27 +10,25 @@ const handleDemoUserLogin = async ( try { toast.loading("Logging in...", { id: "demoLogin" }); - const result = await fetchHandler(endpoint, { + const response = await fetchHandler(endpoint, { method: "POST", body: JSON.stringify({ role }), cache: "no-cache", }); - if (!result.success) { - console.error("Error while demo user login:", result.error); - return { success: false, error: result.error }; + if (response.error) { + console.error("Error while demo user login:", response.error); + toast.error(`${response.error.message}`); + return; } toast.success("Login successful, redirecting...", { id: "demoLogin" }); redirectDemoUser(role); } catch (error) { console.error("Demo login error:", error); - toast.error( - error instanceof Error - ? error.message - : "An unexpected error occurred. Please try again.", - { id: "demoLogin" } - ); + toast.error("An unexpected error occurred. Please try again.", { + id: "demoLogin", + }); } }; diff --git a/app/lib/demo-user/index.ts b/app/lib/demo-user/index.ts index 8a543881..9bb97226 100644 --- a/app/lib/demo-user/index.ts +++ b/app/lib/demo-user/index.ts @@ -1,3 +1,2 @@ import handleDemoUserLogin from "./handleDemoUserLogin"; - export { handleDemoUserLogin }; From 432d2f0f451c20963ba8bfc04a2e95ca632db88c Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:44:37 +0530 Subject: [PATCH 37/41] =?UTF-8?q?refactor:=20replace=20img=20tag=20with=20?= =?UTF-8?q?Next.js=20Image=20component=20for=20optimized=20loading=20?= =?UTF-8?q?=F0=9F=96=BC=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/emails/templates.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/lib/emails/templates.tsx b/app/lib/emails/templates.tsx index e773cff7..c2f0f5bd 100644 --- a/app/lib/emails/templates.tsx +++ b/app/lib/emails/templates.tsx @@ -1,7 +1,8 @@ +import React from "react"; +import { Image } from "@nextui-org/react"; import { UserLog, bookingAppointment } from "@pft-types/index"; import { Html } from "@react-email/html"; import { getCurrentDateFormatted, getFormattedDate } from "@utils/getDate"; -import React from "react"; function Layout({ children }: { children: React.ReactNode }) { return ( @@ -35,8 +36,8 @@ function Layout({ children }: { children: React.ReactNode }) { alignItems: "center", }} > -
- Facebook - Instagram - Twitter - Youtube Date: Wed, 25 Sep 2024 23:46:07 +0530 Subject: [PATCH 38/41] refactor: console log the logging error --- app/lib/logs/index.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/lib/logs/index.tsx b/app/lib/logs/index.tsx index f3e1a26d..6e947567 100644 --- a/app/lib/logs/index.tsx +++ b/app/lib/logs/index.tsx @@ -15,6 +15,8 @@ type userlogType = { async function logUserActivity(userlog: userlogType, req: Request) { await dbConfig(); + const ip_addr = req.headers.get("x-forwarded-for") ?? "127.0.0.1"; + try { const { os, browser, device } = userAgent(req); @@ -25,9 +27,7 @@ async function logUserActivity(userlog: userlogType, req: Request) { action: userlog.action, userType: userlog.role, device: `${os.name} ${os.version}, ${browser.name} ${browser.version}, ${device.type}`, - ip: (req.headers.get("x-forwarded-for") ?? "127.0.0.1") - .split(",")[0] - .trim(), + ip: ip_addr.split(",")[0].trim(), location: await fetchLocationByIP(), }; @@ -46,9 +46,7 @@ async function logUserActivity(userlog: userlogType, req: Request) { }, }); } catch (error: any) { - console.error( - `While logging user activities got an error : ${error.message}` - ); + console.error(`While logging user activities got an error`); } } From 69dbedae2fbb944c871ffd8dd25c4c3d31e2ffad Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:48:11 +0530 Subject: [PATCH 39/41] =?UTF-8?q?feat(update-profile):=20enhance=20profile?= =?UTF-8?q?=20management=20with=20fetchHandler=20integration=20?= =?UTF-8?q?=F0=9F=8C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/update-profile/reset_password.tsx | 22 ++++++++++++----- app/lib/update-profile/update_address.tsx | 22 ++++++++++++----- .../update-profile/update_personal_info.tsx | 24 ++++++++++++++----- .../update-profile/update_profile_picture.tsx | 22 ++++++++++++----- 4 files changed, 66 insertions(+), 24 deletions(-) diff --git a/app/lib/update-profile/reset_password.tsx b/app/lib/update-profile/reset_password.tsx index a55dc2c4..ff15dc94 100644 --- a/app/lib/update-profile/reset_password.tsx +++ b/app/lib/update-profile/reset_password.tsx @@ -1,18 +1,28 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; export default async function resetPassword( currentPassword: string, newPassword: string -) { +): Promise { const endpoint = "/api/update-profile/reset-password"; + const session = getSessionToken(); try { - const result = await fetchHandler(endpoint, { - method: "PUT", - body: JSON.stringify({ currentPassword, newPassword }), - }); + const response = await fetchHandler( + endpoint, + { + method: "PUT", + body: JSON.stringify({ currentPassword, newPassword }), + }, + session! + ); + + if (response.error) return { error: response.error.message }; - return result; + return response.data!; } catch (error) { console.error("Error updating password:", error); throw error; diff --git a/app/lib/update-profile/update_address.tsx b/app/lib/update-profile/update_address.tsx index a0b8c651..3d1ee444 100644 --- a/app/lib/update-profile/update_address.tsx +++ b/app/lib/update-profile/update_address.tsx @@ -1,15 +1,25 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; -export default async function updateAddress(filteredFields: any) { +export default async function updateAddress(filteredFields: any): Promise { const endpoint = "/api/update-profile/address"; + const session = getSessionToken(); try { - const result = await fetchHandler(endpoint, { - method: "PUT", - body: JSON.stringify(filteredFields), - }); + const response = await fetchHandler( + endpoint, + { + method: "PUT", + body: JSON.stringify(filteredFields), + }, + session! + ); + + if (response.error) return { error: response.error.message }; - return result; + return response.data!; } catch (error) { console.error("Error updating address information:", error); throw error; diff --git a/app/lib/update-profile/update_personal_info.tsx b/app/lib/update-profile/update_personal_info.tsx index 5617db9c..25b90180 100644 --- a/app/lib/update-profile/update_personal_info.tsx +++ b/app/lib/update-profile/update_personal_info.tsx @@ -1,15 +1,27 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; -export default async function updatePersonal(filteredFields: any) { +export default async function updatePersonal( + filteredFields: any +): Promise { const endpoint = "/api/update-profile/personal"; + const session = getSessionToken(); try { - const result = await fetchHandler(endpoint, { - method: "PUT", - body: JSON.stringify(filteredFields), - }); + const response = await fetchHandler( + endpoint, + { + method: "PUT", + body: JSON.stringify(filteredFields), + }, + session! + ); + + if (response.error) return { error: response.error.message }; - return result; + return response.data!; } catch (error) { console.error("Error updating personal information:", error); throw error; diff --git a/app/lib/update-profile/update_profile_picture.tsx b/app/lib/update-profile/update_profile_picture.tsx index 21bb3880..4c4d1b68 100644 --- a/app/lib/update-profile/update_profile_picture.tsx +++ b/app/lib/update-profile/update_profile_picture.tsx @@ -1,15 +1,25 @@ +"use server"; + import fetchHandler from "@utils/fetchHandler"; +import { getSessionToken } from "../sessions/sessionUtils"; -async function updateProfilePicture(profile_url: string) { +async function updateProfilePicture(profile_url: string): Promise { const endpoint = "/api/update-profile/profile"; + const session = getSessionToken(); try { - const result = await fetchHandler(endpoint, { - method: "PUT", - body: JSON.stringify(profile_url), - }); + const response = await fetchHandler( + endpoint, + { + method: "PUT", + body: JSON.stringify(profile_url), + }, + session! + ); + + if (response.error) return { error: response.error.message }; - return result; + return response.data!; } catch (error) { console.error("Error updating profile picture:", error); throw error; From 15d1607c77e99016cddc49f4e75c894ff4c2010a Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:49:28 +0530 Subject: [PATCH 40/41] =?UTF-8?q?feat(auth):=20implement=20login=20and=20s?= =?UTF-8?q?ignup=20actions=20with=20fetchHandler=20integration=20?= =?UTF-8?q?=F0=9F=94=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/actions.ts | 66 ++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/app/lib/actions.ts b/app/lib/actions.ts index 6a7e933b..a470eb53 100644 --- a/app/lib/actions.ts +++ b/app/lib/actions.ts @@ -2,58 +2,36 @@ import { logout } from "@sessions/sessionUtils"; import { redirect } from "next/navigation"; -import getBaseUrl from "@utils/getBaseUrl"; +import fetchHandler from "@utils/fetchHandler"; -export async function loginAction(formData: FormData) { +export async function loginAction(formData: FormData): Promise { const usernameOrEmail = formData.get("usernameOrEmail"); const password = formData.get("password"); const role = formData.get("role"); - const serverUrl = getBaseUrl(); + const endpoint = "/api/auth/login"; - try { - const response = await fetch(`${serverUrl}/api/auth/login`, { - method: "POST", - body: JSON.stringify({ usernameOrEmail, password, role }), - }); - - const userData = await response.json(); - - if (!response.ok) { - return { message: userData.error, unauthorized: true }; - } else return userData; - } catch (error) { - console.error("Login failed:", error); - } + return await fetchHandler(endpoint, { + method: "POST", + body: JSON.stringify({ usernameOrEmail, password, role }), + }); } -export async function signupAction(formData: FormData) { - const [firstname, lastname, username, email, password, role] = [ - formData.get("firstname"), - formData.get("lastname"), - formData.get("username"), - formData.get("email"), - formData.get("password"), - formData.get("role"), - ]; - - const user = { firstname, lastname, username, email, password, role }; - - try { - const serverUrl = getBaseUrl(); - const response = await fetch(`${serverUrl}/api/auth/signup`, { - method: "POST", - body: JSON.stringify(user), - }); - - const userData = await response.json(); - - if (!response.ok) { - return { message: userData.error, failure: true }; - } else return userData; - } catch (error) { - console.error("Signup failed:", error); - } +export async function signupAction(formData: FormData): Promise { + const user = { + firstname: formData.get("firstname"), + lastname: formData.get("lastname"), + username: formData.get("username"), + email: formData.get("email"), + password: formData.get("password"), + role: formData.get("role"), + }; + + const endpoint = "/api/auth/signup"; + return await fetchHandler(endpoint, { + method: "POST", + body: JSON.stringify(user), + }); } export async function logoutAction() { From d8d8287095f313dbbde492c33210204d35fa8028 Mon Sep 17 00:00:00 2001 From: Anand Suthar Date: Wed, 25 Sep 2024 23:51:38 +0530 Subject: [PATCH 41/41] =?UTF-8?q?refactor(verifyOtp):=20Integrated=20fetch?= =?UTF-8?q?Handler=20with=20TypeScript=20types=20=F0=9F=94=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/verifyOtp.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/lib/verifyOtp.ts b/app/lib/verifyOtp.ts index 49cf99b6..9d0ab93c 100644 --- a/app/lib/verifyOtp.ts +++ b/app/lib/verifyOtp.ts @@ -5,11 +5,11 @@ export default async function verifyOtp( role: string, action: string, otp: string -) { +): Promise { const endpoint = "/api/auth/verifyotp"; try { - const result = await fetchHandler(endpoint, { + const response = await fetchHandler(endpoint, { method: "POST", body: JSON.stringify({ otp, @@ -19,7 +19,9 @@ export default async function verifyOtp( }), }); - return result; + if (response.error) return { error: response.error.message }; + + return response.data!; } catch (error) { console.error("Error verifying OTP:", error); throw error;