feat(dashboard): replace notifications fetch with stats in server load
Removes /api/notifications from the dashboard widget fetches and replaces it with /api/stats so the page no longer needs to own notification data. Returns stats: StatsDTO | null (null on failure) instead of mentions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { createApiClient } from '$lib/api.server';
|
||||
import type { components } from '$lib/generated/api';
|
||||
|
||||
type IncompleteDocumentDTO = components['schemas']['IncompleteDocumentDTO'];
|
||||
type NotificationDTO = components['schemas']['NotificationDTO'];
|
||||
type StatsDTO = components['schemas']['StatsDTO'];
|
||||
type Document = components['schemas']['Document'];
|
||||
|
||||
export async function load({ url, fetch }) {
|
||||
@@ -55,19 +55,19 @@ export async function load({ url, fetch }) {
|
||||
const receiverObj = allPersons.find((p) => p.id === receiverId);
|
||||
|
||||
// Dashboard widgets — failures are isolated and don't crash the page
|
||||
let mentions: NotificationDTO[] = [];
|
||||
let stats: StatsDTO | null = null;
|
||||
let incompleteDocs: IncompleteDocumentDTO[] = [];
|
||||
let recentDocs: Document[] = [];
|
||||
|
||||
if (isDashboard) {
|
||||
const [mentionsResult, incompleteResult, recentResult] = await Promise.allSettled([
|
||||
api.GET('/api/notifications', { params: { query: { size: 5 } } }),
|
||||
const [statsResult, incompleteResult, recentResult] = await Promise.allSettled([
|
||||
api.GET('/api/stats'),
|
||||
api.GET('/api/documents/incomplete', { params: { query: { size: 5 } } }),
|
||||
api.GET('/api/documents/recent-activity', { params: { query: { size: 5 } } })
|
||||
]);
|
||||
|
||||
if (mentionsResult.status === 'fulfilled' && mentionsResult.value.response.ok) {
|
||||
mentions = mentionsResult.value.data?.content ?? [];
|
||||
if (statsResult.status === 'fulfilled' && statsResult.value.response.ok) {
|
||||
stats = statsResult.value.data ?? null;
|
||||
}
|
||||
if (incompleteResult.status === 'fulfilled' && incompleteResult.value.response.ok) {
|
||||
incompleteDocs = incompleteResult.value.data ?? [];
|
||||
@@ -80,7 +80,7 @@ export async function load({ url, fetch }) {
|
||||
return {
|
||||
isDashboard,
|
||||
documents,
|
||||
mentions,
|
||||
stats,
|
||||
incompleteDocs,
|
||||
recentDocs,
|
||||
initialValues: {
|
||||
@@ -96,7 +96,7 @@ export async function load({ url, fetch }) {
|
||||
return {
|
||||
isDashboard,
|
||||
documents: [],
|
||||
mentions: [],
|
||||
stats: null,
|
||||
incompleteDocs: [],
|
||||
recentDocs: [],
|
||||
initialValues: { senderName: '', receiverName: '' },
|
||||
|
||||
@@ -22,14 +22,14 @@ function makeUrl(params: Record<string, string | string[]> = {}) {
|
||||
// ─── dashboard mode (no search filters) ──────────────────────────────────────
|
||||
|
||||
describe('home page load — dashboard mode', () => {
|
||||
it('sets isDashboard true and fetches all three widget APIs', async () => {
|
||||
it('sets isDashboard true and fetches stats, incomplete, and recent APIs', async () => {
|
||||
const mockGet = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ response: { ok: true, status: 200 }, data: [] }) // persons
|
||||
.mockResolvedValueOnce({
|
||||
response: { ok: true },
|
||||
data: { content: [{ id: 'n1' }] }
|
||||
}) // notifications
|
||||
data: { totalDocuments: 42, totalPersons: 7 }
|
||||
}) // stats
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [{ id: 'd1' }] }) // incomplete
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [{ id: 'd2' }] }); // recent
|
||||
vi.mocked(createApiClient).mockReturnValue({ GET: mockGet } as ReturnType<
|
||||
@@ -39,17 +39,20 @@ describe('home page load — dashboard mode', () => {
|
||||
const result = await load({ url: makeUrl(), fetch: vi.fn() as unknown as typeof fetch });
|
||||
|
||||
expect(result.isDashboard).toBe(true);
|
||||
expect(result.mentions).toHaveLength(1);
|
||||
expect(result.stats).toEqual({ totalDocuments: 42, totalPersons: 7 });
|
||||
expect(result.incompleteDocs).toHaveLength(1);
|
||||
expect(result.recentDocs).toHaveLength(1);
|
||||
expect(result.documents).toEqual([]);
|
||||
});
|
||||
|
||||
it('defaults mentions to [] when notifications API rejects', async () => {
|
||||
it('returns stats with totalDocuments from /api/stats', async () => {
|
||||
const mockGet = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ response: { ok: true, status: 200 }, data: [] }) // persons
|
||||
.mockRejectedValueOnce(new Error('network')) // notifications
|
||||
.mockResolvedValueOnce({
|
||||
response: { ok: true },
|
||||
data: { totalDocuments: 248, totalPersons: 34 }
|
||||
}) // stats
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [] }) // incomplete
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [] }); // recent
|
||||
vi.mocked(createApiClient).mockReturnValue({ GET: mockGet } as ReturnType<
|
||||
@@ -58,7 +61,24 @@ describe('home page load — dashboard mode', () => {
|
||||
|
||||
const result = await load({ url: makeUrl(), fetch: vi.fn() as unknown as typeof fetch });
|
||||
|
||||
expect(result.mentions).toEqual([]);
|
||||
expect(result.stats?.totalDocuments).toBe(248);
|
||||
expect(result.stats?.totalPersons).toBe(34);
|
||||
});
|
||||
|
||||
it('returns stats: null when /api/stats rejects', async () => {
|
||||
const mockGet = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ response: { ok: true, status: 200 }, data: [] }) // persons
|
||||
.mockRejectedValueOnce(new Error('network')) // stats
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [] }) // incomplete
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [] }); // recent
|
||||
vi.mocked(createApiClient).mockReturnValue({ GET: mockGet } as ReturnType<
|
||||
typeof createApiClient
|
||||
>);
|
||||
|
||||
const result = await load({ url: makeUrl(), fetch: vi.fn() as unknown as typeof fetch });
|
||||
|
||||
expect(result.stats).toBeNull();
|
||||
});
|
||||
|
||||
it('defaults incompleteDocs to [] when incomplete API rejects', async () => {
|
||||
@@ -81,7 +101,10 @@ describe('home page load — dashboard mode', () => {
|
||||
const mockGet = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ response: { ok: true, status: 200 }, data: [] }) // persons
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: { content: [] } }) // notifications
|
||||
.mockResolvedValueOnce({
|
||||
response: { ok: true },
|
||||
data: { totalDocuments: 0, totalPersons: 0 }
|
||||
}) // stats
|
||||
.mockResolvedValueOnce({ response: { ok: true }, data: [] }) // incomplete
|
||||
.mockRejectedValueOnce(new Error('network')); // recent
|
||||
vi.mocked(createApiClient).mockReturnValue({ GET: mockGet } as ReturnType<
|
||||
@@ -113,7 +136,7 @@ describe('home page load — search mode', () => {
|
||||
|
||||
expect(result.isDashboard).toBe(false);
|
||||
expect(result.documents).toHaveLength(1);
|
||||
expect(result.mentions).toEqual([]);
|
||||
expect(result.stats).toBeNull();
|
||||
expect(result.incompleteDocs).toEqual([]);
|
||||
expect(result.recentDocs).toEqual([]);
|
||||
// Only two API calls — no widget calls
|
||||
|
||||
Reference in New Issue
Block a user