mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-15 20:20:09 +00:00
feat(accounts-ui): redesign accounts dashboard to column layout
This commit is contained in:
+329
-147
@@ -5,14 +5,87 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { ArrowRight, Link2, Plus, Unlink, Users, Waves, Zap } from 'lucide-react';
|
||||
import { AlertTriangle, ArrowRight, Link2, Plus, Unlink, Users, Waves, Zap } from 'lucide-react';
|
||||
import { AccountsTable } from '@/components/account/accounts-table';
|
||||
import { CreateAuthProfileDialog } from '@/components/account/create-auth-profile-dialog';
|
||||
import { CopyButton } from '@/components/ui/copy-button';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { useAccounts } from '@/hooks/use-accounts';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
|
||||
type MetricTone = 'default' | 'shared' | 'deeper' | 'isolated';
|
||||
|
||||
function MetricTile({
|
||||
label,
|
||||
value,
|
||||
icon: Icon,
|
||||
tone = 'default',
|
||||
}: {
|
||||
label: string;
|
||||
value: number;
|
||||
icon: LucideIcon;
|
||||
tone?: MetricTone;
|
||||
}) {
|
||||
const toneClasses: Record<MetricTone, { border: string; icon: string }> = {
|
||||
default: {
|
||||
border: 'border-border',
|
||||
icon: 'text-primary',
|
||||
},
|
||||
shared: {
|
||||
border: 'border-emerald-300/60 dark:border-emerald-900/40',
|
||||
icon: 'text-emerald-700 dark:text-emerald-400',
|
||||
},
|
||||
deeper: {
|
||||
border: 'border-indigo-300/60 dark:border-indigo-900/40',
|
||||
icon: 'text-indigo-700 dark:text-indigo-400',
|
||||
},
|
||||
isolated: {
|
||||
border: 'border-blue-300/60 dark:border-blue-900/40',
|
||||
icon: 'text-blue-700 dark:text-blue-400',
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn('rounded-md border bg-card px-3 py-2.5', toneClasses[tone].border)}>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-[11px] uppercase tracking-wide text-muted-foreground">{label}</span>
|
||||
<Icon className={cn('h-3.5 w-3.5', toneClasses[tone].icon)} />
|
||||
</div>
|
||||
<p className={cn('mt-1 text-xl font-mono font-semibold', toneClasses[tone].icon)}>{value}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StrategyCard({
|
||||
title,
|
||||
description,
|
||||
variant,
|
||||
}: {
|
||||
title: string;
|
||||
description: string;
|
||||
variant: 'auth' | 'pool';
|
||||
}) {
|
||||
const variantClasses =
|
||||
variant === 'auth'
|
||||
? 'border-emerald-300/70 bg-emerald-50/40 dark:border-emerald-900/40 dark:bg-emerald-900/10'
|
||||
: 'border-blue-300/70 bg-blue-50/40 dark:border-blue-900/40 dark:bg-blue-900/10';
|
||||
const titleClasses =
|
||||
variant === 'auth'
|
||||
? 'text-emerald-800 dark:text-emerald-300'
|
||||
: 'text-blue-800 dark:text-blue-300';
|
||||
|
||||
return (
|
||||
<div className={cn('rounded-md border px-3 py-2.5', variantClasses)}>
|
||||
<p className={cn('text-sm font-semibold', titleClasses)}>{title}</p>
|
||||
<p className="mt-1 text-xs text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function AccountsPage() {
|
||||
const navigate = useNavigate();
|
||||
@@ -26,169 +99,278 @@ export function AccountsPage() {
|
||||
const sharedStandardCount = data?.sharedStandardCount || 0;
|
||||
const deeperSharedCount = data?.deeperSharedCount || 0;
|
||||
const isolatedCount = data?.isolatedCount || 0;
|
||||
const hasLegacyFollowUp = legacyContextCount > 0 || legacyContinuityCount > 0;
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-6xl mx-auto space-y-8">
|
||||
<div className="rounded-xl border bg-gradient-to-br from-background via-background to-muted/40 p-5 sm:p-6">
|
||||
<div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
|
||||
<div className="space-y-2">
|
||||
<Badge variant="outline">ccs auth Continuity</Badge>
|
||||
<h1 className="text-2xl font-bold tracking-tight">Accounts</h1>
|
||||
<p className="text-sm text-muted-foreground max-w-2xl">
|
||||
This page manages
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">ccs auth</code>
|
||||
accounts only. Choose isolated, shared-standard, or shared-deeper continuity per
|
||||
account.
|
||||
</p>
|
||||
<>
|
||||
<div className="h-[calc(100vh-100px)] hidden lg:flex">
|
||||
{/* Left rail */}
|
||||
<div className="w-80 border-r flex flex-col bg-muted/30 shrink-0">
|
||||
<div className="p-4 border-b bg-background space-y-3">
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Users className="h-5 w-5 text-primary" />
|
||||
<h1 className="font-semibold">Accounts</h1>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
Dedicated
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">ccs auth</code>
|
||||
continuity controls.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-2">
|
||||
<Button onClick={() => setCreateDialogOpen(true)} size="sm" className="justify-start">
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Create Account
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="justify-start"
|
||||
onClick={() => navigate('/cliproxy')}
|
||||
>
|
||||
Open CLIProxy Claude Pool
|
||||
<ArrowRight className="w-4 h-4 ml-auto" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-stretch gap-2 sm:flex-row sm:items-center">
|
||||
<Button onClick={() => setCreateDialogOpen(true)}>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Create Account
|
||||
</Button>
|
||||
<Button variant="outline" onClick={() => navigate('/cliproxy')}>
|
||||
Open CLIProxy Claude Pool
|
||||
<ArrowRight className="w-4 h-4 ml-2" />
|
||||
</Button>
|
||||
<ScrollArea className="flex-1">
|
||||
<div className="p-3 space-y-4">
|
||||
<section className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Snapshot
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<MetricTile label="Total" value={authAccounts.length} icon={Users} />
|
||||
<MetricTile label="Shared" value={sharedCount} icon={Link2} tone="shared" />
|
||||
<MetricTile label="Deeper" value={deeperSharedCount} icon={Waves} tone="deeper" />
|
||||
<MetricTile
|
||||
label="Isolated"
|
||||
value={isolatedCount}
|
||||
icon={Unlink}
|
||||
tone="isolated"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Strategy Lanes
|
||||
</p>
|
||||
<StrategyCard
|
||||
variant="auth"
|
||||
title="Lane A: ccs auth continuity"
|
||||
description="Isolation-first accounts with explicit shared/deeper controls per profile."
|
||||
/>
|
||||
<StrategyCard
|
||||
variant="pool"
|
||||
title="Lane B: CLIProxy Claude pool"
|
||||
description="OAuth pool routing for lower manual account switching."
|
||||
/>
|
||||
</section>
|
||||
|
||||
{hasLegacyFollowUp && (
|
||||
<section className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Migration Follow-up
|
||||
</p>
|
||||
<div className="rounded-md border border-amber-500/50 bg-amber-500/10 p-3">
|
||||
<div className="flex items-start gap-2">
|
||||
<AlertTriangle className="h-4 w-4 mt-0.5 text-amber-700 dark:text-amber-400 shrink-0" />
|
||||
<div className="space-y-1 text-xs">
|
||||
{legacyContextCount > 0 && (
|
||||
<p className="text-amber-800 dark:text-amber-300">
|
||||
{legacyContextCount} account
|
||||
{legacyContextCount > 1 ? 's still need' : ' still needs'} first-time
|
||||
mode confirmation.
|
||||
</p>
|
||||
)}
|
||||
{legacyContinuityCount > 0 && (
|
||||
<p className="text-amber-800 dark:text-amber-300">
|
||||
{legacyContinuityCount} shared account
|
||||
{legacyContinuityCount > 1 ? 's remain' : ' remains'} on standard legacy
|
||||
continuity depth.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
<div className="p-3 border-t bg-background text-xs text-muted-foreground">
|
||||
<div className="flex items-center justify-between">
|
||||
<span>Standard shared</span>
|
||||
<span className="font-mono">{sharedStandardCount}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mt-1">
|
||||
<span>CLIProxy hidden</span>
|
||||
<span className="font-mono">{cliproxyCount}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main workspace */}
|
||||
<div className="flex-1 min-w-0 flex">
|
||||
{/* Table column */}
|
||||
<div className="flex-1 min-w-0 flex flex-col border-r bg-background">
|
||||
<div className="px-5 py-4 border-b bg-background">
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge variant="outline">ccs auth Workspace</Badge>
|
||||
<Badge variant="secondary">History Sync Controls</Badge>
|
||||
</div>
|
||||
<h2 className="mt-2 text-xl font-semibold tracking-tight">Auth Accounts</h2>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
This table is intentionally scoped to
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">ccs auth</code>
|
||||
accounts. Edit each account for isolated, shared-standard, or shared-deeper
|
||||
continuity behavior.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 min-h-0 p-5 overflow-auto">
|
||||
{cliproxyCount > 0 && (
|
||||
<Alert variant="info" className="mb-4">
|
||||
<Zap className="h-4 w-4" />
|
||||
<AlertTitle>CLIProxy pool accounts are managed in their own page</AlertTitle>
|
||||
<AlertDescription>
|
||||
{cliproxyCount} OAuth account{cliproxyCount > 1 ? 's are' : ' is'} available in
|
||||
CLIProxy. This table only covers local
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">ccs auth</code>
|
||||
profiles.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Card className="h-full flex flex-col">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-lg">Account Matrix</CardTitle>
|
||||
<CardDescription>
|
||||
Shared total: {sharedCount}. Update sync behavior from the pencil action in each
|
||||
row.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 min-h-0">
|
||||
{isLoading ? (
|
||||
<div className="text-muted-foreground">Loading accounts...</div>
|
||||
) : (
|
||||
<AccountsTable data={authAccounts} defaultAccount={data?.default ?? null} />
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right guidance column */}
|
||||
<div className="w-80 shrink-0 flex flex-col bg-muted/20">
|
||||
<div className="p-4 border-b bg-background">
|
||||
<h3 className="font-semibold">Continuity Guide</h3>
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
Choose the lightest mode that solves your workflow.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ScrollArea className="flex-1">
|
||||
<div className="p-4 space-y-3">
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm">Shared Standard</CardTitle>
|
||||
<CardDescription>Project workspace sync only.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="text-xs text-muted-foreground">
|
||||
Best default when users need continuity but want minimal coupling.
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm">Shared Deeper (Advanced)</CardTitle>
|
||||
<CardDescription>
|
||||
Adds <code>session-env</code>, <code>file-history</code>,{' '}
|
||||
<code>shell-snapshots</code>, <code>todos</code>.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="text-xs text-muted-foreground">
|
||||
Use only when cross-account continuity is worth stronger coupling.
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm">Quick Commands</CardTitle>
|
||||
<CardDescription>Copy and run in terminal.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2">
|
||||
<div className="rounded-md border bg-background px-2 py-2 font-mono text-[11px] flex items-start gap-2">
|
||||
<span className="flex-1 break-all">
|
||||
ccs auth create work --context-group sprint-a --deeper-continuity
|
||||
</span>
|
||||
<CopyButton
|
||||
value="ccs auth create work --context-group sprint-a --deeper-continuity"
|
||||
size="icon"
|
||||
/>
|
||||
</div>
|
||||
<div className="rounded-md border bg-background px-2 py-2 font-mono text-[11px] flex items-start gap-2">
|
||||
<span className="flex-1 break-all">ccs cliproxy auth claude</span>
|
||||
<CopyButton value="ccs cliproxy auth claude" size="icon" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<Card className="border-emerald-200/70 bg-emerald-50/40 dark:border-emerald-900/40 dark:bg-emerald-900/10">
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription className="text-emerald-800/90 dark:text-emerald-300">
|
||||
Lane A: ccs auth continuity
|
||||
</CardDescription>
|
||||
<CardTitle className="text-lg text-emerald-700 dark:text-emerald-300 flex items-center gap-2">
|
||||
<Users className="w-5 h-5" />
|
||||
Profile isolation + opt-in sync
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="text-sm text-muted-foreground">
|
||||
Use this when you want per-account control over isolated vs shared history behavior.
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-blue-200/70 bg-blue-50/40 dark:border-blue-900/40 dark:bg-blue-900/10">
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription className="text-blue-800/90 dark:text-blue-300">
|
||||
Lane B: CLIProxy Claude pool
|
||||
</CardDescription>
|
||||
<CardTitle className="text-lg text-blue-700 dark:text-blue-300 flex items-center gap-2">
|
||||
<Zap className="w-5 h-5" />
|
||||
OAuth pool and lower manual switching
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="text-sm text-muted-foreground">
|
||||
Use CLIProxy when you want pooled Claude OAuth accounts and easier account routing
|
||||
behavior.
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 md:grid-cols-4">
|
||||
{/* Mobile fallback */}
|
||||
<div className="p-4 space-y-4 lg:hidden">
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription>Total Auth Accounts</CardDescription>
|
||||
<CardTitle className="text-2xl font-mono flex items-center gap-2">
|
||||
<Users className="w-5 h-5 text-primary" />
|
||||
{authAccounts.length}
|
||||
</CardTitle>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg">Accounts</CardTitle>
|
||||
<CardDescription>
|
||||
Manage
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">ccs auth</code>
|
||||
continuity per account.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2">
|
||||
<Button className="w-full" onClick={() => setCreateDialogOpen(true)}>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Create Account
|
||||
</Button>
|
||||
<Button variant="outline" className="w-full" onClick={() => navigate('/cliproxy')}>
|
||||
Open CLIProxy Claude Pool
|
||||
<ArrowRight className="w-4 h-4 ml-2" />
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-emerald-200/70 bg-emerald-50/40 dark:border-emerald-900/40 dark:bg-emerald-900/10">
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription className="text-emerald-800/90 dark:text-emerald-300">
|
||||
Shared Standard
|
||||
</CardDescription>
|
||||
<CardTitle className="text-2xl font-mono text-emerald-700 dark:text-emerald-300 flex items-center gap-2">
|
||||
<Link2 className="w-5 h-5" />
|
||||
{sharedStandardCount}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<MetricTile label="Total" value={authAccounts.length} icon={Users} />
|
||||
<MetricTile label="Shared" value={sharedCount} icon={Link2} tone="shared" />
|
||||
<MetricTile label="Deeper" value={deeperSharedCount} icon={Waves} tone="deeper" />
|
||||
<MetricTile label="Isolated" value={isolatedCount} icon={Unlink} tone="isolated" />
|
||||
</div>
|
||||
|
||||
<Card className="border-indigo-200/70 bg-indigo-50/40 dark:border-indigo-900/40 dark:bg-indigo-900/10">
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription className="text-indigo-800/90 dark:text-indigo-300">
|
||||
Shared Deeper
|
||||
</CardDescription>
|
||||
<CardTitle className="text-2xl font-mono text-indigo-700 dark:text-indigo-300 flex items-center gap-2">
|
||||
<Waves className="w-5 h-5" />
|
||||
{deeperSharedCount}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
|
||||
<Card className="border-blue-200/70 bg-blue-50/40 dark:border-blue-900/40 dark:bg-blue-900/10">
|
||||
<CardHeader className="pb-2">
|
||||
<CardDescription className="text-blue-800/90 dark:text-blue-300">
|
||||
Isolated
|
||||
</CardDescription>
|
||||
<CardTitle className="text-2xl font-mono text-blue-700 dark:text-blue-300 flex items-center gap-2">
|
||||
<Unlink className="w-5 h-5" />
|
||||
{isolatedCount}
|
||||
</CardTitle>
|
||||
<Card>
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-base">Account Matrix</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{isLoading ? (
|
||||
<div className="text-muted-foreground">Loading accounts...</div>
|
||||
) : (
|
||||
<AccountsTable data={authAccounts} defaultAccount={data?.default ?? null} />
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{cliproxyCount > 0 && (
|
||||
<Alert variant="info">
|
||||
<Zap className="h-4 w-4" />
|
||||
<AlertTitle>CLIProxy accounts are intentionally excluded from this table</AlertTitle>
|
||||
<AlertDescription>
|
||||
{cliproxyCount} CLIProxy OAuth account{cliproxyCount > 1 ? 's are' : ' is'} available.
|
||||
Manage them in <strong>CLIProxy Plus</strong> to enable account pool usage.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{legacyContextCount > 0 && (
|
||||
<Alert variant="warning">
|
||||
<Users className="h-4 w-4" />
|
||||
<AlertTitle>Legacy accounts need first-time sync mode review</AlertTitle>
|
||||
<AlertDescription>
|
||||
{legacyContextCount} account{legacyContextCount > 1 ? 's were' : ' was'} onboarded
|
||||
before explicit context controls. Use the pencil action to confirm isolated or shared
|
||||
behavior.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{legacyContinuityCount > 0 && (
|
||||
<Alert variant="warning">
|
||||
<Waves className="h-4 w-4" />
|
||||
<AlertTitle>Shared legacy accounts default to standard continuity</AlertTitle>
|
||||
<AlertDescription>
|
||||
{legacyContinuityCount} shared account
|
||||
{legacyContinuityCount > 1 ? 's are' : ' is'} currently on legacy standard depth. Edit
|
||||
and switch to deeper continuity only when you intentionally want broader history sync.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Card>
|
||||
<CardHeader className="pb-4">
|
||||
<CardTitle className="text-lg">ccs auth Accounts</CardTitle>
|
||||
<CardDescription>
|
||||
Shared total: {sharedCount}. Create accounts here, then tune per-account sync mode and
|
||||
continuity depth from the table.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{isLoading ? (
|
||||
<div className="text-muted-foreground">Loading accounts...</div>
|
||||
) : (
|
||||
<AccountsTable data={authAccounts} defaultAccount={data?.default ?? null} />
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<CreateAuthProfileDialog open={createDialogOpen} onClose={() => setCreateDialogOpen(false)} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user