Homepage Banners
-
- Manage sliding heroes, background loops, video graphics, and dynamic contextual landing URLs.
-
diff --git a/frontend/src/pages/InsurancePartner.tsx b/frontend/src/pages/InsurancePartner.tsx
new file mode 100644
index 0000000..3faabec
--- /dev/null
+++ b/frontend/src/pages/InsurancePartner.tsx
@@ -0,0 +1,285 @@
+import { useState, useEffect, useCallback, useMemo } from 'react';
+import toast from 'react-hot-toast';
+import { AxiosError } from 'axios';
+
+import {
+ getInsurancePartnersApi,
+ createInsurancePartnerApi,
+ updateInsurancePartnerApi,
+ deleteInsurancePartnerApi,
+ InsurancePartner,
+} from '@/api/insurancePartner';
+
+import InsurancePartnerModal from '@/components/InsurancePartnerModal/InsurancePartnerModal';
+
+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 { Badge } from '@/components/ui/badge';
+import { Switch } from '@/components/ui/switch';
+import { Input } from '@/components/ui/input';
+
+import { Loader2, RefreshCw, Plus, Pencil, Trash2, Link2 } from 'lucide-react';
+
+export default function InsurancePartnerPage() {
+ const [partners, setPartners] = useState
([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState('');
+
+ const [partnerModal, setPartnerModal] = useState(false);
+ const [editingPartner, setEditingPartner] = useState(null);
+
+ const [searchText, setSearchText] = useState('');
+
+ const [partnerForm, setPartnerForm] = useState>({
+ name: '',
+ logo: '',
+ websiteUrl: '',
+ sortOrder: 1000,
+ isActive: true,
+ });
+
+ const fetchData = useCallback(async () => {
+ setLoading(true);
+ setError('');
+ try {
+ const res = await getInsurancePartnersApi();
+ setPartners(res.data || []);
+ } catch (err) {
+ if (err instanceof AxiosError) {
+ setError(err.response?.data?.message || 'Failed to sync insurance directory records.');
+ } else {
+ setError('An unhandled database communication error occurred.');
+ }
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ fetchData();
+ }, [fetchData]);
+
+ const handleToggleStatus = async (partner: InsurancePartner) => {
+ if (!partner.id) return;
+ try {
+ await updateInsurancePartnerApi(partner.id, { isActive: !partner.isActive });
+ toast.success(`Partner status updated successfully`);
+ fetchData();
+ } catch (err) {
+ console.error(err);
+ toast.error('Could not overwrite corporate status configurations.');
+ }
+ };
+
+ const handleDeletePartner = async (id: number) => {
+ const confirmDelete = window.confirm(
+ 'Are you completely sure you want to remove this insurance partner record? This step is irreversible.'
+ );
+ if (!confirmDelete) return;
+
+ try {
+ await deleteInsurancePartnerApi(id);
+ fetchData();
+ } catch (err) {
+ console.error(err);
+ }
+ };
+
+ const openAddPartner = () => {
+ setEditingPartner(null);
+ setPartnerForm({
+ name: '',
+ logo: '',
+ websiteUrl: '',
+ sortOrder: 1000,
+ isActive: true,
+ });
+ setPartnerModal(true);
+ };
+
+ const openEditPartner = (partner: InsurancePartner) => {
+ setEditingPartner(partner);
+ setPartnerForm({ ...partner });
+ setPartnerModal(true);
+ };
+
+ const savePartner = async () => {
+ if (!partnerForm.name) return toast.error('Insurance Partner Name is required.');
+ if (!partnerForm.logo) return toast.error('Partner Corporate Logo Asset is required.');
+
+ try {
+ const finalData = { ...partnerForm };
+
+ if (editingPartner?.id) {
+ const changedFields: Record = {};
+ Object.keys(finalData).forEach((key) => {
+ const k = key as keyof InsurancePartner;
+ if (JSON.stringify(finalData[k]) !== JSON.stringify(editingPartner[k])) {
+ changedFields[k] = finalData[k];
+ }
+ });
+
+ delete changedFields.id;
+ delete changedFields.createdAt;
+ delete changedFields.updatedAt;
+
+ if (Object.keys(changedFields).length === 0) {
+ setPartnerModal(false);
+ return;
+ }
+
+ await updateInsurancePartnerApi(editingPartner.id, changedFields);
+ } else {
+ await createInsurancePartnerApi(finalData);
+ }
+
+ setPartnerModal(false);
+ fetchData();
+ } catch (err) {
+ console.error(err);
+ toast.error('An unexpected service exception halted corporate resource persistence runtime.');
+ }
+ };
+
+ return (
+
+
+
+
Insurance Partners
+
+
+
+
setSearchText(e.target.value)}
+ className="w-[260px] text-base"
+ />
+
+
+
+
+
+
+
+ {error &&
{error}
}
+
+
+
+ Network Panels Sequence Directory
+
+
+
+
+
+
+ Order
+ Logo Preview
+ Company Identity
+ Portal Website
+ Status
+ Actions
+
+
+
+ {loading ? (
+
+
+
+
+
+ ) : partners.length === 0 ? (
+
+
+ No active healthcare insurance tie-ups found matching criteria.
+
+
+ ) : (
+ partners.map((partner) => (
+
+ {partner.sortOrder}
+
+
+

+
+
+
+
+ {partner.name}
+
+
+
+ {partner.websiteUrl ? (
+
+
+ {partner.websiteUrl}
+
+ ) : (
+ No external URL linked
+ )}
+
+
+
+ handleToggleStatus(partner)} />
+
+ {partner.isActive ? 'Active' : 'Disabled'}
+
+
+
+
+
+
+
+
+
+
+ ))
+ )}
+
+
+
+
+
+
+
+
+ );
+}