Add paginated users/roles, user status, frontend permissions, profile pictures, identifier file storage
- Users page: paginated, searchable, sortable with inline roles (no N+1) - Roles page: paginated, searchable, sortable + /roles/all for dropdowns - User is_active field with migration, PATCH toggle, auth check (disabled=401) - Frontend permission checks: auth store loads permissions, sidebar/buttons conditional - Profile pictures via file storage for users and members, avatar component - Identifier images use file storage API instead of base64 - Fix TypeScript errors across admin UI - 64 API tests passing (10 new)
This commit is contained in:
@@ -124,6 +124,7 @@ export const accountRoutes: FastifyPluginAsync = async (app) => {
|
||||
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}`,
|
||||
billingMode: 'consolidated',
|
||||
})
|
||||
targetAccountId = account.id
|
||||
}
|
||||
@@ -148,8 +149,9 @@ export const accountRoutes: FastifyPluginAsync = async (app) => {
|
||||
|
||||
app.get('/members/:memberId/identifiers', { preHandler: [app.authenticate, app.requirePermission('accounts.view')] }, async (request, reply) => {
|
||||
const { memberId } = request.params as { memberId: string }
|
||||
const identifiers = await MemberIdentifierService.listByMember(app.db, request.companyId, memberId)
|
||||
return reply.send({ data: identifiers })
|
||||
const params = PaginationSchema.parse(request.query)
|
||||
const result = await MemberIdentifierService.listByMember(app.db, request.companyId, memberId, params)
|
||||
return reply.send(result)
|
||||
})
|
||||
|
||||
app.patch('/identifiers/:id', { preHandler: [app.authenticate, app.requirePermission('accounts.edit')] }, async (request, reply) => {
|
||||
@@ -191,8 +193,9 @@ export const accountRoutes: FastifyPluginAsync = async (app) => {
|
||||
|
||||
app.get('/accounts/:accountId/processor-links', { preHandler: [app.authenticate, app.requirePermission('accounts.view')] }, async (request, reply) => {
|
||||
const { accountId } = request.params as { accountId: string }
|
||||
const links = await ProcessorLinkService.listByAccount(app.db, request.companyId, accountId)
|
||||
return reply.send({ data: links })
|
||||
const params = PaginationSchema.parse(request.query)
|
||||
const result = await ProcessorLinkService.listByAccount(app.db, request.companyId, accountId, params)
|
||||
return reply.send(result)
|
||||
})
|
||||
|
||||
app.patch('/processor-links/:id', { preHandler: [app.authenticate, app.requirePermission('accounts.edit')] }, async (request, reply) => {
|
||||
@@ -227,8 +230,9 @@ export const accountRoutes: FastifyPluginAsync = async (app) => {
|
||||
|
||||
app.get('/accounts/:accountId/payment-methods', { preHandler: [app.authenticate, app.requirePermission('accounts.view')] }, async (request, reply) => {
|
||||
const { accountId } = request.params as { accountId: string }
|
||||
const methods = await PaymentMethodService.listByAccount(app.db, request.companyId, accountId)
|
||||
return reply.send({ data: methods })
|
||||
const params = PaginationSchema.parse(request.query)
|
||||
const result = await PaymentMethodService.listByAccount(app.db, request.companyId, accountId, params)
|
||||
return reply.send(result)
|
||||
})
|
||||
|
||||
app.get('/payment-methods/:id', { preHandler: [app.authenticate, app.requirePermission('accounts.view')] }, async (request, reply) => {
|
||||
@@ -270,8 +274,9 @@ export const accountRoutes: FastifyPluginAsync = async (app) => {
|
||||
|
||||
app.get('/accounts/:accountId/tax-exemptions', { preHandler: [app.authenticate, app.requirePermission('accounts.view')] }, async (request, reply) => {
|
||||
const { accountId } = request.params as { accountId: string }
|
||||
const exemptions = await TaxExemptionService.listByAccount(app.db, request.companyId, accountId)
|
||||
return reply.send({ data: exemptions })
|
||||
const params = PaginationSchema.parse(request.query)
|
||||
const result = await TaxExemptionService.listByAccount(app.db, request.companyId, accountId, params)
|
||||
return reply.send(result)
|
||||
})
|
||||
|
||||
app.get('/tax-exemptions/:id', { preHandler: [app.authenticate, app.requirePermission('accounts.view')] }, async (request, reply) => {
|
||||
|
||||
Reference in New Issue
Block a user