Skip to content

Commit

Permalink
feat: add to team mentors
Browse files Browse the repository at this point in the history
  • Loading branch information
angel-penchev committed Mar 15, 2024
1 parent a4b449b commit 2cb0e5d
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 160 deletions.
25 changes: 18 additions & 7 deletions apps/fmicodes-api/src/mentors/mentors.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ import {
Param,
Patch,
Post,
UseGuards,
Version,
} from '@nestjs/common';
import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import {
ApiBearerAuth,
ApiOkResponse,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { MentorsService } from '@fmicodes/fmicodes-services/mentors/mentors.service';
import MentorResponseBodyDto from '@fmicodes/fmicodes-services/mentors/dto/mentor-response-body.dto';
import { User } from '@prisma/client';
import JwtAuthGuard from '@fmicodes/fmicodes-services/auth/guards/jwt-auth.guard';
import UserAuth from '../users/user-auth.decorator';

@Controller('mentors')
@ApiTags('Mentors API')
Expand All @@ -32,22 +41,24 @@ export class MentorsController {
return this.mentorsService.getAll();
}

@Post()
async createAll() {
return this.mentorsService.createAll();
}

@Patch(':id/assign-team/:teamId')
@HttpCode(HttpStatus.OK)
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiOperation({
summary: 'Assign a team to a mentor',
description: 'Endpoint for assigning a team to a mentor.',
})
@ApiOkResponse({
description: 'Team assigned to mentor successfully.',
})
async assignTeam(@Param('id') id: string, @Param('teamId') teamId: string) {
async assignTeam(
@UserAuth() user: User,
@Param('id') id: string,
@Param('teamId') teamId: string,
) {
return this.mentorsService.assignTeam(
user,
parseInt(id, 10),
parseInt(teamId, 10),
);
Expand Down
3 changes: 2 additions & 1 deletion apps/fmicodes-api/src/mentors/mentors.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Module } from '@nestjs/common';
import { PrismaService } from '@fmicodes/fmicodes-services/prisma/prisma.service';
import { MentorsService } from '@fmicodes/fmicodes-services/mentors/mentors.service';
import { UsersService } from '@fmicodes/fmicodes-services/users/users.service';
import { MentorsController } from './mentors.controller';

@Module({
controllers: [MentorsController],
providers: [MentorsService, PrismaService],
providers: [MentorsService, PrismaService, UsersService],
})
export class MentorsModule {}
2 changes: 1 addition & 1 deletion apps/fmicodes-api/src/users/users.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export class UsersController {
})
@ApiUnauthorizedResponse({ description: 'Invalid authentication token.' })
getCurrentV1(@UserAuth() user: Omit<User, 'passwordHash'>) {
return user;
return this.usersService.getById(user.id);
}

@Patch('current/onboarding')
Expand Down
5 changes: 3 additions & 2 deletions apps/fmicodes-site/app/[locale]/(general)/mentors/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Suspense } from 'react';
import { Metadata } from 'next';
import { MentorCard } from '@fmicodes/fmicodes-ui/lib/components/site/mentor-card/mentor-card';
import { ApiClient } from '@fmicodes/fmicodes-api-client/client';
import { getUser } from '@fmicodes/fmicodes-api-client/next';

