mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
Merge branch 'main' of https://github.com/Tria-plc/edr-platform into alpha
This commit is contained in:
@@ -18,12 +18,11 @@
|
||||
* parseEthiopianTime('2026-06-15') // Treats as midnight EAT
|
||||
*/
|
||||
export function parseEthiopianTime(dateInput: string | Date): Date {
|
||||
if (dateInput instanceof Date) {
|
||||
return dateInput;
|
||||
}
|
||||
|
||||
// Parse as local time (EAT) since TZ is set to Africa/Addis_Ababa
|
||||
return new Date(dateInput);
|
||||
if (dateInput instanceof Date) return dateInput;
|
||||
// Already has timezone info (Z or +HH:MM) — parse directly as UTC
|
||||
if (/Z$|[+-]\d{2}:\d{2}$/.test(dateInput)) return new Date(dateInput);
|
||||
// Bare local string (e.g. "2026-07-23T21:00") — treat explicitly as EAT (UTC+3)
|
||||
return new Date(dateInput + '+03:00');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -447,7 +447,7 @@ export class ReportsService {
|
||||
_count: { select: { seats: true } },
|
||||
},
|
||||
},
|
||||
seat: { include: { coach: { select: { number: true, coachType: { select: { name: true } } } } } },
|
||||
seat: { select: { seatNumber: true, bedPosition: true, coach: { select: { number: true, coachType: { select: { name: true, seatClasses: { select: { name: true, bedPosition: true } } } } } } } },
|
||||
},
|
||||
orderBy: [{ seat: { coach: { number: "asc" } } }, { seat: { seatNumber: "asc" } }],
|
||||
});
|
||||
@@ -474,13 +474,25 @@ export class ReportsService {
|
||||
passportNumber: bs.passportNumber,
|
||||
passportCountry: bs.passportCountry,
|
||||
seatLabel: bs.seatLabelSnapshot,
|
||||
seatNumber: bs.seat?.seatNumber ?? null,
|
||||
seatClassName: (() => {
|
||||
const classes = bs.seat?.coach?.coachType?.seatClasses ?? [];
|
||||
const matched = bs.seat?.bedPosition
|
||||
? classes.find((sc: any) => sc.bedPosition?.toLowerCase() === bs.seat!.bedPosition!.toLowerCase())
|
||||
: null;
|
||||
return (matched ?? classes[0])?.name ?? bs.seat?.coach?.coachType?.name ?? null;
|
||||
})(),
|
||||
coachNumber: bs.seat?.coach?.number ?? null,
|
||||
coachType: (bs.seat?.coach as any)?.coachType?.name ?? null,
|
||||
coachType: bs.seat?.coach?.coachType?.name ?? null,
|
||||
nationality: bs.passportCountry
|
||||
? (bs.passportCountry === 'Djibouti' ? 'Djiboutian' : bs.passportCountry)
|
||||
: bs.idDocumentType === 'NATIONAL_ID' ? 'Ethiopian' : null,
|
||||
origin: bs.booking.originStationId ? (stationName.get(bs.booking.originStationId) ?? null) : null,
|
||||
destination: bs.booking.destinationStationId ? (stationName.get(bs.booking.destinationStationId) ?? null) : null,
|
||||
amountPaidMinor: bs.booking.totalMinor,
|
||||
currency: bs.booking.currency ?? 'ETB',
|
||||
isGroupBooking: (bs.booking._count?.seats ?? 0) > 1,
|
||||
bookingStatus: bs.booking.status,
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,13 +52,17 @@ interface PassengerRow {
|
||||
passportNumber: string | null;
|
||||
passportCountry: string | null;
|
||||
seatLabel: string | null;
|
||||
seatNumber: string | null;
|
||||
seatClassName: string | null;
|
||||
coachNumber: string | null;
|
||||
coachType: string | null;
|
||||
nationality: string | null;
|
||||
origin: string | null;
|
||||
destination: string | null;
|
||||
amountPaidMinor: number;
|
||||
currency: string;
|
||||
isGroupBooking: boolean;
|
||||
bookingStatus: string;
|
||||
}
|
||||
|
||||
type Tab = "occupancy" | "list";
|
||||
@@ -105,6 +109,7 @@ export default function PassengersReportPage() {
|
||||
.filter((p) => {
|
||||
if (filterCoach && p.coachNumber !== filterCoach) return false;
|
||||
if (filterOrigin && p.origin !== filterOrigin) return false;
|
||||
if (filterSeatClass && p.seatClassName !== filterSeatClass) return false;
|
||||
if (listSearch.trim()) {
|
||||
const q = listSearch.toLowerCase();
|
||||
return (
|
||||
@@ -454,6 +459,30 @@ export default function PassengersReportPage() {
|
||||
value={listSearch}
|
||||
onChange={(e) => setListSearch(e.target.value)}
|
||||
/>
|
||||
<select
|
||||
className="input w-40"
|
||||
value={filterSeatClass}
|
||||
onChange={(e) => setFilterSeatClass(e.target.value)}
|
||||
>
|
||||
<option value="">All classes</option>
|
||||
{seatClassOptions.map((c) => (
|
||||
<option key={c} value={c}>
|
||||
{c}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<select
|
||||
className="input w-36"
|
||||
value={filterOrigin}
|
||||
onChange={(e) => setFilterOrigin(e.target.value)}
|
||||
>
|
||||
<option value="">All origins</option>
|
||||
{originOptions.map((o) => (
|
||||
<option key={o} value={o}>
|
||||
{o}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{passengerList.length > 0 && (
|
||||
<ActionButton
|
||||
icon={Download}
|
||||
|
||||
@@ -514,7 +514,7 @@ export default function SchedulesPage() {
|
||||
const payload: any = {
|
||||
trainId: bulkForm.trainId,
|
||||
routeId: bulkForm.routeId,
|
||||
startDateTime: bulkForm.startDateTime,
|
||||
startDateTime: new Date(bulkForm.startDateTime).toISOString(),
|
||||
durationHours: parseInt(bulkForm.durationHours),
|
||||
repeatEveryDays: parseInt(bulkForm.repeatEveryDays),
|
||||
forNextDays: parseInt(bulkForm.forNextDays),
|
||||
|
||||
Reference in New Issue
Block a user