Skip to content
Snippets Groups Projects
Commit 4f2a0d31 authored by thibault.capt's avatar thibault.capt
Browse files

(feat): loading spinner

parent abdaeefd
Branches
No related tags found
No related merge requests found
......@@ -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 });
},
})),
);
@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>
......
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 } };
}
......@@ -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>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment