Files
lunarfront-app/packages/admin/src/routes/_authenticated/accounts/$accountId.tsx
Ryan Moon 5ad27bc196 Add lessons module, rate cycles, EC2 deploy scripts, and help content
- Lessons module: lesson types, instructors, schedule slots, enrollments,
  sessions (list + week grid view), lesson plans, grading scales, templates
- Rate cycles: replace monthly_rate with billing_interval + billing_unit on
  enrollments; add weekly/monthly/quarterly rate presets to lesson types and
  schedule slots with auto-fill on enrollment form
- Member detail page: tabbed layout for details, identity documents, enrollments
- Sessions week view: custom 7-column grid replacing react-big-calendar
- Music store seed: instructors, lesson types, slots, enrollments, sessions,
  grading scale, lesson plan template
- Scrollbar styling: themed to match sidebar/app palette
- deploy/: EC2 setup and redeploy scripts, nginx config, systemd service
- Help: add Lessons category (overview, types, instructors, slots, enrollments,
  sessions, plans/grading); collapsible sidebar with independent scroll;
  remove POS/accounting references from docs
2026-03-30 18:52:57 -05:00

73 lines
2.4 KiB
TypeScript

import { createFileRoute, Outlet, Link, useParams } from '@tanstack/react-router'
import { useQuery } from '@tanstack/react-query'
import { accountDetailOptions } from '@/api/accounts'
import { Skeleton } from '@/components/ui/skeleton'
import { Badge } from '@/components/ui/badge'
import { cn } from '@/lib/utils'
export const Route = createFileRoute('/_authenticated/accounts/$accountId')({
component: AccountDetailLayout,
})
const tabs = [
{ label: 'Overview', to: '/accounts/$accountId' },
{ label: 'Members', to: '/accounts/$accountId/members' },
{ label: 'Enrollments', to: '/accounts/$accountId/enrollments' },
{ label: 'Payment Methods', to: '/accounts/$accountId/payment-methods' },
{ label: 'Tax Exemptions', to: '/accounts/$accountId/tax-exemptions' },
{ label: 'Processor Links', to: '/accounts/$accountId/processor-links' },
] as const
function AccountDetailLayout() {
const { accountId } = useParams({ from: '/_authenticated/accounts/$accountId' })
const { data: account, isLoading } = useQuery(accountDetailOptions(accountId))
if (isLoading) {
return (
<div className="space-y-4">
<Skeleton className="h-8 w-64" />
<Skeleton className="h-4 w-96" />
<Skeleton className="h-10 w-full" />
</div>
)
}
if (!account) {
return <p className="text-muted-foreground">Account not found</p>
}
return (
<div className="space-y-6">
<div>
<div className="flex items-center gap-3">
<h1 className="text-2xl font-bold">{account.name}</h1>
<Badge variant="secondary">{account.billingMode}</Badge>
</div>
{account.email && <p className="text-muted-foreground">{account.email}</p>}
</div>
<nav className="flex gap-1 border-b">
{tabs.map((tab) => (
<Link
key={tab.to}
to={tab.to}
params={{ accountId }}
activeOptions={{ exact: tab.to === '/accounts/$accountId' }}
className={cn(
'px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors',
'text-muted-foreground border-transparent hover:text-foreground hover:border-border',
)}
activeProps={{
className: 'text-foreground border-primary',
}}
>
{tab.label}
</Link>
))}
</nav>
<Outlet />
</div>
)
}