Project Initialization

This commit is contained in:
Muluhabt
2026-05-12 15:17:16 +03:00
parent 33fa742e8a
commit 3b8b6979db
259 changed files with 15962 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
import { FormEvent, useState } from 'react';
import { Button, FormField } from '@edr/ui-common';
import type { CreateBookingPayload } from '../../services/bookings.service';
export interface BookingFormProps {
onSubmit: (payload: CreateBookingPayload) => void;
isSubmitting?: boolean;
}
const BookingForm = ({ onSubmit, isSubmitting }: BookingFormProps) => {
const [reference, setReference] = useState('');
const [customerId, setCustomerId] = useState('');
const [scheduledDate, setScheduledDate] = useState('');
const [totalAmount, setTotalAmount] = useState('0');
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
onSubmit({
reference,
customerId,
scheduledDate,
totalAmount: Number(totalAmount),
});
};
return (
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
<FormField label="Reference" value={reference} onChange={(e) => setReference(e.target.value)} required />
<FormField label="Customer ID" value={customerId} onChange={(e) => setCustomerId(e.target.value)} required />
<FormField
label="Scheduled date"
type="date"
value={scheduledDate}
onChange={(e) => setScheduledDate(e.target.value)}
required
/>
<FormField
label="Total amount"
type="number"
value={totalAmount}
onChange={(e) => setTotalAmount(e.target.value)}
min="0"
/>
<Button type="submit" isLoading={isSubmitting}>
Create booking
</Button>
</form>
);
};
export default BookingForm;

View File

@@ -0,0 +1,28 @@
import type { Freight } from '@edr/types';
import { Table, type TableColumn } from '@edr/ui-common';
export interface BookingTableProps {
bookings: Freight.IBooking[];
}
const columns: TableColumn<Freight.IBooking>[] = [
{ key: 'reference', header: 'Reference' },
{ key: 'customerId', header: 'Customer' },
{ key: 'status', header: 'Status' },
{
key: 'scheduledDate',
header: 'Scheduled',
render: (row) => new Date(row.scheduledDate).toLocaleDateString(),
},
{
key: 'totalAmount',
header: 'Total',
render: (row) => row.totalAmount.toFixed(2),
},
];
const BookingTable = ({ bookings }: BookingTableProps) => (
<Table columns={columns} data={bookings} rowKey={(row) => row.id} emptyMessage="No bookings yet" />
);
export default BookingTable;

View File

@@ -0,0 +1,72 @@
import { FormEvent, useState } from 'react';
import { Button, FormField } from '@edr/ui-common';
export interface ConsignmentFormProps {
onSubmit: (payload: {
bookingId: string;
trackingNumber: string;
cargoType: string;
weightKg: number;
originStation: string;
destinationStation: string;
}) => void;
isSubmitting?: boolean;
}
const ConsignmentForm = ({ onSubmit, isSubmitting }: ConsignmentFormProps) => {
const [bookingId, setBookingId] = useState('');
const [trackingNumber, setTrackingNumber] = useState('');
const [cargoType, setCargoType] = useState('GENERAL');
const [weightKg, setWeightKg] = useState('0');
const [originStation, setOriginStation] = useState('');
const [destinationStation, setDestinationStation] = useState('');
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
onSubmit({
bookingId,
trackingNumber,
cargoType,
weightKg: Number(weightKg),
originStation,
destinationStation,
});
};
return (
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
<FormField label="Booking ID" value={bookingId} onChange={(e) => setBookingId(e.target.value)} required />
<FormField
label="Tracking #"
value={trackingNumber}
onChange={(e) => setTrackingNumber(e.target.value)}
required
/>
<FormField label="Cargo type" value={cargoType} onChange={(e) => setCargoType(e.target.value)} />
<FormField
label="Weight (kg)"
type="number"
value={weightKg}
onChange={(e) => setWeightKg(e.target.value)}
min="0"
/>
<FormField
label="Origin station"
value={originStation}
onChange={(e) => setOriginStation(e.target.value)}
required
/>
<FormField
label="Destination station"
value={destinationStation}
onChange={(e) => setDestinationStation(e.target.value)}
required
/>
<Button type="submit" isLoading={isSubmitting}>
Create consignment
</Button>
</form>
);
};
export default ConsignmentForm;

View File

@@ -0,0 +1,26 @@
import type { Freight } from '@edr/types';
import { Table, type TableColumn } from '@edr/ui-common';
export interface ConsignmentTableProps {
consignments: Freight.IConsignment[];
}
const columns: TableColumn<Freight.IConsignment>[] = [
{ key: 'trackingNumber', header: 'Tracking #' },
{ key: 'cargoType', header: 'Cargo' },
{ key: 'status', header: 'Status' },
{ key: 'originStation', header: 'Origin' },
{ key: 'destinationStation', header: 'Destination' },
{ key: 'weightKg', header: 'Weight (kg)', render: (row) => row.weightKg.toFixed(2) },
];
const ConsignmentTable = ({ consignments }: ConsignmentTableProps) => (
<Table
columns={columns}
data={consignments}
rowKey={(row) => row.id}
emptyMessage="No consignments yet"
/>
);
export default ConsignmentTable;

View File

@@ -0,0 +1,35 @@
import type { Freight } from '@edr/types';
import { Badge } from '@edr/ui-common';
export interface TrackingTimelineProps {
events: Freight.ITrackingEvent[];
}
const TrackingTimeline = ({ events }: TrackingTimelineProps) => {
if (events.length === 0) {
return <div className="text-sm text-gray-500">No tracking events yet.</div>;
}
return (
<ol className="relative ml-3 border-l border-gray-200">
{events.map((event) => (
<li key={event.id} className="mb-4 ml-4">
<div className="absolute -left-1.5 mt-1.5 h-3 w-3 rounded-full bg-blue-500" />
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2 text-sm font-medium text-gray-900">
<span>{event.location}</span>
<Badge tone="info">{event.status}</Badge>
</div>
<time className="text-xs text-gray-500">
{new Date(event.occurredAt).toLocaleString()}
</time>
{event.description ? (
<p className="text-sm text-gray-700">{event.description}</p>
) : null}
</div>
</li>
))}
</ol>
);
};
export default TrackingTimeline;