"use client" import { zodResolver } from "@hookform/resolvers/zod" import { Loader2, Trash2Icon, UploadCloudIcon } from "lucide-react" import { type ComponentProps, useContext, useMemo, useRef, useState } from "react" import { useForm } from "react-hook-form" import * as z from "zod" import { AuthUIContext } from "../../lib/auth-ui-provider" import { fileToBase64, resizeAndCropImage } from "../../lib/image-utils" import { cn, getLocalizedError } from "../../lib/utils" import type { AuthLocalization } from "../../localization/auth-localization" import type { SettingsCardClassNames } from "../settings/shared/settings-card" import { Button } from "../ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../ui/dialog" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form" import { Input } from "../ui/input" import { OrganizationLogo } from "./organization-logo" export interface CreateOrganizationDialogProps extends ComponentProps { className?: string classNames?: SettingsCardClassNames localization?: AuthLocalization } export function CreateOrganizationDialog({ className, classNames, localization: localizationProp, onOpenChange, ...props }: CreateOrganizationDialogProps) { const { authClient, localization: contextLocalization, organization: organizationOptions, navigate, toast, localizeErrors } = useContext(AuthUIContext) const localization = useMemo( () => ({ ...contextLocalization, ...localizationProp }), [contextLocalization, localizationProp] ) const [logo, setLogo] = useState(null) const [logoPending, setLogoPending] = useState(false) const fileInputRef = useRef(null) const openFileDialog = () => fileInputRef.current?.click() const formSchema = z.object({ logo: z.string().optional(), name: z.string().min(1, { message: `${localization.ORGANIZATION_NAME} ${localization.IS_REQUIRED}` }), slug: z .string() .min(1, { message: `${localization.ORGANIZATION_SLUG} ${localization.IS_REQUIRED}` }) .regex(/^[a-z0-9-]+$/, { message: `${localization.ORGANIZATION_SLUG} ${localization.IS_INVALID}` }) }) const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { logo: "", name: "", slug: "" } }) const isSubmitting = form.formState.isSubmitting const handleLogoChange = async (file: File) => { if (!organizationOptions?.logo) return setLogoPending(true) try { const resizedFile = await resizeAndCropImage( file, crypto.randomUUID(), organizationOptions.logo.size, organizationOptions.logo.extension ) let image: string | undefined | null if (organizationOptions?.logo.upload) { image = await organizationOptions.logo.upload(resizedFile) } else { image = await fileToBase64(resizedFile) } setLogo(image || null) form.setValue("logo", image || "") } catch (error) { toast({ variant: "error", message: getLocalizedError({ error, localization, localizeErrors }) }) } setLogoPending(false) } const deleteLogo = async () => { setLogoPending(true) const currentUrl = logo || undefined if (currentUrl && organizationOptions?.logo?.delete) { await organizationOptions.logo.delete(currentUrl) } setLogo(null) form.setValue("logo", "") setLogoPending(false) } async function onSubmit({ name, slug, logo }: z.infer) { try { const organization = await authClient.organization.create({ name, slug, logo, fetchOptions: { throw: true } }) if (organizationOptions?.pathMode === "slug") { navigate(`${organizationOptions.basePath}/${organization.slug}`) return } await authClient.organization.setActive({ organizationId: organization.id }) onOpenChange?.(false) form.reset() setLogo(null) toast({ variant: "success", message: localization.CREATE_ORGANIZATION_SUCCESS }) } catch (error) { toast({ variant: "error", message: getLocalizedError({ error, localization, localizeErrors }) }) } } return ( {localization.CREATE_ORGANIZATION} {localization.ORGANIZATIONS_INSTRUCTIONS}
{organizationOptions?.logo && ( ( { const file = e.target.files?.item(0) if (file) handleLogoChange(file) e.target.value = "" }} /> {localization.LOGO}
e.preventDefault() } > { localization.UPLOAD_LOGO } {logo && ( { localization.DELETE_LOGO } )}
)} /> )} ( {localization.ORGANIZATION_NAME} )} /> ( {localization.ORGANIZATION_SLUG} )} />
) }