import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Collapse, Modal, Spin } from 'antd'; import { HttpUtil } from '@/utils'; import { isPostQuantumLink } from '@/lib/xray/inbound-link'; import QrPanel from '@/pages/inbounds/QrPanel'; import type { ClientRecord } from '@/hooks/useClients'; interface SubSettings { enable: boolean; subURI: string; subJsonURI: string; subJsonEnable: boolean; } interface ClientQrModalProps { open: boolean; client: ClientRecord | null; subSettings?: SubSettings; onOpenChange: (open: boolean) => void; } interface ApiMsg { success?: boolean; obj?: T; } const DEFAULT_SUB: SubSettings = { enable: false, subURI: '', subJsonURI: '', subJsonEnable: false }; export default function ClientQrModal({ open, client, subSettings = DEFAULT_SUB, onOpenChange, }: ClientQrModalProps) { const { t } = useTranslation(); const [links, setLinks] = useState([]); const [loading, setLoading] = useState(false); const subLink = useMemo(() => { if (!client?.subId || !subSettings?.enable || !subSettings?.subURI) return ''; return subSettings.subURI + client.subId; }, [client?.subId, subSettings?.enable, subSettings?.subURI]); const subJsonLink = useMemo(() => { if (!client?.subId || !subSettings?.enable) return ''; if (!subSettings?.subJsonEnable || !subSettings?.subJsonURI) return ''; return subSettings.subJsonURI + client.subId; }, [client?.subId, subSettings?.enable, subSettings?.subJsonEnable, subSettings?.subJsonURI]); const hasAnything = !!subLink || !!subJsonLink || links.length > 0; useEffect(() => { if (!open || !client?.subId) { setLinks([]); return; } let cancelled = false; setLoading(true); (async () => { try { const msg = await HttpUtil.get( `/panel/api/clients/subLinks/${encodeURIComponent(client.subId!)}`, ) as ApiMsg; if (!cancelled) { setLinks(msg?.success && Array.isArray(msg.obj) ? msg.obj : []); } } finally { if (!cancelled) setLoading(false); } })(); return () => { cancelled = true; }; }, [open, client?.subId]); const [activeKey, setActiveKey] = useState([]); const items = useMemo(() => { const out: { key: string; label: string; children: React.ReactNode }[] = []; if (subLink) { out.push({ key: 'sub', label: t('subscription.title'), children: , }); } if (subJsonLink) { out.push({ key: 'subJson', label: `${t('subscription.title')} (JSON)`, children: , }); } links.forEach((link, idx) => { out.push({ key: `l${idx}`, label: `${t('pages.clients.link')} ${idx + 1}`, children: ( ), }); }); return out; }, [subLink, subJsonLink, links, client?.email, t]); useEffect(() => { if (!open) { setActiveKey([]); return; } setActiveKey(items.length > 0 ? [items[0].key] : []); }, [open, items]); return ( onOpenChange(false)} > {!client?.subId && !loading && (
{t('pages.clients.noSubId')}
)} {client?.subId && !hasAnything && !loading && (
{t('pages.clients.noLinks')}
)} {hasAnything && ( setActiveKey(typeof keys === 'string' ? [keys] : (keys as string[]))} items={items} /> )}
); }