Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 1 | /** |
| 2 | * What the account menu shows under the avatar, fetched when it opens so | |
| 3 | * no page waits on it: the name people see, the primary address, and how | |
| 4 | * many invites are left when there is a limit. Each part is optional: a | |
| 5 | * service that cannot answer leaves its part out. | |
| 6 | */ | |
| 7 | import type { Route } from "./+types/settings-menu-json"; | |
| 8 | import { accounts, identity } from "../lib/services.server"; | |
| 9 | import { getViewer } from "../lib/session.server"; | |
| 10 | import { loadInvites } from "../lib/invites.server"; | |
| 11 | ||
| 12 | export type AccountMenuData = { | |
| 13 | name: string | null; | |
| 14 | email: string | null; | |
| 15 | /** Invites left, or null when there is no limit (or none can be made yet). */ | |
| 16 | invites_left: number | null; | |
| 17 | }; | |
| 18 | ||
| 19 | export async function loader({ context }: Route.LoaderArgs) { | |
| 20 | const user = getViewer(context); | |
| 21 | if (!user) return Response.json(null, { status: 401, headers: { "cache-control": "private, no-store" } }); | |
| 22 | const [profile, emails, invites] = await Promise.all([ | |
| 23 | identity.profile(user.username).catch(() => null), | |
| 24 | accounts.listEmails(user).catch(() => null), | |
| 25 | loadInvites(user), | |
| 26 | ]); | |
| 27 | const primary = emails?.ok ? (emails.value.emails.find((e) => e.primary)?.email ?? null) : null; | |
| 28 | const data: AccountMenuData = { | |
| 29 | name: profile?.name?.trim() || null, | |
| 30 | email: primary, | |
| 31 | invites_left: invites?.allowance.limit != null ? (invites.allowance.remaining ?? 0) : null, | |
| 32 | }; | |
| 33 | return Response.json(data, { headers: { "cache-control": "private, max-age=60" } }); | |
| 34 | } |