Skip to content

Commit fe74b0d

Browse files
feat: Implement treatment, gallery, and veil content management features across frontend and backend.
1 parent 5e276d4 commit fe74b0d

28 files changed

Lines changed: 463 additions & 220 deletions

backend/src/app.module.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,5 @@ import { PartnershipModule } from '@modules/partnership';
3939
providers: [AppService],
4040
})
4141
export class AppModule {
42-
constructor() {
43-
}
42+
constructor() {}
4443
}

backend/src/common/utils/file-system.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ export async function deleteFileSafe(relativePath: string): Promise<boolean> {
3030
} catch (_) {
3131
return false;
3232
}
33-
};
33+
}

backend/src/common/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './object';
2-
export * from './file-system';
2+
export * from './file-system';

backend/src/common/utils/object.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
export function deleteProperties<T>(object: T, properties: (keyof T)[]): Omit<T, keyof T> {
2-
const newObject = { ...object };
3-
properties.forEach((property) => {
4-
if (!newObject[property]) {
5-
return;
6-
}
7-
delete newObject[property];
8-
});
9-
return newObject;
10-
}
1+
export function deleteProperties<T>(
2+
object: T,
3+
properties: (keyof T)[],
4+
): Omit<T, keyof T> {
5+
const newObject = { ...object };
6+
properties.forEach((property) => {
7+
if (!newObject[property]) {
8+
return;
9+
}
10+
delete newObject[property];
11+
});
12+
return newObject;
13+
}

backend/src/modules/gallery/presentation/gallery.controller.ts

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import {
66
Put,
77
Param,
88
Delete,
9+
UseInterceptors,
10+
UploadedFiles,
911
} from '@nestjs/common';
12+
import { FilesInterceptor } from '@nestjs/platform-express';
13+
import { diskStorage } from 'multer';
14+
import { extname } from 'path';
1015
import { GalleryService } from '../application/gallery.service';
1116
import { Gallery } from '../domain/gallery.entity';
1217
import { CreateGalleryDto } from './dto/create-gallery.dto';
@@ -27,23 +32,73 @@ export class GalleryController {
2732
}
2833

