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:
@@ -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 { FileText, User, Airplane, WarningCircle, CaretRight } from '@phosphor-icons/react';
|
||||||
import {
|
import {
|
||||||
CustomModal,
|
CustomModal,
|
||||||
CustomInput,
|
CustomInput,
|
||||||
CustomDropdown,
|
CustomDropdown,
|
||||||
} from "../../../components/custom";
|
} from "../../../components/custom";
|
||||||
|
import { RecoveryIncidentsApi } from '../RecoveryIncidentsApi';
|
||||||
|
|
||||||
interface AddRecoveryIncidentsProps {
|
interface AddRecoveryIncidentsProps {
|
||||||
isOpen: boolean;
|
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";
|
const SECTION_CONTAINER_CLASS = "bg-[#F9FAFB] rounded-[14px] p-5 border border-gray-100";
|
||||||
|
|
||||||
export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryIncidentsProps) {
|
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 (
|
return (
|
||||||
<CustomModal
|
<CustomModal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
@@ -23,8 +71,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
icon={<FileText className="text-[#1B9869]" />}
|
icon={<FileText className="text-[#1B9869]" />}
|
||||||
size="lg"
|
size="lg"
|
||||||
primaryAction={{
|
primaryAction={{
|
||||||
label: "Assess & Log Incident",
|
label: loading ? "Logging..." : "Assess & Log Incident",
|
||||||
onClick: onClose,
|
onClick: handleSubmit,
|
||||||
icon: <CaretRight size={16} />
|
icon: <CaretRight size={16} />
|
||||||
}}
|
}}
|
||||||
secondaryAction={{
|
secondaryAction={{
|
||||||
@@ -43,14 +91,20 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
<CustomInput
|
<CustomInput
|
||||||
label="Full Name"
|
label="Full Name"
|
||||||
placeholder="e.g. John Doe"
|
placeholder="e.g. John Doe"
|
||||||
|
value={formData.passengerName}
|
||||||
|
onChange={(e) => handleInputChange("passengerName", e.target.value)}
|
||||||
/>
|
/>
|
||||||
<CustomInput
|
<CustomInput
|
||||||
label="PNR Reference"
|
label="PNR Reference"
|
||||||
placeholder="e.g. FT7687T9I"
|
placeholder="e.g. FT7687T9I"
|
||||||
|
value={formData.pnr}
|
||||||
|
onChange={(e) => handleInputChange("pnr", e.target.value)}
|
||||||
/>
|
/>
|
||||||
<CustomDropdown
|
<CustomDropdown
|
||||||
label="Loyalty Tier"
|
label="Loyalty Tier"
|
||||||
placeholder="Selected Option"
|
placeholder="Selected Option"
|
||||||
|
value={formData.loyaltyTier}
|
||||||
|
onChange={(val) => handleInputChange("loyaltyTier", val as string)}
|
||||||
options={[
|
options={[
|
||||||
{ label: "Gold", value: "gold" },
|
{ label: "Gold", value: "gold" },
|
||||||
{ label: "Silver", value: "silver" },
|
{ label: "Silver", value: "silver" },
|
||||||
@@ -70,6 +124,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
<CustomDropdown
|
<CustomDropdown
|
||||||
label="Flight Number"
|
label="Flight Number"
|
||||||
placeholder="e.g. B7687YT"
|
placeholder="e.g. B7687YT"
|
||||||
|
value={formData.flightNumber}
|
||||||
|
onChange={(val) => handleInputChange("flightNumber", val as string)}
|
||||||
options={[
|
options={[
|
||||||
{ label: "B7687YT", value: "B7687YT" },
|
{ label: "B7687YT", value: "B7687YT" },
|
||||||
{ label: "Q23SXD", value: "Q23SXD" },
|
{ label: "Q23SXD", value: "Q23SXD" },
|
||||||
@@ -80,10 +136,14 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
type="date"
|
type="date"
|
||||||
label="Date"
|
label="Date"
|
||||||
placeholder="Selected Option"
|
placeholder="Selected Option"
|
||||||
|
value={formData.date}
|
||||||
|
onChange={(e) => handleInputChange("date", e.target.value)}
|
||||||
/>
|
/>
|
||||||
<CustomDropdown
|
<CustomDropdown
|
||||||
label="Origin (IATA)"
|
label="Origin (IATA)"
|
||||||
placeholder="Selected Option"
|
placeholder="Selected Option"
|
||||||
|
value={formData.origin}
|
||||||
|
onChange={(val) => handleInputChange("origin", val as string)}
|
||||||
options={[
|
options={[
|
||||||
{ label: "FRA", value: "FRA" },
|
{ label: "FRA", value: "FRA" },
|
||||||
{ label: "LHR", value: "LHR" },
|
{ label: "LHR", value: "LHR" },
|
||||||
@@ -93,6 +153,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
<CustomDropdown
|
<CustomDropdown
|
||||||
label="Destination (IATA)"
|
label="Destination (IATA)"
|
||||||
placeholder="Selected Option"
|
placeholder="Selected Option"
|
||||||
|
value={formData.destination}
|
||||||
|
onChange={(val) => handleInputChange("destination", val as string)}
|
||||||
options={[
|
options={[
|
||||||
{ label: "JFK", value: "JFK" },
|
{ label: "JFK", value: "JFK" },
|
||||||
{ label: "CDG", value: "CDG" },
|
{ label: "CDG", value: "CDG" },
|
||||||
@@ -112,6 +174,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
<CustomDropdown
|
<CustomDropdown
|
||||||
label="Category"
|
label="Category"
|
||||||
placeholder="Selected Option"
|
placeholder="Selected Option"
|
||||||
|
value={formData.category}
|
||||||
|
onChange={(val) => handleInputChange("category", val as string)}
|
||||||
options={[
|
options={[
|
||||||
{ label: "Flight Ops", value: "flight_ops" },
|
{ label: "Flight Ops", value: "flight_ops" },
|
||||||
{ label: "Travel Exp", value: "travel_exp" },
|
{ label: "Travel Exp", value: "travel_exp" },
|
||||||
@@ -121,6 +185,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
<CustomDropdown
|
<CustomDropdown
|
||||||
label="Scenario"
|
label="Scenario"
|
||||||
placeholder="Selected Option"
|
placeholder="Selected Option"
|
||||||
|
value={formData.scenario}
|
||||||
|
onChange={(val) => handleInputChange("scenario", val as string)}
|
||||||
options={[
|
options={[
|
||||||
{ label: "Delay", value: "delay" },
|
{ label: "Delay", value: "delay" },
|
||||||
{ label: "Cancellation", value: "cancellation" },
|
{ label: "Cancellation", value: "cancellation" },
|
||||||
@@ -130,6 +196,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
<CustomDropdown
|
<CustomDropdown
|
||||||
label="Jurisdiction"
|
label="Jurisdiction"
|
||||||
placeholder="Selected Option"
|
placeholder="Selected Option"
|
||||||
|
value={formData.jurisdiction}
|
||||||
|
onChange={(val) => handleInputChange("jurisdiction", val as string)}
|
||||||
options={[
|
options={[
|
||||||
{ label: "EU261", value: "eu261" },
|
{ label: "EU261", value: "eu261" },
|
||||||
{ label: "US DOT", value: "us_dot" },
|
{ label: "US DOT", value: "us_dot" },
|
||||||
@@ -139,6 +207,8 @@ export default function AddRecoveryIncidents({ isOpen, onClose }: AddRecoveryInc
|
|||||||
type="number"
|
type="number"
|
||||||
label="Delay Duration (Mins)"
|
label="Delay Duration (Mins)"
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
|
value={formData.delayDuration}
|
||||||
|
onChange={(e) => handleInputChange("delayDuration", e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
import type { Column } from "../../../components/custom/CustomTable";
|
import type { Column } from "../../../components/custom/CustomTable";
|
||||||
import type { RecoveryIncident } from "../RecoveryIncidentsTypes";
|
import type { RecoveryIncident } from "../RecoveryIncidentsTypes";
|
||||||
import AddRecoveryIncidents from "./AddRecoveryIncidents";
|
import AddRecoveryIncidents from "./AddRecoveryIncidents";
|
||||||
|
import { RecoveryIncidentsApi } from "../RecoveryIncidentsApi";
|
||||||
|
|
||||||
// ─── Constants ───────────────────────────────────────────────────────────────
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -303,12 +304,13 @@ export default function RecoveryIncidentsList() {
|
|||||||
// ─── Fetch data ─────────────────────────────────────────────
|
// ─── Fetch data ─────────────────────────────────────────────
|
||||||
|
|
||||||
const fetchIncidents = useCallback(
|
const fetchIncidents = useCallback(
|
||||||
(page: number) => {
|
async (page: number) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
// Simulate API call with timeout
|
try {
|
||||||
setTimeout(() => {
|
const data = await RecoveryIncidentsApi.getAll();
|
||||||
const filteredData = MOCK_INCIDENTS.filter((p) => {
|
|
||||||
|
const filteredData = data.filter((p) => {
|
||||||
const matchesSearch = p.recoveryId.toLowerCase().includes(search.toLowerCase()) ||
|
const matchesSearch = p.recoveryId.toLowerCase().includes(search.toLowerCase()) ||
|
||||||
p.flightNumber.toLowerCase().includes(search.toLowerCase());
|
p.flightNumber.toLowerCase().includes(search.toLowerCase());
|
||||||
const matchesGroup = isGrouped ? true : !p.isGroupHeader;
|
const matchesGroup = isGrouped ? true : !p.isGroupHeader;
|
||||||
@@ -323,8 +325,12 @@ export default function RecoveryIncidentsList() {
|
|||||||
setIncidents(paginatedData);
|
setIncidents(paginatedData);
|
||||||
setTotalItems(total);
|
setTotalItems(total);
|
||||||
setTotalPages(pages || 1);
|
setTotalPages(pages || 1);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch recovery incidents", error);
|
||||||
|
setIncidents([]);
|
||||||
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, 500);
|
}
|
||||||
},
|
},
|
||||||
[search, isGrouped],
|
[search, isGrouped],
|
||||||
);
|
);
|
||||||
@@ -619,7 +625,10 @@ export default function RecoveryIncidentsList() {
|
|||||||
{/* Modal */}
|
{/* Modal */}
|
||||||
<AddRecoveryIncidents
|
<AddRecoveryIncidents
|
||||||
isOpen={isModalOpen}
|
isOpen={isModalOpen}
|
||||||
onClose={() => setIsModalOpen(false)}
|
onClose={() => {
|
||||||
|
setIsModalOpen(false);
|
||||||
|
fetchIncidents(currentPage); // Refresh list
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user