This commit is contained in:
debu-2 2026-10-13 01:33:49 +05:30
parent bb9fc9a9cf
commit 9dbda69db1
5 changed files with 222 additions and 3 deletions

View file

@ -10,6 +10,7 @@ import {
type AdminTemplateConfig,
type AdminUrmiOtpProject,
} from '../../lib/api'
import { AdminTokensPage } from './AdminTokensPage'
import { AdminWhatsAppPage } from './AdminWhatsAppPage'
const KYC_DOC_LABELS: Record<string, string> = {
@ -392,7 +393,7 @@ function AdminCompliance() {
export function AdminApp() {
const [authenticated, setAuthenticated] = useState<boolean | null>(null)
const [section, setSection] = useState<'compliance' | 'whatsapp'>('compliance')
const [section, setSection] = useState<'compliance' | 'whatsapp' | 'tokens'>('compliance')
useEffect(() => {
adminApi.me().then(() => setAuthenticated(true)).catch(() => setAuthenticated(false))
@ -426,6 +427,13 @@ export function AdminApp() {
>
WhatsApp Business
</button>
<button
type="button"
className={section === 'tokens' ? 'active' : ''}
onClick={() => setSection('tokens')}
>
Tokens
</button>
</nav>
<button className="secondary-button" onClick={logout}>Log out</button>
</div>
@ -433,7 +441,7 @@ export function AdminApp() {
</header>
<main>
{authenticated
? (section === 'compliance' ? <AdminCompliance /> : <AdminWhatsAppPage />)
? (section === 'compliance' ? <AdminCompliance /> : section === 'tokens' ? <AdminTokensPage /> : <AdminWhatsAppPage />)
: <AdminLogin onSuccess={() => setAuthenticated(true)} />}
</main>
</div>

View file

@ -0,0 +1,103 @@
import { Copy } from 'lucide-react'
import { useEffect, useState } from 'react'
import { adminApi, type AdminConnectionTokens } from '../../lib/api'
type UserRow = AdminConnectionTokens['users'][number]
type WhatsAppAccount = UserRow['whatsapp_accounts'][number]
function TokenValue({ label, value }: { label: string; value: string }) {
const [copied, setCopied] = useState(false)
const shown = value || 'Not saved'
async function copy() {
if (!value) return
await navigator.clipboard.writeText(value)
setCopied(true)
window.setTimeout(() => setCopied(false), 1500)
}
return (
<div className="admin-token-value">
<div className="admin-token-label">
<strong>{label}</strong>
{value && (
<button type="button" className="secondary-button" onClick={() => void copy()}>
<Copy size={14} /> {copied ? 'Copied' : 'Copy'}
</button>
)}
</div>
<code>{shown}</code>
</div>
)
}
function WhatsAppTokens({ account }: { account: WhatsAppAccount }) {
const phoneIds = account.phones.map((phone) => phone.phone_number_id).filter(Boolean)
return (
<article className="admin-token-account">
<div className="panel-heading">
<div>
<h3>{account.name}</h3>
<p>{account.source === 'token' ? 'Pasted token' : 'Facebook signup'} · {account.status}</p>
</div>
</div>
<TokenValue label="Access token" value={account.access_token} />
<TokenValue label="WhatsApp Business account ID" value={account.waba_id} />
<TokenValue label="Phone number ID" value={phoneIds.join('\n')} />
{account.phones.length > 0 && (
<p className="admin-token-phones">
{account.phones.map((phone) => phone.display_phone || phone.phone_number_id).join(' · ')}
</p>
)}
</article>
)
}
export function AdminTokensPage() {
const [users, setUsers] = useState<UserRow[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState('')
useEffect(() => {
adminApi.connectionTokens()
.then((payload) => setUsers(payload.users))
.catch((reason) => setError(reason instanceof Error ? reason.message : 'Could not load tokens'))
.finally(() => setLoading(false))
}, [])
if (loading) return <div className="auth-loading">Loading tokens…</div>
return (
<div className="admin-content">
<div className="account-heading">
<span className="eyebrow">Connections</span>
<h1>Saved tokens</h1>
<p>Each customer account, with the WhatsApp access token, account ID, and phone number ID, plus the Facebook token when one is saved.</p>
</div>
{error && <p className="auth-error">{error}</p>}
{!error && users.length === 0 && <section className="panel placeholder"><p>No tokens have been saved yet.</p></section>}
{users.map((user) => (
<section className="panel admin-kyc-card" key={user.id}>
<div className="panel-heading">
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
</div>
{user.whatsapp_accounts.map((account) => <WhatsAppTokens key={account.id} account={account} />)}
{user.facebook && (
<article className="admin-token-account">
<div className="panel-heading">
<div>
<h3>Facebook</h3>
<p>{user.facebook.user_name || 'Facebook user'} · {user.facebook.status}</p>
</div>
</div>
<TokenValue label="Access token" value={user.facebook.access_token} />
</article>
)}
</section>
))}
</div>
)
}