import { Body, Controller, Delete, Get, Param, Patch, Post, Query, Res, StreamableFile, UseGuards, } from '@nestjs/common'; import type { Response } from 'express'; import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { CurrentUser } from '../auth/current-user.decorator'; import { Roles } from '../auth/roles.decorator'; import { RolesGuard } from '../auth/roles.guard'; import type { Actor } from '../common/record-scope'; import { AdjustLoyaltyPointsDto, BulkAdjustLoyaltyDto, CreateLoyaltyRewardDto, CreateLoyaltyTierDto, LoyaltyMessageDto, RedeemLoyaltyRewardDto, UpdateLoyaltyRewardDto, UpdateLoyaltySettingsDto, UpdateLoyaltyTierDto, } from './dto'; import { LoyaltyService } from './loyalty.service'; import { brand } from '@mento/shared'; @Controller('loyalty') @UseGuards(JwtAuthGuard, RolesGuard) export class LoyaltyController { constructor(private readonly loyalty: LoyaltyService) {} @Get('stats') stats(@CurrentUser() user: Actor) { return this.loyalty.getStats(user); } @Get('settings') settings(@CurrentUser() user: Actor) { return this.loyalty.getSettings(user.organizationId); } @Patch('settings') @Roles('owner', 'admin') updateSettings( @CurrentUser() user: Actor, @Body() dto: UpdateLoyaltySettingsDto, ) { return this.loyalty.updateSettings(user.organizationId, dto); } @Get('tiers') listTiers(@CurrentUser() user: Actor) { return this.loyalty.listTiers(user.organizationId); } @Post('tiers') @Roles('owner', 'admin') createTier( @CurrentUser() user: Actor, @Body() dto: CreateLoyaltyTierDto, ) { return this.loyalty.createTier(user.organizationId, dto); } @Patch('tiers/:id') @Roles('owner', 'admin') updateTier( @CurrentUser() user: Actor, @Param('id') id: string, @Body() dto: UpdateLoyaltyTierDto, ) { return this.loyalty.updateTier(user.organizationId, id, dto); } @Delete('tiers/:id') @Roles('owner', 'admin') async deleteTier(@CurrentUser() user: Actor, @Param('id') id: string) { await this.loyalty.deleteTier(user.organizationId, id); return { ok: true }; } @Get('members/export') async exportMembers( @CurrentUser() user: Actor, @Query('q') q: string | undefined, @Query('tierId') tierId: string | undefined, @Res({ passthrough: true }) res: Response, ) { const buffer = await this.loyalty.exportMembers(user, q, tierId); res.set({ 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition': `attachment; filename="${brand.filePrefix}-loyalty-members.xlsx"`, }); return new StreamableFile(buffer); } @Get('members') listMembers( @CurrentUser() user: Actor, @Query('q') q?: string, @Query('tierId') tierId?: string, ) { return this.loyalty.listMembers(user, q, tierId); } @Get('members/:personId/ledger') listLedger( @CurrentUser() user: Actor, @Param('personId') personId: string, ) { return this.loyalty.listLedger(user, personId); } @Post('members/bulk-adjust') bulkAdjust( @CurrentUser() user: Actor, @Body() dto: BulkAdjustLoyaltyDto, ) { return this.loyalty.bulkAdjust(user, dto.personIds, dto.delta, dto.reason); } @Post('members/message') sendMessage(@CurrentUser() user: Actor, @Body() dto: LoyaltyMessageDto) { return this.loyalty.sendMessage(user, dto.personIds, dto.text); } @Post('members/:personId/adjust') adjust( @CurrentUser() user: Actor, @Param('personId') personId: string, @Body() dto: AdjustLoyaltyPointsDto, ) { return this.loyalty.adjustPoints(user, personId, dto.delta, dto.reason); } @Get('rewards') listRewards(@CurrentUser() user: Actor) { return this.loyalty.listRewards(user.organizationId); } @Post('rewards') @Roles('owner', 'admin') createReward( @CurrentUser() user: Actor, @Body() dto: CreateLoyaltyRewardDto, ) { return this.loyalty.createReward(user.organizationId, dto); } @Patch('rewards/:id') @Roles('owner', 'admin') updateReward( @CurrentUser() user: Actor, @Param('id') id: string, @Body() dto: UpdateLoyaltyRewardDto, ) { return this.loyalty.updateReward(user.organizationId, id, dto); } @Delete('rewards/:id') @Roles('owner', 'admin') async deleteReward(@CurrentUser() user: Actor, @Param('id') id: string) { await this.loyalty.deleteReward(user.organizationId, id); return { ok: true }; } @Post('rewards/:id/redeem') redeem( @CurrentUser() user: Actor, @Param('id') id: string, @Body() dto: RedeemLoyaltyRewardDto, ) { return this.loyalty.redeemReward(user, id, dto.personId); } }