Public Access
1
0

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:
pguerrerox
2026-05-07 17:40:10 +00:00
parent d4bce92872
commit 1f7737e5cb
24 changed files with 1397 additions and 489 deletions
+58
View File
@@ -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.' });
}
});
};