mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-14 05:35:12 +00:00
153 lines
4.8 KiB
TypeScript
153 lines
4.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Button } from "@app/components/ui/button";
|
|
import { useTranslations } from "next-intl";
|
|
import LoginPasswordForm from "./LoginPasswordForm";
|
|
import IdpLoginButtons from "./IdpLoginButtons";
|
|
import { LookupUserResponse } from "@server/routers/auth/lookupUser";
|
|
import UserProfileCard from "./UserProfileCard";
|
|
|
|
type LoginOrgSelectorProps = {
|
|
identifier: string;
|
|
lookupResult: LookupUserResponse;
|
|
redirect?: string;
|
|
forceLogin?: boolean;
|
|
onUseDifferentAccount?: () => void;
|
|
};
|
|
|
|
export default function LoginOrgSelector({
|
|
identifier,
|
|
lookupResult,
|
|
redirect,
|
|
forceLogin,
|
|
onUseDifferentAccount
|
|
}: LoginOrgSelectorProps) {
|
|
const t = useTranslations();
|
|
const [showPasswordForm, setShowPasswordForm] = useState(false);
|
|
|
|
// Collect all unique orgs from all accounts
|
|
const orgMap = new Map<
|
|
string,
|
|
{
|
|
orgId: string;
|
|
orgName: string;
|
|
idps: Array<{
|
|
idpId: number;
|
|
name: string;
|
|
variant: string | null;
|
|
}>;
|
|
hasInternalAuth: boolean;
|
|
}
|
|
>();
|
|
|
|
for (const account of lookupResult.accounts) {
|
|
for (const org of account.orgs) {
|
|
if (!orgMap.has(org.orgId)) {
|
|
orgMap.set(org.orgId, {
|
|
orgId: org.orgId,
|
|
orgName: org.orgName,
|
|
idps: org.idps,
|
|
hasInternalAuth: org.hasInternalAuth
|
|
});
|
|
} else {
|
|
// Merge IdPs if org appears in multiple accounts
|
|
const existing = orgMap.get(org.orgId)!;
|
|
const existingIdpIds = new Set(
|
|
existing.idps.map((i) => i.idpId)
|
|
);
|
|
for (const idp of org.idps) {
|
|
if (!existingIdpIds.has(idp.idpId)) {
|
|
existing.idps.push(idp);
|
|
}
|
|
}
|
|
if (org.hasInternalAuth) {
|
|
existing.hasInternalAuth = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const orgs = Array.from(orgMap.values());
|
|
|
|
// Check if there's an internal account (can only be one)
|
|
const hasInternalAccount = lookupResult.accounts.some(
|
|
(acc) => acc.hasInternalAuth
|
|
);
|
|
|
|
// If user selected password auth, show password form
|
|
if (showPasswordForm) {
|
|
return (
|
|
<div className="space-y-4">
|
|
<UserProfileCard
|
|
identifier={identifier}
|
|
description={t("loginSelectAuthenticationMethod")}
|
|
onUseDifferentAccount={onUseDifferentAccount}
|
|
useDifferentAccountText={t(
|
|
"deviceLoginUseDifferentAccount"
|
|
)}
|
|
/>
|
|
<LoginPasswordForm
|
|
identifier={identifier}
|
|
redirect={redirect}
|
|
forceLogin={forceLogin}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<UserProfileCard
|
|
identifier={identifier}
|
|
description={t("loginSelectAuthenticationMethod")}
|
|
onUseDifferentAccount={onUseDifferentAccount}
|
|
useDifferentAccountText={t("deviceLoginUseDifferentAccount")}
|
|
/>
|
|
|
|
{hasInternalAccount && (
|
|
<div className="mt-3">
|
|
<Button
|
|
type="button"
|
|
className="w-full"
|
|
onClick={() => setShowPasswordForm(true)}
|
|
>
|
|
{t("signInWithPassword")}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-0 mt-3">
|
|
{orgs.map((org, index) => {
|
|
const hasIdps = org.idps.length > 0;
|
|
|
|
if (!hasIdps) {
|
|
return null;
|
|
}
|
|
|
|
// Convert org.idps to LoginFormIDP format
|
|
const idps = org.idps.map((idp) => ({
|
|
idpId: idp.idpId,
|
|
name: idp.name,
|
|
variant: idp.variant || undefined
|
|
}));
|
|
|
|
return (
|
|
<div key={org.orgId}>
|
|
<div className="py-3">
|
|
<h3 className="text-base font-semibold mb-3">
|
|
{org.orgName}
|
|
</h3>
|
|
<IdpLoginButtons
|
|
idps={idps}
|
|
redirect={redirect}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|