Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm';

export class AddDeletedAtToMentorProfiles1234567890 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.addColumn(
'mentor_profiles',
new TableColumn({
name: 'deleted_at',
type: 'timestamp',
isNullable: true,
default: null,
}),
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn('mentor_profiles', 'deleted_at');
}
}
56 changes: 56 additions & 0 deletions apps/api/src/mentors-profile/dto/query-mentors-profile.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { IsOptional, IsString, IsNumber, Min, Max } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiPropertyOptional } from '@nestjs/swagger';

export class QueryMentorProfileDto {
@ApiPropertyOptional({
description: 'Filter by expertise/headline (partial match)',
example: 'JavaScript'
})
@IsOptional()
@IsString()
expertise?: string;

@ApiPropertyOptional({
description: 'Minimum hourly rate in NGN',
example: 5000
})
@IsOptional()
@IsNumber()
@Type(() => Number)
@Min(0)
minPrice?: number;

@ApiPropertyOptional({
description: 'Maximum hourly rate in NGN',
example: 50000
})
@IsOptional()
@IsNumber()
@Type(() => Number)
@Min(0)
maxPrice?: number;

@ApiPropertyOptional({
description: 'Page number',
example: 1,
default: 1
})
@IsOptional()
@IsNumber()
@Type(() => Number)
@Min(1)
page?: number = 1;

@ApiPropertyOptional({
description: 'Items per page',
example: 10,
default: 10
})
@IsOptional()
@IsNumber()
@Type(() => Number)
@Min(1)
@Max(100)
limit?: number = 10;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// src/mentors-profile/entities/mentors-profile.entity.ts
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
DeleteDateColumn,
OneToOne,
JoinColumn,
Index,
Expand Down Expand Up @@ -56,4 +58,7 @@ export class MentorProfile {

@UpdateDateColumn({ name: 'updated_at' })
updatedAt!: Date;
}

@DeleteDateColumn({ name: 'deleted_at', nullable: true })
deletedAt?: Date;
}
78 changes: 73 additions & 5 deletions apps/api/src/mentors-profile/mentors-profile.controller.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// src/mentors/mentors.controller.ts
// src/mentors-profile/mentors-profile.controller.ts
import {
Controller,
Get,
Post,
Put,
Patch,
Delete,
Body,
Param,
Query,
UseGuards,
Request,
HttpCode,
Expand All @@ -15,13 +19,14 @@ import {
ApiOperation,
ApiResponse,
ApiBearerAuth,
ApiBody,
ApiParam,
ApiQuery,
} from '@nestjs/swagger';
import { MentorsService } from './mentors-profile.service';
import { MentorProfileResponseDto } from './dto/mentor-profile-response';
import { CreateMentorProfileDto } from './dto/create-mentors-profile.dto';
import { UpdateMentorProfileDto } from './dto/update-mentors-profile.dto';
// Assuming you have a JwtAuthGuard
import { QueryMentorProfileDto } from './dto/query-mentors-profile.dto';
// import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';

@ApiTags('Mentors')
Expand All @@ -46,10 +51,23 @@ export class MentorsController {
@Request() req: any,
@Body() dto: CreateMentorProfileDto,
): Promise<MentorProfileResponseDto> {
const userId = req.user?.id || 'test-user-id'; // Replace with actual user from JWT
const userId = req.user?.id || 'test-user-id';
return this.mentorsService.createProfile(userId, dto);
}

@Get()
@ApiOperation({
summary: 'List all approved mentor profiles with filters',
description: 'Public endpoint to list approved mentors. Supports filtering by expertise and price range.'
})
@ApiResponse({
status: 200,
description: 'List of approved mentor profiles',
})
async findAll(@Query() queryDto: QueryMentorProfileDto) {
return this.mentorsService.findAll(queryDto);
}

@Get('me/profile')
@ApiOperation({ summary: 'Get my mentor profile' })
@ApiResponse({
Expand All @@ -63,6 +81,19 @@ export class MentorsController {
return this.mentorsService.getProfileByUserId(userId);
}

@Get(':id')
@ApiOperation({ summary: 'Get mentor profile by ID' })
@ApiParam({ name: 'id', description: 'Mentor profile ID' })
@ApiResponse({
status: 200,
description: 'Profile retrieved successfully',
type: MentorProfileResponseDto,
})
@ApiResponse({ status: 404, description: 'Profile not found' })
async findOne(@Param('id') id: string): Promise<MentorProfileResponseDto> {
return this.mentorsService.findOne(id);
}

@Put('me/profile')
@ApiOperation({ summary: 'Update my mentor profile (only in draft status)' })
@ApiResponse({
Expand All @@ -83,6 +114,43 @@ export class MentorsController {
return this.mentorsService.updateProfile(userId, dto);
}

@Patch(':id')
@ApiOperation({
summary: 'Update mentor profile by ID',
description: 'Mentors can only update their own profile and only in draft status'
})
@ApiParam({ name: 'id', description: 'Mentor profile ID' })
@ApiResponse({
status: 200,
description: 'Profile updated successfully',
type: MentorProfileResponseDto,
})
@ApiResponse({ status: 403, description: 'Forbidden - not your profile' })
@ApiResponse({ status: 404, description: 'Profile not found' })
async updateProfileById(
@Param('id') id: string,
@Request() req: any,
@Body() dto: UpdateMentorProfileDto,
): Promise<MentorProfileResponseDto> {
const userId = req.user?.id || 'test-user-id';
return this.mentorsService.updateProfileById(id, userId, dto);
}

@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({
summary: 'Soft delete mentor profile',
description: 'Mentors can only delete their own profile'
})
@ApiParam({ name: 'id', description: 'Mentor profile ID' })
@ApiResponse({ status: 204, description: 'Profile deleted successfully' })
@ApiResponse({ status: 403, description: 'Forbidden - not your profile' })
@ApiResponse({ status: 404, description: 'Profile not found' })
async remove(@Param('id') id: string, @Request() req: any): Promise<void> {
const userId = req.user?.id || 'test-user-id';
await this.mentorsService.remove(id, userId);
}

@Post('me/profile/submit')
@HttpCode(HttpStatus.OK)
@ApiOperation({
Expand All @@ -99,4 +167,4 @@ export class MentorsController {
const userId = req.user?.id || 'test-user-id';
return this.mentorsService.submitProfile(userId);
}
}
}
Loading
Loading