Files
Epicure/apps/web/components/auth/social-login-buttons.tsx
T
2026-07-01 11:10:37 +02:00

67 lines
3.5 KiB
TypeScript

"use client";
import { Button } from "@/components/ui/button";
import { authClient } from "@/lib/auth/client";
type Provider = {
id: string;
label: string;
icon: React.ReactNode;
};
const GithubIcon = () => (
<svg viewBox="0 0 24 24" className="h-4 w-4 fill-current" aria-hidden="true">
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
</svg>
);
const DiscordIcon = () => (
<svg viewBox="0 0 24 24" className="h-4 w-4 fill-current" aria-hidden="true">
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057.1 18.08.11 18.1.128 18.11a19.9 19.9 0 0 0 5.993 3.03.077.077 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z" />
</svg>
);
const authentikIcon = (
<svg viewBox="0 0 24 24" className="h-4 w-4 fill-current" aria-hidden="true">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
type Props = {
showGithub?: boolean;
showDiscord?: boolean;
showAuthentik?: boolean;
};
export function SocialLoginButtons({ showGithub, showDiscord, showAuthentik }: Props) {
const providers: Provider[] = [
...(showGithub ? [{ id: "github", label: "Continue with GitHub", icon: <GithubIcon /> }] : []),
...(showDiscord ? [{ id: "discord", label: "Continue with Discord", icon: <DiscordIcon /> }] : []),
...(showAuthentik ? [{ id: "authentik", label: "Continue with Authentik", icon: authentikIcon }] : []),
];
if (providers.length === 0) return null;
async function handleSocial(providerId: string) {
if (providerId === "authentik") {
await (authClient as unknown as { signIn: { genericOAuth: (opts: { providerId: string; callbackURL: string }) => Promise<void> } }).signIn.genericOAuth({
providerId: "authentik",
callbackURL: "/recipes",
});
} else {
await authClient.signIn.social({ provider: providerId as "github" | "discord" | "google", callbackURL: "/recipes" });
}
}
return (
<>
{providers.map((p) => (
<Button key={p.id} variant="outline" className="w-full gap-2" type="button" onClick={() => handleSocial(p.id)}>
{p.icon}
{p.label}
</Button>
))}
</>
);
}