You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
// frontend/components/connectors/AddAccountMenu.tsx — "계정 추가" OAuth 진입(phase-16)
|
|
// providers() 로 추가 가능한 provider를 받아 메뉴로 보여주고, 선택 시 OAuth 동의 화면으로 리다이렉트.
|
|
"use client";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { Button } from "@/components/Button";
|
|
import { connectorsApi } from "@/lib/connectors/api";
|
|
import type { ConnectorProvider } from "@/lib/types";
|
|
|
|
export function AddAccountMenu({
|
|
domain,
|
|
redirectAfter,
|
|
onError,
|
|
}: {
|
|
domain: string;
|
|
redirectAfter: string;
|
|
onError?: (msg: string) => void;
|
|
}) {
|
|
const [providers, setProviders] = useState<ConnectorProvider[]>([]);
|
|
const [open, setOpen] = useState(false);
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
connectorsApi
|
|
.providers(domain)
|
|
.then(setProviders)
|
|
.catch(() => setProviders([]));
|
|
}, [domain]);
|
|
|
|
useEffect(() => {
|
|
if (!open) return;
|
|
const onDoc = (e: MouseEvent) => {
|
|
if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);
|
|
};
|
|
document.addEventListener("mousedown", onDoc);
|
|
return () => document.removeEventListener("mousedown", onDoc);
|
|
}, [open]);
|
|
|
|
if (providers.length === 0) return null;
|
|
|
|
const connect = async (p: ConnectorProvider) => {
|
|
setOpen(false);
|
|
try {
|
|
const { authorize_url } = await connectorsApi.oauthStart(domain, p.provider, redirectAfter);
|
|
window.location.assign(authorize_url); // 외부 OAuth 동의 화면으로 이동
|
|
} catch {
|
|
onError?.(`${p.label} 연결을 시작하지 못했어요`);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="cn-add" ref={ref}>
|
|
<Button
|
|
variant="lime"
|
|
icon="plus"
|
|
onClick={() => setOpen((v) => !v)}
|
|
aria-haspopup="menu"
|
|
aria-expanded={open}
|
|
>
|
|
계정 추가
|
|
</Button>
|
|
{open && (
|
|
<div className="cn-add-menu" role="menu" aria-label="추가할 계정 제공자">
|
|
{providers.map((p) => (
|
|
<button
|
|
key={p.provider}
|
|
type="button"
|
|
role="menuitem"
|
|
className="cn-add-item"
|
|
disabled={!p.configured}
|
|
onClick={() => connect(p)}
|
|
title={p.configured ? "" : "관리자 설정이 필요해요 (client_id 미설정)"}
|
|
>
|
|
<span>{p.label}</span>
|
|
{!p.configured && <em className="cn-add-hint">설정 필요</em>}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|