Skip to content

Roko/fly talks be #533

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
32 changes: 32 additions & 0 deletions apps/api/src/event/event.controller.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {
EventDto,
EventModifyDto,
EventWithCompanyDto,
EventWithSpeakerDto,
UserToEventDto,
} from '@ddays-app/types';
import {
BadRequestException,
Body,
Controller,
Delete,
Expand All @@ -12,8 +15,11 @@ import {
ParseIntPipe,
Patch,
Post,
UploadedFile,
UseGuards,
UseInterceptors,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { AdminGuard } from 'src/auth/admin.guard';

import { EventService } from './event.service';
Expand All @@ -28,11 +34,30 @@ export class EventController {
return await this.eventService.create(dto);
}

@Post('apply-to-flytalk')
async applyToFlyTalk(@Body() dto: UserToEventDto): Promise<UserToEventDto> {
return await this.eventService.applyToFlyTalk(dto);
}

@Post('upload-cv')
@UseInterceptors(FileInterceptor('file'))
async uploadCV(@UploadedFile() file: Express.Multer.File): Promise<string> {
if (!file) {
throw new BadRequestException('File is required');
}
return await this.eventService.uploadCV(file);
}

@Get('with-speaker')
async getAllWithSpeakerAnd(): Promise<EventWithSpeakerDto[]> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jel ovaj "And" osta ili je samo malo cudno ime?

return await this.eventService.getAllWithSpeaker();
}

@Get('with-company')
async GetAllWithCompany(): Promise<EventWithCompanyDto[]> {
return await this.eventService.getAllWithCompany();
}

@Get(':id')
async findOne(@Param('id', ParseIntPipe) id: number): Promise<EventDto> {
return await this.eventService.getOne(id);
Expand All @@ -43,6 +68,13 @@ export class EventController {
return await this.eventService.getAll();
}

@Delete('delete-flytalk-application')
async deleteFlyTalkApplication(
@Body() { userId, eventId }: UserToEventDto,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ovo ne znam jel bolje uzet @Req pa osposobit userId od logiranog korisnika, pogledaj druge kontrolere kako se koristi jednostavno je al @bdeak4 neka provjeri

): Promise<UserToEventDto> {
return await this.eventService.deleteFlyTalkApplication(userId, eventId);
}

@UseGuards(AdminGuard)
@Delete(':id')
async remove(@Param('id', ParseIntPipe) id: number): Promise<EventDto> {
Expand Down
3 changes: 2 additions & 1 deletion apps/api/src/event/event.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Module } from '@nestjs/common';
import { BlobService } from 'src/blob/blob.service';
import { PrismaService } from 'src/prisma.service';

import { EventController } from './event.controller';
import { EventService } from './event.service';

@Module({
controllers: [EventController],
providers: [EventService, PrismaService],
providers: [EventService, PrismaService, BlobService],
})
export class EventModule {}
100 changes: 99 additions & 1 deletion apps/api/src/event/event.service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import {
EventDto,
EventModifyDto,
EventWithCompanyDto,
EventWithSpeakerDto,
UserToEventDto,
} from '@ddays-app/types';
import { Injectable } from '@nestjs/common';
import { BlobService } from 'src/blob/blob.service';
import { PrismaService } from 'src/prisma.service';

@Injectable()
export class EventService {
constructor(private readonly prisma: PrismaService) {}
constructor(
private readonly prisma: PrismaService,
private readonly blobService: BlobService,
) {}

async create(dto: EventModifyDto): Promise<EventDto> {
const createdEvent = await this.prisma.event.create({
Expand All @@ -18,6 +24,32 @@ export class EventService {
return createdEvent;
}

async applyToFlyTalk(dto: UserToEventDto): Promise<UserToEventDto> {
const appliedFlyTalk = await this.prisma.userToEvent.create({
data: {
userId: dto.userId,
eventId: dto.eventId,
linkedinProfile: dto.linkedinProfile,
githubProfile: dto.githubProfile,
portfolioProfile: dto.portfolioProfile,
cv: dto.cv,
description: dto.description,
},
});

return appliedFlyTalk;
}

async uploadCV(file: Express.Multer.File): Promise<string> {
const cv = await this.blobService.upload(
'user-cv',
file.buffer,
file.mimetype,
);
console.log(cv);
return cv;
}

async getAll(): Promise<EventDto[]> {
const events = await this.prisma.event.findMany({
orderBy: { name: 'asc' },
Expand Down Expand Up @@ -117,6 +149,56 @@ export class EventService {
}));
}

async getAllWithCompany(): Promise<EventWithCompanyDto[]> {
const events = await this.prisma.event.findMany({
include: {
companyToFlyTalk: {
include: {
company: {
select: {
id: true,
name: true,
logoImage: true,
},
},
},
},
userToEvent: {
include: {
user: {
select: {
id: true,
},
},
},
},
},
});

return events.map((event) => ({
id: event.id,
name: event.name,
description: event.description,
startsAt: event.startsAt,
endsAt: event.endsAt,
maxParticipants: event.maxParticipants,
requirements: event.requirements,
footageLink: event.footageLink,
type: event.type,
theme: event.theme,
codeId: event.codeId,
isOnEnglish: event.isOnEnglish,
companies: event.companyToFlyTalk.map((relation) => ({
id: relation.company.id,
name: relation.company.name,
logoImage: relation.company.logoImage,
})),
users: event.userToEvent.map((relation) => ({
id: relation.user.id,
})),
}));
}

async remove(id: number): Promise<EventDto> {
const deletedEvent = await this.prisma.event.delete({
where: { id },
Expand All @@ -125,6 +207,22 @@ export class EventService {
return deletedEvent;
}

async deleteFlyTalkApplication(
userId: number,
eventId: number,
): Promise<UserToEventDto> {
const deletedApplication = await this.prisma.userToEvent.delete({
where: {
userId_eventId: {
userId,
eventId,
},
},
});

return deletedApplication;
}

async update(id: number, dto: EventModifyDto): Promise<EventDto> {
const updatedEvent = await this.prisma.event.update({
where: { id },
Expand Down
32 changes: 32 additions & 0 deletions apps/app/src/api/flyTalks/useDeleteFlyTalkApplication.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { QueryClient, useMutation } from 'react-query';
import axios from '../base';
import { QUERY_KEYS } from '@/constants/queryKeys';
import toast from 'react-hot-toast';

const queryClient = new QueryClient();

const deleteFlyTalkApplication = async (data: {
userId: number;
eventId: number;
}): Promise<{ userId: number; eventId: number }> => {
return axios.delete('/event/delete-flytalk-application', {
data: data ,
});
};

export const useDeleteFlyTalkApplication = () => {
return useMutation(deleteFlyTalkApplication, {
onSuccess: () => {
queryClient.invalidateQueries([QUERY_KEYS.applyFlyTalk]);
toast.success('Successfully deleted the application.');
},
onError: (error: import('axios').AxiosError<{ message?: string }>) => {
console.error('Error deleting FlyTalk application:', error);
const errorMessage =
error?.response?.data?.message ||
error?.message ||
'An unexpected error occurred.';
toast.error(errorMessage);
},
});
};
15 changes: 15 additions & 0 deletions apps/app/src/api/flyTalks/useGetGroupCompanies.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import axios from '../base';
import { useQuery } from 'react-query';
import { QUERY_KEYS } from '@/constants/queryKeys';
import { EventWithCompanyDto } from '@ddays-app/types';

const getAllFlyTalkGroups = async (): Promise<EventWithCompanyDto[]> => {
return axios.get('/event/with-company');
};

export const useGetAllFlyTalkGroups = () => {
return useQuery<EventWithCompanyDto[]>(
[QUERY_KEYS.events],
getAllFlyTalkGroups,
);
};
28 changes: 28 additions & 0 deletions apps/app/src/api/flyTalks/usePostApplyToFlyTalks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { QUERY_KEYS } from "@/constants/queryKeys";
import { UserToEventDto } from "@ddays-app/types";
import axios from "../base";
import toast from "react-hot-toast";
import { useMutation, QueryClient } from "react-query";

const queryClient = new QueryClient();


const postApplyToFlyTalks = async (data: UserToEventDto): Promise<UserToEventDto> => {
return axios.post<UserToEventDto, UserToEventDto>('/event/apply-to-flytalk', data);
}

export const usePostApplyToFlyTalks = () => {
return useMutation(
postApplyToFlyTalks, {
onSuccess: () => {
queryClient.invalidateQueries([QUERY_KEYS.applyFlyTalk]);
},
onError: (error: import("axios").AxiosError<{ message?: string }>) => {
console.error("Error applying to FlyTalk:", error);
const errorMessage = error?.response?.data?.message || error?.message || "An unexpected error occurred.";
toast.error(errorMessage);
},
}

);
};
23 changes: 23 additions & 0 deletions apps/app/src/api/flyTalks/usePostUploadCV.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useMutation } from 'react-query';
import axios from '../base';
import toast from 'react-hot-toast';

const uploadCV = async (file: File): Promise<string> => {
const formData = new FormData();
formData.append('file', file);

return await axios.post('event/upload-cv', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
responseType: 'text',
});
};

export const useUploadCV = () => {
return useMutation((file: File) => uploadCV(file), {
onError: () => {
toast.error('Greška prilikom slanja CV-a');
},
});
};
Loading
Loading