Profile page UI and functionality implemented

This commit is contained in:
adilallo
2026-04-25 17:57:58 -06:00
parent 7dd2562bae
commit 68517796a9
103 changed files with 4439 additions and 1476 deletions
+41
View File
@@ -46,3 +46,44 @@ export async function getPublicPublishedRuleById(
return null;
}
}
/** Metadata for signed-in “my rules” profile list (no full `document` JSON). */
const PUBLISHED_RULE_OWNER_LIST_SELECT = {
id: true,
title: true,
summary: true,
createdAt: true,
updatedAt: true,
} as const;
export type OwnerPublishedRuleListItem = {
id: string;
title: string;
summary: string | null;
createdAt: Date;
updatedAt: Date;
};
/**
* Lists published rules owned by the given user (alphabetical by title, then id).
* Returns `null` when the database is not configured or the query throws.
*/
export async function listPublishedRulesForUser(
userId: string,
take: number,
): Promise<OwnerPublishedRuleListItem[] | null> {
if (!isDatabaseConfigured()) return null;
if (typeof userId !== "string" || userId.trim() === "") return null;
const clamped = Math.min(Math.max(0, take), 100);
if (clamped === 0) return [];
try {
return await prisma.publishedRule.findMany({
where: { userId },
orderBy: [{ title: "asc" }, { id: "asc" }],
take: clamped,
select: PUBLISHED_RULE_OWNER_LIST_SELECT,
});
} catch {
return null;
}
}
+4
View File
@@ -62,6 +62,10 @@ export function notFound(message = "Not found"): NextResponse {
return errorJson("not_found", message, 404);
}
export function forbidden(message = "Forbidden"): NextResponse {
return errorJson("forbidden", message, 403);
}
export function rateLimited(retryAfterMs: number): NextResponse {
const retryAfterSec = Math.max(1, Math.ceil(retryAfterMs / 1000));
return errorJson("rate_limited", "Too many requests", 429, {
+1 -1
View File
@@ -81,7 +81,7 @@ export const createFlowStateSchema = z
.object({
title: z.string().max(500).optional(),
summary: z.string().max(8000).optional(),
communityContext: z.string().max(48).optional(),
communityContext: z.string().max(200).optional(),
communitySaveEmail: z.string().max(320).optional(),
selectedCommunitySizeIds: z.array(z.string()).optional(),
selectedOrganizationTypeIds: z.array(z.string()).optional(),