diff --git a/backend/src/controllers/academicsResearch.controller.js b/backend/src/controllers/academicsResearch.controller.js
index cf72e49..e89edb3 100644
--- a/backend/src/controllers/academicsResearch.controller.js
+++ b/backend/src/controllers/academicsResearch.controller.js
@@ -1,10 +1,13 @@
import prisma from "../prisma/client.js";
+import { sendEmail } from "../utils/sendEmail.js";
+import { getEmailsByType } from "../utils/getEmailByTypes.js";
// CREATE ACADEMICS & RESEARCH
export const createAcademicsResearch = async (req, res) => {
try {
- const {fullName, number, emailId, subject, courseName, message} = req.body;
+ const { fullName, number, emailId, subject, courseName, message } =
+ req.body;
if (!fullName || !number) {
return res.status(400).json({
@@ -24,6 +27,32 @@ export const createAcademicsResearch = async (req, res) => {
},
});
+ try {
+ const emailList = await getEmailsByType("ACADEMICS");
+
+ if (emailList && emailList.length > 0) {
+ await sendEmail({
+ to: emailList,
+ subject: "New Academics & Research Inquiry",
+ html: `
+
New Academics & Research Inquiry
+
+ Name: ${fullName}
+ Phone: ${number}
+ Email: ${emailId || "-"}
+
+ Course: ${courseName || "-"}
+ Subject: ${subject || "-"}
+
+ Message:
+ ${message || "-"}
+ `,
+ });
+ }
+ } catch (err) {
+ console.error("Academics email failed:", err);
+ }
+
res.status(200).json({
success: true,
status: 200,
@@ -65,7 +94,7 @@ export const getAcademicsResearch = async (req, res) => {
export const getSingleAcademicsResearch = async (req, res) => {
try {
- const {id} = req.params;
+ const { id } = req.params;
const data = await prisma.academicsResearch.findUnique({
where: {
@@ -96,7 +125,7 @@ export const getSingleAcademicsResearch = async (req, res) => {
export const deleteAcademicsResearch = async (req, res) => {
try {
- const {id} = req.params;
+ const { id } = req.params;
await prisma.academicsResearch.delete({
where: {
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index fb6e48f..6584407 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -18,6 +18,7 @@ import EmailPage from "./pages/email";
import CareerPage from "./pages/Career";
import CandidatePage from "./pages/candidates";
import InquiryPage from "./pages/inquiry";
+import AcademicsPage from "./pages/Academics";
export default function App() {
return (
@@ -40,6 +41,7 @@ export default function App() {
} />
} />
} />
+ } />
diff --git a/frontend/src/api/academics.ts b/frontend/src/api/academics.ts
new file mode 100644
index 0000000..57c6903
--- /dev/null
+++ b/frontend/src/api/academics.ts
@@ -0,0 +1,11 @@
+import apiClient from "@/api/client";
+
+export const getAcademicsApi = async () => {
+ const res = await apiClient.get("/academics/getAll");
+ return res.data;
+};
+
+export const deleteAcademicsApi = async (id: number) => {
+ const res = await apiClient.delete(`/academics/${id}`);
+ return res.data;
+};
diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx
index a7413e5..95e2762 100644
--- a/frontend/src/components/layout/Sidebar.tsx
+++ b/frontend/src/components/layout/Sidebar.tsx
@@ -31,6 +31,10 @@ export default function Sidebar() {
name: "Inquiry",
path: "/inquiry",
},
+ {
+ name: "Academics & Research",
+ path: "/academics",
+ },
{
name: "Email",
path: "/email",
diff --git a/frontend/src/pages/Academics.tsx b/frontend/src/pages/Academics.tsx
new file mode 100644
index 0000000..dd8aa09
--- /dev/null
+++ b/frontend/src/pages/Academics.tsx
@@ -0,0 +1,172 @@
+import { useState, useEffect, useCallback } from "react";
+
+import { getAcademicsApi, deleteAcademicsApi } from "@/api/academics";
+import { exportToExcel } from "@/utils/exportToExcel";
+
+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 { Input } from "@/components/ui/input";
+
+import { Loader2, Trash, RefreshCw, Download } from "lucide-react";
+
+export default function AcademicsPage() {
+ const [records, setRecords] = useState([]);
+ const [loading, setLoading] = useState(true);
+
+ const [searchText, setSearchText] = useState("");
+
+ const fetchAll = useCallback(async () => {
+ setLoading(true);
+ try {
+ const res = await getAcademicsApi();
+ setRecords(res?.data || []);
+ } catch (err) {
+ console.error(err);
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ fetchAll();
+ }, [fetchAll]);
+
+ const filteredRecords = records.filter((item) => {
+ return (
+ item.fullName?.toLowerCase().includes(searchText.toLowerCase()) ||
+ item.number?.includes(searchText) ||
+ item.emailId?.toLowerCase().includes(searchText.toLowerCase()) ||
+ item.subject?.toLowerCase().includes(searchText.toLowerCase()) ||
+ item.courseName?.toLowerCase().includes(searchText.toLowerCase())
+ );
+ });
+
+ async function handleDelete(id: number) {
+ if (!confirm("Delete record?")) return;
+ await deleteAcademicsApi(id);
+ fetchAll();
+ }
+
+ const handleExport = () => {
+ const exportData = filteredRecords.map((item) => ({
+ ID: item.id,
+ Name: item.fullName,
+ Phone: item.number,
+ Email: item.emailId,
+ Course: item.courseName,
+ Subject: item.subject,
+ Message: item.message,
+ Date: new Date(item.createdAt).toLocaleDateString(),
+ }));
+
+ exportToExcel(exportData, "academics");
+ };
+
+ return (
+
+
+
Academics & Research
+
+
+ setSearchText(e.target.value)}
+ className="w-[260px]"
+ />
+
+
+
+
+
+
+
+
+
+ Academics Records
+
+
+
+
+
+
+
+ ID
+ Name
+ Phone
+ Email
+ Course
+ Subject
+ Message
+ Date
+ Actions
+
+
+
+
+ {loading ? (
+
+
+
+
+
+ ) : filteredRecords.length === 0 ? (
+
+
+ No records found
+
+
+ ) : (
+ filteredRecords.map((item) => (
+
+ {item.id}
+ {item.fullName}
+ {item.number}
+ {item.emailId}
+
+ {item.courseName}
+ {item.subject}
+
+
+ {item.message}
+
+
+
+ {new Date(item.createdAt).toLocaleDateString()}
+
+
+
+
+
+
+ ))
+ )}
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/pages/email.tsx b/frontend/src/pages/email.tsx
index 220c4c5..449a3ee 100644
--- a/frontend/src/pages/email.tsx
+++ b/frontend/src/pages/email.tsx
@@ -1,4 +1,4 @@
-import {useState, useEffect, useCallback} from "react";
+import { useState, useEffect, useCallback } from "react";
import {
getEmailConfigsApi,
@@ -16,9 +16,9 @@ import {
TableRow,
} from "@/components/ui/table";
-import {Card, CardContent, CardHeader, CardTitle} from "@/components/ui/card";
-import {Button} from "@/components/ui/button";
-import {Input} from "@/components/ui/input";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
import {
Dialog,
@@ -28,7 +28,7 @@ import {
DialogFooter,
} from "@/components/ui/dialog";
-import {Loader2, Plus, Pencil, Trash, RefreshCw} from "lucide-react";
+import { Loader2, Plus, Pencil, Trash, RefreshCw } from "lucide-react";
export default function EmailPage() {
const [emails, setEmails] = useState([]);
@@ -69,7 +69,7 @@ export default function EmailPage() {
);
function handleChange(e: any) {
- setForm({...form, [e.target.name]: e.target.value});
+ setForm({ ...form, [e.target.name]: e.target.value });
}
function openAdd() {
@@ -181,16 +181,14 @@ export default function EmailPage() {
@@ -227,11 +225,10 @@ export default function EmailPage() {
name="type"
value={form.type}
onChange={handleChange}
- className="border rounded px-2 py-2 w-full"
- >
+ className="border rounded px-2 py-2 w-full">
-
+