better-auth/apps/web/modules/saas/organizations/components/OrganizationSelect.tsx

161 lines
4.9 KiB
TypeScript
Raw Normal View History

2025-10-29 13:43:43 +05:00
"use client";
import { config } from "@repo/config";
import { useSession } from "@saas/auth/hooks/use-session";
import { useActiveOrganization } from "@saas/organizations/hooks/use-active-organization";
import { useOrganizationListQuery } from "@saas/organizations/lib/api";
import { ActivePlanBadge } from "@saas/payments/components/ActivePlanBadge";
import { UserAvatar } from "@shared/components/UserAvatar";
import { useRouter } from "@shared/hooks/router";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@ui/components/dropdown-menu";
import { ChevronsUpDownIcon, PlusIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import Link from "next/link";
import { OrganizationLogo } from "./OrganizationLogo";
export function OrganzationSelect({ className }: { className?: string }) {
const t = useTranslations();
const { user } = useSession();
const router = useRouter();
const { activeOrganization, setActiveOrganization } =
useActiveOrganization();
const { data: allOrganizations } = useOrganizationListQuery();
if (!user) {
return null;
}
return (
<div className={className}>
<DropdownMenu>
<DropdownMenuTrigger className="flex w-full items-center justify-between gap-2 rounded-md border p-2 text-left outline-none focus-visible:bg-primary/10 focus-visible:ring-none">
<div className="flex flex-1 items-center justify-start gap-2 text-sm overflow-hidden">
{activeOrganization ? (
<>
<OrganizationLogo
name={activeOrganization.name}
logoUrl={activeOrganization.logo}
className="hidden size-6 sm:block"
/>
<span className="block flex-1 truncate">
{activeOrganization.name}
</span>
{config.organizations.enableBilling && (
<ActivePlanBadge
organizationId={activeOrganization.id}
/>
)}
</>
) : (
<>
<UserAvatar
className="hidden size-6 sm:block"
name={user.name ?? ""}
avatarUrl={user.image}
/>
<span className="block truncate">
{t(
"organizations.organizationSelect.personalAccount",
)}
</span>
{config.users.enableBilling && (
<ActivePlanBadge />
)}
</>
)}
</div>
<ChevronsUpDownIcon className="block size-4 opacity-50" />
</DropdownMenuTrigger>
<DropdownMenuContent className="w-full">
{!config.organizations.requireOrganization && (
<>
<DropdownMenuRadioGroup
value={activeOrganization?.id ?? user.id}
onValueChange={(value: string) => {
if (value === user.id) {
router.replace("/app");
}
}}
>
<DropdownMenuLabel className="text-foreground/60 text-xs">
{t(
"organizations.organizationSelect.personalAccount",
)}
</DropdownMenuLabel>
<DropdownMenuRadioItem
value={user.id}
className="flex cursor-pointer items-center justify-center gap-2 pl-3"
>
<div className="flex flex-1 items-center justify-start gap-2">
<UserAvatar
className="size-8"
name={user.name ?? ""}
avatarUrl={user.image}
/>
{user.name}
</div>
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
<DropdownMenuSeparator />
</>
)}
<DropdownMenuRadioGroup
value={activeOrganization?.slug}
onValueChange={(organizationSlug: string) =>
setActiveOrganization(organizationSlug)
}
>
<DropdownMenuLabel className="text-foreground/60 text-xs">
{t(
"organizations.organizationSelect.organizations",
)}
</DropdownMenuLabel>
{allOrganizations?.map((organization) => (
<DropdownMenuRadioItem
key={organization.slug}
value={organization.slug}
className="flex cursor-pointer items-center justify-center gap-2 pl-3"
>
<div className="flex flex-1 items-center justify-start gap-2">
<OrganizationLogo
className="size-8"
name={organization.name}
logoUrl={organization.logo}
/>
{organization.name}
</div>
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
{config.organizations.enableUsersToCreateOrganizations && (
<DropdownMenuGroup>
<DropdownMenuItem
asChild
className="text-primary! cursor-pointer text-sm"
>
<Link href="/app/new-organization">
<PlusIcon className="mr-2 size-6 rounded-md bg-primary/20 p-1" />
{t(
"organizations.organizationSelect.createNewOrganization",
)}
</Link>
</DropdownMenuItem>
</DropdownMenuGroup>
)}
</DropdownMenuContent>
</DropdownMenu>
</div>
);
}