feat: add workspace account page and mobile app shell
Normalize the UI with shared primitives, add a workspace-backed account surface, and improve authenticated mobile navigation, map behavior, and dashboard browsing.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import type { FastifyPluginAsync } from 'fastify';
|
||||
import { ZodError, z } from 'zod';
|
||||
import { requireAuth } from '../auth/middleware.js';
|
||||
import { getDbPool } from '../db/pool.js';
|
||||
import { buildAccountPageData, ensureWorkspaceForUser, updateUserProfile, updateWorkspaceName } from '../account/repository.js';
|
||||
|
||||
const updateAccountSchema = z.object({
|
||||
displayName: z.string().trim().min(1).max(120).optional(),
|
||||
avatarUrl: z.string().trim().url().nullable().optional().or(z.literal('')),
|
||||
workspaceName: z.string().trim().min(1).max(160).optional(),
|
||||
});
|
||||
|
||||
export const accountRoutes: FastifyPluginAsync = async (app) => {
|
||||
app.get('/account/me', { preHandler: requireAuth }, async (request, reply) => {
|
||||
try {
|
||||
const account = await buildAccountPageData(getDbPool(), request.authUser!);
|
||||
return { account };
|
||||
} catch (error) {
|
||||
request.log.error(error);
|
||||
return reply.code(500).send({ error: 'Failed to load account page.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.patch('/account/me', { preHandler: requireAuth }, async (request, reply) => {
|
||||
try {
|
||||
const payload = updateAccountSchema.parse(request.body);
|
||||
const db = getDbPool();
|
||||
const workspace = await ensureWorkspaceForUser(db, request.authUser!);
|
||||
|
||||
if (!workspace) {
|
||||
return reply.code(500).send({ error: 'Failed to load workspace.' });
|
||||
}
|
||||
|
||||
if (payload.workspaceName && workspace.role !== 'owner' && workspace.role !== 'admin') {
|
||||
return reply.code(403).send({ error: 'You do not have permission to update this workspace.' });
|
||||
}
|
||||
|
||||
const profile = await updateUserProfile(db, request.authUser!.id, {
|
||||
displayName: payload.displayName,
|
||||
avatarUrl: payload.avatarUrl === '' ? null : payload.avatarUrl,
|
||||
});
|
||||
|
||||
if (payload.workspaceName) {
|
||||
await updateWorkspaceName(db, workspace.id, payload.workspaceName);
|
||||
}
|
||||
|
||||
const account = await buildAccountPageData(db, profile);
|
||||
return { account };
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return reply.code(400).send({ error: error.issues[0]?.message || 'Invalid account payload.' });
|
||||
}
|
||||
|
||||
request.log.error(error);
|
||||
return reply.code(500).send({ error: 'Failed to update account.' });
|
||||
}
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user