Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { Injectable, inject, effect } from '@angular/core';
- import {
- signalStore,
- withState,
- withMethods,
- patchState,
- withHooks,
- } from '@ngrx/signals';
- import { HttpClient } from '@angular/common/http';
- import { firstValueFrom } from 'rxjs';
- import { Product } from './product.model';
- interface ProductState {
- products: Product[];
- isLoading: boolean;
- error: string | null;
- }
- const initialState: ProductState = {
- products: [],
- isLoading: false,
- error: null,
- };
- @Injectable({
- providedIn: 'root',
- })
- export class ProductStore extends signalStore(
- withState(initialState),
- withMethods((store, http = inject(HttpClient)) => ({
- async loadProducts(): Promise<void> {
- patchState(store, { isLoading: true, error: null });
- try {
- const res = await firstValueFrom(
- http.get<{ products: Product[] }>('https://dummyjson.com/products')
- );
- patchState(store, {
- products: res.products,
- isLoading: false,
- error: null,
- });
- } catch (error) {
- patchState(store, {
- products: [],
- isLoading: false,
- error:
- error instanceof Error ? error.message : 'Failed to load products',
- });
- }
- },
- addProduct(newProduct: Product): void {
- const currentProducts = store.products();
- const exists = currentProducts.some((p) => p.id === newProduct.id);
- if (exists) {
- patchState(store, {
- error: `Product with ID ${newProduct.id} already exists`,
- });
- return;
- }
- patchState(store, {
- products: [...currentProducts, newProduct],
- error: null,
- });
- },
- updateProduct(productId: number, updatedProduct: Product): void {
- const currentProducts = store.products();
- const productIndex = currentProducts.findIndex((p) => p.id === productId);
- if (productIndex === -1) {
- patchState(store, {
- error: `Product with ID ${productId} not found`,
- });
- return;
- }
- const updatedProducts = [...currentProducts];
- updatedProducts[productIndex] = updatedProduct;
- patchState(store, {
- products: updatedProducts,
- error: null,
- });
- },
- deleteProduct(productId: number): void {
- const currentProducts = store.products();
- const exists = currentProducts.some((p) => p.id === productId);
- if (!exists) {
- patchState(store, {
- error: `Product with ID ${productId} not found`,
- });
- return;
- }
- patchState(store, {
- products: currentProducts.filter((p) => p.id !== productId),
- error: null,
- });
- },
- findProduct(productId: number): Product | undefined {
- return store.products().find((p) => p.id === productId);
- },
- productExists(productId: number): boolean {
- return store.products().some((p) => p.id === productId);
- },
- clearError(): void {
- patchState(store, { error: null });
- },
- reset(): void {
- patchState(store, initialState);
- },
- })),
- // ✅ AUTOMATIC SORTING using withHooks and effect
- withHooks({
- onInit(store) {
- effect(() => {
- const products = store.products();
- // Only sort if products exist and we have more than one product
- if (products && products.length > 1) {
- // Check if the array is already sorted to avoid unnecessary updates
- const sorted = [...products].sort((a, b) =>
- a.title.localeCompare(b.title)
- );
- // Only update if the order actually changed
- const needsSorting = products.some(
- (prod, index) => prod.id !== sorted[index]?.id
- );
- if (needsSorting) {
- console.log('Products not sorted, auto-sorting now...');
- patchState(store, { products: sorted });
- }
- }
- });
- },
- })
- ) {}
Advertisement
Add Comment
Please, Sign In to add comment