'use client'; import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Globe, Plus, Edit, Trash2 } from 'lucide-react'; import DataTable from '@/components/ui/DataTable'; import Badge from '@/components/ui/Badge'; import ActionButton from '@/components/ui/ActionButton'; import Modal from '@/components/ui/Modal'; import ConfirmDialog from '@/components/ui/ConfirmDialog'; import { stationsApi } from '@/lib/api'; import Pagination from '@/components/ui/Pagination'; import { usePagination } from '@/lib/use-pagination'; export default function StationsPage() { const [filters, setFilters] = useState({ search: '', country: '', operational: '' }); const [showModal, setShowModal] = useState(false); const [editingStation, setEditingStation] = useState(null); const [deleteConfirm, setDeleteConfirm] = useState<{ isOpen: boolean; station: any | null; error?: string; cascade?: boolean; cascadeChecked?: boolean }>({ isOpen: false, station: null }); const [formError, setFormError] = useState(null); const queryClient = useQueryClient(); const { data, isLoading, error } = useQuery({ queryKey: ['stations', filters], queryFn: () => stationsApi.getAll(filters), }); const createMutation = useMutation({ mutationFn: stationsApi.create, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['stations'] }); setShowModal(false); setEditingStation(null); setFormError(null); }, onError: (e: any) => setFormError(e?.response?.data?.message || e?.message || 'Failed to create station'), }); const updateMutation = useMutation({ mutationFn: ({ id, data }: { id: string; data: any }) => stationsApi.update(id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['stations'] }); setShowModal(false); setEditingStation(null); setFormError(null); }, onError: (e: any) => setFormError(e?.response?.data?.message || e?.message || 'Failed to update station'), }); const deleteMutation = useMutation({ mutationFn: ({ id, cascade }: { id: string; cascade?: boolean }) => stationsApi.delete(id, cascade), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['stations'] }); }, onError: (e: any) => { const msg = e?.response?.data?.message || e?.message || 'Failed to delete station'; const isFkError = msg?.includes('Cannot delete') || e?.response?.status === 400; if (isFkError && !deleteConfirm.cascade) { setDeleteConfirm(prev => ({ ...prev, cascade: true, cascadeChecked: false, error: Array.isArray(msg) ? msg.join(' ') : msg })); } else { setDeleteConfirm(prev => ({ ...prev, error: Array.isArray(msg) ? msg.join(' ') : msg })); } }, }); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const sequence = parseInt(formData.get('sequence') as string); if (isNaN(sequence)) { alert('Sequence Number is required'); return; } const stationData = { code: formData.get('code') as string, name: formData.get('name') as string, city: formData.get('city') as string, countryCode: formData.get('countryCode') as string, lat: parseFloat(formData.get('lat') as string) || undefined, lng: parseFloat(formData.get('lng') as string) || undefined, timezone: formData.get('timezone') as string, sequence, isOperational: formData.get('isOperational') === 'true', }; if (editingStation) { await updateMutation.mutateAsync({ id: editingStation.id, data: stationData }); } else { await createMutation.mutateAsync(stationData); } }; const stationItems = data?.items || []; const { paged: pagedStations, page, totalPages, setPage } = usePagination(stationItems, 20); const handleDelete = (station: any) => { setDeleteConfirm({ isOpen: true, station, error: undefined }); }; const confirmDelete = async () => { if (!deleteConfirm.station) return; try { await deleteMutation.mutateAsync({ id: deleteConfirm.station.id, cascade: deleteConfirm.cascade && deleteConfirm.cascadeChecked }); setDeleteConfirm({ isOpen: false, station: null }); } catch { // error is set by onError handler } }; const columns = [ { key: 'sequence', label: 'Sequence', sortable: true, render: (station: any) => ( {station.sequence || 0} ), }, { key: 'code', label: 'Code', sortable: true, render: (station: any) => ( {station.code || 'N/A'} ), }, { key: 'name', label: 'Station Name', sortable: true, render: (station: any) => (
{station.name || 'N/A'}
{station.city || 'N/A'}
), }, { key: 'countryCode', label: 'Country', render: (station: any) => (
{station.countryCode || 'N/A'}
), }, { key: 'isOperational', label: 'Status', render: (station: any) => ( {station.isOperational ? 'Operational' : 'Closed'} ), }, ]; const actions = [ { label: 'Edit', onClick: (station: any) => { setEditingStation(station); setFormError(null); setShowModal(true); }, variant: 'secondary' as const, icon: Edit, }, { label: 'Delete', onClick: handleDelete, variant: 'danger' as const, icon: Trash2, }, ]; return (

Stations

Manage railway stations and their operational status

{ setEditingStation(null); setFormError(null); setShowModal(true); }} > Add Station
{/* Filters */}
setFilters({ ...filters, search: e.target.value })} />
{/* Stations Table */} {/* Delete Confirmation */} setDeleteConfirm({ isOpen: false, station: null })} onConfirm={confirmDelete} title="Delete Station" message={`Are you sure you want to delete ${deleteConfirm.station?.name}?`} confirmText="Delete" isDanger={true} isLoading={deleteMutation.isPending} error={deleteConfirm.error} warning={!deleteConfirm.cascade ? "This station may be referenced by routes, schedules, and bookings. Deleting it may impact these systems." : undefined} cascadeWarning={deleteConfirm.cascade ? "This station has related records (route stops, schedules, or stop times) that will also be permanently deleted." : undefined} cascadeChecked={deleteConfirm.cascadeChecked} onCascadeChange={(checked) => setDeleteConfirm(prev => ({ ...prev, cascadeChecked: checked }))} /> {/* Add/Edit Modal */} { setShowModal(false); setEditingStation(null); setFormError(null); }} title={`${editingStation ? 'Edit' : 'Add'} Station`} size="lg" >
{formError && (
{formError}
)} {editingStation && (

⚠ Warning

Editing this station may impact routes, schedules, and bookings that reference it. Proceed with caution.

)}

Used for ordering stations in routes

{ setShowModal(false); setEditingStation(null); }} > Cancel {editingStation ? 'Update' : 'Create'} Station
); }