diff --git a/garage-workspace/garage/projects/garage-ui/src/app/core/cars/car.store.ts b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/car.store.ts index dbb4091d44fbcf48ee61673508ced2ea8d3cb986..80a9d3eb8da4409d0b2af4122e88eb75fb20e5db 100644 --- a/garage-workspace/garage/projects/garage-ui/src/app/core/cars/car.store.ts +++ b/garage-workspace/garage/projects/garage-ui/src/app/core/cars/car.store.ts @@ -14,28 +14,34 @@ import { exhaustMap, pipe, tap } from 'rxjs'; interface CarState { cars: Cars; + loading: boolean; } const InitialCarState: CarState = { cars: [], + loading: false, }; export const CarStore = signalStore( withState<CarState>(InitialCarState), withComputed((store) => ({ isEmpty: computed(() => store.cars().length === 0), + isLoading: computed(() => store.loading()), })), withMethods((store, carGateway = inject(CarService)) => ({ getCars: rxMethod<void>( pipe( + tap(() => patchState(store, { loading: true })), exhaustMap(() => carGateway.getAll()), - tap((cars) => patchState(store, { cars })), + tap((cars) => patchState(store, { cars: cars, loading: false })), ), ), })), withHooks((store) => ({ onInit() { + patchState(store, { loading: true }); store.getCars(); + patchState(store, { loading: false }); }, })), ); diff --git a/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html index 83cb6e06cac984351ee0847323561f8044a2d672..555630adfdb85eeeaa733bd8c57f5b92620eda08 100644 --- a/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html +++ b/garage-workspace/garage/projects/garage-ui/src/app/features/cars/cars.component.html @@ -1,4 +1,5 @@ @let empty = this.store.isEmpty(); +@let loading = this.store.isLoading(); <div class="container mx-auto py-6"> <h1 class="text-4xl font-bold text-center mb-6">My cars</h1> @@ -16,15 +17,23 @@ </tr> </thead> @if (!empty) { - @for (car of this.store.cars(); track car.id) { + @if(loading) { <tr> - <td>{{ car.id }}</td> - <td>{{ car.brand }}</td> - <td>{{ car.model }}</td> - <td>{{ car.year }}</td> - <td>{{ car.color }}</td> - <td>Modify | Delete</td> + <td colspan="6" class="text-center"> + <span class="loading loading-spinner loading-xl"></span> + </td> </tr> + } @else { + @for (car of this.store.cars(); track car.id) { + <tr> + <td>{{ car.id }}</td> + <td>{{ car.brand }}</td> + <td>{{ car.model }}</td> + <td>{{ car.year }}</td> + <td>{{ car.color }}</td> + <td>Modify | Delete</td> + </tr> + } } } @else { <tr> diff --git a/garage-workspace/garage/projects/garage-ui/src/app/shared/services/request-status.feature.ts b/garage-workspace/garage/projects/garage-ui/src/app/shared/services/request-status.feature.ts deleted file mode 100644 index aaf504bf58894dc2234966351e54098665820136..0000000000000000000000000000000000000000 --- a/garage-workspace/garage/projects/garage-ui/src/app/shared/services/request-status.feature.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { signalStoreFeature, withComputed, withState } from '@ngrx/signals'; -import { computed } from '@angular/core'; - -export type RequestStatus = 'idle' | 'pending' | 'success' | { error: string }; - -export interface RequestStatusState { - requestStatus: RequestStatus; -} - -export function withRequestStatus() { - return signalStoreFeature( - withState<RequestStatusState>({ requestStatus: 'idle' }), - withComputed(({ requestStatus }) => ({ - isPending: computed(() => requestStatus() === 'pending'), - isSuccess: computed(() => requestStatus() === 'success'), - error: computed(() => { - const status = requestStatus(); - return typeof status === 'object' ? status.error : null; - }), - })), - ); -} - -export function setPending(): RequestStatusState { - return { requestStatus: 'pending' }; -} - -export function setSuccess(): RequestStatusState { - return { requestStatus: 'success' }; -} - -export function setError(error: string): RequestStatusState { - return { requestStatus: { error } }; -} diff --git a/garage-workspace/garage/projects/garage-ui/src/index.html b/garage-workspace/garage/projects/garage-ui/src/index.html index 2163e364e5e6bdddd2b331e30d1233b340439e2b..d0c048631f64261cdc76667e5ba994c6e11f77a0 100644 --- a/garage-workspace/garage/projects/garage-ui/src/index.html +++ b/garage-workspace/garage/projects/garage-ui/src/index.html @@ -8,6 +8,11 @@ <link href="favicon.ico" rel="icon" type="image/x-icon" /> </head> <body> - <app-root></app-root> + <app-root> + <div class="flex flex-col items-center justify-center h-screen"> + <h1 class="text-4xl font-bold mb-5">Garage</h1> + <span class="loading loading-spinner loading-xl"></span> + </div> + </app-root> </body> </html>