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

@@ -1,6 +1,7 @@
import { createFileRoute, useNavigate } from '@tanstack/react-router'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { accountMutations, accountKeys } from '@/api/accounts'
import { memberMutations } from '@/api/members'
import { AccountForm } from '@/components/accounts/account-form'
import { toast } from 'sonner'
@@ -13,7 +14,39 @@ function NewAccountPage() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: accountMutations.create,
mutationFn: async (data: Record<string, unknown>) => {
// Extract member fields
const memberFirstName = data.memberFirstName as string | undefined
const memberLastName = data.memberLastName as string | undefined
const memberEmail = data.memberEmail as string | undefined
const memberPhone = data.memberPhone as string | undefined
const memberDateOfBirth = data.memberDateOfBirth as string | undefined
const memberIsMinor = data.memberIsMinor as boolean | undefined
// Create account (without member fields)
const { memberFirstName: _, memberLastName: __, memberEmail: ___, memberPhone: ____, memberDateOfBirth: _____, memberIsMinor: ______, ...accountData } = data
// Auto-generate account name from member if not provided
if (!accountData.name && memberFirstName && memberLastName) {
accountData.name = `${memberLastName}, ${memberFirstName}`
}
const account = await accountMutations.create(accountData)
// Create first member if name provided
if (memberFirstName && memberLastName) {
await memberMutations.create(account.id, {
firstName: memberFirstName,
lastName: memberLastName,
email: memberEmail || undefined,
phone: memberPhone || undefined,
dateOfBirth: memberDateOfBirth || undefined,
isMinor: memberIsMinor,
})
}
return account
},
onSuccess: (account) => {
queryClient.invalidateQueries({ queryKey: accountKeys.lists() })
toast.success('Account created')
@@ -27,7 +60,7 @@ function NewAccountPage() {
return (
<div className="space-y-6">
<h1 className="text-2xl font-bold">New Account</h1>
<AccountForm onSubmit={mutation.mutate} loading={mutation.isPending} />
<AccountForm onSubmit={mutation.mutate} loading={mutation.isPending} includeFirstMember />
</div>
)
}