diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 46ed472..e46e2ab 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -28,6 +28,7 @@ "radix-ui": "^1.4.3", "react": "^19.2.0", "react-dom": "^19.2.0", + "react-hot-toast": "^2.6.0", "react-router-dom": "^7.13.1", "shadcn": "^4.0.5", "tailwind-merge": "^3.5.0", @@ -5187,7 +5188,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, "license": "MIT" }, "node_modules/data-uri-to-buffer": { @@ -6352,6 +6352,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz", + "integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -8136,6 +8145,23 @@ "react": "^19.2.4" } }, + "node_modules/react-hot-toast": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz", + "integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-refresh": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index a97269e..7fd66ff 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,6 +30,7 @@ "radix-ui": "^1.4.3", "react": "^19.2.0", "react-dom": "^19.2.0", + "react-hot-toast": "^2.6.0", "react-router-dom": "^7.13.1", "shadcn": "^4.0.5", "tailwind-merge": "^3.5.0", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a57396c..54fcdf9 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,5 @@ -import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; +import {BrowserRouter, Routes, Route, Navigate} from "react-router-dom"; +import {Toaster} from "react-hot-toast"; import Login from "@/pages/Login"; @@ -8,7 +9,7 @@ import DashboardLayout from "./layouts/DashboardLayout"; import ProtectedRoute from "./auth/ProtectedRoute"; import PublicRoute from "./auth/PublicRoute"; -import { AuthProvider } from "./context/AuthContext"; +import {AuthProvider} from "./context/AuthContext"; import Department from "./pages/Department"; import Doctor from "./pages/Doctor"; import Blog from "./pages/Blog"; @@ -26,6 +27,8 @@ import ImportData from "./pages/ImportData"; export default function App() { return ( + + }> diff --git a/frontend/src/api/career.ts b/frontend/src/api/career.ts index cf1ec36..2f35a22 100644 --- a/frontend/src/api/career.ts +++ b/frontend/src/api/career.ts @@ -1,11 +1,49 @@ import apiClient from "@/api/client"; +import toast from "react-hot-toast"; export const getCareersApi = async () => { const res = await apiClient.get("/careers/getAll?admin=true"); return res.data; }; -export const deleteCareerApi = async (id: number) => { - const res = await apiClient.delete(`/careers/${id}`); - return res.data; +export const createCareerApi = async (data: any) => { + try { + const res = await apiClient.post("/careers", data); + + toast.success("Career created successfully"); + + return res.data; + } catch (error: any) { + toast.error(error?.response?.data?.message || "Failed to create career"); + + throw error; + } +}; + +export const updateCareerApi = async (id: number, data: any) => { + try { + const res = await apiClient.patch(`/careers/${id}`, data); + + toast.success("Career updated successfully"); + + return res.data; + } catch (error: any) { + toast.error(error?.response?.data?.message || "Failed to update career"); + + throw error; + } +}; + +export const deleteCareerApi = async (id: number) => { + try { + const res = await apiClient.delete(`/careers/${id}`); + + toast.success("Career deleted successfully"); + + return res.data; + } catch (error: any) { + toast.error(error?.response?.data?.message || "Failed to delete career"); + + throw error; + } }; diff --git a/frontend/src/api/department.ts b/frontend/src/api/department.ts index 716e8c5..406d33e 100644 --- a/frontend/src/api/department.ts +++ b/frontend/src/api/department.ts @@ -1,4 +1,5 @@ import apiClient from "@/api/client"; +import toast from "react-hot-toast"; export interface Department { departmentId: string; @@ -9,6 +10,8 @@ export interface Department { para3: string; facilities: string; services: string; + isActive?: boolean; + sortOrder?: number; } export const getDepartmentsApi = async () => { @@ -25,8 +28,19 @@ export const createDepartmentApi = async (data: { facilities?: string; services?: string; }) => { - const res = await apiClient.post("/departments", data); - return res.data; + try { + const res = await apiClient.post("/departments", data); + + toast.success("Department created successfully"); + + return res.data; + } catch (error: any) { + toast.error( + error?.response?.data?.message || "Failed to create department", + ); + + throw error; + } }; export const updateDepartmentApi = async ( @@ -40,11 +54,33 @@ export const updateDepartmentApi = async ( services?: string; }, ) => { - const res = await apiClient.put(`/departments/${departmentId}`, data); - return res.data; + try { + const res = await apiClient.put(`/departments/${departmentId}`, data); + + toast.success("Department updated successfully"); + + return res.data; + } catch (error: any) { + toast.error( + error?.response?.data?.message || "Failed to update department", + ); + + throw error; + } }; export const deleteDepartmentApi = async (departmentId: string) => { - const res = await apiClient.delete(`/departments/${departmentId}`); - return res.data; + try { + const res = await apiClient.delete(`/departments/${departmentId}`); + + toast.success("Department deleted successfully"); + + return res.data; + } catch (error: any) { + toast.error( + error?.response?.data?.message || "Failed to delete department", + ); + + throw error; + } }; diff --git a/frontend/src/api/doctor.ts b/frontend/src/api/doctor.ts index b2c652a..7e1b1df 100644 --- a/frontend/src/api/doctor.ts +++ b/frontend/src/api/doctor.ts @@ -1,4 +1,5 @@ import apiClient from "@/api/client"; +import toast from "react-hot-toast"; export interface Doctor { doctorId: string; @@ -34,21 +35,48 @@ export const getDoctorByIdApi = async (doctorId: string) => { }; export const createDoctorApi = async (data: Doctor) => { - const res = await apiClient.post("/doctors", data); - return res.data; + try { + const res = await apiClient.post("/doctors", data); + + toast.success("Doctor created successfully"); + + return res.data; + } catch (error: any) { + toast.error(error?.response?.data?.message || "Failed to create doctor"); + + throw error; + } }; export const updateDoctorApi = async ( doctorId: string, data: Partial, ) => { - const res = await apiClient.patch(`/doctors/${doctorId}`, data); - return res.data; + try { + const res = await apiClient.patch(`/doctors/${doctorId}`, data); + + toast.success("Doctor updated successfully"); + + return res.data; + } catch (error: any) { + toast.error(error?.response?.data?.message || "Failed to update doctor"); + + throw error; + } }; export const deleteDoctorApi = async (doctorId: string) => { - const res = await apiClient.delete(`/doctors/${doctorId}`); - return res.data; + try { + const res = await apiClient.delete(`/doctors/${doctorId}`); + + toast.success("Doctor deleted successfully"); + + return res.data; + } catch (error: any) { + toast.error(error?.response?.data?.message || "Failed to delete doctor"); + + throw error; + } }; export const getDoctorTimingApi = async (doctorId: string) => {