Merge pull request 'feat: add bulk excel data import functionality' (#14) from feat/import-excel-data into dev

Reviewed-on: #14
This commit was merged in pull request #14.
This commit is contained in:
2026-04-20 10:02:06 +00:00
5 changed files with 441 additions and 1 deletions
+2
View File
@@ -21,6 +21,7 @@ import InquiryPage from "./pages/inquiry";
import AcademicsPage from "./pages/Academics";
import NewsPage from "./pages/newsMedia";
import BlogDetail from "./pages/BlogDetails";
import ImportData from "./pages/ImportData";
export default function App() {
return (
@@ -46,6 +47,7 @@ export default function App() {
<Route path="/inquiry" element={<InquiryPage />} />
<Route path="/academics" element={<AcademicsPage />} />
<Route path="/news" element={<NewsPage />} />
<Route path="/import" element={<ImportData />} />
</Route>
</Route>
+158
View File
@@ -0,0 +1,158 @@
import React, { useState, ChangeEvent } from "react";
import * as XLSX from "xlsx";
import apiClient from "@/api/client";
interface ImportPayload {
departments: any[];
doctors: any[];
timings: any[];
careers: any[];
inquiries: any[];
academics: any[];
appointments: any[];
candidates: any[];
news: any[];
}
const ImportData: React.FC = () => {
const [loading, setLoading] = useState<boolean>(false);
const [status, setStatus] = useState<string>("");
const handleFileUpload = (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
setLoading(true);
setStatus("Reading Excel file...");
const reader = new FileReader();
reader.onload = async (evt: ProgressEvent<FileReader>) => {
try {
const bstr = evt.target?.result;
if (!bstr) throw new Error("Failed to read file content.");
const wb = XLSX.read(bstr, { type: "binary" });
const payload: ImportPayload = {
departments: XLSX.utils.sheet_to_json(wb.Sheets["Departments"]) || [],
doctors: XLSX.utils.sheet_to_json(wb.Sheets["Doctors"]) || [],
timings: XLSX.utils.sheet_to_json(wb.Sheets["Doctor Timings"]) || [],
careers: XLSX.utils.sheet_to_json(wb.Sheets["Careers"]) || [],
inquiries: XLSX.utils.sheet_to_json(wb.Sheets["Inquiry"]) || [],
academics:
XLSX.utils.sheet_to_json(wb.Sheets["Academics & Research"]) || [],
appointments:
XLSX.utils.sheet_to_json(wb.Sheets["Appointment"]) || [],
candidates: XLSX.utils.sheet_to_json(wb.Sheets["Candidate"]) || [],
news: XLSX.utils.sheet_to_json(wb.Sheets["News & Media"]) || [],
};
setStatus("Uploading data to server (this may take a moment)...");
const response = await apiClient.post("/import/bulk", payload);
if (response.status === 200) {
setStatus("✅ ALL DATA IMPORT COMPLETED SUCCESSFULLY!");
} else {
setStatus("❌ Server responded with an error.");
}
} catch (err: any) {
console.error("Import Error:", err);
const errorMsg = err.response?.data?.error || "Error processing file.";
setStatus(`${errorMsg}`);
} finally {
setLoading(false);
if (e.target) e.target.value = "";
}
};
reader.onerror = () => {
setStatus("❌ Failed to read the file.");
setLoading(false);
};
reader.readAsBinaryString(file);
};
return (
<div style={containerStyle}>
<div style={cardStyle}>
<h2 style={{ color: "#333", marginBottom: "10px" }}>
Database Bulk Import
</h2>
<p style={{ color: "#666", marginBottom: "30px" }}>
Select the <b>gg_hospital.xlsx</b> file. This will update all tables.
</p>
<div style={{ marginBottom: "20px" }}>
<input
type="file"
accept=".xlsx, .xls"
onChange={handleFileUpload}
id="excel-upload"
style={{ display: "none" }}
disabled={loading}
/>
<label
htmlFor="excel-upload"
style={{
...buttonStyle,
backgroundColor: loading ? "#a0aec0" : "#3182ce",
cursor: loading ? "not-allowed" : "pointer",
}}
>
{loading ? "⌛ Processing..." : "📂 Choose Excel File"}
</label>
</div>
{status && (
<div
style={{
marginTop: "25px",
padding: "15px",
borderRadius: "8px",
backgroundColor: status.includes("✅") ? "#f0fff4" : "#fff5f5",
color: status.includes("✅") ? "#2f855a" : "#c53030",
border: `1px solid ${status.includes("✅") ? "#c6f6d5" : "#fed7d7"}`,
fontWeight: "500",
whiteSpace: "pre-wrap",
}}
>
{status}
</div>
)}
</div>
</div>
);
};
const containerStyle: React.CSSProperties = {
display: "flex",
justifyContent: "center",
alignItems: "center",
minHeight: "80vh",
backgroundColor: "#f7fafc",
fontFamily: "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif",
};
const cardStyle: React.CSSProperties = {
backgroundColor: "white",
padding: "40px",
borderRadius: "12px",
boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
maxWidth: "500px",
width: "100%",
textAlign: "center",
};
const buttonStyle: React.CSSProperties = {
padding: "12px 24px",
color: "white",
borderRadius: "6px",
fontSize: "16px",
fontWeight: "bold",
transition: "all 0.2s ease",
display: "inline-block",
};
export default ImportData;