Files
esign/apps/remix/app/components/dialogs/organisation-create-dialog.tsx
zooqueen fb4e3df0e3 rename: @hanzo/sign-* → @hanzo/esign-* (full eSign brand consistency)
The product is branded Hanzo eSign (esign.hanzo.ai, repo hanzoai/esign).
Rename all workspace packages @hanzo/sign-* → @hanzo/esign-* (1052 files)
and align docker/Dockerfile turbo --scope/--filter to the actual remix
package name @hanzo/esign (was a pre-existing mismatch with -remix that
broke the build). Protected deps (@hanzo/insights, @hanzo/logo) untouched.
2026-06-21 19:56:09 -07:00

176 lines
5.1 KiB
TypeScript

import { useEffect, useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { useLingui } from '@lingui/react/macro';
import { Trans } from '@lingui/react/macro';
import type * as DialogPrimitive from '@radix-ui/react-dialog';
import { useForm } from 'react-hook-form';
import { useSearchParams } from 'react-router';
import type { z } from 'zod';
import { useUpdateSearchParams } from '@hanzo/esign-lib/client-only/hooks/use-update-search-params';
import { useSession } from '@hanzo/esign-lib/client-only/providers/session';
import { AppError } from '@hanzo/esign-lib/errors/app-error';
import {
type TCreateOrganisationResponse,
ZCreateOrganisationRequestSchema,
} from '@hanzo/esign-trpc/server/organisation-router/create-organisation.types';
import { useZapMutation } from '@hanzo/esign-trpc/zap/react';
import { Button } from '@hanzo/esign-ui/primitives/button';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@hanzo/esign-ui/primitives/dialog';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@hanzo/esign-ui/primitives/form/form';
import { Input } from '@hanzo/esign-ui/primitives/input';
import { useToast } from '@hanzo/esign-ui/primitives/use-toast';
export type OrganisationCreateDialogProps = {
trigger?: React.ReactNode;
} & Omit<DialogPrimitive.DialogProps, 'children'>;
export const ZCreateOrganisationFormSchema = ZCreateOrganisationRequestSchema.pick({
name: true,
});
export type TCreateOrganisationFormSchema = z.infer<typeof ZCreateOrganisationFormSchema>;
export const OrganisationCreateDialog = ({ trigger, ...props }: OrganisationCreateDialogProps) => {
const { t } = useLingui();
const { toast } = useToast();
const { refreshSession } = useSession();
const [searchParams] = useSearchParams();
const updateSearchParams = useUpdateSearchParams();
const actionSearchParam = searchParams?.get('action');
const [open, setOpen] = useState(false);
const form = useForm({
resolver: zodResolver(ZCreateOrganisationFormSchema),
defaultValues: {
name: '',
},
});
const { mutateAsync: createOrganisation } = useZapMutation<TCreateOrganisationResponse, unknown>(
'organisation.create',
);
const onFormSubmit = async ({ name }: TCreateOrganisationFormSchema) => {
try {
await createOrganisation({ name });
await refreshSession();
setOpen(false);
toast({
title: t`Success`,
description: t`Your organisation has been created.`,
duration: 5000,
});
} catch (err) {
const error = AppError.parseError(err);
console.error(error);
toast({
title: t`An unknown error occurred`,
description: t`We encountered an unknown error while attempting to create a organisation. Please try again later.`,
variant: 'destructive',
});
}
};
useEffect(() => {
if (actionSearchParam === 'add-organisation') {
setOpen(true);
updateSearchParams({ action: null });
}
}, [actionSearchParam, open]);
useEffect(() => {
form.reset();
}, [open, form]);
return (
<Dialog
{...props}
open={open}
onOpenChange={(value) => !form.formState.isSubmitting && setOpen(value)}
>
<DialogTrigger onClick={(e) => e.stopPropagation()} asChild={true}>
{trigger ?? (
<Button className="flex-shrink-0" variant="secondary">
<Trans>Create organisation</Trans>
</Button>
)}
</DialogTrigger>
<DialogContent position="center">
<DialogHeader>
<DialogTitle>
<Trans>Create organisation</Trans>
</DialogTitle>
<DialogDescription>
<Trans>Create an organisation to collaborate with teams</Trans>
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onFormSubmit)}>
<fieldset
className="flex h-full flex-col space-y-4"
disabled={form.formState.isSubmitting}
>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel required>
<Trans>Organisation Name</Trans>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<DialogFooter>
<Button type="button" variant="secondary" onClick={() => setOpen(false)}>
<Trans>Cancel</Trans>
</Button>
<Button
type="submit"
data-testid="dialog-create-organisation-button"
loading={form.formState.isSubmitting}
>
<Trans>Create</Trans>
</Button>
</DialogFooter>
</fieldset>
</form>
</Form>
</DialogContent>
</Dialog>
);
};