Files
tripz-llc/backend/src/modules/trips/trips.controller.ts
T

114 lines
3.9 KiB
TypeScript

import { Body, Controller, Get, Param, Patch, Post, Query, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { TripsService, RequestTripDto } from './trips.service';
import { TripAudioService } from './trip-audio.service';
import { TripStatus } from './entities/trip.entity';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';
import { CurrentUser, AuthUser } from '../auth/decorators/current-user.decorator';
@ApiTags('trips')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Controller('trips')
export class TripsController {
constructor(
private readonly trips: TripsService,
private readonly audio: TripAudioService,
) {}
/** سرد رحلات المستأجر — للوحة الأدمن، بترشيح الحالة (docs/22 — N4). */
@UseGuards(RolesGuard)
@Roles('admin', 'dispatcher')
@Get('admin/list')
adminList(
@CurrentUser() user: AuthUser,
@Query('status') status?: string,
@Query('rider') rider?: string,
) {
return this.trips.listByTenant(user.tenantId, status, rider);
}
// الراكب يطلب رحلة
@Post()
request(@CurrentUser() user: AuthUser, @Body() body: RequestTripDto) {
return this.trips.request(user.tenantId, user.userId, body);
}
@Get('mine')
mine(@CurrentUser() user: AuthUser) {
return this.trips.listForRider(user.tenantId, user.userId);
}
// السائق يسحب الطلبات المتاحة قربه (بديل/مكمّل للعرض المباشر)
@Get('available')
available(@CurrentUser() user: AuthUser) {
return this.trips.availableForDriver(user.tenantId, user.userId);
}
@Get(':id')
get(@CurrentUser() user: AuthUser, @Param('id') id: string) {
return this.trips.get(user.tenantId, id);
}
// السائق يقبل الرحلة
@Post(':id/accept')
accept(@CurrentUser() user: AuthUser, @Param('id') id: string) {
return this.trips.accept(user.tenantId, id, user.userId);
}
// تحديث الحالة (driver_arriving / driver_arrived / in_progress / completed / paid)
@Patch(':id/status')
status(
@CurrentUser() user: AuthUser,
@Param('id') id: string,
@Body('status') status: TripStatus,
) {
const actor = user.role === 'driver' ? 'driver' : 'rider';
return this.trips.updateStatus(user.tenantId, id, status, actor);
}
@Post(':id/cancel')
cancel(@CurrentUser() user: AuthUser, @Param('id') id: string) {
const actor = user.role === 'driver' ? 'driver' : 'rider';
return this.trips.cancel(user.tenantId, id, actor, user.userId);
}
// ---- التسجيل الصوتي (R2) ----
/** رفع مقطع صوتي مرتبط بالرحلة. */
@Post(':id/audio')
@UseInterceptors(FileInterceptor('file', { limits: { fileSize: 50 * 1024 * 1024 } }))
uploadAudio(
@CurrentUser() user: AuthUser,
@Param('id') id: string,
@UploadedFile() file: any,
@Body('duration_sec') durationSec?: string,
@Body('destination_name') destName?: string,
) {
const role = user.role === 'driver' ? 'driver' as const : 'rider' as const;
return this.audio.upload(user.tenantId, id, user.userId, role, file, {
duration_sec: durationSec ? parseInt(durationSec, 10) : undefined,
destination_name: destName,
});
}
/** كل المقاطع الصوتية للرحلة. */
@Get(':id/audio')
listAudio(@CurrentUser() user: AuthUser, @Param('id') id: string) {
return this.audio.listByTrip(user.tenantId, id);
}
/** رابط تحميل مقطع صوتي. */
@Get(':id/audio/:audioId')
getAudioUrl(
@CurrentUser() user: AuthUser,
@Param('id') id: string,
@Param('audioId') audioId: string,
) {
return this.audio.getDownloadUrl(user.tenantId, audioId);
}
}