feat: extract admin account management rework from PR 124 (#138)
* feat: reorganize admin panel around accounts * feat: expand admin customer account controls * feat: add admin account detail management * fix: remove unused admin account icon import * refactor: design critique fixes for account pages - Admin accounts: replace dense card grid with compact DataTable - Account settings: remove redundant hero card, stat grid, header pills - Fix bg-accent (orange) misuse on decorative elements across 7 files - Add ConfirmButton for destructive actions (deactivate, remove member) - Replace single-field modals with inline editing (plan, trial) - Add contextual help: display code tooltip, improved empty states - Non-owner aside explanation for hidden owner-only sections - Admin sidebar: group 11 items into 5 labeled sections - Rename UsersPage.tsx → AccountsPage.tsx to match route - Fix border radius consistency, hide zero-count badges Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use get_admin_db for all new admin account endpoints All admin endpoints query across tenants without a tenant context. get_db (app-role, subject to RLS) was never imported and would crash at runtime — replace all 6 occurrences with get_admin_db (BYPASSRLS). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #138.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import {
|
||||
LayoutDashboard,
|
||||
Users,
|
||||
Building2,
|
||||
Ticket,
|
||||
FileText,
|
||||
Gauge,
|
||||
@@ -15,18 +15,54 @@ import {
|
||||
} from 'lucide-react'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const navItems = [
|
||||
{ path: '/admin', label: 'Dashboard', icon: LayoutDashboard, end: true },
|
||||
{ path: '/admin/users', label: 'Users', icon: Users },
|
||||
{ path: '/admin/invite-codes', label: 'Invite Codes', icon: Ticket },
|
||||
{ path: '/admin/audit-logs', label: 'Audit Logs', icon: FileText },
|
||||
{ path: '/admin/plan-limits', label: 'Plan Limits', icon: Gauge },
|
||||
{ path: '/admin/feature-flags', label: 'Feature Flags', icon: ToggleLeft },
|
||||
{ path: '/admin/settings', label: 'Settings', icon: Settings },
|
||||
{ path: '/admin/categories', label: 'Categories', icon: FolderTree },
|
||||
{ path: '/admin/survey-invites', label: 'Survey Invites', icon: ClipboardList },
|
||||
{ path: '/admin/survey-responses', label: 'Survey Responses', icon: MessageSquareText },
|
||||
{ path: '/admin/gallery', label: 'Gallery', icon: LayoutGrid },
|
||||
interface NavItem {
|
||||
path: string
|
||||
label: string
|
||||
icon: typeof LayoutDashboard
|
||||
end?: boolean
|
||||
}
|
||||
|
||||
interface NavSection {
|
||||
label?: string
|
||||
items: NavItem[]
|
||||
}
|
||||
|
||||
const navSections: NavSection[] = [
|
||||
{
|
||||
items: [
|
||||
{ path: '/admin', label: 'Dashboard', icon: LayoutDashboard, end: true },
|
||||
{ path: '/admin/accounts', label: 'Accounts', icon: Building2 },
|
||||
{ path: '/admin/invite-codes', label: 'Invite Codes', icon: Ticket },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Platform',
|
||||
items: [
|
||||
{ path: '/admin/plan-limits', label: 'Plan Limits', icon: Gauge },
|
||||
{ path: '/admin/feature-flags', label: 'Feature Flags', icon: ToggleLeft },
|
||||
{ path: '/admin/settings', label: 'Settings', icon: Settings },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Content',
|
||||
items: [
|
||||
{ path: '/admin/categories', label: 'Categories', icon: FolderTree },
|
||||
{ path: '/admin/gallery', label: 'Gallery', icon: LayoutGrid },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Feedback',
|
||||
items: [
|
||||
{ path: '/admin/survey-invites', label: 'Survey Invites', icon: ClipboardList },
|
||||
{ path: '/admin/survey-responses', label: 'Survey Responses', icon: MessageSquareText },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Audit',
|
||||
items: [
|
||||
{ path: '/admin/audit-logs', label: 'Audit Logs', icon: FileText },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
interface AdminSidebarProps {
|
||||
@@ -47,22 +83,33 @@ export function AdminSidebar({ className, onNavigate }: AdminSidebarProps) {
|
||||
<div className="p-4">
|
||||
<h2 className="text-lg font-bold text-foreground">Admin Panel</h2>
|
||||
</div>
|
||||
<nav className="flex-1 space-y-1 px-3">
|
||||
{navItems.map((item) => (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
onClick={onNavigate}
|
||||
className={cn(
|
||||
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
||||
isActive(item.path, item.end)
|
||||
? 'bg-accent text-foreground'
|
||||
: 'text-muted-foreground hover:bg-accent hover:text-foreground'
|
||||
<nav className="flex-1 space-y-4 overflow-y-auto px-3">
|
||||
{navSections.map((section, i) => (
|
||||
<div key={i}>
|
||||
{section.label && (
|
||||
<p className="mb-1 px-3 text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground">
|
||||
{section.label}
|
||||
</p>
|
||||
)}
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.label}
|
||||
</Link>
|
||||
<div className="space-y-0.5">
|
||||
{section.items.map((item) => (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
onClick={onNavigate}
|
||||
className={cn(
|
||||
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors',
|
||||
isActive(item.path, item.end)
|
||||
? 'bg-elevated text-foreground'
|
||||
: 'text-muted-foreground hover:bg-elevated hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<item.icon className="h-4 w-4" />
|
||||
{item.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
<div className="border-t border-border p-3">
|
||||
@@ -71,7 +118,7 @@ export function AdminSidebar({ className, onNavigate }: AdminSidebarProps) {
|
||||
onClick={onNavigate}
|
||||
className={cn(
|
||||
'flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium',
|
||||
'text-muted-foreground hover:bg-accent hover:text-foreground'
|
||||
'text-muted-foreground hover:bg-elevated hover:text-foreground'
|
||||
)}
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
|
||||
Reference in New Issue
Block a user