Merge pull request 'done recovery incidents' (#25) from azeem into development

Reviewed-on: https://gitea.maskantech.in/gitea_admin/aeroresolve_frontend/pulls/25
This commit is contained in:
Syed Waseem khadri Rafai
2026-08-04 09:16:44 +00:00
3 changed files with 111 additions and 8 deletions
@@ -0,0 +1,24 @@
import { ApiClient } from '../api/ApiClient';
import type { RecoveryIncident } from './RecoveryIncidentsTypes';
export const RecoveryIncidentsApi = {
getAll: async (): Promise<RecoveryIncident[]> => {
return ApiClient.get('/recovery-incidents');
},
getById: async (id: string): Promise<RecoveryIncident> => {
return ApiClient.get(`/recovery-incidents/${id}`);
},
create: async (data: Omit<RecoveryIncident, 'id'>): Promise<RecoveryIncident> => {
return ApiClient.post('/recovery-incidents', data);
},
update: async (id: string, data: Partial<RecoveryIncident>): Promise<RecoveryIncident> => {
return ApiClient.patch(`/recovery-incidents/${id}`, data);
},
delete: async (id: string): Promise<void> => {
return ApiClient.delete(`/recovery-incidents/${id}`);
},
};
@@ -1,9 +1,11 @@
import { useState } from 'react';
import { FileText, User, Airplane, WarningCircle, CaretRight } from '@phosphor-icons/react';
import {
CustomModal,
CustomInput,
CustomDropdown,
} from "../../../components/custom";
import { RecoveryIncidentsApi } from '../RecoveryIncidentsApi';
interface AddRecoveryIncidentsProps {
isOpen: boolean;
@@ -14,6 +16,52 @@ const SECTION_TITLE_CLASS = "flex items-center gap-2 mb-4 text-[#4A5568] font-bo
const SECTION_CONTAINER_CLASS = "bg-[#F9FAFB] rounded-[14px] p-5 border border-gray-100";
export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryIncidentsProps) {
const [formData, setFormData] = useState({
passengerName: "",
pnr: "",
loyaltyTier: "",
flightNumber: "",
date: "",
origin: "",
destination: "",
category: "",
scenario: "",
jurisdiction: "",
delayDuration: "",
});
const [loading, setLoading] = useState(false);
const handleInputChange = (field: string, value: string) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
const handleSubmit = async () => {
setLoading(true);
try {
const payload = {
recoveryId: "REC-" + Math.floor(Math.random() * 10000),
passengerName: formData.passengerName || "Unknown",
pnr: formData.pnr || "N/A",
flightNumber: formData.flightNumber || "TBD",
flightRoute: `${formData.origin || 'UNK'}${formData.destination || 'UNK'}`,
date: formData.date ? new Date(formData.date).toISOString() : new Date().toISOString(),
category: formData.category || "General",
statuses: [{ text: "New", variant: "info" as const }],
value: "$0",
};
console.log("Submitting payload:", payload);
await RecoveryIncidentsApi.create(payload);
onClose(); // Will trigger refresh in parent list
} catch (error: any) {
console.error("Error creating incident:", error.response?.data || error.message || error);
alert(`Failed to add incident: ${error.response?.data?.message || 'Unknown error'}`);
} finally {
setLoading(false);
}
};
return (
<CustomModal
isOpen={isOpen}
@@ -23,8 +71,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
icon={<FileText className="text-[#1B9869]" />}
size="lg"
primaryAction={{
label: "Assess & Log Incident",
onClick: onClose,
label: loading ? "Logging..." : "Assess & Log Incident",
onClick: handleSubmit,
icon: <CaretRight size={16} />
}}
secondaryAction={{
@@ -43,14 +91,20 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
<CustomInput
label="Full Name"
placeholder="e.g. John Doe"
value={formData.passengerName}
onChange={(e) => handleInputChange("passengerName", e.target.value)}
/>
<CustomInput
label="PNR Reference"
placeholder="e.g. FT7687T9I"
value={formData.pnr}
onChange={(e) => handleInputChange("pnr", e.target.value)}
/>
<CustomDropdown
label="Loyalty Tier"
placeholder="Selected Option"
value={formData.loyaltyTier}
onChange={(val) => handleInputChange("loyaltyTier", val as string)}
options={[
{ label: "Gold", value: "gold" },
{ label: "Silver", value: "silver" },
@@ -70,6 +124,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
<CustomDropdown
label="Flight Number"
placeholder="e.g. B7687YT"
value={formData.flightNumber}
onChange={(val) => handleInputChange("flightNumber", val as string)}
options={[
{ label: "B7687YT", value: "B7687YT" },
{ label: "Q23SXD", value: "Q23SXD" },
@@ -80,10 +136,14 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
type="date"
label="Date"
placeholder="Selected Option"
value={formData.date}
onChange={(e) => handleInputChange("date", e.target.value)}
/>
<CustomDropdown
label="Origin (IATA)"
placeholder="Selected Option"
value={formData.origin}
onChange={(val) => handleInputChange("origin", val as string)}
options={[
{ label: "FRA", value: "FRA" },
{ label: "LHR", value: "LHR" },
@@ -93,6 +153,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
<CustomDropdown
label="Destination (IATA)"
placeholder="Selected Option"
value={formData.destination}
onChange={(val) => handleInputChange("destination", val as string)}
options={[
{ label: "JFK", value: "JFK" },
{ label: "CDG", value: "CDG" },
@@ -112,6 +174,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
<CustomDropdown
label="Category"
placeholder="Selected Option"
value={formData.category}
onChange={(val) => handleInputChange("category", val as string)}
options={[
{ label: "Flight Ops", value: "flight_ops" },
{ label: "Travel Exp", value: "travel_exp" },
@@ -121,6 +185,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
<CustomDropdown
label="Scenario"
placeholder="Selected Option"
value={formData.scenario}
onChange={(val) => handleInputChange("scenario", val as string)}
options={[
{ label: "Delay", value: "delay" },
{ label: "Cancellation", value: "cancellation" },
@@ -130,6 +196,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
<CustomDropdown
label="Jurisdiction"
placeholder="Selected Option"
value={formData.jurisdiction}
onChange={(val) => handleInputChange("jurisdiction", val as string)}
options={[
{ label: "EU261", value: "eu261" },
{ label: "US DOT", value: "us_dot" },
@@ -139,6 +207,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
type="number"
label="Delay Duration (Mins)"
placeholder="0"
value={formData.delayDuration}
onChange={(e) => handleInputChange("delayDuration", e.target.value)}
/>
</div>
</div>
@@ -20,6 +20,7 @@ import {
import type { Column } from "../../../components/custom/CustomTable";
import type { RecoveryIncident } from "../RecoveryIncidentsTypes";
import AddRecoveryIncidents from "./AddRecoveryIncidents";
import { RecoveryIncidentsApi } from "../RecoveryIncidentsApi";
// ─── Constants ───────────────────────────────────────────────────────────────
@@ -303,12 +304,13 @@ export default function RecoveryIncidentsList() {
// ─── Fetch data ─────────────────────────────────────────────
const fetchIncidents = useCallback(
(page: number) => {
async (page: number) => {
setLoading(true);
// Simulate API call with timeout
setTimeout(() => {
const filteredData = MOCK_INCIDENTS.filter((p) => {
try {
const data = await RecoveryIncidentsApi.getAll();
const filteredData = data.filter((p) => {
const matchesSearch = p.recoveryId.toLowerCase().includes(search.toLowerCase()) ||
p.flightNumber.toLowerCase().includes(search.toLowerCase());
const matchesGroup = isGrouped ? true : !p.isGroupHeader;
@@ -323,8 +325,12 @@ export default function RecoveryIncidentsList() {
setIncidents(paginatedData);
setTotalItems(total);
setTotalPages(pages || 1);
} catch (error) {
console.error("Failed to fetch recovery incidents", error);
setIncidents([]);
} finally {
setLoading(false);
}, 500);
}
},
[search, isGrouped],
);
@@ -619,7 +625,10 @@ export default function RecoveryIncidentsList() {
{/* Modal */}
<AddRecoveryIncidents
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onClose={() => {
setIsModalOpen(false);
fetchIncidents(currentPage); // Refresh list
}}
/>
</div>
);