fix(logout): enhance logout handling with success and error toasts
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { vi } from 'vitest';
|
||||
import { ToastService } from './toast.service';
|
||||
@@ -6,14 +7,16 @@ describe('ToastService', () => {
|
||||
let service: ToastService;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ToastService]
|
||||
});
|
||||
TestBed.inject(DOCUMENT).defaultView?.sessionStorage.removeItem('shopit.pending-toast');
|
||||
service = TestBed.inject(ToastService);
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
TestBed.inject(DOCUMENT).defaultView?.sessionStorage.removeItem('shopit.pending-toast');
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
@@ -98,4 +101,23 @@ describe('ToastService', () => {
|
||||
|
||||
expect(service.toasts().length).toBe(1);
|
||||
});
|
||||
|
||||
it('should restore a toast queued for after a full page reload', () => {
|
||||
service.showAfterReload('Sesión iniciada correctamente.', 'success', 0);
|
||||
|
||||
TestBed.resetTestingModule();
|
||||
TestBed.configureTestingModule({ providers: [ToastService] });
|
||||
service = TestBed.inject(ToastService);
|
||||
|
||||
expect(service.toasts()).toEqual([
|
||||
expect.objectContaining({
|
||||
message: 'Sesión iniciada correctamente.',
|
||||
type: 'success',
|
||||
duration: 0,
|
||||
}),
|
||||
]);
|
||||
expect(
|
||||
TestBed.inject(DOCUMENT).defaultView?.sessionStorage.getItem('shopit.pending-toast'),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { Injectable, signal } from '@angular/core';
|
||||
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
||||
import { inject, Injectable, PLATFORM_ID, signal } from '@angular/core';
|
||||
|
||||
const PENDING_TOAST_STORAGE_KEY = 'shopit.pending-toast';
|
||||
|
||||
export interface Toast {
|
||||
id: string;
|
||||
@@ -11,9 +14,15 @@ export interface Toast {
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ToastService {
|
||||
private readonly document = inject(DOCUMENT);
|
||||
private readonly platformId = inject(PLATFORM_ID);
|
||||
private readonly toastsSignal = signal<Toast[]>([]);
|
||||
readonly toasts = this.toastsSignal.asReadonly();
|
||||
|
||||
constructor() {
|
||||
this.restorePendingToast();
|
||||
}
|
||||
|
||||
show(message: string, type: 'success' | 'danger' | 'info' = 'info', duration = 3000): string {
|
||||
const id = Math.random().toString(36).substring(2, 9);
|
||||
const newToast: Toast = { id, message, type, duration };
|
||||
@@ -41,7 +50,50 @@ export class ToastService {
|
||||
return this.show(message, 'success', duration);
|
||||
}
|
||||
|
||||
showAfterReload(
|
||||
message: string,
|
||||
type: Toast['type'] = 'info',
|
||||
duration = 3000,
|
||||
): void {
|
||||
if (!isPlatformBrowser(this.platformId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.document.defaultView?.sessionStorage.setItem(
|
||||
PENDING_TOAST_STORAGE_KEY,
|
||||
JSON.stringify({ message, type, duration }),
|
||||
);
|
||||
}
|
||||
|
||||
dismiss(id: string): void {
|
||||
this.toastsSignal.update((toasts) => toasts.filter((t) => t.id !== id));
|
||||
}
|
||||
|
||||
private restorePendingToast(): void {
|
||||
if (!isPlatformBrowser(this.platformId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const storage = this.document.defaultView?.sessionStorage;
|
||||
const pendingToast = storage?.getItem(PENDING_TOAST_STORAGE_KEY);
|
||||
|
||||
if (!pendingToast) {
|
||||
return;
|
||||
}
|
||||
|
||||
storage?.removeItem(PENDING_TOAST_STORAGE_KEY);
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(pendingToast) as Partial<Toast>;
|
||||
|
||||
if (
|
||||
typeof parsed.message === 'string' &&
|
||||
(parsed.type === 'success' || parsed.type === 'danger' || parsed.type === 'info')
|
||||
) {
|
||||
this.show(parsed.message, parsed.type, parsed.duration);
|
||||
}
|
||||
} catch {
|
||||
// Ignore malformed session data left by an older or interrupted client.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user