Add top-level members list, primary member on account, member move, combined create flows

- GET /v1/members with search across all members (includes account name)
- POST /members/:id/move with optional accountId (creates new account if omitted)
- primary_member_id on account table, auto-set when first member added
- isMinor flag on member create (manual override when no DOB provided)
- Account search now includes member names
- New account form includes primary contact fields, auto-generates name
- Members page in sidebar with global search
This commit is contained in:
Ryan Moon
2026-03-28 09:08:06 -05:00
parent 7c64a928e1
commit 572af05a3f
16 changed files with 796 additions and 77 deletions

View File

@@ -63,7 +63,15 @@ export const accountRoutes: FastifyPluginAsync = async (app) => {
return reply.send(account)
})
// --- Members ---
// --- Members (top-level) ---
app.get('/members', { preHandler: [app.authenticate] }, async (request, reply) => {
const params = PaginationSchema.parse(request.query)
const result = await MemberService.list(app.db, request.companyId, params)
return reply.send(result)
})
// --- Members (scoped to account) ---
app.post('/accounts/:accountId/members', { preHandler: [app.authenticate] }, async (request, reply) => {
const { accountId } = request.params as { accountId: string }
@@ -100,6 +108,27 @@ export const accountRoutes: FastifyPluginAsync = async (app) => {
return reply.send(member)
})
app.post('/members/:id/move', { preHandler: [app.authenticate] }, async (request, reply) => {
const { id } = request.params as { id: string }
const { accountId } = (request.body as { accountId?: string }) ?? {}
let targetAccountId = accountId
// If no accountId provided, create a new account from the member's name
if (!targetAccountId) {
const member = await MemberService.getById(app.db, request.companyId, id)
if (!member) return reply.status(404).send({ error: { message: 'Member not found', statusCode: 404 } })
const account = await AccountService.create(app.db, request.companyId, {
name: `${member.firstName} ${member.lastName}`,
})
targetAccountId = account.id
}
const member = await MemberService.move(app.db, request.companyId, id, targetAccountId)
if (!member) return reply.status(404).send({ error: { message: 'Member not found', statusCode: 404 } })
return reply.send(member)
})
app.delete('/members/:id', { preHandler: [app.authenticate] }, async (request, reply) => {
const { id } = request.params as { id: string }
const member = await MemberService.delete(app.db, request.companyId, id)