Skip to content

Commit

Permalink
Merge pull request #248 from dump-hr/book-of-standards-pdf-upload
Browse files Browse the repository at this point in the history
Book of standards pdf upload
  • Loading branch information
bdeak4 authored Feb 20, 2024
2 parents 67dec34 + 715f78b commit e71ca85
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 2 deletions.
2 changes: 1 addition & 1 deletion apps/api/db/migrations/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@
"breakpoints": true
}
]
}
}
1 change: 1 addition & 0 deletions apps/api/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export const company = pgTable('company', {
logoImage: text('logo_image'),
landingImage: text('landing_image'),
landingImageCompanyCulture: text('landing_image_company_culture'),
bookOfStandards: text('book_of_standards'),
video: text('video'),
codeId: integer('code_id').references(() => code.id),
});
Expand Down
40 changes: 40 additions & 0 deletions apps/api/src/company/company.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ export class CompanyController {
return await this.companyService.removeLandingImageCompanyCulture(user.id);
}

@UseGuards(SponsorGuard)
@ApiBearerAuth()
@Delete('/book-of-standards')
async removeBookOfStandards(
@Req() { user }: AuthenticatedRequest,
): Promise<void> {
return await this.companyService.removeBookOfStandards(user.id);
}

@UseGuards(SponsorGuard)
@ApiBearerAuth()
@Delete('/logo-image')
Expand Down Expand Up @@ -196,6 +205,37 @@ export class CompanyController {
return await this.companyService.updateLogoImage(user.id, file);
}

@UseGuards(SponsorGuard)
@ApiBearerAuth()
@ApiConsumes('multipart/form-data')
@ApiBody({
schema: {
type: 'object',
properties: {
file: {
type: 'string',
format: 'binary',
},
},
},
})
@Patch('/book-of-standards')
@UseInterceptors(FileInterceptor('file'))
async updateBookOfStandards(
@Req() { user }: AuthenticatedRequest,
@UploadedFile(
new ParseFilePipe({
validators: [
new FileTypeValidator({ fileType: 'pdf' }),
new MaxFileSizeValidator({ maxSize: 1024 * 1024 * 10 }),
],
}),
)
file: Express.Multer.File,
): Promise<CompanyPublicDto> {
return await this.companyService.updateBookOfStandards(user.id, file);
}

@UseGuards(SponsorGuard)
@ApiBearerAuth()
@ApiConsumes('multipart/form-data')
Expand Down
42 changes: 42 additions & 0 deletions apps/api/src/company/company.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export class CompanyService {
logoImage: company.logoImage,
landingImage: company.landingImage,
landingImageCompanyCulture: company.landingImageCompanyCulture,
bookOfStandards: company.bookOfStandards,
video: company.video,
})
.from(company)
Expand Down Expand Up @@ -133,6 +134,13 @@ export class CompanyService {
.where(eq(company.id, id));
}

async removeBookOfStandards(id: number): Promise<void> {
await db
.update(company)
.set({ bookOfStandards: null })
.where(eq(company.id, id));
}

