feat: add route definitions and incident management modal for recovery workflows
This commit is contained in:
+27
-15
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user