export async function generateMetadata(): Promise<Metadata> {
const t = await getTranslations('mentors-page');
Expand All @@ -21,7 +22,7 @@ export async function generateMetadata(): Promise<Metadata> {
export default async function TeamsPage() {
const t = await getTranslations('mentors-page');

// const user = await getUser();
const user = await getUser();

async function MentorCards() {
const mentors = await ApiClient.MentorsApiService.mentorsControllerGetV1(
Expand All @@ -31,7 +32,7 @@ export default async function TeamsPage() {
return mentors.map((mentor) => (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
<MentorCard key={mentor.id} mentor={mentor} />
<MentorCard key={mentor.id} mentor={mentor} user={user} />
));
}

Expand Down
145 changes: 15 additions & 130 deletions libs/fmicodes-services/src/mentors/mentors.service.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { Injectable } from '@nestjs/common';
import { InjectRedis } from '@songkeys/nestjs-redis';
import Redis from 'ioredis';
import { User } from '@prisma/client';
import UsersService from '@fmicodes/fmicodes-services/users/users.service';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class MentorsService {
constructor(
private readonly prisma: PrismaService,
@InjectRedis() private readonly redis: Redis,
private readonly usersService: UsersService,
) {}

getAll() {
Expand All @@ -28,136 +31,7 @@ export class MentorsService {
});
}

createAll() {
return this.prisma.mentor.create({
data: {
name: 'Мартин Димитров Несторов',
pictureUrl: '/assets/images/mentors/Martin_Nestorov.jpg',
discordId: 'anarcroth#6344',
company: {
connect: {
name: 'ROITI',
},
},
jobTitle: 'Senior Cloud Software Engineer',
availability: [
'Събота 10:00 - 13:00',
'Събота 13:00 - 16:00',
'Събота 16:00 - 19:00',
'Неделя 10:00 - 13:00',
'Неделя 13:00 - 16:00',
],
technologies: {
connect: [
{
name: 'Уеб програмиране',
},
{
name: 'DevOps',
},
{
name: 'Python',
},
{
name: 'Java',
},
{
name: 'JavaScript',
},
{
name: 'TypeScript',
},
{
name: 'Bash',
},
{
name: 'HTML/CSS',
},
{
name: 'React',
},
{
name: 'jQuery',
},
{
name: 'WebSockets',
},
{
name: 'Electron',
},
{
name: 'Node.js',
},
{
name: 'Express',
},
{
name: 'Flask',
},
{
name: 'Spring Boot',
},
{
name: 'REST',
},
{
name: 'JWT',
},
{
name: 'RabbitMQ',
},
{
name: 'Apache Kafka',
},
{
name: 'SQL (MySQL, PostgreSQL, etc.)',
},
{
name: 'NoSQL (MongoDB, Cassandra, etc.)',
},
{
name: 'Redis (Key-Value store)',
},
{
name: 'InfluxDB (Time Series Database)',
},
{
name: 'Grafana',
},
{
name: 'Elasticsearch',
},
{
name: 'Amazon Web Services',
},
{
name: 'Heroku',
},
{
name: 'Git',
},
{
name: 'GitHub',
},
{
name: 'GitLab',
},
{
name: 'Bitbucket',
},
{
name: 'Docker',
},
{
name: 'Kubernetes',
},
],
},
},
});
}

async assignTeam(id: number, teamId: number) {
async assignTeam(user: User, id: number, teamId: number) {
// Find the mentor and their linked mentors
const mentor = await this.prisma.mentor.findUnique({
where: {
Expand All @@ -177,6 +51,17 @@ export class MentorsService {
throw new Error('Mentor already has a team');
}

// Get user team mentor by user id
const userById = await this.usersService.getById(user.id);

// If user's team has a mentor, throw
if (!userById) {
throw Error('How?');
}
if (userById.team && userById.team.mentors.length > 0) {
throw new Error('Team already has a mentor.');
}

// Update the mentor's team
await this.prisma.mentor.update({
where: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export class TeamResponseBodyDto extends TeamsBaseDto {
})
capitanId!: string;

@ApiProperty({
description: 'Mentor',
})
mentors!: [string];

@ApiProperty({
description: 'Team creation date',
})
Expand Down
1 change: 1 addition & 0 deletions libs/fmicodes-services/src/teams/teams.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export class TeamsService {
avatarUrl: true,
},
},
mentors: true,
},
});
}
Expand Down
10 changes: 10 additions & 0 deletions libs/fmicodes-services/src/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ export class UsersService {
},
include: {
discord: true,
team: {
select: {
id: true,
name: true,
capitanId: true,
mentors: true,
},
},
},
});

Expand Down Expand Up @@ -84,6 +92,7 @@ export class UsersService {
},
include: {
discord: true,
team: true,
},
});

Expand Down Expand Up @@ -117,6 +126,7 @@ export class UsersService {
},
include: {
discord: true,
team: true,
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use client';

import React from 'react';
import ApiClient from '@fmicodes/fmicodes-api-client/client';
import { getBearerToken } from '@fmicodes/fmicodes-api-client/next';
import { useLocale, useTranslations } from 'next-intl';
import { Button } from '../../../common/button/button';

interface AddToTeamButtonProps {
user: ApiClient.UserResponseBodyDto;
mentorId: number;
}

export function AddToTeamButton({ user, mentorId }: AddToTeamButtonProps) {
const locale = useLocale();
const t = useTranslations('site.mentor-card');

async function assignMentor() {
await ApiClient.MentorsApiService.mentorsControllerAssignTeam({
id: `${mentorId}`,
teamId: `${user.team?.id}`,
authorization: await getBearerToken(),
acceptLanguage: locale,
});

// refresh the page
window.location.reload();
}

return (
<Button
onClick={() => assignMentor()}
className="w-full"
disabled={
!user ||
!user.team ||
user.team.capitanId !== user.id ||
(user.team.mentors && user.team.mentors.length > 0)
}
>
{t('add-to-team')}
</Button>
);
}
Loading

0 comments on commit 2cb0e5d

Please sign in to comment.