2934
@Post()
30-
async create(@Body() createGalleryDto: CreateGalleryDto): Promise<Gallery> {
35+
@UseInterceptors(
36+
FilesInterceptor('files', 10, {
37+
storage: diskStorage({
38+
destination: './uploads/gallery',
39+
filename: (req, file, callback) => {
40+
const uniqueSuffix =
41+
Date.now() + '-' + Math.round(Math.random() * 1e9);
42+
const ext = extname(file.originalname);
43+
callback(null, `${file.fieldname}-${uniqueSuffix}${ext}`);
44+
},
45+
}),
46+
}),
47+
)
48+
async create(
49+
@Body() createGalleryDto: CreateGalleryDto,
50+
@UploadedFiles() files: Array<Express.Multer.File>,
51+
): Promise<Gallery> {
52+
const imagePath =
53+
files && files.length > 0
54+
? `/uploads/gallery/${files[0].filename}`
55+
: null;
56+
57+
const galleryData = {
58+
...createGalleryDto,
59+
imageUrl: imagePath || (createGalleryDto as any).imageUrl,
60+
};
61+
3162
// Mapping DTO to Domain Entity
32-
const gallery = createGalleryDto as unknown as Omit<
33-
Gallery,
34-
'id' | 'createdAt'
35-
>;
63+
const gallery = galleryData as unknown as Omit<Gallery, 'id' | 'createdAt'>;
3664
return this.galleryService.create(gallery);
3765
}
3866

3967
@Put(':id')
68+
@UseInterceptors(
69+
FilesInterceptor('files', 10, {
70+
storage: diskStorage({
71+
destination: './uploads/gallery',
72+
filename: (req, file, callback) => {
73+
const uniqueSuffix =
74+
Date.now() + '-' + Math.round(Math.random() * 1e9);
75+
const ext = extname(file.originalname);
76+
callback(null, `${file.fieldname}-${uniqueSuffix}${ext}`);
77+
},
78+
}),
79+
}),
80+
)
4081
async update(
4182
@Param('id') id: string,
4283
@Body() updateGalleryDto: UpdateGalleryDto,
84+
@UploadedFiles() files: Array<Express.Multer.File>,
4385
): Promise<Gallery> {
86+
const imagePath =
87+
files && files.length > 0
88+
? `/uploads/gallery/${files[0].filename}`
89+
: null;
90+
91+
const galleryData = {
92+
...updateGalleryDto,
93+
};
94+
95+
if (imagePath) {
96+
(galleryData as any).imageUrl = imagePath;
97+
}
98+
4499
return this.galleryService.update(
45100
id,
46-
updateGalleryDto as unknown as Partial<Gallery>,
101+
galleryData as unknown as Partial<Gallery>,
47102
);
48103
}
49104

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { PartialType } from '@nestjs/mapped-types';
22
import { CreateServiceDto } from './create-treatments.dto';
33

4-
export class UpdateServiceDto extends PartialType(CreateServiceDto) {
5-
}
4+
export class UpdateServiceDto extends PartialType(CreateServiceDto) {}

backend/src/modules/treatments/presentation/treatments.controller.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { CreateServiceDto as CreateTreatmentDto, Treatments, TreatmentsService, UpdateServiceDto as UpdateTreatmentDto } from '@modules/treatments';
1+
import {
2+
CreateServiceDto as CreateTreatmentDto,
3+
Treatments,
4+
TreatmentsService,
5+
UpdateServiceDto as UpdateTreatmentDto,
6+
} from '@modules/treatments';
27
import {
38
Body,
49
Controller,

frontend/src/core/constants/api-endpoints.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ export const API_ENDPOINTS = {
1212
URL_BY_ID: (id: string) =>
1313
linkServerConvert(API_ENDPOINTS.TREATMENTS.URL, id),
1414
},
15+
GALLERY: {
16+
URL: "gallery",
17+
BASE: linkServerConvert("gallery"),
18+
URL_BY_ID: (id: string) => linkServerConvert(API_ENDPOINTS.GALLERY.URL, id),
19+
},
1520
AUTH: {
1621
LOGIN: "/auth/login",
1722
REGISTER: "/auth/register",
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export enum GalleryCategories {
2+
ALL = "all",
3+
VISAGE = "visage",
4+
MEDICAL_SPA = "medical_spa",
5+
BRIDAL_VEILS = "bridal_veils",
6+
INTERIOR = "interior",
7+
PRODUCT = "product",
8+
}
9+
10+
export const GALLERY_CATEGORIES = Object.values(GalleryCategories);

frontend/src/entities/gallery/gallery.service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ export class GalleryService {
2525
}
2626

2727
// Use this for both create and update if sending full object, or create specific methods
28-
createImage(image: Omit<Gallery, "id" | "createdAt">): Observable<Gallery> {
28+
createImage(formData: FormData): Observable<Gallery> {
2929
return this.http
30-
.post<Gallery>(this.apiUrl, image)
30+
.post<Gallery>(this.apiUrl, formData)
3131
.pipe(
3232
tap((newImage) => this._images.update((imgs) => [newImage, ...imgs])),
3333
);
3434
}
3535

36-
updateImage(id: string, image: Partial<Gallery>): Observable<Gallery> {
36+
updateImage(id: string, formData: FormData): Observable<Gallery> {
3737
return this.http
38-
.put<Gallery>(`${this.apiUrl}/${id}`, image)
38+
.put<Gallery>(`${this.apiUrl}/${id}`, formData)
3939
.pipe(
4040
tap((updatedImage) =>
4141
this._images.update((imgs) =>

0 commit comments

Comments
 (0)