160 lines
4.9 KiB
TypeScript
160 lines
4.9 KiB
TypeScript
"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>
|
|
);
|
|
}
|