Admin: overview improvements + provider/event detail#11
Conversation
MGeovany
commented
May 27, 2026
- Overview: adjust KPIs (GMV shows — when null), show Paygate status via platform status endpoint\n- Events: add detail page (/events/[eventId]) + extract status actions\n- Providers: add detail page (/providers/[userId]) + extract status actions + link from list\n- Admin libs: add provider/event detail data loaders, add getUserById helper\n
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ded8e766d3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| listEventTicketTypes(eventId), | ||
| loadEventPaymentOrders(eventId), | ||
| listEventAuditLogs(eventId), | ||
| resolveProviderOwnerUserId(event.providerId), |
There was a problem hiding this comment.
Narrow the event before using it
With strict null checks enabled, this new route does not compile: event is declared as AdminEventDetailItem | null, and the catch { notFound(); } path does not narrow the variable for the rest of the function. pnpm run typecheck reports TS18047 at this access and then on the subsequent event.* reads, so a production Next build will fail even for valid event IDs unless the result is assigned to a non-null local or explicitly guarded after the fetch.
Useful? React with 👍 / 👎.
| <ProviderStatusActions | ||
| userId={p.id} | ||
| currentPlan={p.subscriptionPlan ?? "pendiente"} | ||
| status={status} | ||
| emailConfirmedAt={p.emailConfirmedAt} | ||
| revalidatePath="/providers" |
There was a problem hiding this comment.
Preserve the provider plan control
Replacing the old inline controls with ProviderStatusActions drops the only caller of setProviderPlanAction (repo-wide search now finds no UI usage of that action), so after this change admins can view a comercio's plan but can no longer move an existing provider between pendiente, single_event, basico, and pro. That breaks the existing subscription-management workflow for any provider whose plan needs to be corrected or renewed after creation.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR enhances the admin dashboard by improving the Overview KPIs/status reporting and adding new detail pages for Events and Providers, while extracting reusable status-action UI components.
Changes:
- Overview: adjusts KPI display (GMV shows “—” when null), replaces scans KPI with PostHog errors KPI, and adds Paygate status via a new platform status endpoint.
- Events: adds
/events/[eventId]detail page, addsgetAdminEvent, and extracts event status actions into a shared component. - Providers: adds
/providers/[userId]detail page, links to it from the providers list, and adds provider/event detail data loaders plus agetUserByIdhelper.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| lib/admin/users.ts | Adds getUserById helper for provider detail lookup. |
| lib/admin/providerDetail.ts | New server-only loaders for provider detail (provider/members, audit logs, events, payments, ticket counts, subscription orders). |
| lib/admin/eventsApi.ts | Adds event detail API (getAdminEvent) and platform status API (getAdminPlatformStatus); updates metrics types. |
| lib/admin/eventDetail.ts | New server-only loaders for event detail (orders, tickets, ticket types, audit logs, provider owner resolution). |
| lib/admin/eventActions.ts | Adds configurable revalidate path handling when updating event status. |
| app/(dashboard)/providers/page.tsx | Adds “Ver” link to provider detail; replaces inline actions with ProviderStatusActions (and removes plan controls). |
| app/(dashboard)/providers/[userId]/page.tsx | New provider detail page aggregating KPIs, team, events, billing, and audit history. |
| app/(dashboard)/providers/_components/ProviderStatusActions.tsx | Extracted provider status action buttons (approve/pause/suspend + resend invite). |
| app/(dashboard)/overview/page.tsx | Updates KPIs and adds Paygate status row using the new platform status endpoint. |
| app/(dashboard)/events/page.tsx | Adds “Ver” link to event detail; replaces inline actions with EventStatusActions. |
| app/(dashboard)/events/[eventId]/page.tsx | New event detail page with KPIs, ticket types, orders, audit history, and provider link. |
| app/(dashboard)/events/_components/EventStatusActions.tsx | Extracted event status action buttons (publish/suspend/reactivate). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const { data: membership } = await admin | ||
| .from("provider_members") | ||
| .select("provider_id, role") | ||
| .eq("user_id", userId) | ||
| .maybeSingle(); | ||
|
|
||
| if (!membership?.provider_id) { |
| export async function loadProviderSubscriptionOrders(userId: string) { | ||
| try { | ||
| const data = await listSubscriptionOrders(); | ||
| return data.items.filter((o) => o.userId === userId); | ||
| } catch (error) { |
| <div className="flex flex-wrap justify-end gap-1.5"> | ||
| {p.emailConfirmedAt === null ? ( | ||
| <ResendInviteButton userId={p.id} /> | ||
| ) : null} | ||
| {status !== "approved" ? ( | ||
| <ActionButton | ||
| userId={p.id} | ||
| status="approved" | ||
| label="Aprobar" | ||
| tone="success" | ||
| /> | ||
| ) : null} | ||
| {status !== "paused" && status !== "pending" ? ( | ||
| <ActionButton | ||
| userId={p.id} | ||
| status="paused" | ||
| label="Pausar" | ||
| tone="muted" | ||
| /> | ||
| ) : null} | ||
| {status !== "suspended" ? ( | ||
| <ActionButton | ||
| userId={p.id} | ||
| status="suspended" | ||
| label="Suspender" | ||
| tone="danger" | ||
| /> | ||
| ) : ( | ||
| <ActionButton | ||
| userId={p.id} | ||
| status="approved" | ||
| label="Reactivar" | ||
| tone="success" | ||
| /> | ||
| )} | ||
| <PlanControl | ||
| <Link | ||
| href={`/providers/${p.id}` as never} | ||
| className="border border-white/15 px-2.5 py-1.5 text-[10px] font-bold uppercase tracking-wide text-white/80 transition hover:bg-white/5" | ||
| > | ||
| Ver | ||
| </Link> | ||
| <ProviderStatusActions | ||
| userId={p.id} | ||
| currentPlan={p.subscriptionPlan ?? "pendiente"} | ||
| status={status} | ||
| emailConfirmedAt={p.emailConfirmedAt} | ||
| revalidatePath="/providers" | ||
| /> | ||
| </div> |
| tone="success" | ||
| revalidatePath={revalidatePath} | ||
| /> | ||
| )} |