feat: add route definitions and incident management modal for recovery workflows

This commit is contained in:
azeeee05
2026-08-19 11:41:13 +05:30
parent a1ea47c0f5
commit 13c043ba56
2 changed files with 85 additions and 72 deletions
+27 -15
View File
@@ -1,16 +1,25 @@
import { lazy, Suspense } from 'react'
import { Route, Routes, Navigate } from 'react-router-dom'
import Layout from './layout/AppLayout'
import { lazy, Suspense } from "react";
import { Route, Routes, Navigate } from "react-router-dom";
import Layout from "./layout/AppLayout";
const HomePage = lazy(() => import('./app/dashboard'))
const CohortManage = lazy(() => import('./app/cohartManage'))
const PolicyEngineList = lazy(() => import('./app/policyEngine/components/PolicyEngineList'))
const AddPolicyEngine = lazy(() => import('./app/policyEngine/components/AddPolicyEngine'))
const RecoveryIncidentsList = lazy(() => import('./app/recoveryIncidents/components/RecoveryIncidentsList'))
const RecoveryIncidentTabs = lazy(() => import('./app/recoveryIncidents/tabs/index'))
const AuditLogsList = lazy(() => import('./app/auditLogs/components/AuditLogsList'))
const ConfigurationPage = lazy(() => import('./app/configuration'))
const HomePage = lazy(() => import("./app/dashboard"));
const CohortManage = lazy(() => import("./app/cohartManage"));
const PolicyEngineList = lazy(
() => import("./app/policyEngine/components/PolicyEngineList"),
);
const AddPolicyEngine = lazy(
() => import("./app/policyEngine/components/AddPolicyEngine"),
);
const RecoveryIncidentsList = lazy(
() => import("./app/recoveryIncidents/components/RecoveryIncidentsList"),
);
const RecoveryIncidentTabs = lazy(
() => import("./app/recoveryIncidents/tabs/index"),
);
const AuditLogsList = lazy(
() => import("./app/auditLogs/components/AuditLogsList"),
);
const ConfigurationPage = lazy(() => import("./app/configuration"));
function AppRoutes() {
return (
@@ -22,7 +31,10 @@ function AppRoutes() {
<Route path="/policy-engine" element={<PolicyEngineList />} />
<Route path="/policy-engine/add" element={<AddPolicyEngine />} />
<Route path="/policy-engine/edit/:id" element={<AddPolicyEngine />} />
<Route path="/action-builder" element={<Navigate to="/config?tab=action-builder" replace />} />
<Route
path="/action-builder"
element={<Navigate to="/config?tab=action-builder" replace />}
/>
<Route path="/config" element={<ConfigurationPage />} />
<Route path="/recovery" element={<RecoveryIncidentsList />} />
<Route path="/recovery/:id" element={<RecoveryIncidentTabs />} />
@@ -30,7 +42,7 @@ function AppRoutes() {
</Routes>
</Suspense>
</Layout>
)
);
}
export default AppRoutes
export default AppRoutes;
@@ -6,7 +6,7 @@ import {
CustomDropdown,
CustomCheckBox,
} from "../../../components/custom";
import { createRecoveryIncident, updateRecoveryIncident } from '../RecoveryIncidentsApi';
import { createRecoveryIncident, updateRecoveryIncident, getRecoveryIncidents } from '../RecoveryIncidentsApi';
import { getMembershipTiers, getCategoryValues } from '../../configuration/masterData/MasterDataApi';
import {
getMockFlightNumbers,
@@ -53,6 +53,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
const [passengersList, setPassengersList] = useState<MockPassenger[]>([]);
const [selectedPassengerIds, setSelectedPassengerIds] = useState<string[]>([]);
const [autoFilledNotice, setAutoFilledNotice] = useState<string | null>(null);
const [perksClaimedMap, setPerksClaimedMap] = useState<Record<string, boolean>>({});
const [existingIncidents, setExistingIncidents] = useState<RecoveryIncident[]>([]);
const [formData, setFormData] = useState({
passengerName: "",
@@ -153,11 +155,33 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
if (res.disruption) {
const passengers = res.disruption.passengers || [];
setPassengersList(passengers);
if (res.matchedPassengerId) {
setSelectedPassengerIds([res.matchedPassengerId]);
} else {
setSelectedPassengerIds(passengers.map((p) => p.id));
}
getRecoveryIncidents().then(all => {
const flightIncidents = all.filter(i => i.flightNumber === res.disruption!.flightNumber);
setExistingIncidents(flightIncidents);
const newPerks: Record<string, boolean> = {};
const newSelected: string[] = [];
flightIncidents.forEach(fi => {
const p = passengers.find(pass => pass.pnr === fi.pnr && pass.passengerName === fi.passengerName);
if (p) {
newSelected.push(p.id);
if (fi.isPerksClaimed) newPerks[p.id] = true;
}
});
const p = passengers.find(pass => pass.pnr === incident.pnr && pass.passengerName === incident.passengerName);
if (p) {
if (!newSelected.includes(p.id)) newSelected.push(p.id);
if (incident.isPerksClaimed) newPerks[p.id] = true;
}
setSelectedPassengerIds(newSelected.length > 0 ? newSelected : passengers.map(p => p.id));
setPerksClaimedMap(newPerks);
}).catch(() => {
setSelectedPassengerIds(passengers.map(p => p.id));
});
}
setAutoFilledNotice(null);
} else if (isOpen) {
@@ -179,6 +203,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
setPassengersList([]);
setSelectedPassengerIds([]);
setAutoFilledNotice(null);
setPerksClaimedMap({});
setExistingIncidents([]);
}
}, [incident, isOpen]);
@@ -188,9 +214,6 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
setFormData((prev) => ({ ...prev, [field]: value }));
};
const handleCheckboxChange = (field: string, checked: boolean) => {
setFormData((prev) => ({ ...prev, [field]: checked }));
};
// Helper when user types or selects flight number or PNR
const handleQueryChange = (val: string) => {
@@ -252,6 +275,10 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
}
};
const handleTogglePerksClaimed = (passengerId: string, checked: boolean) => {
setPerksClaimedMap(prev => ({ ...prev, [passengerId]: checked }));
};
// Toggle individual passenger row selection
const handleTogglePassengerRow = (passengerId: string) => {
setSelectedPassengerIds((prev) => {
@@ -281,11 +308,13 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
try {
const selectedPassengers = passengersList.filter((p) => selectedPassengerIds.includes(p.id));
if (selectedPassengers.length > 1 && !incident) {
// Batch log incidents for all selected passengers
if (selectedPassengers.length > 0) {
const promises = selectedPassengers.map((p) => {
const existingInc = existingIncidents.find(fi => fi.pnr === p.pnr && fi.passengerName === p.passengerName)
|| (incident && incident.pnr === p.pnr && incident.passengerName === p.passengerName ? incident : null);
const payload = {
recoveryCode: "REC-" + Math.floor(Math.random() * 100000),
recoveryCode: existingInc ? existingInc.recoveryCode : "REC-" + Math.floor(Math.random() * 100000),
passengerName: p.passengerName,
pnr: p.pnr,
loyaltyTier: p.loyaltyTier,
@@ -301,50 +330,22 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
destination: formData.destination || undefined,
date: formData.date ? new Date(formData.date).toISOString() : new Date().toISOString(),
category: formData.category || "General",
status: "Pending",
value: "$0",
isPerksClaimed: formData.isPerksClaimed,
status: existingInc ? (existingInc.status || "Pending") : "Pending",
value: existingInc ? existingInc.value : "$0",
isPerksClaimed: perksClaimedMap[p.id] || false,
jurisdiction: formData.jurisdiction || undefined,
delayDuration: formData.delayDuration ? Number(formData.delayDuration) : undefined,
scenario: formData.scenario || undefined,
};
return createRecoveryIncident(payload);
if (existingInc) {
return updateRecoveryIncident(existingInc.id, payload);
} else {
return createRecoveryIncident(payload);
}
});
await Promise.all(promises);
} else {
// Single passenger log or edit
const primaryPassenger = selectedPassengers[0];
const payload = {
recoveryCode: incident ? incident.recoveryCode : "REC-" + Math.floor(Math.random() * 100000),
passengerName: primaryPassenger ? primaryPassenger.passengerName : (formData.passengerName || "Unknown"),
pnr: primaryPassenger ? primaryPassenger.pnr : (formData.pnr || "N/A"),
loyaltyTier: primaryPassenger ? primaryPassenger.loyaltyTier : (formData.loyaltyTier || undefined),
passengerType: primaryPassenger ? primaryPassenger.passengerType : undefined,
nationality: primaryPassenger ? primaryPassenger.nationality : undefined,
specialAssistance: primaryPassenger ? primaryPassenger.specialAssistance : undefined,
cabinClass: primaryPassenger ? primaryPassenger.cabinClass : undefined,
originalCabin: primaryPassenger ? primaryPassenger.originalCabin : undefined,
actualCabin: primaryPassenger ? primaryPassenger.actualCabin : undefined,
flightNumber: formData.flightNumber || "TBD",
flightRoute: `${formData.origin || 'UNK'}${formData.destination || 'UNK'}`,
origin: formData.origin || undefined,
destination: formData.destination || undefined,
date: formData.date ? new Date(formData.date).toISOString() : new Date().toISOString(),
category: formData.category || "General",
status: incident ? (incident.status || "Pending") : "Pending",
value: incident ? incident.value : "$0",
isPerksClaimed: formData.isPerksClaimed,
jurisdiction: formData.jurisdiction || undefined,
delayDuration: formData.delayDuration ? Number(formData.delayDuration) : undefined,
scenario: formData.scenario || undefined,
};
if (incident) {
await updateRecoveryIncident(incident.id, payload);
} else {
await createRecoveryIncident(payload);
}
}
onClose();
} catch (error: any) {
@@ -364,7 +365,7 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
title={incident ? "Edit Recovery Incident" : "New Recovery Incident"}
description="Log disruption cases and assess against policy frameworks"
icon={<FileText className="text-[#1B9869]" />}
size="lg"
size="xl"
primaryAction={{
label: loading
? "Saving..."
@@ -453,6 +454,7 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
<th className="py-3 px-4">Nationality</th>
<th className="py-3 px-4">loyality type</th>
<th className="py-3 px-4">Special assisstance</th>
<th className="py-3 px-4 text-center">Perks Claimed</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
@@ -505,6 +507,12 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
</span>
</td>
<td className="py-3 px-4 text-gray-600">{p.specialAssistance}</td>
<td className="py-3 px-4 text-center" onClick={(e) => e.stopPropagation()}>
<CustomCheckBox
checked={perksClaimedMap[p.id] || false}
onChange={(e) => handleTogglePerksClaimed(p.id, e.target.checked)}
/>
</td>
</tr>
);
})}
@@ -590,13 +598,6 @@ export default function AddRecoveryIncidents({ isOpen, onClose, incident }: AddR
onChange={(e) => handleInputChange("delayDuration", e.target.value)}
/>
</div>
<div className="mt-4">
<CustomCheckBox
label="Passenger claimed the perks"
checked={formData.isPerksClaimed}
onChange={(e) => handleCheckboxChange("isPerksClaimed", e.target.checked)}
/>
</div>
</div>
</div>
</CustomModal>