113 lines
3.7 KiB
TypeScript
113 lines
3.7 KiB
TypeScript
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<string>(API_URL);
|
|
categoryService = inject(CategoryService);
|
|
|
|
@ViewChild("imageDialog") imageDialog!: ElementRef<HTMLDialogElement>;
|
|
activeImage = signal<ImageSelection | null>(null);
|
|
selectedImages = signal<Record<string, { url: string; file: File }>>({});
|
|
categories = signal<Category[]>([]);
|
|
successMessage = signal<string | null>(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);
|
|
}
|
|
}
|