resolve confilict

This commit is contained in:
marshal
2026-06-05 13:06:16 +03:00
82 changed files with 3296 additions and 65 deletions

View File

@@ -0,0 +1,117 @@
// pages/admin/rateMatrix/RateMatrixApproval.tsx
import React from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { LoadingScreen } from '@/ui/LoadingScreen';
import { useRateMatrixAuth } from '@/auth/hooks/useAuth';
import { queryKeys } from '../../../constants/QUERY_KEYS';
import { API_URLS } from '@/constants/URL_CONSTANTS';
//import { MATRIX_STATUS } from '@/constants/rateMatrixConstants';
import { toast } from 'sonner';
import { Navigate } from 'react-router-dom';
export default function RateMatrixApprovalPage() {
const { isChiefExecutive } = useRateMatrixAuth();
const queryClient = useQueryClient();
const pendingMatricesQueryKey = [...queryKeys.rateMatrix.all, 'pending-approval'];
const { data: pendingMatrices, isLoading } = useQuery({
queryKey: pendingMatricesQueryKey,
queryFn: async () => {
const response = await fetch(`${API_URLS.RATE_MATRIX.LIST}?status=pending_approval`);
return response.json();
},
});
const authorizeMutation = useMutation({
mutationFn: async ({ matrixId, signature }: { matrixId: string; signature: string }) => {
const response = await fetch(API_URLS.RATE_MATRIX.AUTHORIZE(matrixId), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ digitalSignature: signature }),
});
if (!response.ok) throw new Error('Authorization failed');
return response.json();
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: pendingMatricesQueryKey });
toast.success('Rate matrix authorized successfully!');
},
onError: () => {
toast.error('Failed to authorize rate matrix');
},
});
if (!isChiefExecutive) {
return <Navigate to="/unauthorized" replace />;
}
if (isLoading) return <LoadingScreen />;
return (
<div className="container mx-auto py-8">
<h1 className="text-3xl font-bold mb-8">Pending Rate Matrix Approvals</h1>
<div className="space-y-6">
{pendingMatrices?.map((matrix: any) => (
<Card key={matrix.id}>
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span>{matrix.matrixName}</span>
<Badge variant="secondary">{matrix.status}</Badge>
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<p className="text-sm font-semibold">Effective Date</p>
<p>{matrix.effectiveDate}</p>
</div>
<div>
<p className="text-sm font-semibold">Submitted By</p>
<p>{matrix.createdBy}</p>
</div>
</div>
<div>
<p className="text-sm font-semibold mb-2">Rate Types Included:</p>
<div className="flex flex-wrap gap-2">
{matrix.rateEntries?.map((entry: any) => (
<Badge key={entry.id} variant="outline">
{entry.rateType}
</Badge>
))}
</div>
</div>
<div className="flex gap-4">
<Button
onClick={() => {
// Implement digital signature collection
const signature = prompt('Enter digital signature:');
if (signature) {
authorizeMutation.mutate({
matrixId: matrix.id,
signature
});
}
}}
disabled={authorizeMutation.isPending}
>
Authorize & Release
</Button>
<Button variant="outline">
Request Changes
</Button>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</div>
);
}

View File

@@ -0,0 +1,25 @@
// pages/admin/rateMatrix/RateMatrixRegistration.tsx
import React from 'react';
import { RateMatrixForm } from '@/components/baselineRatematrix/RateMatrixForm';
import { useRateMatrixAuth } from '@/auth/useAuth';
import { Navigate } from 'react-router-dom';
// Local lightweight fallback for LoadingScreen to avoid import errors
const LoadingScreen: React.FC<{ message?: string }> = ({ message = 'Loading...' }) => (
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
<div>{message}</div>
</div>
);
export default function RateMatrixRegistrationPage() {
const { isDirector, isLoading } = useRateMatrixAuth();
if (isLoading) {
return <LoadingScreen message="Checking permissions..." />;
}
if (!isDirector) {
return <Navigate to="/unauthorized" replace />;
}
return <RateMatrixForm />;
}

View File

@@ -0,0 +1,34 @@
import { useCargoes } from '@/hooks/useCargoes';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Badge } from '@/components/ui/badge';
import { LoadCargoDialog } from '@/components/cargoes/LoadCargoDialog';
export default function CargoesPage() {
const { data: cargoes, refetch, isLoading } = useCargoes();
if (isLoading) return <div>Loading cargoes...</div>;
return (
<Card>
<CardHeader><CardTitle>All Cargoes</CardTitle></CardHeader>
<CardContent>
<Table>
<TableHeader><TableRow><TableHead>Reference</TableHead><TableHead>Description</TableHead><TableHead>Quantity</TableHead><TableHead>Weight</TableHead><TableHead>Status</TableHead><TableHead>Actions</TableHead></TableRow></TableHeader>
<TableBody>
{cargoes?.map(c => (
<TableRow key={c.id}>
<TableCell>{c.cargoReference}</TableCell>
<TableCell>{c.description || '-'}</TableCell>
<TableCell>{c.quantity}</TableCell>
<TableCell>{c.weight} kg</TableCell>
<TableCell><Badge variant="outline">{c.status}</Badge></TableCell>
<TableCell>
{c.status === 'PENDING' && <LoadCargoDialog cargoId={c.id} onSuccess={() => refetch()} />}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,29 @@
import { useContainers } from '@/hooks/useContainers';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Badge } from '@/components/ui/badge';
export default function ContainersPage() {
const { data: containers, isLoading } = useContainers();
if (isLoading) return <div>Loading containers...</div>;
return (
<Card>
<CardHeader><CardTitle>All Containers</CardTitle></CardHeader>
<CardContent>
<Table>
<TableHeader><TableRow><TableHead>Number</TableHead><TableHead>Type</TableHead><TableHead>Wagon</TableHead><TableHead>Status</TableHead></TableRow></TableHeader>
<TableBody>
{containers?.map(c => (
<TableRow key={c.id}>
<TableCell>{c.containerNumber}</TableCell>
<TableCell>{c.containerTypeId}</TableCell>
<TableCell>{c.wagonId || 'Unassigned'}</TableCell>
<TableCell><Badge variant="outline">{c.status}</Badge></TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,33 @@
import { useParams } from 'react-router-dom';
import { useTrain } from '@/hooks/useTrains';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';
import { AssignWagonDialog } from '@/components/AssignWagonDialog';
import { WagonsTable } from '@/components/WagonsTable';
export default function TrainDetailPage() {
const { id } = useParams<{ id: string }>();
const { data: train, isLoading } = useTrain(id!);
if (isLoading) return <Skeleton className="h-96 w-full" />;
if (!train) return <div>Train not found</div>;
return (
<div className="space-y-6">
<Card>
<CardHeader><CardTitle>{train.trainNumber || train.code} - {train.trainName || 'Unnamed'}</CardTitle></CardHeader>
<CardContent className="grid md:grid-cols-2 gap-4">
<div><span className="font-medium">Status:</span> {train.status}</div>
<div><span className="font-medium">Capacity:</span> {train.capacityTons} tons</div>
<div><span className="font-medium">Origin Station:</span> {train.originStationId || '-'}</div>
<div><span className="font-medium">Destination:</span> {train.destinationStationId || '-'}</div>
</CardContent>
</Card>
<div className="flex justify-between items-center">
<h2 className="text-xl font-semibold">Wagons</h2>
<AssignWagonDialog trainId={train.id} />
</div>
<WagonsTable trainId={train.id} />
</div>
);
}

View File

@@ -1,3 +1,42 @@
<<<<<<< HEAD
import { useState } from 'react';
import { useTrains, useDeleteTrain, useCreateTrain } from '@/hooks/useTrains';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useToast } from '@/hooks/use-toast';
import { Plus, Eye, Trash2 } from 'lucide-react';
import { Link } from 'react-router-dom';
const CreateTrainForm = ({ onSuccess }: { onSuccess: () => void }) => {
const [form, setForm] = useState({ code: '', capacityTons: 0, trainNumber: '', trainName: '' });
const createTrain = useCreateTrain();
const { toast } = useToast();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
await createTrain.mutateAsync(form);
toast({ title: 'Train created', description: `${form.code} added.` });
onSuccess();
} catch {
toast({ title: 'Error', description: 'Failed to create train.', variant: 'destructive' });
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div><Label>Code*</Label><Input required value={form.code} onChange={e => setForm({...form, code: e.target.value})} /></div>
<div><Label>Capacity (tons)*</Label><Input type="number" required value={form.capacityTons} onChange={e => setForm({...form, capacityTons: parseFloat(e.target.value)})} /></div>
<div><Label>Train Number</Label><Input value={form.trainNumber} onChange={e => setForm({...form, trainNumber: e.target.value})} /></div>
<div><Label>Train Name</Label><Input value={form.trainName} onChange={e => setForm({...form, trainName: e.target.value})} /></div>
<Button type="submit" disabled={createTrain.isPending}>Save</Button>
</form>
=======
import { useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { isAxiosError } from 'axios';
@@ -755,7 +794,45 @@ const TrainsPage = () => {
</DialogContent>
</Dialog>
</div>
>>>>>>> 523d7e58422f1bde8024c2dd237092a7cf6aa190
);
};
export default TrainsPage;
export default function TrainsPage() {
const { data: trains, isLoading } = useTrains();
const deleteTrain = useDeleteTrain();
const [open, setOpen] = useState(false);
if (isLoading) return <div className="p-8">Loading trains...</div>;
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Trains</CardTitle>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild><Button size="sm"><Plus className="mr-2 h-4 w-4" />New Train</Button></DialogTrigger>
<DialogContent><DialogHeader><DialogTitle>Create Train</DialogTitle></DialogHeader><CreateTrainForm onSuccess={() => setOpen(false)} /></DialogContent>
</Dialog>
</CardHeader>
<CardContent>
<Table>
<TableHeader><TableRow><TableHead>Number</TableHead><TableHead>Name</TableHead><TableHead>Status</TableHead><TableHead>Capacity</TableHead><TableHead>Actions</TableHead></TableRow></TableHeader>
<TableBody>
{trains?.map(train => (
<TableRow key={train.id}>
<TableCell>{train.trainNumber || train.code}</TableCell>
<TableCell>{train.trainName || '-'}</TableCell>
<TableCell><Badge variant="outline">{train.status}</Badge></TableCell>
<TableCell>{train.capacityTons} t</TableCell>
<TableCell className="flex space-x-2">
<Link to={`/trains/${train.id}`}><Button variant="ghost" size="icon"><Eye className="h-4 w-4" /></Button></Link>
<Button variant="ghost" size="icon" onClick={() => deleteTrain.mutate(train.id)}><Trash2 className="h-4 w-4" /></Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
);
}

View File

@@ -0,0 +1,29 @@
import { useWagons } from '@/hooks/useWagons';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
export default function WagonsPage() {
const { data: wagons, isLoading } = useWagons();
if (isLoading) return <div>Loading wagons...</div>;
return (
<Card>
<CardHeader><CardTitle>All Wagons</CardTitle></CardHeader>
<CardContent>
<Table>
<TableHeader><TableRow><TableHead>Number</TableHead><TableHead>Type</TableHead><TableHead>Train</TableHead><TableHead>Status</TableHead></TableRow></TableHeader>
<TableBody>
{wagons?.map(w => (
<TableRow key={w.id}>
<TableCell>{w.wagonNumber}</TableCell>
<TableCell>{w.wagonTypeId}</TableCell>
<TableCell>{w.trainId || 'Unassigned'}</TableCell>
<TableCell><Badge variant="outline">{w.status}</Badge></TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
);
}