import { Body, Controller, Get, NotFoundException, Param, ParseUUIDPipe, Post, } from "@nestjs/common"; import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger"; import { BookingStaff } from "../../common/booking-guards"; import { FREIGHT_PERMS } from "../../seed/freight-permissions.registry"; import { BackofficeResetPasswordDto } from "./dto/forgot-password.dto"; import { CustomerResetService, CustomerResetTarget, } from "./customer-reset.service"; /** * Staff-triggered password reset. The customer receives a single-use link and * sets their own password — staff never see or handle a credential. */ @ApiTags("backoffice") @Controller("backoffice/customers") @ApiBearerAuth() export class CustomerResetController { constructor(private readonly customerResetService: CustomerResetService) {} @Get(":companyId/reset-target") @BookingStaff(FREIGHT_PERMS.customers.resetPassword) @ApiOperation({ summary: "The primary contact's IAM account a reset link would be sent to", }) async resetTarget( @Param("companyId", ParseUUIDPipe) companyId: string, ): Promise { const target = await this.customerResetService.getResetTarget(companyId); if (!target) { throw new NotFoundException( "This customer has no active primary-contact account to reset", ); } return target; } @Post(":companyId/reset-password") @BookingStaff(FREIGHT_PERMS.customers.resetPassword) @ApiOperation({ summary: "Send a password-reset link to a customer's primary contact", }) async resetPassword( @Param("companyId", ParseUUIDPipe) companyId: string, @Body() dto: BackofficeResetPasswordDto, ) { const sent = await this.customerResetService.sendResetLinkToCustomer( companyId, dto.channel, ); if (!sent) { throw new NotFoundException( `No active primary contact with ${dto.channel === "email" ? "an email address" : "a phone number"} for this customer`, ); } return sent; } }