From 9e56b4457555a7f587fc3a724dafca103e3edbb2 Mon Sep 17 00:00:00 2001 From: Julien Von Der Marck Date: Sat, 13 Apr 2024 15:05:40 +0200 Subject: [PATCH] feat: add CategoriesController and CategoriesService --- .../app/controllers/categories_controller.ts | 19 +++++ backend/app/mocks/categories_mock.ts | 26 +++++++ backend/app/mocks/products_mock.ts | 72 +++++++++++++++++++ backend/app/services/categories_service.ts | 37 ++++++++++ backend/start/routes.ts | 5 ++ frontend/src/app/core/services/api.service.ts | 6 +- .../src/app/core/services/product.service.ts | 10 ++- frontend/src/environments/environment.ts | 2 +- 8 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 backend/app/controllers/categories_controller.ts create mode 100644 backend/app/mocks/categories_mock.ts create mode 100644 backend/app/mocks/products_mock.ts create mode 100644 backend/app/services/categories_service.ts diff --git a/backend/app/controllers/categories_controller.ts b/backend/app/controllers/categories_controller.ts new file mode 100644 index 0000000..528a2b2 --- /dev/null +++ b/backend/app/controllers/categories_controller.ts @@ -0,0 +1,19 @@ +// import type { HttpContext } from '@adonisjs/core/http' + +import { inject } from '@adonisjs/core' +import { HttpContext } from '@adonisjs/core/http' +import { CategoriesService } from '../services/categories_service.js' + +@inject() +export default class CategoriesController { + constructor(private categoryService: CategoriesService) {} + + async getAll({ response }: HttpContext) { + try { + const categories = await this.categoryService.getAll() + return response.json(categories) + } catch (error) { + return response.status(500).json({ message: 'Internal server error' }) + } + } +} diff --git a/backend/app/mocks/categories_mock.ts b/backend/app/mocks/categories_mock.ts new file mode 100644 index 0000000..04dd31d --- /dev/null +++ b/backend/app/mocks/categories_mock.ts @@ -0,0 +1,26 @@ +export const categoriesMock = [ + { + id: 1, + name: 'Food', + image: 'assets/img/categories/category_food.png', + products: [], + }, + { + id: 2, + name: 'Cooking', + image: 'assets/img/categories/category_kitchen.png', + products: [], + }, + { + id: 3, + name: 'Fashion', + image: 'assets/img/categories/category_fashion.png', + products: [], + }, + { + id: 4, + name: 'Culture', + image: 'assets/img/categories/category_culture.png', + products: [], + }, +] diff --git a/backend/app/mocks/products_mock.ts b/backend/app/mocks/products_mock.ts new file mode 100644 index 0000000..64def27 --- /dev/null +++ b/backend/app/mocks/products_mock.ts @@ -0,0 +1,72 @@ +export const productsMock = [ + { + id: 1, + categoryID: 1, + image: 'assets/img/products/caputo.png', + title: "Caputo® - Farina TIP0 '00' Pizzeria", + info: '1 kg - Il Mulino di Napoli', + price: 12, + isBestSeller: true, + isFavorite: true, + }, + { + id: 2, + categoryID: 1, + image: 'assets/img/products/olive_oil.png', + title: 'De Cecco Olio di Oliva', + info: '1L - Extra Virgin', + price: 22.95, + isBestSeller: true, + isFavorite: false, + }, + { + id: 3, + categoryID: 3, + image: 'assets/img/products/tshirt_girl.png', + title: "T-Shirt 'Everybody Loves Italian Girls'", + info: 'Sizes from S to XL', + price: 19.99, + isBestSeller: true, + isFavorite: false, + }, + { + id: 4, + categoryID: 1, + image: 'assets/img/products/kimbo.png', + title: 'Kimbo® Espresso Crema Intensa', + info: '1kg - Caffè di Napoli', + price: 4.99, + isBestSeller: true, + isFavorite: false, + }, + { + id: 5, + categoryID: 1, + image: 'assets/img/products/mascarpone.png', + title: 'Galbani® Mascarpone', + info: '250mg - Best for Tiramisù', + price: 2.99, + isBestSeller: false, + isFavorite: false, + }, + { + id: 6, + categoryID: 1, + image: 'assets/img/products/bacio_latte.png', + title: 'Baci® Latte Vellutato Scatola Bijou', + info: '200g - quotes by famous poets inside!', + price: 12.49, + isBestSeller: false, + isFavorite: false, + }, + { + id: 7, + categoryID: 3, + image: 'assets/img/products/scarf.png', + title: 'Sciarpa rossa', + info: '70% wool / 30% acrylic', + price: 99.99, + isBestSeller: false, + isFavorite: false, + }, +] diff --git a/backend/app/services/categories_service.ts b/backend/app/services/categories_service.ts new file mode 100644 index 0000000..cdfd686 --- /dev/null +++ b/backend/app/services/categories_service.ts @@ -0,0 +1,37 @@ +import { inject } from '@adonisjs/core' +import { categoriesMock } from '../mocks/categories_mock.js' +import { productsMock } from '../mocks/products_mock.js' + +export interface Category { + id: number + name: string + image: string + products: Product[] +} + +export interface Product { + id: number + categoryID: number + image: string + title: string + info: string + price: number + isBestSeller: boolean + isFavorite: boolean +} + +@inject() +export class CategoriesService { + async getAll() { + // Retrieve the categories from a mock json file + const categories = categoriesMock as Category[] + const products = productsMock as Product[] + + // Assign products to their respective categories + categories.forEach((category) => { + category.products = products.filter((product) => product.categoryID === category.id) + }) + + return categories + } +} diff --git a/backend/start/routes.ts b/backend/start/routes.ts index 919fd32..ebc11a5 100644 --- a/backend/start/routes.ts +++ b/backend/start/routes.ts @@ -10,6 +10,7 @@ import router from '@adonisjs/core/services/router' import { middleware } from './kernel.js' +const CategoriesController = () => import('#controllers/categories_controller') const UsersController = () => import('#controllers/users_controller') router.get('/', async () => 'It works!') @@ -21,3 +22,7 @@ router router.put('/', [UsersController, 'update']).middleware(middleware.jwt()) }) .prefix('auth') + +router.group(() => { + router.get('/categories', [CategoriesController, 'getAll']) +}) diff --git a/frontend/src/app/core/services/api.service.ts b/frontend/src/app/core/services/api.service.ts index a217883..7bc07b4 100644 --- a/frontend/src/app/core/services/api.service.ts +++ b/frontend/src/app/core/services/api.service.ts @@ -11,12 +11,8 @@ import { Category } from '../../shared/models/category.interface'; export class ApiService { constructor(private http:HttpClient) { } - - public getProducts() : Observable { - return this.http.get(environment.API_Endpoint + 'products.mock.json'); - } public getCategories() : Observable { - return this.http.get(environment.API_Endpoint + 'categories.mock.json'); + return this.http.get(environment.API_Endpoint + 'categories'); } } diff --git a/frontend/src/app/core/services/product.service.ts b/frontend/src/app/core/services/product.service.ts index d06362f..7dc9267 100644 --- a/frontend/src/app/core/services/product.service.ts +++ b/frontend/src/app/core/services/product.service.ts @@ -2,6 +2,8 @@ import { Injectable } from '@angular/core'; import {Product} from "../../shared/models/product.interface"; import { ApiService } from './api.service'; import { BehaviorSubject, Observable, map } from 'rxjs'; +import { CategoryService } from './category.service'; +import { Category } from '../../shared/models/category.interface'; @Injectable({ providedIn: 'root' @@ -11,8 +13,12 @@ export class ProductService { private _bestSellersProducts = new BehaviorSubject([]); private _products = new BehaviorSubject([]); - constructor(private apiService: ApiService) { - this.apiService.getProducts().subscribe((products: Product[]) => { + constructor(private categoryService: CategoryService) { + this.categoryService.categories.subscribe((categories: Category[]) => { + const products = categories.reduce((acc: Product[], category: Category) => { + return acc.concat(category.products); + }, []); + this._bestSellersProducts.next(products.filter((product: Product) => product.isBestSeller)); this._products.next(products); }); diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index 3c6fb88..ac7fe14 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -1,4 +1,4 @@ export const environment = { production: false, - API_Endpoint : '../assets/mocks/', + API_Endpoint : '/api/', }; \ No newline at end of file