All files / src/modules/analytics analytics.controller.ts

89.65% Statements 26/29
37.5% Branches 3/8
70% Functions 7/10
88.88% Lines 24/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 12012x                         12x 12x 12x 12x 12x       12x 12x         12x       21x             12x       1x           12x         1x 1x             12x 12x               12x     1x               12x                       12x                     12x                   12x 1x        
import {
  Controller,
  Get,
  Post,
  Param,
  Query,
  Body,
  Req,
  UseGuards,
  ParseIntPipe,
  DefaultValuePipe,
  HttpCode,
} from '@nestjs/common';
import { AnalyticsService } from './analytics.service';
import { JwtAuthGuard } from '@app/common/guards/jwt-auth.guard';
import { RolesGuard } from '@app/common/guards/roles.guard';
import { Roles } from '@app/common/decorators/roles.decorator';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
 
@ApiTags('Analytics')
@Controller('analytics')
export class AnalyticsController {
  constructor(private readonly analyticsService: AnalyticsService) {}
 
  @Post('listings/:id/views')
  @HttpCode(201)
  @ApiOperation({ summary: 'Track a listing view (public endpoint)' })
  trackView(
    @Param('id', ParseIntPipe) id: number,
    @Body() dto: { source?: string; referrer?: string },
  ) {
    return this.analyticsService.trackView(id, dto.source, dto.referrer);
  }
 
  // Alias endpoint for test compatibility
  @Post('listings/:id/view')
  @HttpCode(201)
  @ApiOperation({ summary: 'Track a listing view (public endpoint)' })
  trackViewAlias(
    @Param('id', ParseIntPipe) id: number,
    @Body() dto: { source?: string; referrer?: string },
  ) {
    return this.analyticsService.trackView(id, dto.source, dto.referrer);
  }
 
  @Post('listings/:id/click')
  @HttpCode(200)
  @ApiOperation({ summary: 'Track a listing click (public endpoint)' })
  trackClick(
    @Param('id', ParseIntPipe) id: number,
    @Body() dto: { clickType: 'phone' | 'website' | 'email' },
    @Req() req?: any,
  ) {
    const userId = req?.user?.id;
    return this.analyticsService.trackClick(id, dto.clickType, userId);
  }
 
  @Get('listings/:id')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Get listing analytics (owner/agent only)' })
  getListingAnalytics(@Param('id', ParseIntPipe) id: number, @Req() req: any) {
    return this.analyticsService.getListingAnalytics(id, req.user.id);
  }
 
  @Get('popular-searches')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMIN', 'MODERATOR')
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Get popular searches (admin only)' })
  getPopularSearches(
    @Query('period', new DefaultValuePipe('week')) period: 'day' | 'week' | 'month',
  ) {
    return this.analyticsService.getPopularSearches(period);
  }
 
  @Get('cohorts')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMIN', 'MODERATOR')
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Cohort analysis (admin only)' })
  getCohorts(
    @Query('start') start?: string,
    @Query('end') end?: string,
  ) {
    return this.analyticsService.getCohortAnalysis(start ? new Date(start) : undefined, end ? new Date(end) : undefined);
  }
 
  @Get('attribution')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMIN', 'MODERATOR')
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Channel attribution (admin only)' })
  getAttribution(
    @Query('period', new DefaultValuePipe('week')) period: 'day' | 'week' | 'month',
  ) {
    return this.analyticsService.getChannelAttribution(period);
  }
 
  @Get('geo-heatmap')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('ADMIN', 'MODERATOR')
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Geo heatmap of activity (admin only)' })
  getGeoHeatmap(
    @Query('period', new DefaultValuePipe('week')) period: 'day' | 'week' | 'month',
  ) {
    return this.analyticsService.getGeoHeatmap(period);
  }
 
  @Get('dashboard/agent')
  @UseGuards(JwtAuthGuard)
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Get agent dashboard data' })
  getAgentDashboard(@Req() req: any) {
    return this.analyticsService.getAgentDashboard(req.user.id);
  }
}