Rebuild admin pages around DataTable/AdminModal; restructure categories/groups and v2 groups API
Remove the generic $lib/svelte-admin CRUD layer and AdminTable.svelte; each admin route now owns its own form/modal logic. Add DataTable.svelte, superform-errors.ts, and profile-specific modal/field components. Flatten proclamation categories/groups and drop subscription levels; add the v2 groups API; update v1/v2 endpoints, serializers, auth, and regenerated Prisma client with the new migrations. Document the overhaul plan in docs/ADMIN_OVERHAUL.md.
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
vi.mock('$lib/db', () => ({
|
||||
prisma: {
|
||||
user: { findUnique: vi.fn() },
|
||||
profile: { update: vi.fn(), findUnique: vi.fn() },
|
||||
profile: { findFirst: vi.fn(), updateMany: vi.fn() },
|
||||
address: { create: vi.fn() }
|
||||
}
|
||||
}));
|
||||
@@ -19,8 +19,8 @@ import { prisma } from '$lib/db';
|
||||
import { load, actions } from './+page.server';
|
||||
|
||||
const userFindUnique = prisma.user.findUnique as ReturnType<typeof vi.fn>;
|
||||
const profileUpdate = prisma.profile.update as ReturnType<typeof vi.fn>;
|
||||
const profileFindUnique = prisma.profile.findUnique as ReturnType<typeof vi.fn>;
|
||||
const profileFindFirst = prisma.profile.findFirst as ReturnType<typeof vi.fn>;
|
||||
const profileUpdateMany = prisma.profile.updateMany as ReturnType<typeof vi.fn>;
|
||||
const addressCreate = prisma.address.create as ReturnType<typeof vi.fn>;
|
||||
|
||||
const invokeAction = (name: string, request: Request, locals: App.Locals) =>
|
||||
@@ -29,8 +29,8 @@ const invokeAction = (name: string, request: Request, locals: App.Locals) =>
|
||||
describe('(protected)/account page server', () => {
|
||||
beforeEach(() => {
|
||||
userFindUnique.mockReset();
|
||||
profileUpdate.mockReset();
|
||||
profileFindUnique.mockReset();
|
||||
profileFindFirst.mockReset();
|
||||
profileUpdateMany.mockReset();
|
||||
addressCreate.mockReset();
|
||||
});
|
||||
|
||||
@@ -51,24 +51,26 @@ describe('(protected)/account page server', () => {
|
||||
});
|
||||
|
||||
it('returns user with profile and addresses', async () => {
|
||||
const user = mockUserWithProfileAndAddresses();
|
||||
const { profile, ...user } = mockUserWithProfileAndAddresses() as any;
|
||||
userFindUnique.mockResolvedValue(user);
|
||||
profileFindFirst.mockResolvedValue(profile);
|
||||
|
||||
const locals = createLocals(mockUser() as any);
|
||||
const result = (await load({ locals } as any)) as any;
|
||||
expect(result.user).toEqual(user);
|
||||
expect(result.user).toEqual({ ...user, profile });
|
||||
expect(result.user.profile.addresses).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('includes addresses in the query', async () => {
|
||||
userFindUnique.mockResolvedValue(mockUserWithProfileAndAddresses());
|
||||
it('loads the profile with addresses by user id', async () => {
|
||||
userFindUnique.mockResolvedValue(mockUser());
|
||||
profileFindFirst.mockResolvedValue({ id: 'profile-1' });
|
||||
|
||||
const locals = createLocals(mockUser() as any);
|
||||
await load({ locals } as any);
|
||||
|
||||
expect(userFindUnique).toHaveBeenCalledWith({
|
||||
where: { id: 'user-1' },
|
||||
include: { profile: { include: { addresses: true } } }
|
||||
expect(profileFindFirst).toHaveBeenCalledWith({
|
||||
where: { userId: 'user-1' },
|
||||
include: { addresses: true }
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -125,7 +127,7 @@ describe('(protected)/account page server', () => {
|
||||
});
|
||||
|
||||
it('updates profile with server-formatted phone number on success', async () => {
|
||||
profileUpdate.mockResolvedValue({});
|
||||
profileUpdateMany.mockResolvedValue({});
|
||||
|
||||
const request = createFormRequest({
|
||||
firstName: 'Jane',
|
||||
@@ -136,14 +138,14 @@ describe('(protected)/account page server', () => {
|
||||
const locals = createLocals(mockUser() as any);
|
||||
const result = await invokeAction('updateProfile', request, locals);
|
||||
expect(result).toEqual({ success: true, action: 'updateProfile' });
|
||||
expect(profileUpdate).toHaveBeenCalledWith({
|
||||
expect(profileUpdateMany).toHaveBeenCalledWith({
|
||||
where: { userId: 'user-1' },
|
||||
data: { firstName: 'Jane', lastName: 'Smith', phoneNumber: '8175551234' }
|
||||
});
|
||||
});
|
||||
|
||||
it('returns fail(500) when prisma update throws', async () => {
|
||||
profileUpdate.mockRejectedValue(new Error('db error'));
|
||||
profileUpdateMany.mockRejectedValue(new Error('db error'));
|
||||
|
||||
const request = createFormRequest({
|
||||
firstName: 'Jane',
|
||||
@@ -190,7 +192,7 @@ describe('(protected)/account page server', () => {
|
||||
});
|
||||
|
||||
it('throws 400 when profile is not found', async () => {
|
||||
profileFindUnique.mockResolvedValue(null);
|
||||
profileFindFirst.mockResolvedValue(null);
|
||||
|
||||
const request = createFormRequest({
|
||||
street: '123 Main St',
|
||||
@@ -208,7 +210,7 @@ describe('(protected)/account page server', () => {
|
||||
});
|
||||
|
||||
it('creates address linked to profile on success', async () => {
|
||||
profileFindUnique.mockResolvedValue({ id: 'profile-1' });
|
||||
profileFindFirst.mockResolvedValue({ id: 'profile-1' });
|
||||
addressCreate.mockResolvedValue({});
|
||||
|
||||
const request = createFormRequest({
|
||||
@@ -235,7 +237,7 @@ describe('(protected)/account page server', () => {
|
||||
});
|
||||
|
||||
it('returns fail(500) when prisma create throws', async () => {
|
||||
profileFindUnique.mockResolvedValue({ id: 'profile-1' });
|
||||
profileFindFirst.mockResolvedValue({ id: 'profile-1' });
|
||||
addressCreate.mockRejectedValue(new Error('db error'));
|
||||
|
||||
const request = createFormRequest({
|
||||
|
||||
Reference in New Issue
Block a user