mirror of
https://github.com/documenso/documenso.git
synced 2026-07-27 02:15:05 +10:00
fix: lint project (#2693)
This commit is contained in:
@@ -1,13 +1,3 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
@@ -20,17 +10,18 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@documenso/ui/primitives/dialog';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { PinInput, PinInputGroup, PinInputSlot } from '@documenso/ui/primitives/pin-input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { useState } from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZDisable2FAForm = z.object({
|
||||
totpCode: z.string().trim().optional(),
|
||||
@@ -120,8 +111,8 @@ export const DisableAuthenticatorAppDialog = () => {
|
||||
|
||||
<DialogDescription>
|
||||
<Trans>
|
||||
Please provide a token from the authenticator, or a backup code. If you do not have a
|
||||
backup code available, please contact support.
|
||||
Please provide a token from the authenticator, or a backup code. If you do not have a backup code
|
||||
available, please contact support.
|
||||
</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
@@ -171,11 +162,7 @@ export const DisableAuthenticatorAppDialog = () => {
|
||||
)}
|
||||
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={onToggleTwoFactorDisableMethodClick}
|
||||
>
|
||||
<Button type="button" variant="secondary" onClick={onToggleTwoFactorDisableMethodClick}>
|
||||
{twoFactorDisableMethod === 'totp' ? (
|
||||
<Trans>Use Backup Code</Trans>
|
||||
) : (
|
||||
|
||||
@@ -1,13 +1,3 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { renderSVG } from 'uqr';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { downloadFile } from '@documenso/lib/client-only/download-file';
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
@@ -22,16 +12,17 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@documenso/ui/primitives/dialog';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { PinInput, PinInputGroup, PinInputSlot } from '@documenso/ui/primitives/pin-input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { renderSVG } from 'uqr';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { RecoveryCodeList } from './recovery-code-list';
|
||||
|
||||
@@ -100,9 +91,7 @@ export const EnableAuthenticatorAppDialog = ({ onSuccess }: EnableAuthenticatorA
|
||||
|
||||
toast({
|
||||
title: _(msg`Two-factor authentication enabled`),
|
||||
description: _(
|
||||
msg`You will now be required to enter a code from your authenticator app when signing in.`,
|
||||
),
|
||||
description: _(msg`You will now be required to enter a code from your authenticator app when signing in.`),
|
||||
});
|
||||
} catch (_err) {
|
||||
toast({
|
||||
@@ -162,119 +151,112 @@ export const EnableAuthenticatorAppDialog = ({ onSuccess }: EnableAuthenticatorA
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent position="center">
|
||||
{setup2FAData && (
|
||||
<>
|
||||
{recoveryCodes ? (
|
||||
<div>
|
||||
{setup2FAData &&
|
||||
(recoveryCodes ? (
|
||||
<div>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans>Backup codes</Trans>
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Trans>Your recovery codes are listed below. Please store them in a safe place.</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="mt-4">
|
||||
<RecoveryCodeList recoveryCodes={recoveryCodes} />
|
||||
</div>
|
||||
|
||||
<DialogFooter className="mt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="secondary">
|
||||
<Trans>Close</Trans>
|
||||
</Button>
|
||||
</DialogClose>
|
||||
|
||||
<Button onClick={downloadRecoveryCodes}>
|
||||
<Trans>Download</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</div>
|
||||
) : (
|
||||
<Form {...enable2FAForm}>
|
||||
<form onSubmit={enable2FAForm.handleSubmit(onEnable2FAFormSubmit)}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans>Backup codes</Trans>
|
||||
<Trans>Enable Authenticator App</Trans>
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Trans>
|
||||
Your recovery codes are listed below. Please store them in a safe place.
|
||||
To enable two-factor authentication, scan the following QR code using your authenticator app.
|
||||
</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="mt-4">
|
||||
<RecoveryCodeList recoveryCodes={recoveryCodes} />
|
||||
</div>
|
||||
<fieldset disabled={isEnabling2FA} className="mt-4 flex flex-col gap-y-4">
|
||||
<div
|
||||
className="flex h-36 justify-center"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: renderSVG(setup2FAData?.uri ?? ''),
|
||||
}}
|
||||
/>
|
||||
|
||||
<DialogFooter className="mt-4">
|
||||
<DialogClose asChild>
|
||||
<Button variant="secondary">
|
||||
<Trans>Close</Trans>
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
<Trans>
|
||||
If your authenticator app does not support QR codes, you can use the following code instead:
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<Button onClick={downloadRecoveryCodes}>
|
||||
<Trans>Download</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</div>
|
||||
) : (
|
||||
<Form {...enable2FAForm}>
|
||||
<form onSubmit={enable2FAForm.handleSubmit(onEnable2FAFormSubmit)}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<Trans>Enable Authenticator App</Trans>
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Trans>
|
||||
To enable two-factor authentication, scan the following QR code using your
|
||||
authenticator app.
|
||||
</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<p className="rounded-lg bg-muted/60 p-2 text-center font-mono text-muted-foreground tracking-widest">
|
||||
{setup2FAData?.secret}
|
||||
</p>
|
||||
|
||||
<fieldset disabled={isEnabling2FA} className="mt-4 flex flex-col gap-y-4">
|
||||
<div
|
||||
className="flex h-36 justify-center"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: renderSVG(setup2FAData?.uri ?? ''),
|
||||
}}
|
||||
/>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
<Trans>
|
||||
Once you have scanned the QR code or entered the code manually, enter the code provided by your
|
||||
authenticator app below.
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<p className="text-muted-foreground text-sm">
|
||||
<Trans>
|
||||
If your authenticator app does not support QR codes, you can use the
|
||||
following code instead:
|
||||
</Trans>
|
||||
</p>
|
||||
<FormField
|
||||
name="token"
|
||||
control={enable2FAForm.control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-muted-foreground">
|
||||
<Trans>Token</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<PinInput {...field} value={field.value ?? ''} maxLength={6}>
|
||||
{Array(6)
|
||||
.fill(null)
|
||||
.map((_, i) => (
|
||||
<PinInputGroup key={i}>
|
||||
<PinInputSlot index={i} />
|
||||
</PinInputGroup>
|
||||
))}
|
||||
</PinInput>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<p className="bg-muted/60 text-muted-foreground rounded-lg p-2 text-center font-mono tracking-widest">
|
||||
{setup2FAData?.secret}
|
||||
</p>
|
||||
|
||||
<p className="text-muted-foreground text-sm">
|
||||
<Trans>
|
||||
Once you have scanned the QR code or entered the code manually, enter the
|
||||
code provided by your authenticator app below.
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<FormField
|
||||
name="token"
|
||||
control={enable2FAForm.control}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-muted-foreground">
|
||||
<Trans>Token</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<PinInput {...field} value={field.value ?? ''} maxLength={6}>
|
||||
{Array(6)
|
||||
.fill(null)
|
||||
.map((_, i) => (
|
||||
<PinInputGroup key={i}>
|
||||
<PinInputSlot index={i} />
|
||||
</PinInputGroup>
|
||||
))}
|
||||
</PinInput>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="secondary">
|
||||
<Trans>Cancel</Trans>
|
||||
</Button>
|
||||
</DialogClose>
|
||||
|
||||
<Button type="submit" loading={isEnabling2FA}>
|
||||
<Trans>Enable 2FA</Trans>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="secondary">
|
||||
<Trans>Cancel</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</fieldset>
|
||||
</form>
|
||||
</Form>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</DialogClose>
|
||||
|
||||
<Button type="submit" loading={isEnabling2FA}>
|
||||
<Trans>Enable 2FA</Trans>
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</fieldset>
|
||||
</form>
|
||||
</Form>
|
||||
))}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Copy } from 'lucide-react';
|
||||
|
||||
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export type RecoveryCodeListProps = {
|
||||
recoveryCodes: string[];
|
||||
};
|
||||
@@ -29,9 +28,7 @@ export const RecoveryCodeList = ({ recoveryCodes }: RecoveryCodeListProps) => {
|
||||
} catch (_err) {
|
||||
toast({
|
||||
title: _(msg`Unable to copy recovery code`),
|
||||
description: _(
|
||||
msg`We were unable to copy your recovery code to your clipboard. Please try again.`,
|
||||
),
|
||||
description: _(msg`We were unable to copy your recovery code to your clipboard. Please try again.`),
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
@@ -40,17 +37,11 @@ export const RecoveryCodeList = ({ recoveryCodes }: RecoveryCodeListProps) => {
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{recoveryCodes.map((code) => (
|
||||
<div
|
||||
key={code}
|
||||
className="bg-muted text-muted-foreground relative rounded-lg p-4 font-mono md:text-center"
|
||||
>
|
||||
<div key={code} className="relative rounded-lg bg-muted p-4 font-mono text-muted-foreground md:text-center">
|
||||
<span>{code}</span>
|
||||
|
||||
<div className="absolute inset-y-0 right-4 flex items-center justify-center">
|
||||
<button
|
||||
className="opacity-60 hover:opacity-80"
|
||||
onClick={() => void onCopyRecoveryCodeClick(code)}
|
||||
>
|
||||
<button className="opacity-60 hover:opacity-80" onClick={() => void onCopyRecoveryCodeClick(code)}>
|
||||
<Copy className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { downloadFile } from '@documenso/lib/client-only/download-file';
|
||||
import { AppError } from '@documenso/lib/errors/app-error';
|
||||
@@ -21,14 +13,14 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@documenso/ui/primitives/dialog';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { PinInput, PinInputGroup, PinInputSlot } from '@documenso/ui/primitives/pin-input';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { RecoveryCodeList } from './recovery-code-list';
|
||||
|
||||
@@ -97,9 +89,7 @@ export const ViewRecoveryCodesDialog = () => {
|
||||
</DialogTitle>
|
||||
|
||||
<DialogDescription>
|
||||
<Trans>
|
||||
Your recovery codes are listed below. Please store them in a safe place.
|
||||
</Trans>
|
||||
<Trans>Your recovery codes are listed below. Please store them in a safe place.</Trans>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -156,9 +146,7 @@ export const ViewRecoveryCodesDialog = () => {
|
||||
<Alert variant="destructive">
|
||||
<AlertDescription>
|
||||
{match(AppError.parseError(error).message)
|
||||
.with('INCORRECT_TWO_FACTOR_CODE', () => (
|
||||
<Trans>Invalid code. Please try again.</Trans>
|
||||
))
|
||||
.with('INCORRECT_TWO_FACTOR_CODE', () => <Trans>Invalid code. Please try again.</Trans>)
|
||||
.otherwise(() => (
|
||||
<Trans>Something went wrong. Please try again or contact support.</Trans>
|
||||
))}
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { ErrorCode, useDropzone } from 'react-dropzone';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { AppError } from '@documenso/lib/errors/app-error';
|
||||
import { base64 } from '@documenso/lib/universal/base64';
|
||||
@@ -18,15 +7,17 @@ import { trpc } from '@documenso/trpc/react';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@documenso/ui/primitives/avatar';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { useMemo } from 'react';
|
||||
import { ErrorCode, useDropzone } from 'react-dropzone';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZAvatarImageFormSchema = z.object({
|
||||
bytes: z.string().nullish(),
|
||||
@@ -69,11 +60,7 @@ export const AvatarImageForm = ({ className, team, organisation }: AvatarImageFo
|
||||
return user.avatarImageId !== null;
|
||||
}, [team, organisation, user.avatarImageId]);
|
||||
|
||||
const avatarImageId = team
|
||||
? team.avatarImageId
|
||||
: organisation
|
||||
? organisation.avatarImageId
|
||||
: user.avatarImageId;
|
||||
const avatarImageId = team ? team.avatarImageId : organisation ? organisation.avatarImageId : user.avatarImageId;
|
||||
|
||||
const form = useForm<TAvatarImageFormSchema>({
|
||||
values: {
|
||||
@@ -127,8 +114,7 @@ export const AvatarImageForm = ({ className, team, organisation }: AvatarImageFo
|
||||
const error = AppError.parseError(err);
|
||||
|
||||
const errorMessage = match(error.code).otherwise(
|
||||
() =>
|
||||
msg`We encountered an unknown error while attempting to update your password. Please try again later.`,
|
||||
() => msg`We encountered an unknown error while attempting to update your password. Please try again later.`,
|
||||
);
|
||||
|
||||
toast({
|
||||
@@ -160,15 +146,13 @@ export const AvatarImageForm = ({ className, team, organisation }: AvatarImageFo
|
||||
<div className="relative">
|
||||
<Avatar className="h-16 w-16 border-2 border-solid">
|
||||
{avatarImageId && <AvatarImage src={formatAvatarUrl(avatarImageId)} />}
|
||||
<AvatarFallback className="text-sm text-gray-400">
|
||||
{initials}
|
||||
</AvatarFallback>
|
||||
<AvatarFallback className="text-gray-400 text-sm">{initials}</AvatarFallback>
|
||||
</Avatar>
|
||||
|
||||
{hasAvatarImage && (
|
||||
<button
|
||||
type="button"
|
||||
className="bg-background/70 text-destructive absolute inset-0 flex cursor-pointer items-center justify-center text-xs opacity-0 transition-opacity hover:opacity-100"
|
||||
className="absolute inset-0 flex cursor-pointer items-center justify-center bg-background/70 text-destructive text-xs opacity-0 transition-opacity hover:opacity-100"
|
||||
disabled={form.formState.isSubmitting}
|
||||
onClick={() => void onFormSubmit({ bytes: null })}
|
||||
>
|
||||
|
||||
@@ -1,33 +1,18 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import type { TeamGlobalSettings } from '@prisma/client';
|
||||
import { Loader } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { Textarea } from '@documenso/ui/primitives/textarea';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import type { TeamGlobalSettings } from '@prisma/client';
|
||||
import { Loader } from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useOptionalCurrentTeam } from '~/providers/team';
|
||||
|
||||
@@ -39,10 +24,7 @@ const ZBrandingPreferencesFormSchema = z.object({
|
||||
brandingLogo: z
|
||||
.instanceof(File)
|
||||
.refine((file) => file.size <= MAX_FILE_SIZE, 'File size must be less than 5MB')
|
||||
.refine(
|
||||
(file) => ACCEPTED_FILE_TYPES.includes(file.type),
|
||||
'Only .jpg, .png, and .webp files are accepted',
|
||||
)
|
||||
.refine((file) => ACCEPTED_FILE_TYPES.includes(file.type), 'Only .jpg, .png, and .webp files are accepted')
|
||||
.nullish(),
|
||||
brandingUrl: z.string().url().optional().or(z.literal('')),
|
||||
brandingCompanyDetails: z.string().max(500).optional(),
|
||||
@@ -136,10 +118,7 @@ export function BrandingPreferencesForm({
|
||||
field.onChange(value === 'true' ? true : value === 'false' ? false : null)
|
||||
}
|
||||
>
|
||||
<SelectTrigger
|
||||
className="bg-background text-muted-foreground"
|
||||
data-testid="enable-branding"
|
||||
>
|
||||
<SelectTrigger className="bg-background text-muted-foreground" data-testid="enable-branding">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
||||
@@ -187,13 +166,9 @@ export function BrandingPreferencesForm({
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="relative h-48 w-full overflow-hidden rounded-lg border border-border bg-background">
|
||||
{previewUrl ? (
|
||||
<img
|
||||
src={previewUrl}
|
||||
alt="Logo preview"
|
||||
className="h-full w-full object-contain p-4"
|
||||
/>
|
||||
<img src={previewUrl} alt="Logo preview" className="h-full w-full object-contain p-4" />
|
||||
) : (
|
||||
<div className="relative flex h-full w-full items-center justify-center bg-muted/20 text-sm text-muted-foreground dark:bg-muted">
|
||||
<div className="relative flex h-full w-full items-center justify-center bg-muted/20 text-muted-foreground text-sm dark:bg-muted">
|
||||
<Trans>Please upload a logo</Trans>
|
||||
|
||||
{!hasLoadedPreview && (
|
||||
@@ -238,12 +213,12 @@ export function BrandingPreferencesForm({
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<div className="absolute right-2 top-0 inline-flex h-full items-center justify-center">
|
||||
<div className="absolute top-0 right-2 inline-flex h-full items-center justify-center">
|
||||
<Button
|
||||
type="button"
|
||||
variant="link"
|
||||
size="sm"
|
||||
className="text-xs text-destructive"
|
||||
className="text-destructive text-xs"
|
||||
onClick={() => {
|
||||
setPreviewUrl('');
|
||||
onChange(null);
|
||||
@@ -279,12 +254,7 @@ export function BrandingPreferencesForm({
|
||||
</FormLabel>
|
||||
|
||||
<FormControl>
|
||||
<Input
|
||||
type="url"
|
||||
placeholder="https://example.com"
|
||||
disabled={!isBrandingEnabled}
|
||||
{...field}
|
||||
/>
|
||||
<Input type="url" placeholder="https://example.com" disabled={!isBrandingEnabled} {...field} />
|
||||
</FormControl>
|
||||
|
||||
<FormDescription>
|
||||
|
||||
@@ -1,12 +1,3 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg, t } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TeamGlobalSettings } from '@prisma/client';
|
||||
import { DocumentVisibility, OrganisationType, type RecipientRole } from '@prisma/client';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { DATE_FORMATS } from '@documenso/lib/constants/date-formats';
|
||||
@@ -15,22 +6,12 @@ import {
|
||||
type TEnvelopeExpirationPeriod,
|
||||
ZEnvelopeExpirationPeriod,
|
||||
} from '@documenso/lib/constants/envelope-expiration';
|
||||
import {
|
||||
type TEnvelopeReminderSettings,
|
||||
ZEnvelopeReminderSettings,
|
||||
} from '@documenso/lib/constants/envelope-reminder';
|
||||
import {
|
||||
SUPPORTED_LANGUAGES,
|
||||
SUPPORTED_LANGUAGE_CODES,
|
||||
isValidLanguageCode,
|
||||
} from '@documenso/lib/constants/i18n';
|
||||
import { type TEnvelopeReminderSettings, ZEnvelopeReminderSettings } from '@documenso/lib/constants/envelope-reminder';
|
||||
import { isValidLanguageCode, SUPPORTED_LANGUAGE_CODES, SUPPORTED_LANGUAGES } from '@documenso/lib/constants/i18n';
|
||||
import { TIME_ZONES } from '@documenso/lib/constants/time-zones';
|
||||
import type { TDefaultRecipients } from '@documenso/lib/types/default-recipients';
|
||||
import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';
|
||||
import {
|
||||
type TDocumentMetaDateFormat,
|
||||
ZDocumentMetaTimezoneSchema,
|
||||
} from '@documenso/lib/types/document-meta';
|
||||
import { type TDocumentMetaDateFormat, ZDocumentMetaTimezoneSchema } from '@documenso/lib/types/document-meta';
|
||||
import { isPersonalLayout } from '@documenso/lib/utils/organisations';
|
||||
import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter';
|
||||
import { extractTeamSignatureSettings } from '@documenso/lib/utils/teams';
|
||||
@@ -52,13 +33,15 @@ import {
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { MultiSelectCombobox } from '@documenso/ui/primitives/multi-select-combobox';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg, t } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TeamGlobalSettings } from '@prisma/client';
|
||||
import { DocumentVisibility, OrganisationType, type RecipientRole } from '@prisma/client';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useOptionalCurrentTeam } from '~/providers/team';
|
||||
|
||||
@@ -147,9 +130,7 @@ export const DocumentPreferencesForm = ({
|
||||
const form = useForm<TDocumentPreferencesFormSchema>({
|
||||
defaultValues: {
|
||||
documentVisibility: settings.documentVisibility,
|
||||
documentLanguage: isValidLanguageCode(settings.documentLanguage)
|
||||
? settings.documentLanguage
|
||||
: null,
|
||||
documentLanguage: isValidLanguageCode(settings.documentLanguage) ? settings.documentLanguage : null,
|
||||
documentTimezone: settings.documentTimezone,
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
documentDateFormat: settings.documentDateFormat as TDocumentMetaDateFormat | null,
|
||||
@@ -157,9 +138,7 @@ export const DocumentPreferencesForm = ({
|
||||
includeSigningCertificate: settings.includeSigningCertificate,
|
||||
includeAuditLog: settings.includeAuditLog,
|
||||
signatureTypes: extractTeamSignatureSettings({ ...settings }),
|
||||
defaultRecipients: settings.defaultRecipients
|
||||
? ZDefaultRecipientsSchema.parse(settings.defaultRecipients)
|
||||
: null,
|
||||
defaultRecipients: settings.defaultRecipients ? ZDefaultRecipientsSchema.parse(settings.defaultRecipients) : null,
|
||||
delegateDocumentOwnership: settings.delegateDocumentOwnership,
|
||||
aiFeaturesEnabled: settings.aiFeaturesEnabled,
|
||||
envelopeExpirationPeriod: settings.envelopeExpirationPeriod ?? null,
|
||||
@@ -171,10 +150,7 @@ export const DocumentPreferencesForm = ({
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset
|
||||
className="flex h-full max-w-2xl flex-col gap-y-6"
|
||||
disabled={form.formState.isSubmitting}
|
||||
>
|
||||
<fieldset className="flex h-full max-w-2xl flex-col gap-y-6" disabled={form.formState.isSubmitting}>
|
||||
{!isPersonalLayoutMode && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -264,8 +240,8 @@ export const DocumentPreferencesForm = ({
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Controls the default language of an uploaded document. This will be used as the
|
||||
language in email communications with the recipients.
|
||||
Controls the default language of an uploaded document. This will be used as the language in email
|
||||
communications with the recipients.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
@@ -322,9 +298,7 @@ export const DocumentPreferencesForm = ({
|
||||
|
||||
<FormControl>
|
||||
<Combobox
|
||||
triggerPlaceholder={
|
||||
canInherit ? t`Inherit from organisation` : t`Local timezone`
|
||||
}
|
||||
triggerPlaceholder={canInherit ? t`Inherit from organisation` : t`Local timezone`}
|
||||
placeholder={t`Select a time zone`}
|
||||
options={TIME_ZONES}
|
||||
value={field.value}
|
||||
@@ -358,9 +332,7 @@ export const DocumentPreferencesForm = ({
|
||||
onChange={field.onChange}
|
||||
className="w-full bg-background"
|
||||
enableSearch={false}
|
||||
emptySelectionPlaceholder={
|
||||
canInherit ? t`Inherit from organisation` : t`Select signature types`
|
||||
}
|
||||
emptySelectionPlaceholder={canInherit ? t`Inherit from organisation` : t`Select signature types`}
|
||||
testId="signature-types-trigger"
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -369,9 +341,7 @@ export const DocumentPreferencesForm = ({
|
||||
<FormMessage />
|
||||
) : (
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Controls which signatures are allowed to be used when signing a document.
|
||||
</Trans>
|
||||
<Trans>Controls which signatures are allowed to be used when signing a document.</Trans>
|
||||
</FormDescription>
|
||||
)}
|
||||
</FormItem>
|
||||
@@ -422,15 +392,14 @@ export const DocumentPreferencesForm = ({
|
||||
</FormControl>
|
||||
|
||||
<div className="pt-2">
|
||||
<div className="text-xs font-medium text-muted-foreground">
|
||||
<div className="font-medium text-muted-foreground text-xs">
|
||||
<Trans>Preview</Trans>
|
||||
</div>
|
||||
|
||||
<Alert variant="neutral" className="mt-1 px-2.5 py-1.5 text-sm">
|
||||
{field.value ? (
|
||||
<Trans>
|
||||
"{placeholderEmail}" on behalf of "Team Name" has invited you to sign
|
||||
"example document".
|
||||
"{placeholderEmail}" on behalf of "Team Name" has invited you to sign "example document".
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>"Team Name" has invited you to sign "example document".</Trans>
|
||||
@@ -440,9 +409,9 @@ export const DocumentPreferencesForm = ({
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Controls the formatting of the message that will be sent when inviting a
|
||||
recipient to sign a document. If a custom message has been provided while
|
||||
configuring the document, it will be used instead.
|
||||
Controls the formatting of the message that will be sent when inviting a recipient to sign a
|
||||
document. If a custom message has been provided while configuring the document, it will be used
|
||||
instead.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
@@ -494,9 +463,8 @@ export const DocumentPreferencesForm = ({
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Controls whether the signing certificate will be included in the document when
|
||||
it is downloaded. The signing certificate can still be downloaded from the logs
|
||||
page separately.
|
||||
Controls whether the signing certificate will be included in the document when it is downloaded. The
|
||||
signing certificate can still be downloaded from the logs page separately.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
@@ -544,9 +512,8 @@ export const DocumentPreferencesForm = ({
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Controls whether the audit logs will be included in the document when it is
|
||||
downloaded. The audit logs can still be downloaded from the logs page
|
||||
separately.
|
||||
Controls whether the audit logs will be included in the document when it is downloaded. The audit
|
||||
logs can still be downloaded from the logs page separately.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
@@ -602,15 +569,11 @@ export const DocumentPreferencesForm = ({
|
||||
<AvatarWithText
|
||||
avatarFallback={recipientAbbreviation(recipient)}
|
||||
primaryText={
|
||||
<span className="text-sm font-medium">
|
||||
{recipient.name || recipient.email}
|
||||
</span>
|
||||
<span className="font-medium text-sm">{recipient.name || recipient.email}</span>
|
||||
}
|
||||
secondaryText={
|
||||
recipient.name ? (
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{recipient.email}
|
||||
</span>
|
||||
<span className="text-muted-foreground text-xs">{recipient.email}</span>
|
||||
) : undefined
|
||||
}
|
||||
className="flex-1"
|
||||
@@ -653,9 +616,7 @@ export const DocumentPreferencesForm = ({
|
||||
<Select
|
||||
{...field}
|
||||
value={field.value === null ? '-1' : field.value.toString()}
|
||||
onValueChange={(value) =>
|
||||
field.onChange(value === 'true' ? true : value === 'false' ? false : null)
|
||||
}
|
||||
onValueChange={(value) => field.onChange(value === 'true' ? true : value === 'false' ? false : null)}
|
||||
>
|
||||
<SelectTrigger className="bg-background text-muted-foreground">
|
||||
<SelectValue />
|
||||
@@ -679,9 +640,7 @@ export const DocumentPreferencesForm = ({
|
||||
</Select>
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Enable team API tokens to delegate document ownership to another team member.
|
||||
</Trans>
|
||||
<Trans>Enable team API tokens to delegate document ownership to another team member.</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
@@ -706,8 +665,8 @@ export const DocumentPreferencesForm = ({
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Controls how long recipients have to complete signing before the document
|
||||
expires. After expiration, recipients can no longer sign the document.
|
||||
Controls how long recipients have to complete signing before the document expires. After expiration,
|
||||
recipients can no longer sign the document.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
|
||||
@@ -735,8 +694,8 @@ export const DocumentPreferencesForm = ({
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Controls when and how often reminder emails are sent to recipients who have not
|
||||
yet completed signing.
|
||||
Controls when and how often reminder emails are sent to recipients who have not yet completed
|
||||
signing.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
|
||||
@@ -787,10 +746,9 @@ export const DocumentPreferencesForm = ({
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Enable AI-powered features such as automatic recipient detection. When
|
||||
enabled, document content will be sent to AI providers. We only use providers
|
||||
that do not retain data for training and prefer European regions where
|
||||
available.
|
||||
Enable AI-powered features such as automatic recipient detection. When enabled, document content
|
||||
will be sent to AI providers. We only use providers that do not retain data for training and
|
||||
prefer European regions where available.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
|
||||
@@ -1,12 +1,3 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { PlusIcon, Trash } from 'lucide-react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { validateCheckboxLength } from '@documenso/lib/advanced-fields-validation/validate-checkbox';
|
||||
import {
|
||||
type TCheckboxFieldMeta as CheckboxFieldMeta,
|
||||
@@ -20,23 +11,17 @@ import {
|
||||
checkboxValidationRules,
|
||||
checkboxValidationSigns,
|
||||
} from '@documenso/ui/primitives/document-flow/field-items-advanced-settings/constants';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { Separator } from '@documenso/ui/primitives/separator';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { PlusIcon, Trash } from 'lucide-react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
@@ -150,19 +135,13 @@ export const EditorFieldCheckboxForm = ({
|
||||
const preselectedValues = (formValues.values || [])?.filter((value) => value.checked);
|
||||
|
||||
if (formValues.validationLength && formValues.validationRule && preselectedValues.length > 0) {
|
||||
const validationRule = checkboxValidationSigns.find(
|
||||
(sign) => sign.label === formValues.validationRule,
|
||||
);
|
||||
const validationRule = checkboxValidationSigns.find((sign) => sign.label === formValues.validationRule);
|
||||
|
||||
if (!validationRule) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return validateCheckboxLength(
|
||||
preselectedValues.length,
|
||||
validationRule.value,
|
||||
formValues.validationLength,
|
||||
);
|
||||
return validateCheckboxLength(preselectedValues.length, validationRule.value, formValues.validationLength);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -251,8 +230,7 @@ export const EditorFieldCheckboxForm = ({
|
||||
|
||||
const currentValues = formValues.values || [];
|
||||
|
||||
const minimumNumberOfValuesRequired =
|
||||
validationNumber - currentValues.length;
|
||||
const minimumNumberOfValuesRequired = validationNumber - currentValues.length;
|
||||
|
||||
if (!formValues.validationRule) {
|
||||
form.setValue('validationRule', checkboxValidationRules[0]);
|
||||
@@ -295,12 +273,12 @@ export const EditorFieldCheckboxForm = ({
|
||||
<EditorGenericReadOnlyField formControl={form.control} />
|
||||
|
||||
<section className="space-y-2">
|
||||
<div className="-mx-4 mb-4 mt-2">
|
||||
<div className="-mx-4 mt-2 mb-4">
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center justify-between gap-2">
|
||||
<p className="text-sm font-medium">
|
||||
<p className="font-medium text-sm">
|
||||
<Trans>Checkbox values</Trans>
|
||||
</p>
|
||||
|
||||
@@ -335,11 +313,7 @@ export const EditorFieldCheckboxForm = ({
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
data-testid={`field-form-values-${index}-value`}
|
||||
className="w-full"
|
||||
{...field}
|
||||
/>
|
||||
<Input data-testid={`field-form-values-${index}-value`} className="w-full" {...field} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
@@ -360,9 +334,7 @@ export const EditorFieldCheckboxForm = ({
|
||||
{!isValidationRuleMetForPreselectedValues && (
|
||||
<Alert variant="warning">
|
||||
<AlertDescription>
|
||||
<Trans>
|
||||
The preselected values will be ignored unless they meet the validation criteria.
|
||||
</Trans>
|
||||
<Trans>The preselected values will be ignored unless they meet the validation criteria.</Trans>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
type TDateFieldMeta as DateFieldMeta,
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
FIELD_DATE_META_DEFAULT_VALUES,
|
||||
FIELD_DEFAULT_GENERIC_ALIGN,
|
||||
ZDateFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { Form } from '@documenso/ui/primitives/form/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
EditorGenericTextAlignField,
|
||||
} from './editor-field-generic-field-forms';
|
||||
import { EditorGenericFontSizeField, EditorGenericTextAlignField } from './editor-field-generic-field-forms';
|
||||
|
||||
const ZDateFieldFormSchema = ZDateFieldMeta.pick({
|
||||
fontSize: true,
|
||||
|
||||
@@ -1,35 +1,16 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { DEFAULT_FIELD_FONT_SIZE, type TDropdownFieldMeta as DropdownFieldMeta } from '@documenso/lib/types/field-meta';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { Separator } from '@documenso/ui/primitives/separator';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { PlusIcon, Trash } from 'lucide-react';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
type TDropdownFieldMeta as DropdownFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Separator } from '@documenso/ui/primitives/separator';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
EditorGenericReadOnlyField,
|
||||
@@ -209,12 +190,12 @@ export const EditorFieldDropdownForm = ({
|
||||
<EditorGenericReadOnlyField formControl={form.control} />
|
||||
|
||||
<section className="space-y-2">
|
||||
<div className="-mx-4 mb-4 mt-2">
|
||||
<div className="-mx-4 mt-2 mb-4">
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center justify-between gap-2">
|
||||
<p className="text-sm font-medium">
|
||||
<p className="font-medium text-sm">
|
||||
<Trans>Dropdown values</Trans>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
type TEmailFieldMeta as EmailFieldMeta,
|
||||
@@ -12,11 +6,12 @@ import {
|
||||
ZEmailFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { Form } from '@documenso/ui/primitives/form/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
EditorGenericTextAlignField,
|
||||
} from './editor-field-generic-field-forms';
|
||||
import { EditorGenericFontSizeField, EditorGenericTextAlignField } from './editor-field-generic-field-forms';
|
||||
|
||||
const ZEmailFieldFormSchema = ZEmailFieldMeta.pick({
|
||||
fontSize: true,
|
||||
|
||||
@@ -1,29 +1,17 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { type Control, useFormContext } from 'react-hook-form';
|
||||
|
||||
import { FIELD_MIN_LINE_HEIGHT } from '@documenso/lib/types/field-meta';
|
||||
import { FIELD_MAX_LINE_HEIGHT } from '@documenso/lib/types/field-meta';
|
||||
import { FIELD_MIN_LETTER_SPACING } from '@documenso/lib/types/field-meta';
|
||||
import { FIELD_MAX_LETTER_SPACING } from '@documenso/lib/types/field-meta';
|
||||
import {
|
||||
FIELD_MAX_LETTER_SPACING,
|
||||
FIELD_MAX_LINE_HEIGHT,
|
||||
FIELD_MIN_LETTER_SPACING,
|
||||
FIELD_MIN_LINE_HEIGHT,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Checkbox } from '@documenso/ui/primitives/checkbox';
|
||||
import {
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { useEffect } from 'react';
|
||||
import { type Control, useFormContext } from 'react-hook-form';
|
||||
|
||||
// Can't seem to get the non-any type to work with correct types.
|
||||
// Eg Control<{ fontSize?: number } doesn't seem to work when there are required items.
|
||||
@@ -259,7 +247,7 @@ export const EditorGenericRequiredField = ({
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
|
||||
<label className="ml-2 text-sm text-muted-foreground" htmlFor="field-required">
|
||||
<label className="ml-2 text-muted-foreground text-sm" htmlFor="field-required">
|
||||
<Trans>Required Field</Trans>
|
||||
</label>
|
||||
</div>
|
||||
@@ -303,7 +291,7 @@ export const EditorGenericReadOnlyField = ({
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
|
||||
<label className="ml-2 text-sm text-muted-foreground" htmlFor="field-read-only">
|
||||
<label className="ml-2 text-muted-foreground text-sm" htmlFor="field-read-only">
|
||||
<Trans>Read Only</Trans>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
FIELD_DEFAULT_GENERIC_ALIGN,
|
||||
@@ -11,11 +5,12 @@ import {
|
||||
ZInitialsFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { Form } from '@documenso/ui/primitives/form/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
EditorGenericTextAlignField,
|
||||
} from './editor-field-generic-field-forms';
|
||||
import { EditorGenericFontSizeField, EditorGenericTextAlignField } from './editor-field-generic-field-forms';
|
||||
|
||||
const ZInitialsFieldFormSchema = ZInitialsFieldMeta.pick({
|
||||
fontSize: true,
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
FIELD_DEFAULT_GENERIC_ALIGN,
|
||||
@@ -11,11 +5,12 @@ import {
|
||||
ZNameFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { Form } from '@documenso/ui/primitives/form/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
EditorGenericTextAlignField,
|
||||
} from './editor-field-generic-field-forms';
|
||||
import { EditorGenericFontSizeField, EditorGenericTextAlignField } from './editor-field-generic-field-forms';
|
||||
|
||||
const ZNameFieldFormSchema = ZNameFieldMeta.pick({
|
||||
fontSize: true,
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
FIELD_DEFAULT_GENERIC_ALIGN,
|
||||
@@ -15,23 +8,15 @@ import {
|
||||
ZNumberFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { numberFormatValues } from '@documenso/ui/primitives/document-flow/field-items-advanced-settings/constants';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { Separator } from '@documenso/ui/primitives/separator';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
@@ -188,12 +173,7 @@ export const EditorFieldNumberForm = ({
|
||||
<Trans>Value</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
data-testid="field-form-value"
|
||||
className="bg-background"
|
||||
placeholder={t`Value`}
|
||||
{...field}
|
||||
/>
|
||||
<Input data-testid="field-form-value" className="bg-background" placeholder={t`Value`} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -251,11 +231,11 @@ export const EditorFieldNumberForm = ({
|
||||
|
||||
{/* Validation section */}
|
||||
<section className="space-y-2">
|
||||
<div className="-mx-4 mb-4 mt-2">
|
||||
<div className="-mx-4 mt-2 mb-4">
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
<p className="text-sm font-medium">
|
||||
<p className="font-medium text-sm">
|
||||
<Trans>Validation</Trans>
|
||||
</p>
|
||||
|
||||
@@ -275,9 +255,7 @@ export const EditorFieldNumberForm = ({
|
||||
placeholder={t`E.g. 0`}
|
||||
{...field}
|
||||
value={field.value ?? ''}
|
||||
onChange={(e) =>
|
||||
field.onChange(e.target.value === '' ? null : e.target.value)
|
||||
}
|
||||
onChange={(e) => field.onChange(e.target.value === '' ? null : e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -300,9 +278,7 @@ export const EditorFieldNumberForm = ({
|
||||
placeholder={t`E.g. 100`}
|
||||
{...field}
|
||||
value={field.value ?? ''}
|
||||
onChange={(e) =>
|
||||
field.onChange(e.target.value === '' ? null : e.target.value)
|
||||
}
|
||||
onChange={(e) => field.onChange(e.target.value === '' ? null : e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
|
||||
@@ -1,34 +1,19 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { PlusIcon, Trash } from 'lucide-react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
type TRadioFieldMeta as RadioFieldMeta,
|
||||
ZRadioFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { Checkbox } from '@documenso/ui/primitives/checkbox';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { Separator } from '@documenso/ui/primitives/separator';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { PlusIcon, Trash } from 'lucide-react';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
@@ -93,8 +78,7 @@ export const EditorFieldRadioForm = ({
|
||||
|
||||
const addValue = () => {
|
||||
const currentValues = form.getValues('values') || [];
|
||||
const newId =
|
||||
currentValues.length > 0 ? Math.max(...currentValues.map((val) => val.id)) + 1 : 1;
|
||||
const newId = currentValues.length > 0 ? Math.max(...currentValues.map((val) => val.id)) + 1 : 1;
|
||||
|
||||
const newValues = [...currentValues, { id: newId, checked: false, value: '' }];
|
||||
form.setValue('values', newValues);
|
||||
@@ -166,12 +150,12 @@ export const EditorFieldRadioForm = ({
|
||||
<EditorGenericReadOnlyField formControl={form.control} />
|
||||
|
||||
<section className="space-y-2">
|
||||
<div className="-mx-4 mb-4 mt-2">
|
||||
<div className="-mx-4 mt-2 mb-4">
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center justify-between gap-2">
|
||||
<p className="text-sm font-medium">
|
||||
<p className="font-medium text-sm">
|
||||
<Trans>Radio values</Trans>
|
||||
</p>
|
||||
|
||||
@@ -220,11 +204,7 @@ export const EditorFieldRadioForm = ({
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
data-testid={`field-form-values-${index}-value`}
|
||||
className="w-full"
|
||||
{...field}
|
||||
/>
|
||||
<Input data-testid={`field-form-values-${index}-value`} className="w-full" {...field} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { DEFAULT_SIGNATURE_TEXT_FONT_SIZE } from '@documenso/lib/constants/pdf';
|
||||
import {
|
||||
FIELD_SIGNATURE_META_DEFAULT_VALUES,
|
||||
@@ -12,6 +5,11 @@ import {
|
||||
ZSignatureFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { Form } from '@documenso/ui/primitives/form/form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { EditorGenericFontSizeField } from './editor-field-generic-field-forms';
|
||||
|
||||
@@ -66,7 +64,7 @@ export const EditorFieldSignatureForm = ({
|
||||
<fieldset className="flex flex-col gap-2">
|
||||
<div>
|
||||
<EditorGenericFontSizeField formControl={form.control} />
|
||||
<p className="mt-0.5 text-xs text-muted-foreground">
|
||||
<p className="mt-0.5 text-muted-foreground text-xs">
|
||||
<Trans>The typed signature font size</Trans>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
DEFAULT_FIELD_FONT_SIZE,
|
||||
FIELD_DEFAULT_GENERIC_ALIGN,
|
||||
@@ -14,16 +7,14 @@ import {
|
||||
type TTextFieldMeta as TextFieldMeta,
|
||||
ZTextFieldMeta,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Textarea } from '@documenso/ui/primitives/textarea';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
EditorGenericFontSizeField,
|
||||
@@ -150,11 +141,7 @@ export const EditorFieldTextForm = ({
|
||||
<Trans>Placeholder</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
data-testid="field-form-placeholder"
|
||||
placeholder={t`Field placeholder`}
|
||||
{...field}
|
||||
/>
|
||||
<Input data-testid="field-form-placeholder" placeholder={t`Field placeholder`} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TeamGlobalSettings } from '@prisma/client';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
|
||||
import { FROM_ADDRESS } from '@documenso/lib/constants/email';
|
||||
import {
|
||||
DEFAULT_DOCUMENT_EMAIL_SETTINGS,
|
||||
ZDocumentEmailSettingsSchema,
|
||||
} from '@documenso/lib/types/document-email';
|
||||
import { DEFAULT_DOCUMENT_EMAIL_SETTINGS, ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';
|
||||
import { zEmail } from '@documenso/lib/utils/zod';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { DocumentEmailCheckboxes } from '@documenso/ui/components/document/document-email-checkboxes';
|
||||
@@ -24,13 +15,12 @@ import {
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TeamGlobalSettings } from '@prisma/client';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
const ZEmailPreferencesFormSchema = z.object({
|
||||
emailId: z.string().nullable(),
|
||||
@@ -41,10 +31,7 @@ const ZEmailPreferencesFormSchema = z.object({
|
||||
|
||||
export type TEmailPreferencesFormSchema = z.infer<typeof ZEmailPreferencesFormSchema>;
|
||||
|
||||
type SettingsSubset = Pick<
|
||||
TeamGlobalSettings,
|
||||
'emailId' | 'emailReplyTo' | 'emailDocumentSettings'
|
||||
>;
|
||||
type SettingsSubset = Pick<TeamGlobalSettings, 'emailId' | 'emailReplyTo' | 'emailDocumentSettings'>;
|
||||
|
||||
export type EmailPreferencesFormProps = {
|
||||
settings: SettingsSubset;
|
||||
@@ -52,11 +39,7 @@ export type EmailPreferencesFormProps = {
|
||||
onFormSubmit: (data: TEmailPreferencesFormSchema) => Promise<void>;
|
||||
};
|
||||
|
||||
export const EmailPreferencesForm = ({
|
||||
settings,
|
||||
onFormSubmit,
|
||||
canInherit,
|
||||
}: EmailPreferencesFormProps) => {
|
||||
export const EmailPreferencesForm = ({ settings, onFormSubmit, canInherit }: EmailPreferencesFormProps) => {
|
||||
const organisation = useCurrentOrganisation();
|
||||
|
||||
const form = useForm<TEmailPreferencesFormSchema>({
|
||||
@@ -69,21 +52,17 @@ export const EmailPreferencesForm = ({
|
||||
resolver: zodResolver(ZEmailPreferencesFormSchema),
|
||||
});
|
||||
|
||||
const { data: emailData, isLoading: isLoadingEmails } =
|
||||
trpc.enterprise.organisation.email.find.useQuery({
|
||||
organisationId: organisation.id,
|
||||
perPage: 100,
|
||||
});
|
||||
const { data: emailData, isLoading: isLoadingEmails } = trpc.enterprise.organisation.email.find.useQuery({
|
||||
organisationId: organisation.id,
|
||||
perPage: 100,
|
||||
});
|
||||
|
||||
const emails = emailData?.data || [];
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset
|
||||
className="flex h-full max-w-2xl flex-col gap-y-6"
|
||||
disabled={form.formState.isSubmitting}
|
||||
>
|
||||
<fieldset className="flex h-full max-w-2xl flex-col gap-y-6" disabled={form.formState.isSubmitting}>
|
||||
{organisation.organisationClaim.flags.emailDomains && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -145,9 +124,7 @@ export const EmailPreferencesForm = ({
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
The email address which will show up in the "Reply To" field in emails
|
||||
</Trans>
|
||||
<Trans>The email address which will show up in the "Reply To" field in emails</Trans>
|
||||
|
||||
{canInherit && (
|
||||
<span>
|
||||
@@ -188,9 +165,7 @@ export const EmailPreferencesForm = ({
|
||||
<Select
|
||||
value={field.value === null ? 'INHERIT' : 'CONTROLLED'}
|
||||
onValueChange={(value) =>
|
||||
field.onChange(
|
||||
value === 'CONTROLLED' ? DEFAULT_DOCUMENT_EMAIL_SETTINGS : null,
|
||||
)
|
||||
field.onChange(value === 'CONTROLLED' ? DEFAULT_DOCUMENT_EMAIL_SETTINGS : null)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
@@ -220,8 +195,8 @@ export const EmailPreferencesForm = ({
|
||||
|
||||
<FormDescription>
|
||||
<Trans>
|
||||
Controls the default email settings when new documents or templates are created.
|
||||
Updating these settings will not affect existing documents or templates.
|
||||
Controls the default email settings when new documents or templates are created. Updating these
|
||||
settings will not affect existing documents or templates.
|
||||
</Trans>
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { zEmail } from '@documenso/lib/utils/zod';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -6,21 +13,6 @@ import { useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { zEmail } from '@documenso/lib/utils/zod';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export const ZForgotPasswordFormSchema = z.object({
|
||||
email: zEmail().min(1),
|
||||
});
|
||||
@@ -64,10 +56,7 @@ export const ForgotPasswordForm = ({ className }: ForgotPasswordFormProps) => {
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={cn('flex w-full flex-col gap-y-4', className)}
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<form className={cn('flex w-full flex-col gap-y-4', className)} onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { ZUpdateOrganisationRequestSchema } from '@documenso/trpc/server/organisation-router/update-organisation.types';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -7,24 +17,6 @@ import { useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { ZUpdateOrganisationRequestSchema } from '@documenso/trpc/server/organisation-router/update-organisation.types';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
const ZOrganisationUpdateFormSchema = ZUpdateOrganisationRequestSchema.shape.data.pick({
|
||||
name: true,
|
||||
url: true,
|
||||
@@ -131,7 +123,7 @@ export const OrganisationUpdateForm = () => {
|
||||
<Input className="bg-background" {...field} />
|
||||
</FormControl>
|
||||
{!form.formState.errors.url && (
|
||||
<span className="text-foreground/50 text-xs font-normal">
|
||||
<span className="font-normal text-foreground/50 text-xs">
|
||||
{field.value ? (
|
||||
`${NEXT_PUBLIC_WEBAPP_URL()}/o/${field.value}`
|
||||
) : (
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import type { SessionUser } from '@documenso/auth/server/lib/session/session';
|
||||
import { AppError } from '@documenso/lib/errors/app-error';
|
||||
import { ZCurrentPasswordSchema, ZPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { PasswordInput } from '@documenso/ui/primitives/password-input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -6,23 +15,6 @@ import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import type { SessionUser } from '@documenso/auth/server/lib/session/session';
|
||||
import { AppError } from '@documenso/lib/errors/app-error';
|
||||
import { ZCurrentPasswordSchema, ZPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { PasswordInput } from '@documenso/ui/primitives/password-input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export const ZPasswordFormSchema = z
|
||||
.object({
|
||||
currentPassword: ZCurrentPasswordSchema,
|
||||
@@ -76,13 +68,9 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
|
||||
const errorMessage = match(error.code)
|
||||
.with('NO_PASSWORD', () => msg`User has no password.`)
|
||||
.with('INCORRECT_PASSWORD', () => msg`Current password is incorrect.`)
|
||||
.with(
|
||||
'SAME_PASSWORD',
|
||||
() => msg`Your new password cannot be the same as your old password.`,
|
||||
)
|
||||
.with('SAME_PASSWORD', () => msg`Your new password cannot be the same as your old password.`)
|
||||
.otherwise(
|
||||
() =>
|
||||
msg`We encountered an unknown error while attempting to update your password. Please try again later.`,
|
||||
() => msg`We encountered an unknown error while attempting to update your password. Please try again later.`,
|
||||
);
|
||||
|
||||
toast({
|
||||
@@ -95,10 +83,7 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={cn('flex w-full flex-col gap-y-4', className)}
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<form className={cn('flex w-full flex-col gap-y-4', className)} onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -149,7 +134,7 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
|
||||
/>
|
||||
</fieldset>
|
||||
|
||||
<div className="ml-auto mt-4">
|
||||
<div className="mt-4 ml-auto">
|
||||
<Button type="submit" loading={isSubmitting}>
|
||||
{isSubmitting ? <Trans>Updating password...</Trans> : <Trans>Update password</Trans>}
|
||||
</Button>
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { ZNameSchema } from '@documenso/lib/constants/auth';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Label } from '@documenso/ui/primitives/label';
|
||||
import { SignaturePadDialog } from '@documenso/ui/primitives/signature-pad/signature-pad-dialog';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -5,24 +15,6 @@ import { Trans } from '@lingui/react/macro';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { ZNameSchema } from '@documenso/lib/constants/auth';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Label } from '@documenso/ui/primitives/label';
|
||||
import { SignaturePadDialog } from '@documenso/ui/primitives/signature-pad/signature-pad-dialog';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export const ZProfileFormSchema = z.object({
|
||||
name: ZNameSchema,
|
||||
signature: z.string().min(1, { message: msg`Signature Pad cannot be empty.`.id }),
|
||||
@@ -83,10 +75,7 @@ export const ProfileForm = ({ className }: ProfileFormProps) => {
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={cn('flex w-full flex-col gap-y-4', className)}
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<form className={cn('flex w-full flex-col gap-y-4', className)} onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
||||
@@ -1,38 +1,25 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Plural, Trans } from '@lingui/react/macro';
|
||||
import type { TeamProfile } from '@prisma/client';
|
||||
import { motion } from 'framer-motion';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
import { CheckSquareIcon, CopyIcon } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
|
||||
import { useSession } from '@documenso/lib/client-only/providers/session';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { isPersonalLayout } from '@documenso/lib/utils/organisations';
|
||||
import { formatUserProfilePath } from '@documenso/lib/utils/public-profiles';
|
||||
import {
|
||||
MAX_PROFILE_BIO_LENGTH,
|
||||
ZUpdateTeamRequestSchema,
|
||||
} from '@documenso/trpc/server/team-router/update-team.types';
|
||||
import { MAX_PROFILE_BIO_LENGTH, ZUpdateTeamRequestSchema } from '@documenso/trpc/server/team-router/update-team.types';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Textarea } from '@documenso/ui/primitives/textarea';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Plural, Trans } from '@lingui/react/macro';
|
||||
import type { TeamProfile } from '@prisma/client';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { CheckSquareIcon, CopyIcon } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { useCurrentTeam } from '~/providers/team';
|
||||
|
||||
@@ -48,11 +35,7 @@ export type PublicProfileFormProps = {
|
||||
onProfileUpdate: (data: TPublicProfileFormSchema) => Promise<unknown>;
|
||||
profile: TeamProfile;
|
||||
};
|
||||
export const PublicProfileForm = ({
|
||||
className,
|
||||
profile,
|
||||
onProfileUpdate,
|
||||
}: PublicProfileFormProps) => {
|
||||
export const PublicProfileForm = ({ className, profile, onProfileUpdate }: PublicProfileFormProps) => {
|
||||
const { _ } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
@@ -137,10 +120,7 @@ export const PublicProfileForm = ({
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={cn('flex w-full flex-col gap-y-4', className)}
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<form className={cn('flex w-full flex-col gap-y-4', className)} onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -156,22 +136,19 @@ export const PublicProfileForm = ({
|
||||
|
||||
{!isPersonalLayoutMode && (
|
||||
<p className="text-muted-foreground text-xs">
|
||||
<Trans>
|
||||
You can update the profile URL by updating the team URL in the general
|
||||
settings page.
|
||||
</Trans>
|
||||
<Trans>You can update the profile URL by updating the team URL in the general settings page.</Trans>
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="h-8">
|
||||
{!form.formState.errors.url && (
|
||||
<div className="text-muted-foreground h-8 text-sm">
|
||||
<div className="h-8 text-muted-foreground text-sm">
|
||||
{field.value ? (
|
||||
<div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="none"
|
||||
className="h-7 rounded bg-neutral-50 pl-2 pr-0.5 font-normal dark:border dark:border-neutral-500 dark:bg-neutral-600"
|
||||
className="h-7 rounded bg-neutral-50 pr-0.5 pl-2 font-normal dark:border dark:border-neutral-500 dark:bg-neutral-600"
|
||||
onClick={async () => onCopy()}
|
||||
>
|
||||
<p>
|
||||
@@ -222,10 +199,7 @@ export const PublicProfileForm = ({
|
||||
<FormItem>
|
||||
<FormLabel>Bio</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
{...field}
|
||||
placeholder={_(msg`Write a description to display on your public profile`)}
|
||||
/>
|
||||
<Textarea {...field} placeholder={_(msg`Write a description to display on your public profile`)} />
|
||||
</FormControl>
|
||||
|
||||
{!form.formState.errors.profileBio && (
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { ZPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { PasswordInput } from '@documenso/ui/primitives/password-input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -7,22 +15,6 @@ import { useNavigate } from 'react-router';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { ZPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { PasswordInput } from '@documenso/ui/primitives/password-input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export const ZResetPasswordFormSchema = z
|
||||
.object({
|
||||
password: ZPasswordSchema,
|
||||
@@ -78,13 +70,9 @@ export const ResetPasswordForm = ({ className, token }: ResetPasswordFormProps)
|
||||
const errorMessage = match(error.code)
|
||||
.with(AppErrorCode.EXPIRED_CODE, () => msg`Token has expired. Please try again.`)
|
||||
.with('INVALID_TOKEN', () => msg`Invalid token provided. Please try again.`)
|
||||
.with(
|
||||
'SAME_PASSWORD',
|
||||
() => msg`Your new password cannot be the same as your old password.`,
|
||||
)
|
||||
.with('SAME_PASSWORD', () => msg`Your new password cannot be the same as your old password.`)
|
||||
.otherwise(
|
||||
() =>
|
||||
msg`We encountered an unknown error while attempting to reset your password. Please try again later.`,
|
||||
() => msg`We encountered an unknown error while attempting to reset your password. Please try again later.`,
|
||||
);
|
||||
|
||||
toast({
|
||||
@@ -97,10 +85,7 @@ export const ResetPasswordForm = ({ className, token }: ResetPasswordFormProps)
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={cn('flex w-full flex-col gap-y-4', className)}
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<form className={cn('flex w-full flex-col gap-y-4', className)} onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { useLocation, useNavigate } from 'react-router';
|
||||
import { useSearchParams } from 'react-router';
|
||||
|
||||
import { Select, SelectContent, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import type React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useLocation, useNavigate, useSearchParams } from 'react-router';
|
||||
|
||||
export type SearchParamSelector = {
|
||||
paramKey: string;
|
||||
@@ -41,7 +39,7 @@ export const SearchParamSelector = ({ children, paramKey, isValueValid }: Search
|
||||
|
||||
return (
|
||||
<Select defaultValue={value} onValueChange={onValueChange}>
|
||||
<SelectTrigger className="text-muted-foreground max-w-[200px]">
|
||||
<SelectTrigger className="max-w-[200px] text-muted-foreground">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { zEmail } from '@documenso/lib/utils/zod';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -5,21 +12,6 @@ import { Trans } from '@lingui/react/macro';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { zEmail } from '@documenso/lib/utils/zod';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export const ZSendConfirmationEmailFormSchema = z.object({
|
||||
email: zEmail().min(1),
|
||||
});
|
||||
@@ -49,9 +41,7 @@ export const SendConfirmationEmailForm = ({ className }: SendConfirmationEmailFo
|
||||
|
||||
toast({
|
||||
title: _(msg`Confirmation email sent`),
|
||||
description: _(
|
||||
msg`A confirmation email has been sent, and it should arrive in your inbox shortly.`,
|
||||
),
|
||||
description: _(msg`A confirmation email has been sent, and it should arrive in your inbox shortly.`),
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
@@ -67,10 +57,7 @@ export const SendConfirmationEmailForm = ({ className }: SendConfirmationEmailFo
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={cn('mt-6 flex w-full flex-col gap-y-4', className)}
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<form className={cn('mt-6 flex w-full flex-col gap-y-4', className)} onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
|
||||
@@ -1,21 +1,3 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import type { MessageDescriptor } from '@lingui/core';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TurnstileInstance } from '@marsidev/react-turnstile';
|
||||
import { Turnstile } from '@marsidev/react-turnstile';
|
||||
import { browserSupportsWebAuthn, startAuthentication } from '@simplewebauthn/browser';
|
||||
import { KeyRoundIcon } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { FaIdCardClip } from 'react-icons/fa6';
|
||||
import { FcGoogle } from 'react-icons/fc';
|
||||
import { Link, useNavigate } from 'react-router';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { AuthenticationErrorCode } from '@documenso/auth/server/lib/errors/error-codes';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
@@ -25,25 +7,28 @@ import { trpc } from '@documenso/trpc/react';
|
||||
import { ZCurrentPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@documenso/ui/primitives/dialog';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@documenso/ui/primitives/dialog';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { PasswordInput } from '@documenso/ui/primitives/password-input';
|
||||
import { PinInput, PinInputGroup, PinInputSlot } from '@documenso/ui/primitives/pin-input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import type { MessageDescriptor } from '@lingui/core';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TurnstileInstance } from '@marsidev/react-turnstile';
|
||||
import { Turnstile } from '@marsidev/react-turnstile';
|
||||
import { browserSupportsWebAuthn, startAuthentication } from '@simplewebauthn/browser';
|
||||
import { KeyRoundIcon } from 'lucide-react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { FaIdCardClip } from 'react-icons/fa6';
|
||||
import { FcGoogle } from 'react-icons/fc';
|
||||
import { Link, useNavigate } from 'react-router';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
const CommonErrorMessages: Record<string, MessageDescriptor> = {
|
||||
[AuthenticationErrorCode.AccountDisabled]: msg`This account has been disabled. Please contact support.`,
|
||||
@@ -94,13 +79,10 @@ export const SignInForm = ({
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [isTwoFactorAuthenticationDialogOpen, setIsTwoFactorAuthenticationDialogOpen] =
|
||||
useState(false);
|
||||
const [isTwoFactorAuthenticationDialogOpen, setIsTwoFactorAuthenticationDialogOpen] = useState(false);
|
||||
const [isEmbeddedRedirect, setIsEmbeddedRedirect] = useState(false);
|
||||
|
||||
const [twoFactorAuthenticationMethod, setTwoFactorAuthenticationMethod] = useState<
|
||||
'totp' | 'backup'
|
||||
>('totp');
|
||||
const [twoFactorAuthenticationMethod, setTwoFactorAuthenticationMethod] = useState<'totp' | 'backup'>('totp');
|
||||
|
||||
const hasSocialAuthEnabled = isGoogleSSOEnabled || isMicrosoftSSOEnabled || isOIDCSSOEnabled;
|
||||
|
||||
@@ -127,8 +109,7 @@ export const SignInForm = ({
|
||||
return url.toString();
|
||||
}, [returnTo]);
|
||||
|
||||
const { mutateAsync: createPasskeySigninOptions } =
|
||||
trpc.auth.passkey.createSigninOptions.useMutation();
|
||||
const { mutateAsync: createPasskeySigninOptions } = trpc.auth.passkey.createSigninOptions.useMutation();
|
||||
|
||||
const form = useForm<TSignInFormSchema>({
|
||||
values: {
|
||||
@@ -203,10 +184,7 @@ export const SignInForm = ({
|
||||
() =>
|
||||
msg`This passkey is not configured for this application. Please login and add one in the user settings.`,
|
||||
)
|
||||
.with(
|
||||
AuthenticationErrorCode.SessionExpired,
|
||||
() => msg`This session has expired. Please try again.`,
|
||||
)
|
||||
.with(AuthenticationErrorCode.SessionExpired, () => msg`This session has expired. Please try again.`)
|
||||
.otherwise(() => handleFallbackErrorMessages(error.code));
|
||||
|
||||
toast({
|
||||
@@ -248,27 +226,19 @@ export const SignInForm = ({
|
||||
|
||||
toast({
|
||||
title: _(msg`Unable to sign in`),
|
||||
description: _(
|
||||
msg`This account has not been verified. Please verify your account before signing in.`,
|
||||
),
|
||||
description: _(msg`This account has not been verified. Please verify your account before signing in.`),
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const errorMessage = match(error.code)
|
||||
.with(
|
||||
AuthenticationErrorCode.InvalidCredentials,
|
||||
() => msg`The email or password provided is incorrect.`,
|
||||
)
|
||||
.with(AuthenticationErrorCode.InvalidCredentials, () => msg`The email or password provided is incorrect.`)
|
||||
.with(
|
||||
AuthenticationErrorCode.InvalidTwoFactorCode,
|
||||
() => msg`The two-factor authentication code provided is incorrect.`,
|
||||
)
|
||||
.with(
|
||||
AppErrorCode.INVALID_CAPTCHA,
|
||||
() => msg`We were unable to verify that you're human. Please try again.`,
|
||||
)
|
||||
.with(AppErrorCode.INVALID_CAPTCHA, () => msg`We were unable to verify that you're human. Please try again.`)
|
||||
.otherwise(() => handleFallbackErrorMessages(error.code));
|
||||
|
||||
toast({
|
||||
@@ -290,9 +260,7 @@ export const SignInForm = ({
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: _(msg`An unknown error occurred`),
|
||||
description: _(
|
||||
msg`We encountered an unknown error while attempting to sign you In. Please try again later.`,
|
||||
),
|
||||
description: _(msg`We encountered an unknown error while attempting to sign you In. Please try again later.`),
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
@@ -306,9 +274,7 @@ export const SignInForm = ({
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: _(msg`An unknown error occurred`),
|
||||
description: _(
|
||||
msg`We encountered an unknown error while attempting to sign you In. Please try again later.`,
|
||||
),
|
||||
description: _(msg`We encountered an unknown error while attempting to sign you In. Please try again later.`),
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
@@ -322,9 +288,7 @@ export const SignInForm = ({
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: _(msg`An unknown error occurred`),
|
||||
description: _(
|
||||
msg`We encountered an unknown error while attempting to sign you In. Please try again later.`,
|
||||
),
|
||||
description: _(msg`We encountered an unknown error while attempting to sign you In. Please try again later.`),
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
@@ -346,14 +310,8 @@ export const SignInForm = ({
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={cn('flex w-full flex-col gap-y-4', className)}
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<fieldset
|
||||
className="flex w-full flex-col gap-y-4"
|
||||
disabled={isSubmitting || isPasskeyLoading}
|
||||
>
|
||||
<form className={cn('flex w-full flex-col gap-y-4', className)} onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting || isPasskeyLoading}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
@@ -388,10 +346,7 @@ export const SignInForm = ({
|
||||
<FormMessage />
|
||||
|
||||
<p className="mt-2 text-right">
|
||||
<Link
|
||||
to="/forgot-password"
|
||||
className="text-sm text-muted-foreground duration-200 hover:opacity-70"
|
||||
>
|
||||
<Link to="/forgot-password" className="text-muted-foreground text-sm duration-200 hover:opacity-70">
|
||||
<Trans>Forgot your password?</Trans>
|
||||
</Link>
|
||||
</p>
|
||||
@@ -412,12 +367,7 @@ export const SignInForm = ({
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
size="lg"
|
||||
loading={isSubmitting}
|
||||
className="dark:bg-documenso dark:hover:opacity-90"
|
||||
>
|
||||
<Button type="submit" size="lg" loading={isSubmitting} className="dark:bg-documenso dark:hover:opacity-90">
|
||||
{isSubmitting ? <Trans>Signing in...</Trans> : <Trans>Sign In</Trans>}
|
||||
</Button>
|
||||
|
||||
@@ -456,11 +406,7 @@ export const SignInForm = ({
|
||||
disabled={isSubmitting}
|
||||
onClick={onSignInWithMicrosoftClick}
|
||||
>
|
||||
<img
|
||||
className="mr-2 h-4 w-4"
|
||||
alt="Microsoft Logo"
|
||||
src={'/static/microsoft.svg'}
|
||||
/>
|
||||
<img className="mr-2 h-4 w-4" alt="Microsoft Logo" src={'/static/microsoft.svg'} />
|
||||
Microsoft
|
||||
</Button>
|
||||
)}
|
||||
@@ -490,16 +436,13 @@ export const SignInForm = ({
|
||||
className="border bg-background text-muted-foreground"
|
||||
onClick={onSignInWithPasskey}
|
||||
>
|
||||
{!isPasskeyLoading && <KeyRoundIcon className="-ml-1 mr-1 h-5 w-5" />}
|
||||
{!isPasskeyLoading && <KeyRoundIcon className="mr-1 -ml-1 h-5 w-5" />}
|
||||
<Trans>Passkey</Trans>
|
||||
</Button>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<Dialog
|
||||
open={isTwoFactorAuthenticationDialogOpen}
|
||||
onOpenChange={onCloseTwoFactorAuthenticationDialog}
|
||||
>
|
||||
<Dialog open={isTwoFactorAuthenticationDialogOpen} onOpenChange={onCloseTwoFactorAuthenticationDialog}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
@@ -567,11 +510,7 @@ export const SignInForm = ({
|
||||
)}
|
||||
|
||||
<DialogFooter className="mt-4">
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={onToggleTwoFactorAuthenticationMethodClick}
|
||||
>
|
||||
<Button type="button" variant="secondary" onClick={onToggleTwoFactorAuthenticationMethodClick}>
|
||||
{twoFactorAuthenticationMethod === 'totp' ? (
|
||||
<Trans>Use Backup Code</Trans>
|
||||
) : (
|
||||
@@ -579,11 +518,7 @@ export const SignInForm = ({
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
loading={isSubmitting}
|
||||
disabled={Boolean(turnstileSiteKey) && !captchaToken}
|
||||
>
|
||||
<Button type="submit" loading={isSubmitting} disabled={Boolean(turnstileSiteKey) && !captchaToken}>
|
||||
{isSubmitting ? <Trans>Signing in...</Trans> : <Trans>Sign In</Trans>}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import type { MessageDescriptor } from '@lingui/core';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TurnstileInstance } from '@marsidev/react-turnstile';
|
||||
import { Turnstile } from '@marsidev/react-turnstile';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { FaIdCardClip } from 'react-icons/fa6';
|
||||
import { FcGoogle } from 'react-icons/fc';
|
||||
import { Link, useNavigate, useSearchParams } from 'react-router';
|
||||
import { z } from 'zod';
|
||||
|
||||
import communityCardsImage from '@documenso/assets/images/community-cards.png';
|
||||
import { authClient } from '@documenso/auth/client';
|
||||
import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics';
|
||||
@@ -23,18 +8,24 @@ import { zEmail } from '@documenso/lib/utils/zod';
|
||||
import { ZPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { PasswordInput } from '@documenso/ui/primitives/password-input';
|
||||
import { SignaturePadDialog } from '@documenso/ui/primitives/signature-pad/signature-pad-dialog';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import type { MessageDescriptor } from '@lingui/core';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { TurnstileInstance } from '@marsidev/react-turnstile';
|
||||
import { Turnstile } from '@marsidev/react-turnstile';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { FaIdCardClip } from 'react-icons/fa6';
|
||||
import { FcGoogle } from 'react-icons/fc';
|
||||
import { Link, useNavigate, useSearchParams } from 'react-router';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { UserProfileTimur } from '~/components/general/user-profile-timur';
|
||||
|
||||
@@ -138,8 +129,7 @@ export const SignUpForm = ({
|
||||
} catch (err) {
|
||||
const error = AppError.parseError(err);
|
||||
|
||||
const errorMessage =
|
||||
SIGNUP_ERROR_MESSAGES[error.code] ?? SIGNUP_ERROR_MESSAGES.INVALID_REQUEST;
|
||||
const errorMessage = SIGNUP_ERROR_MESSAGES[error.code] ?? SIGNUP_ERROR_MESSAGES.INVALID_REQUEST;
|
||||
|
||||
toast({
|
||||
title: _(msg`An error occurred`),
|
||||
@@ -158,9 +148,7 @@ export const SignUpForm = ({
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: _(msg`An unknown error occurred`),
|
||||
description: _(
|
||||
msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`,
|
||||
),
|
||||
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
@@ -172,9 +160,7 @@ export const SignUpForm = ({
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: _(msg`An unknown error occurred`),
|
||||
description: _(
|
||||
msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`,
|
||||
),
|
||||
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
@@ -186,9 +172,7 @@ export const SignUpForm = ({
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: _(msg`An unknown error occurred`),
|
||||
description: _(
|
||||
msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`,
|
||||
),
|
||||
description: _(msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`),
|
||||
variant: 'destructive',
|
||||
});
|
||||
}
|
||||
@@ -220,15 +204,12 @@ export const SignUpForm = ({
|
||||
<div className="absolute -inset-8 -z-[1] bg-background/50 backdrop-blur-[2px]" />
|
||||
|
||||
<div className="relative flex h-full w-full flex-col items-center justify-evenly">
|
||||
<div className="rounded-2xl border bg-background px-4 py-1 text-sm font-medium">
|
||||
<div className="rounded-2xl border bg-background px-4 py-1 font-medium text-sm">
|
||||
<Trans>User profiles are here!</Trans>
|
||||
</div>
|
||||
|
||||
<div className="w-full max-w-md">
|
||||
<UserProfileTimur
|
||||
rows={2}
|
||||
className="rounded-2xl border border-border bg-background shadow-md"
|
||||
/>
|
||||
<UserProfileTimur rows={2} className="rounded-2xl border border-border bg-background shadow-md" />
|
||||
</div>
|
||||
|
||||
<div />
|
||||
@@ -237,14 +218,14 @@ export const SignUpForm = ({
|
||||
|
||||
<div className="relative z-10 flex min-h-[min(850px,80vh)] w-full max-w-lg flex-col rounded-xl border border-border bg-neutral-100 p-6 dark:bg-background">
|
||||
<div className="h-20">
|
||||
<h1 className="text-xl font-semibold md:text-2xl">
|
||||
<h1 className="font-semibold text-xl md:text-2xl">
|
||||
<Trans>Create a new account</Trans>
|
||||
</h1>
|
||||
|
||||
<p className="mt-2 text-xs text-muted-foreground md:text-sm">
|
||||
<p className="mt-2 text-muted-foreground text-xs md:text-sm">
|
||||
<Trans>
|
||||
Create your account and start using state-of-the-art document signing. Open and
|
||||
beautiful signing is within your grasp.
|
||||
Create your account and start using state-of-the-art document signing. Open and beautiful signing is
|
||||
within your grasp.
|
||||
</Trans>
|
||||
</p>
|
||||
</div>
|
||||
@@ -252,10 +233,7 @@ export const SignUpForm = ({
|
||||
<hr className="-mx-6 my-4" />
|
||||
|
||||
<Form {...form}>
|
||||
<form
|
||||
className="flex w-full flex-1 flex-col gap-y-4"
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<form className="flex w-full flex-1 flex-col gap-y-4" onSubmit={form.handleSubmit(onFormSubmit)}>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -316,11 +294,7 @@ export const SignUpForm = ({
|
||||
<Trans>Sign Here</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<SignaturePadDialog
|
||||
disabled={isSubmitting}
|
||||
value={value}
|
||||
onChange={(v) => onChange(v ?? '')}
|
||||
/>
|
||||
<SignaturePadDialog disabled={isSubmitting} value={value} onChange={(v) => onChange(v ?? '')} />
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
@@ -374,11 +348,7 @@ export const SignUpForm = ({
|
||||
disabled={isSubmitting}
|
||||
onClick={onSignUpWithMicrosoftClick}
|
||||
>
|
||||
<img
|
||||
className="mr-2 h-4 w-4"
|
||||
alt="Microsoft Logo"
|
||||
src={'/static/microsoft.svg'}
|
||||
/>
|
||||
<img className="mr-2 h-4 w-4" alt="Microsoft Logo" src={'/static/microsoft.svg'} />
|
||||
<Trans>Sign Up with Microsoft</Trans>
|
||||
</Button>
|
||||
)}
|
||||
@@ -397,7 +367,7 @@ export const SignUpForm = ({
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<p className="mt-4 text-sm text-muted-foreground">
|
||||
<p className="mt-4 text-muted-foreground text-sm">
|
||||
<Trans>
|
||||
Already have an account?{' '}
|
||||
<Link to="/signin" className="text-documenso-700 duration-200 hover:opacity-70">
|
||||
@@ -407,17 +377,12 @@ export const SignUpForm = ({
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<Button
|
||||
loading={form.formState.isSubmitting}
|
||||
type="submit"
|
||||
size="lg"
|
||||
className="mt-6 w-full"
|
||||
>
|
||||
<Button loading={form.formState.isSubmitting} type="submit" size="lg" className="mt-6 w-full">
|
||||
<Trans>Create account</Trans>
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
<p className="mt-6 text-xs text-muted-foreground">
|
||||
<p className="mt-6 text-muted-foreground text-xs">
|
||||
<Trans>
|
||||
By proceeding, you agree to our{' '}
|
||||
<Link
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import type { SubscriptionClaim } from '@prisma/client';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { Link } from 'react-router';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import type { TLicenseClaim } from '@documenso/lib/types/license';
|
||||
import { SUBSCRIPTION_CLAIM_FEATURE_FLAGS } from '@documenso/lib/types/subscription';
|
||||
import { ZCreateSubscriptionClaimRequestSchema } from '@documenso/trpc/server/admin-router/create-subscription-claim.types';
|
||||
@@ -20,6 +13,12 @@ import {
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import type { SubscriptionClaim } from '@prisma/client';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { Link } from 'react-router';
|
||||
import type { z } from 'zod';
|
||||
|
||||
export type SubscriptionClaimFormValues = z.infer<typeof ZCreateSubscriptionClaimRequestSchema>;
|
||||
|
||||
@@ -152,42 +151,39 @@ export const SubscriptionClaimForm = ({
|
||||
</FormLabel>
|
||||
|
||||
<div className="mt-2 space-y-2 rounded-md border p-4">
|
||||
{Object.values(SUBSCRIPTION_CLAIM_FEATURE_FLAGS).map(
|
||||
({ key, label, isEnterprise }) => {
|
||||
const isRestrictedFeature =
|
||||
isEnterprise && !licenseFlags?.[key as keyof TLicenseClaim]; // eslint-disable-line @typescript-eslint/consistent-type-assertions
|
||||
{Object.values(SUBSCRIPTION_CLAIM_FEATURE_FLAGS).map(({ key, label, isEnterprise }) => {
|
||||
const isRestrictedFeature = isEnterprise && !licenseFlags?.[key as keyof TLicenseClaim]; // eslint-disable-line @typescript-eslint/consistent-type-assertions
|
||||
|
||||
return (
|
||||
<FormField
|
||||
key={key}
|
||||
control={form.control}
|
||||
name={`flags.${key}`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2">
|
||||
<FormControl>
|
||||
<div className="flex items-center">
|
||||
<Checkbox
|
||||
id={`flag-${key}`}
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
disabled={isRestrictedFeature && !field.value} // Allow disabling of restricted features.
|
||||
/>
|
||||
return (
|
||||
<FormField
|
||||
key={key}
|
||||
control={form.control}
|
||||
name={`flags.${key}`}
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2">
|
||||
<FormControl>
|
||||
<div className="flex items-center">
|
||||
<Checkbox
|
||||
id={`flag-${key}`}
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
disabled={isRestrictedFeature && !field.value} // Allow disabling of restricted features.
|
||||
/>
|
||||
|
||||
<label
|
||||
className="ml-2 flex flex-row items-center text-sm text-muted-foreground"
|
||||
htmlFor={`flag-${key}`}
|
||||
>
|
||||
{label}
|
||||
{isRestrictedFeature && ' ¹'}
|
||||
</label>
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
)}
|
||||
<label
|
||||
className="ml-2 flex flex-row items-center text-muted-foreground text-sm"
|
||||
htmlFor={`flag-${key}`}
|
||||
>
|
||||
{label}
|
||||
{isRestrictedFeature && ' ¹'}
|
||||
</label>
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{hasRestrictedEnterpriseFeatures && (
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Textarea } from '@documenso/ui/primitives/textarea';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { Textarea } from '@documenso/ui/primitives/textarea';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
const ZSupportTicketSchema = z.object({
|
||||
subject: z.string().min(3, 'Subject is required'),
|
||||
message: z.string().min(10, 'Message must be at least 10 characters'),
|
||||
@@ -31,17 +23,11 @@ export type SupportTicketFormProps = {
|
||||
onClose?: () => void;
|
||||
};
|
||||
|
||||
export const SupportTicketForm = ({
|
||||
organisationId,
|
||||
teamId,
|
||||
onSuccess,
|
||||
onClose,
|
||||
}: SupportTicketFormProps) => {
|
||||
export const SupportTicketForm = ({ organisationId, teamId, onSuccess, onClose }: SupportTicketFormProps) => {
|
||||
const { t } = useLingui();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { mutateAsync: submitSupportTicket, isPending } =
|
||||
trpc.profile.submitSupportTicket.useMutation();
|
||||
const { mutateAsync: submitSupportTicket, isPending } = trpc.profile.submitSupportTicket.useMutation();
|
||||
|
||||
const form = useForm<TSupportTicket>({
|
||||
resolver: zodResolver(ZSupportTicketSchema),
|
||||
@@ -84,55 +70,53 @@ export const SupportTicketForm = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<fieldset disabled={isLoading} className="flex flex-col gap-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="subject"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required>
|
||||
<Trans>Subject</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<fieldset disabled={isLoading} className="flex flex-col gap-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="subject"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required>
|
||||
<Trans>Subject</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="message"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required>
|
||||
<Trans>Message</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea rows={5} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="message"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel required>
|
||||
<Trans>Message</Trans>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea rows={5} {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="mt-2 flex flex-row gap-2">
|
||||
<Button type="submit" size="sm" loading={isLoading}>
|
||||
<Trans>Submit</Trans>
|
||||
<div className="mt-2 flex flex-row gap-2">
|
||||
<Button type="submit" size="sm" loading={isLoading}>
|
||||
<Trans>Submit</Trans>
|
||||
</Button>
|
||||
{onClose && (
|
||||
<Button variant="outline" size="sm" type="button" onClick={onClose}>
|
||||
<Trans>Close</Trans>
|
||||
</Button>
|
||||
{onClose && (
|
||||
<Button variant="outline" size="sm" type="button" onClick={onClose}>
|
||||
<Trans>Close</Trans>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { ZUpdateTeamRequestSchema } from '@documenso/trpc/server/team-router/update-team.types';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
@@ -7,22 +15,6 @@ import { useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
import { ZUpdateTeamRequestSchema } from '@documenso/trpc/server/team-router/update-team.types';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
export type UpdateTeamDialogProps = {
|
||||
teamId: number;
|
||||
teamName: string;
|
||||
@@ -129,7 +121,7 @@ export const TeamUpdateForm = ({ teamId, teamName, teamUrl }: UpdateTeamDialogPr
|
||||
<Input className="bg-background" {...field} />
|
||||
</FormControl>
|
||||
{!form.formState.errors.url && (
|
||||
<span className="text-foreground/50 text-xs font-normal">
|
||||
<span className="font-normal text-foreground/50 text-xs">
|
||||
{field.value ? (
|
||||
`${NEXT_PUBLIC_WEBAPP_URL()}/t/${field.value}`
|
||||
) : (
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { ApiToken } from '@prisma/client';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { useCopyToClipboard } from '@documenso/lib/client-only/hooks/use-copy-to-clipboard';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { trpc } from '@documenso/trpc/react';
|
||||
@@ -27,15 +15,19 @@ import {
|
||||
FormMessage,
|
||||
} from '@documenso/ui/primitives/form/form';
|
||||
import { Input } from '@documenso/ui/primitives/input';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@documenso/ui/primitives/select';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
|
||||
import { Switch } from '@documenso/ui/primitives/switch';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import type { ApiToken } from '@prisma/client';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { match } from 'ts-pattern';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { useCurrentTeam } from '~/providers/team';
|
||||
|
||||
@@ -129,10 +121,7 @@ export const ApiTokenForm = ({ className, tokens }: ApiTokenFormProps) => {
|
||||
const error = AppError.parseError(err);
|
||||
|
||||
const errorMessage = match(error.code)
|
||||
.with(
|
||||
AppErrorCode.UNAUTHORIZED,
|
||||
() => msg`You do not have permission to create a token for this team.`,
|
||||
)
|
||||
.with(AppErrorCode.UNAUTHORIZED, () => msg`You do not have permission to create a token for this team.`)
|
||||
.otherwise(() => msg`Something went wrong. Please try again later.`);
|
||||
|
||||
toast({
|
||||
@@ -148,10 +137,7 @@ export const ApiTokenForm = ({ className, tokens }: ApiTokenFormProps) => {
|
||||
<div className={cn(className)}>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<fieldset
|
||||
className="mt-6 flex w-full flex-col gap-4"
|
||||
disabled={form.formState.isSubmitting}
|
||||
>
|
||||
<fieldset className="mt-6 flex w-full flex-col gap-4" disabled={form.formState.isSubmitting}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="tokenName"
|
||||
@@ -168,10 +154,7 @@ export const ApiTokenForm = ({ className, tokens }: ApiTokenFormProps) => {
|
||||
</div>
|
||||
|
||||
<FormDescription className="text-xs italic">
|
||||
<Trans>
|
||||
Please enter a meaningful name for your token. This will help you identify it
|
||||
later.
|
||||
</Trans>
|
||||
<Trans>Please enter a meaningful name for your token. This will help you identify it later.</Trans>
|
||||
</FormDescription>
|
||||
|
||||
<FormMessage />
|
||||
@@ -225,11 +208,7 @@ export const ApiTokenForm = ({ className, tokens }: ApiTokenFormProps) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
className="hidden md:inline-flex"
|
||||
loading={form.formState.isSubmitting}
|
||||
>
|
||||
<Button type="submit" className="hidden md:inline-flex" loading={form.formState.isSubmitting}>
|
||||
<Trans>Create token</Trans>
|
||||
</Button>
|
||||
|
||||
@@ -243,35 +222,32 @@ export const ApiTokenForm = ({ className, tokens }: ApiTokenFormProps) => {
|
||||
</Form>
|
||||
|
||||
<AnimatePresence>
|
||||
{newlyCreatedToken &&
|
||||
tokens &&
|
||||
tokens.find((token) => token.id === newlyCreatedToken.id) && (
|
||||
<motion.div
|
||||
className="mt-8"
|
||||
initial={{ opacity: 0, y: -40 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 40 }}
|
||||
>
|
||||
<Card gradient>
|
||||
<CardContent className="p-4">
|
||||
<p className="mt-2 text-sm text-muted-foreground">
|
||||
<Trans>
|
||||
Your token was created successfully! Make sure to copy it because you won't be
|
||||
able to see it again!
|
||||
</Trans>
|
||||
</p>
|
||||
{newlyCreatedToken && tokens && tokens.find((token) => token.id === newlyCreatedToken.id) && (
|
||||
<motion.div
|
||||
className="mt-8"
|
||||
initial={{ opacity: 0, y: -40 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 40 }}
|
||||
>
|
||||
<Card gradient>
|
||||
<CardContent className="p-4">
|
||||
<p className="mt-2 text-muted-foreground text-sm">
|
||||
<Trans>
|
||||
Your token was created successfully! Make sure to copy it because you won't be able to see it again!
|
||||
</Trans>
|
||||
</p>
|
||||
|
||||
<p className="my-4 rounded-md bg-muted-foreground/10 px-2.5 py-1 font-mono text-sm">
|
||||
{newlyCreatedToken.token}
|
||||
</p>
|
||||
<p className="my-4 rounded-md bg-muted-foreground/10 px-2.5 py-1 font-mono text-sm">
|
||||
{newlyCreatedToken.token}
|
||||
</p>
|
||||
|
||||
<Button variant="outline" onClick={() => void copyToken(newlyCreatedToken.token)}>
|
||||
<Trans>Copy token</Trans>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
)}
|
||||
<Button variant="outline" onClick={() => void copyToken(newlyCreatedToken.token)}>
|
||||
<Trans>Copy token</Trans>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user