async removeVideo(id: number): Promise<void> {
await db
.update(company)
Expand Down Expand Up @@ -258,6 +266,40 @@ export class CompanyService {
return updatedCompany;
}

async updateBookOfStandards(
id: number,
file: Express.Multer.File,
): Promise<CompanyPublicDto> {
const bookOfStandards = await this.blobService.upload(
'book-of-standards',
file.buffer,
file.mimetype,
);

const [updatedBookOfStandards] = await db
.update(company)
.set({
bookOfStandards,
})
.where(eq(company.id, id))
.returning({
id: company.id,
category: company.category,
name: company.name,
description: company.description,
opportunitiesDescription: company.opportunitiesDescription,
website: company.website,
boothLocation: company.boothLocation,
logoImage: company.logoImage,
landingImage: company.landingImage,
landingImageCompanyCulture: company.landingImageCompanyCulture,
bookOfStandards: company.bookOfStandards,
video: company.video,
});

return updatedBookOfStandards;
}

async updateLogoImage(
id: number,
file: Express.Multer.File,
Expand Down
22 changes: 22 additions & 0 deletions apps/sponsor/src/api/company/useCompanyRemoveBookOfStandards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import toast from 'react-hot-toast';
import { useMutation, useQueryClient } from 'react-query';

import { api } from '..';

const companyRemoveBookOfStandards = async () => {
return await api.delete('/company/book-of-standards');
};

export const useCompanyRemoveBookOfStandards = () => {
const queryClient = useQueryClient();

return useMutation(companyRemoveBookOfStandards, {
onSuccess: () => {
queryClient.invalidateQueries(['company', 'current']);
toast.success('Knjiga standarda uspješno izbrisana');
},
onError: (error: string) => {
toast.error(error);
},
});
};
25 changes: 25 additions & 0 deletions apps/sponsor/src/api/company/useCompanyUpdateBookOfStandards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import toast from 'react-hot-toast';
import { useMutation, useQueryClient } from 'react-query';

import { api } from '..';

const companyUpdateBookOfStandards = async (file: File) => {
const data = new FormData();
data.append('file', file);

return await api.patchForm('company/book-of-standards', data);
};

export const useCompanyUpdateBookOfStandards = () => {
const queryClient = useQueryClient();

return useMutation(companyUpdateBookOfStandards, {
onSuccess: () => {
queryClient.invalidateQueries(['company', 'current']);
toast.success('Knjiga standarda uspješno uploadana');
},
onError: (error: string) => {
toast.error(error);
},
});
};
64 changes: 64 additions & 0 deletions apps/sponsor/src/components/PdfUpload/PdfInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useDropzone } from 'react-dropzone';
import toast from 'react-hot-toast';

import RemoveSvg from '../../assets/icons/remove.svg';
import UploadSvg from '../../assets/icons/upload.svg';
import c from '../PhotoInput/PhotoInput.module.scss';

type PdfInputProps = {
label?: string;
fileSrc?: string;
isDisabled?: boolean;
height?: number;
handleUpload: (files: File[]) => void;
handleRemove: () => void;
};

export const PdfInput: React.FC<PdfInputProps> = ({
label,
fileSrc,
isDisabled = false,
height = 300,
handleRemove,
handleUpload,
}) => {
const { getRootProps, getInputProps } = useDropzone({
accept: { 'application/pdf': [] },
onDrop: async (acceptedFiles) => {
if (!acceptedFiles) {
toast.error('PDF file is required');
return;
}
handleUpload(acceptedFiles);
},
});

return (
<div className={c.inputArea} style={{ height: `${height}px` }}>
<div className={c.inputAreaContainer} style={{ height: `${height}px` }}>
{!fileSrc && (
<div className={c.inputField} {...getRootProps()}>
<input disabled={isDisabled} {...getInputProps()} />
<div className={c.inputFieldLabel}>
<img src={UploadSvg} alt='Upload' />
<p>{label}</p>
</div>
</div>
)}

<aside className={c.thumbsContainer}>
{!!fileSrc && (
<div className={c.inputFieldLabel}>Knjiga standarda spremljena</div>
)}
</aside>

{!!fileSrc && (
<button className={c.removeButton} onClick={() => handleRemove()}>
<img className={c.removeSvg} src={RemoveSvg} alt='Ukloni' />
<p>Ukloni</p>
</button>
)}
</div>
</div>
);
};
1 change: 1 addition & 0 deletions apps/sponsor/src/components/PdfUpload/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './PdfInput';
9 changes: 9 additions & 0 deletions apps/sponsor/src/components/PhotoInput/PhotoInput.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,13 @@ body {

.removeButton:hover .removeSvg {
visibility: visible;
}

.centeredParagraph {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;

}
29 changes: 29 additions & 0 deletions apps/sponsor/src/formSteps/LogoUpload/LogoUpload.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useCompanyGetCurrentPublic } from '../../api/company/useCompanyGetCurrentPublic';
import { useCompanyRemoveBookOfStandards } from '../../api/company/useCompanyRemoveBookOfStandards';
import { useCompanyRemoveLogoImage } from '../../api/company/useCompanyRemoveLogoImage';
import { useCompanyUpdateBookOfStandards } from '../../api/company/useCompanyUpdateBookOfStandards';
import { useCompanyUpdateLogoImage } from '../../api/company/useCompanyUpdateLogoImage';
import { PdfInput } from '../../components/PdfUpload/PdfInput';
import { PhotoInput, PhotoInputLabel } from '../../components/PhotoInput';
import { FormComponent } from '../../types/form';
import styles from './LogoUpload.module.scss';
Expand All @@ -9,6 +12,8 @@ export const LogoUpload: FormComponent = ({ close }) => {
const updateLogoImage = useCompanyUpdateLogoImage();
const removeLogoImage = useCompanyRemoveLogoImage();
const { data: company } = useCompanyGetCurrentPublic();
const updateBookOfStandards = useCompanyUpdateBookOfStandards();
const removeBookOfStandards = useCompanyRemoveBookOfStandards();

const handleUpload = async (files: File[]) => {
await updateLogoImage.mutateAsync(files[0]);
Expand All @@ -18,6 +23,14 @@ export const LogoUpload: FormComponent = ({ close }) => {
await removeLogoImage.mutateAsync();
};

const handleUploadBookOfStandards = async (files: File[]) => {
await updateBookOfStandards.mutateAsync(files[0]);
};

const handleRemoveBookOfStandards = async () => {
await removeBookOfStandards.mutateAsync();
};

return (
<div>
<div className={styles.descriptionContainer}>
Expand Down Expand Up @@ -52,6 +65,22 @@ export const LogoUpload: FormComponent = ({ close }) => {
handleUpload={handleUpload}
handleRemove={handleRemove}
/>
<PhotoInputLabel
title='Knjiga standarda'
content='Knjiga standarda je dokument koji sadrži uspostavljene specifikacije, smjernice ili zahtjeve za branding'
/>
<PdfInput
label={
updateBookOfStandards.isLoading
? 'Uploadanje u procesu...'
: 'Prinesite knjigu standarda (PDF)'
}
isDisabled={false}
fileSrc={company?.bookOfStandards}
height={326}
handleUpload={handleUploadBookOfStandards}
handleRemove={handleRemoveBookOfStandards}
/>
</div>

<button onClick={close} className={styles.button}>
Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/dto/company.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ export type CompanyPublicDto = {
id: number;
category: `${CompanyCategory}`;
name: string;

description?: string;
opportunitiesDescription?: string;
website?: string;
boothLocation?: string;
logoImage?: string;
landingImage?: string;
landingImageCompanyCulture?: string;
bookOfStandards?: string;
video?: string;
interests?: InterestDto[];
};
Expand Down

0 comments on commit e71ca85

Please sign in to comment.