import { Component, ElementRef, inject, signal, ViewChild } from "@angular/core"; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms"; import { ImageInput } from "../../../shared/components/image-input/image-input"; import { HttpClient } from "@angular/common/http"; import { API_URL } from "../../../core/tokens/api-url-tokens"; import { Error } from "../../../shared/components/error/error"; import { Category, CategoryService } from "../services/category-service"; import { forkJoin, switchMap } from "rxjs"; export interface ImageSelection { id: string; url: string; file: File; } @Component({ selector: "app-add-product", imports: [ReactiveFormsModule, ImageInput, Error], templateUrl: "./add-product.html", styleUrl: "./add-product.css", }) export class AddProduct { http = inject(HttpClient); apiUrl = inject(API_URL); categoryService = inject(CategoryService); @ViewChild("imageDialog") imageDialog!: ElementRef; activeImage = signal(null); selectedImages = signal>({}); categories = signal([]); successMessage = signal(null); productAddFrom = new FormGroup({ title: new FormControl("", { validators: [Validators.required, Validators.minLength(3)], }), description: new FormControl("", { validators: [Validators.required, Validators.minLength(10)], }), actual_price: new FormControl(0, { validators: [Validators.required, Validators.min(0)] }), list_price: new FormControl(0, { validators: [Validators.required, Validators.min(0)] }), product_category_id: new FormControl("", { validators: [Validators.required] }), }); ngOnInit() { this.categoryService.getCategories().subscribe({ next: (categories) => this.categories.set(categories), error: (error) => console.log(error), }); } openPreview(image: ImageSelection) { this.activeImage.set(image); this.imageDialog.nativeElement.showModal(); } confirmImage() { // Add the current image to the selected images const current = this.activeImage(); if (current) { this.selectedImages.update((images) => ({ ...images, [current.id]: current })); } this.closeDialog(); } closeDialog() { this.activeImage.set(null); this.imageDialog.nativeElement.close(); } submitProductForm() { if (this.productAddFrom.invalid) { this.productAddFrom.markAllAsTouched(); return; } this.http .post<{ id: string | number }>(`${this.apiUrl}/products`, this.productAddFrom.value) .pipe( switchMap((response) => { const productId = response.id; const images = Object.values(this.selectedImages()); if (images.length === 0) { return [response]; } const uploadRequests = images.map((img) => this.uploadImage(img.file, productId)); return forkJoin(uploadRequests); }), ) .subscribe({ next: (results) => { this.successMessage.set("Product and images uploaded successfully!"); console.log("Product and all images uploaded successfully", results); this.productAddFrom.reset(); this.selectedImages.set({}); setTimeout(() => this.successMessage.set(null), 3000); }, error: (err) => console.error("Upload failed", err), }); } private uploadImage(file: File, productId: string | number) { const formData = new FormData(); formData.append("image", file); formData.append("product_id", productId.toString()); return this.http.post(`${this.apiUrl}/upload/images`, formData); } }