fix and update

This commit is contained in:
lendry
2026-06-29 14:40:35 +03:00
parent 75ccbe5fc4
commit 0df7240dc8
21 changed files with 934 additions and 113 deletions

View File

@@ -0,0 +1,137 @@
'use client';
import { useMemo, useState } from 'react';
import { Copy, ExternalLink } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { OAuthClient } from '@/lib/api';
import { buildOneTapExamples } from '@/lib/one-tap-examples';
import { OAuthEndpoints } from '@/lib/oauth-url';
function SnippetBlock({ code, onCopy }: { code: string; onCopy: (value: string, label: string) => void }) {
return (
<div className="relative rounded-2xl bg-[#111827] p-4 text-xs text-[#e5e7eb]">
<Button
type="button"
variant="ghost"
size="icon"
className="absolute right-2 top-2 h-8 w-8 text-white hover:bg-white/10 hover:text-white"
aria-label="Скопировать код"
onClick={() => onCopy(code, 'Код интеграции')}
>
<Copy className="h-4 w-4" />
</Button>
<pre className="max-h-72 overflow-auto whitespace-pre-wrap break-all pr-10">{code}</pre>
</div>
);
}
export function OAuthClientOneTapSection({
client,
endpoints,
frontendBase,
projectName,
onCopy
}: {
client: OAuthClient;
endpoints: OAuthEndpoints;
frontendBase: string;
projectName: string;
onCopy: (value: string, label: string) => void;
}) {
const primaryRedirect = client.redirectUris[0] ?? `${frontendBase}/auth/callback`;
const examples = useMemo(
() =>
buildOneTapExamples(
{
apiBase: endpoints.issuer,
frontendBase,
widgetUrl: endpoints.widgetUrl,
fedcmConfigUrl: endpoints.fedcmConfigUrl,
webIdentityUrl: endpoints.webIdentityUrl,
fedcmDiscoverUrl: endpoints.fedcmDiscoverUrl,
projectName
},
client.clientId,
primaryRedirect
),
[client.clientId, endpoints, frontendBase, primaryRedirect, projectName]
);
const [activeTab, setActiveTab] = useState(examples[0]?.id ?? 'widget-script');
return (
<section className="space-y-4 rounded-2xl border border-[#eceef4] p-4">
<div>
<h3 className="font-medium">One Tap Login</h3>
<p className="mt-1 text-xs leading-relaxed text-[#667085]">
FedCM (Chrome/Edge) и виджет <code className="rounded bg-[#f4f5f8] px-1 py-0.5">sso-widget.js</code> с popup fallback.
Убедитесь, что в настройках указаны <strong>PUBLIC_API_URL</strong> и <strong>PUBLIC_FRONTEND_URL</strong>.
</p>
</div>
<div className="grid gap-2 sm:grid-cols-2">
<CopyRowCompact label="FedCM config" value={endpoints.fedcmConfigUrl} onCopy={onCopy} />
<CopyRowCompact label="Web identity" value={endpoints.webIdentityUrl} onCopy={onCopy} />
<CopyRowCompact label="Виджет" value={endpoints.widgetUrl} onCopy={onCopy} />
<CopyRowCompact label="Discover" value={endpoints.fedcmDiscoverUrl} onCopy={onCopy} />
</div>
<Tabs value={activeTab} onValueChange={setActiveTab}>
<TabsList className="mb-2 flex h-auto max-w-full flex-wrap gap-1">
{examples.map((example) => (
<TabsTrigger key={example.id} value={example.id} className="text-xs">
{example.label}
</TabsTrigger>
))}
</TabsList>
{examples.map((example) => (
<TabsContent key={example.id} value={example.id}>
<SnippetBlock code={example.code} onCopy={onCopy} />
</TabsContent>
))}
</Tabs>
<div className="rounded-xl bg-[#eef4ff] px-4 py-3 text-xs text-[#1d4ed8]">
<p className="font-medium">Проверка FedCM</p>
<ol className="mt-2 list-decimal space-y-1 pl-4">
<li>Войдите на IdP ({frontendBase}) в этом браузере.</li>
<li>Откройте сайт клиента с виджетом Chrome покажет нативный диалог или плашку One Tap.</li>
<li>
При ошибке NetworkError проверьте, что <code>PUBLIC_API_URL</code> = <code>{endpoints.issuer}</code>.
</li>
</ol>
<a
href={`${frontendBase.replace(/\/$/, '')}/sso-widget.js`}
target="_blank"
rel="noreferrer"
className="mt-2 inline-flex items-center gap-1 font-medium hover:underline"
>
Открыть sso-widget.js
<ExternalLink className="h-3.5 w-3.5" />
</a>
</div>
</section>
);
}
function CopyRowCompact({
label,
value,
onCopy
}: {
label: string;
value: string;
onCopy: (value: string, label: string) => void;
}) {
return (
<div className="rounded-xl bg-[#f4f5f8] p-3">
<div className="mb-1 flex items-center justify-between gap-2">
<span className="text-xs font-medium">{label}</span>
<Button variant="ghost" size="icon" className="h-7 w-7" aria-label={`Скопировать ${label}`} onClick={() => onCopy(value, label)}>
<Copy className="h-3.5 w-3.5" />
</Button>
</div>
<code className="block break-all text-[11px] text-[#667085]">{value}</code>
</div>
);
}