diff --git a/apps/backend/lambdas/projects/controllers/projects.ts b/apps/backend/lambdas/projects/controllers/projects.ts index 30376e41..ceee9836 100644 --- a/apps/backend/lambdas/projects/controllers/projects.ts +++ b/apps/backend/lambdas/projects/controllers/projects.ts @@ -237,9 +237,9 @@ export const createProject: RouteHandler = async ({ event, auth }) => { } try { - // Creating the project and its roster together: a project that saved - // without its staff would look complete but fail the form's own - // "at least one staff member" rule on the next read. + // Creating the project and its roster together so a partial save cannot + // leave a project without the staff the caller picked. The roster may be + // empty — admins reach every project through `users.is_admin`. const inserted = await db.transaction().execute(async (trx) => { const row = await trx .insertInto('branch.projects') diff --git a/apps/frontend/src/app/components/ProjectFormModal.tsx b/apps/frontend/src/app/components/ProjectFormModal.tsx index b12ffe84..e9d740ce 100644 --- a/apps/frontend/src/app/components/ProjectFormModal.tsx +++ b/apps/frontend/src/app/components/ProjectFormModal.tsx @@ -85,10 +85,6 @@ function validate(values: ProjectFormValues): FieldErrors { } } - if (values.members.length === 0) { - errors.members = 'Select AT LEAST 1 staff member for the project'; - } - return errors; } @@ -343,13 +339,10 @@ export default function ProjectFormModal({ update('members', v)} - isError={showError('members')} - errorMessage={errors.members} disabled={saving} /> diff --git a/apps/frontend/test/components/ProjectFormModal.test.tsx b/apps/frontend/test/components/ProjectFormModal.test.tsx index a5599b33..b07d9221 100644 --- a/apps/frontend/test/components/ProjectFormModal.test.tsx +++ b/apps/frontend/test/components/ProjectFormModal.test.tsx @@ -161,7 +161,7 @@ describe('ProjectFormModal staff roles', () => { ]); }); - it('drops a removed member from the roster it saves', async () => { + it('saves an empty roster, since admins reach every project anyway', async () => { renderEdit(); const list = await screen.findByRole('list', { @@ -173,11 +173,11 @@ describe('ProjectFormModal staff roles', () => { fireEvent.click(screen.getByRole('button', { name: 'Save' })); - expect( - await screen.findByText('Select AT LEAST 1 staff member for the project'), - ).toBeInTheDocument(); - expect( - mockFetch.mock.calls.some(([, init]) => init?.method === 'PUT'), - ).toBe(false); + await waitFor(() => { + expect( + mockFetch.mock.calls.some(([, init]) => init?.method === 'PUT'), + ).toBe(true); + }); + expect(savedBody().members).toEqual([]); }); });