Restructures frontend to a feature-based folder layout
Continuous Integration / config (pull_request) Successful in 11s
Continuous Integration / changes (pull_request) Successful in 21s
Continuous Integration / backend-build (pull_request) Skipped
Continuous Integration / backend-test (pull_request) Skipped
Continuous Integration / vulnerability-scan (pull_request) Skipped
Continuous Integration / frontend-prepare (pull_request) Successful in 1m37s
Continuous Integration / frontend-build (pull_request) Successful in 2m12s
Continuous Integration / frontend-test (pull_request) Successful in 4m42s
Continuous Integration / frontend-lint (pull_request) Successful in 2m2s
Continuous Integration / publish-production (pull_request) Skipped
Continuous Integration / deploy-production (pull_request) Skipped
Continuous Integration / publish-test (pull_request) Successful in 6m51s
Continuous Integration / deploy-test (pull_request) Skipped
Continuous Integration / config (pull_request) Successful in 11s
Continuous Integration / changes (pull_request) Successful in 21s
Continuous Integration / backend-build (pull_request) Skipped
Continuous Integration / backend-test (pull_request) Skipped
Continuous Integration / vulnerability-scan (pull_request) Skipped
Continuous Integration / frontend-prepare (pull_request) Successful in 1m37s
Continuous Integration / frontend-build (pull_request) Successful in 2m12s
Continuous Integration / frontend-test (pull_request) Successful in 4m42s
Continuous Integration / frontend-lint (pull_request) Successful in 2m2s
Continuous Integration / publish-production (pull_request) Skipped
Continuous Integration / deploy-production (pull_request) Skipped
Continuous Integration / publish-test (pull_request) Successful in 6m51s
Continuous Integration / deploy-test (pull_request) Skipped
Groups auth, setup, invitation, profile, users, cms, availability and system code (services/hooks, components, schemas, mocks, pages) under src/features/<name> instead of splitting by technical layer (api/, components/, lib/schemas/, mocks/, pages/). Renames the old connection-oriented `api` layer to `services` per feature, and splits the monolithic api/types.ts into per-feature types.ts files (with ProblemDetails/ApiResult merged into lib/api-client.ts as shared infra). Layout-agnostic code (ui primitives, app shell, i18n, test utils, lib) stays at the top level. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
import { http, HttpResponse } from 'msw';
|
||||
import type { UserListItem } from '@/features/users/services/types';
|
||||
import { API_BASE, mockUser } from '@/features/auth/mocks/fixtures';
|
||||
|
||||
let mockUsers: UserListItem[] = [
|
||||
{
|
||||
...mockUser,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
invitationPending: false,
|
||||
inviteLink: null,
|
||||
},
|
||||
{
|
||||
id: '22222222-2222-2222-2222-222222222222',
|
||||
email: 'admin@example.com',
|
||||
name: 'Admin User',
|
||||
role: 'Administrator',
|
||||
isActive: true,
|
||||
createdAt: '2026-01-15T00:00:00.000Z',
|
||||
invitationPending: false,
|
||||
inviteLink: null,
|
||||
},
|
||||
{
|
||||
id: '33333333-3333-3333-3333-333333333333',
|
||||
email: 'pending@example.com',
|
||||
name: 'pending@example.com',
|
||||
role: 'User',
|
||||
isActive: true,
|
||||
createdAt: '2026-06-01T00:00:00.000Z',
|
||||
invitationPending: true,
|
||||
inviteLink: '/invite/complete?token=pending-mock-token',
|
||||
},
|
||||
];
|
||||
|
||||
export const resetMockUsers = () => {
|
||||
mockUsers = [
|
||||
{
|
||||
...mockUser,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
invitationPending: false,
|
||||
inviteLink: null,
|
||||
},
|
||||
{
|
||||
id: '22222222-2222-2222-2222-222222222222',
|
||||
email: 'admin@example.com',
|
||||
name: 'Admin User',
|
||||
role: 'Administrator',
|
||||
isActive: true,
|
||||
createdAt: '2026-01-15T00:00:00.000Z',
|
||||
invitationPending: false,
|
||||
inviteLink: null,
|
||||
},
|
||||
{
|
||||
id: '33333333-3333-3333-3333-333333333333',
|
||||
email: 'pending@example.com',
|
||||
name: 'pending@example.com',
|
||||
role: 'User',
|
||||
isActive: true,
|
||||
createdAt: '2026-06-01T00:00:00.000Z',
|
||||
invitationPending: true,
|
||||
inviteLink: '/invite/complete?token=pending-mock-token',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const getMockUsers = () => mockUsers;
|
||||
|
||||
export const userHandlers = [
|
||||
http.get(`${API_BASE}/api/v1/Users`, () => HttpResponse.json(mockUsers)),
|
||||
|
||||
http.post(`${API_BASE}/api/v1/Users/invite`, async ({ request }) => {
|
||||
const body = (await request.json()) as { email: string; role: string };
|
||||
const token = `mock-token-${Date.now()}`;
|
||||
const inviteLink = `/invite/complete?token=${token}`;
|
||||
|
||||
const newUser: UserListItem = {
|
||||
id: crypto.randomUUID(),
|
||||
email: body.email,
|
||||
name: body.email,
|
||||
role: body.role as UserListItem['role'],
|
||||
isActive: true,
|
||||
createdAt: new Date().toISOString(),
|
||||
invitationPending: true,
|
||||
inviteLink,
|
||||
};
|
||||
mockUsers = [...mockUsers, newUser];
|
||||
|
||||
return HttpResponse.json({ inviteLink });
|
||||
}),
|
||||
|
||||
http.put(`${API_BASE}/api/v1/Users/:userId/role`, () => new HttpResponse(null, { status: 200 })),
|
||||
|
||||
http.put(`${API_BASE}/api/v1/Users/:userId/active`, () => new HttpResponse(null, { status: 200 })),
|
||||
|
||||
http.put(`${API_BASE}/api/v1/Users/me`, async ({ request }) => {
|
||||
const body = (await request.json()) as { name: string; email: string };
|
||||
const owner = mockUsers.find((u) => u.role === 'Owner') ?? mockUsers[0];
|
||||
const updated: UserListItem = {
|
||||
...owner,
|
||||
name: body.name,
|
||||
email: body.email,
|
||||
};
|
||||
mockUsers = mockUsers.map((u) => (u.id === owner.id ? updated : u));
|
||||
return HttpResponse.json(updated);
|
||||
}),
|
||||
|
||||
http.delete(`${API_BASE}/api/v1/Users/:userId`, ({ params }) => {
|
||||
const { userId } = params as { userId: string };
|
||||
const ownerUser = mockUsers.find((u) => u.role === 'Owner');
|
||||
if (userId === ownerUser?.id) {
|
||||
return HttpResponse.json(
|
||||
{ title: 'Bad Request', detail: 'At least one Owner must remain.', status: 400 },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
mockUsers = mockUsers.filter((u) => u.id !== userId);
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
}),
|
||||
];
|
||||
Reference in New Issue
Block a user