feat: add Transit Clearance Action Panel for managing delivery and release orders

- Implemented TransitClearanceActionPanel component for transit agents to handle DO/RO uploads and amendments.
- Added file picker for uploading documents with validation for vessel arrival and collection dates.
- Introduced modals for uploading T1 documents and requesting RO amendments.
- Enhanced transit assignments service with new API endpoints for clearance history, GL exchange documents, and incident reports.
- Updated types to include new document upload sources and statuses.
- Created CSS styles for transit bookings table to improve layout and responsiveness.
- Exported new TransitAgentBookingDetailPage for detailed booking views.
This commit is contained in:
Marshal
2026-08-31 13:56:39 +00:00
parent 678c5d7d49
commit b5ad46f317
23 changed files with 3524 additions and 385 deletions

View File

@@ -4,6 +4,7 @@ import {
Delete,
Get,
HttpCode,
NotFoundException,
Param,
ParseUUIDPipe,
Patch,
@@ -1359,18 +1360,30 @@ export class ContractsController {
return this.glOperationsService.uploadTransportDocument(bookingId, files ?? []);
}
// Also filed by the transit agent assigned to the shipment — T1 is their own
// transit paperwork. Any other portal caller is rejected below.
@Post('bookings/:bookingId/t1-documents')
@BookingStaff(FREIGHT_PERMS.contracts.clearanceDjActions)
@MixedAudience(FREIGHT_PERMS.contracts.clearanceDjActions)
@UseInterceptors(AnyFilesInterceptor())
@ApiConsumes('multipart/form-data')
@ApiOperation({
summary:
'GL Djibouti uploads T1 transit documents (multi-file) after wagon allocation; locked once the train departs',
})
uploadT1Documents(
async uploadT1Documents(
@Param('bookingId', ParseUUIDPipe) bookingId: string,
@UploadedFiles() files: Express.Multer.File[],
@CurrentUser() user: TCurrentUser,
) {
if (
!hasFreightPermission(user, FREIGHT_PERMS.contracts.clearanceDjActions) &&
!(await this.bookingsService.isTransitAgentForBooking(
user?.id,
bookingId,
))
) {
throw new NotFoundException(`Booking ${bookingId} not found`);
}
return this.glOperationsService.uploadT1Documents(bookingId, files ?? []);
}
@@ -1534,6 +1547,8 @@ export class ContractsController {
@MixedAudience(FREIGHT_PERMS.contracts.view)
@ApiOperation({ summary: 'List cargo exception/damage reports for a shipment' })
listIncidents(@Param('bookingId', ParseUUIDPipe) bookingId: string) {
// Reads are open to both audiences (a transit agent assigned to the
// shipment included); reporting an incident stays staff-only below.
return this.glOperationsService.listIncidents(bookingId);
}