From 827764107751bb11cc582dd0d6df10e266439653 Mon Sep 17 00:00:00 2001 From: ARJUN S THAMPI <61703062+arjun-thampi@users.noreply.github.com> Date: Tue, 24 Mar 2026 14:35:23 +0530 Subject: [PATCH] feat: career page added --- frontend/src/App.tsx | 6 +- frontend/src/api/career.ts | 11 + frontend/src/components/layout/Sidebar.tsx | 10 +- frontend/src/pages/Career.tsx | 287 +++++++++++++++++++++ package-lock.json | 6 + 5 files changed, 315 insertions(+), 5 deletions(-) create mode 100644 frontend/src/api/career.ts create mode 100644 frontend/src/pages/Career.tsx create mode 100644 package-lock.json diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 9a1e549..d8a1b4d 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,4 @@ -import {BrowserRouter, Routes, Route, Navigate} from "react-router-dom"; +import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; import Login from "@/pages/Login"; @@ -8,13 +8,14 @@ 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"; import BlogEditorPage from "./pages/BlogEditor"; import Appointment from "./pages/Appointment"; import EmailPage from "./pages/email"; +import CareerPage from "./pages/Career"; export default function App() { return ( @@ -34,6 +35,7 @@ export default function App() { } /> } /> } /> + } /> diff --git a/frontend/src/api/career.ts b/frontend/src/api/career.ts new file mode 100644 index 0000000..0ded9f0 --- /dev/null +++ b/frontend/src/api/career.ts @@ -0,0 +1,11 @@ +import apiClient from "@/api/client"; + +export const getCareersApi = async () => { + const res = await apiClient.get("/careers/getAll"); + return res.data; +}; + +export const deleteCareerApi = async (id: number) => { + const res = await apiClient.delete(`/careers/${id}`); + return res.data; +}; diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index a36c7df..a3e1acd 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -1,7 +1,7 @@ -import {Link, useLocation} from "react-router-dom"; +import { Link, useLocation } from "react-router-dom"; -import {Button} from "@/components/ui/button"; -import {Separator} from "@/components/ui/separator"; +import { Button } from "@/components/ui/button"; +import { Separator } from "@/components/ui/separator"; export default function Sidebar() { const location = useLocation(); @@ -19,6 +19,10 @@ export default function Sidebar() { name: "Appointments", path: "/appointment", }, + { + name: "Career", + path: "/career", + }, { name: "Email", path: "/email", diff --git a/frontend/src/pages/Career.tsx b/frontend/src/pages/Career.tsx new file mode 100644 index 0000000..5782bd8 --- /dev/null +++ b/frontend/src/pages/Career.tsx @@ -0,0 +1,287 @@ +import { useState, useEffect, useCallback } from "react"; + +import { getCareersApi, deleteCareerApi } from "@/api/career"; + +import apiClient from "@/api/client"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; + +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "@/components/ui/dialog"; + +import { Input } from "@/components/ui/input"; + +import { Loader2, Plus, Pencil, Trash, RefreshCw } from "lucide-react"; + +export default function CareerPage() { + const [careers, setCareers] = useState([]); + const [loading, setLoading] = useState(true); + + const [openModal, setOpenModal] = useState(false); + const [editing, setEditing] = useState(null); + + const [searchText, setSearchText] = useState(""); + + const [form, setForm] = useState({ + post: "", + designation: "", + qualification: "", + experienceNeed: "", + email: "", + number: "", + status: "new", + }); + + const fetchAll = useCallback(async () => { + setLoading(true); + try { + const res = await getCareersApi(); + setCareers(res?.data || []); + } catch (err) { + console.error(err); + } finally { + setLoading(false); + } + }, []); + + useEffect(() => { + fetchAll(); + }, [fetchAll]); + + const filteredCareers = careers.filter((item) => + item.post?.toLowerCase().includes(searchText.toLowerCase()), + ); + + function handleChange(e: any) { + setForm({ ...form, [e.target.name]: e.target.value }); + } + + function openAdd() { + setEditing(null); + setForm({ + post: "", + designation: "", + qualification: "", + experienceNeed: "", + email: "", + number: "", + status: "new", + }); + setOpenModal(true); + } + + function openEdit(item: any) { + setEditing(item); + + setForm({ + post: item.post || "", + designation: item.designation || "", + qualification: item.qualification || "", + experienceNeed: item.experienceNeed || "", + email: item.email || "", + number: item.number || "", + status: item.status || "new", + }); + + setOpenModal(true); + } + + async function handleSubmit() { + try { + if (editing) { + await apiClient.patch(`/careers/${editing.id}`, form); + } else { + await apiClient.post("/careers", form); + } + + setOpenModal(false); + fetchAll(); + } catch (err) { + console.error(err); + } + } + + async function handleDelete(id: number) { + if (!confirm("Delete career?")) return; + await deleteCareerApi(id); + fetchAll(); + } + + return ( +
+
+

Careers

+ +
+ setSearchText(e.target.value)} + className="w-[220px]" + /> + + + + +
+
+ + + + Career List + + + +
+ + + + ID + Post + Designation + Qualification + Experience + Email + Phone + Status + Actions + + + + + {loading ? ( + + + + + + ) : filteredCareers.length === 0 ? ( + + + No careers found + + + ) : ( + filteredCareers.map((item) => ( + + {item.id} + {item.post} + {item.designation} + {item.qualification} + {item.experienceNeed} + {item.email} + {item.number} + {item.status} + + + + + + + + )) + )} + +
+
+
+
+ + {/* MODAL */} + + + + {editing ? "Edit Career" : "Add Career"} + + +
+ + + + + + + +
+ + + + + +
+
+
+ ); +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7f73ca3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "gg-backend-new", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}