mirror of
https://github.com/documenso/documenso.git
synced 2025-11-16 17:51:49 +10:00
feat: updated ui items
Signed-off-by: Adithya Krishna <adithya@documenso.com>
This commit is contained in:
@ -2,11 +2,14 @@
|
||||
|
||||
import React, { useRef, useState } from 'react';
|
||||
|
||||
import Image from 'next/image';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { BadgeCheck, File } from 'lucide-react';
|
||||
import { File } from 'lucide-react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
|
||||
import Check from '@documenso/assets/Check.svg';
|
||||
import Lucas from '@documenso/assets/images/Lucas.png';
|
||||
import Timur from '@documenso/assets/images/Timur.png';
|
||||
import type { User } from '@documenso/prisma/client';
|
||||
@ -60,7 +63,7 @@ export const PublicProfileIntro = ({ user }: PublicProfileIntroProps) => {
|
||||
|
||||
const isProfileURLClaimed = user.profileURL ? false : true;
|
||||
const [showClaimingDialog, setShowClaimingDialog] = useState(isProfileURLClaimed);
|
||||
const [showClaimedDialog, setShowClaimedDialog] = useState(false);
|
||||
const [showClaimedDialog, setShowClaimedDialog] = useState(true);
|
||||
|
||||
const onFormSubmit = async ({ profileURL }: TPublicProfileFormSchema) => {
|
||||
try {
|
||||
@ -92,40 +95,38 @@ export const PublicProfileIntro = ({ user }: PublicProfileIntroProps) => {
|
||||
<Dialog open={showClaimingDialog} onOpenChange={setShowClaimingDialog}>
|
||||
<DialogContent position="center" className="pb-4">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="font-semi-bold text-center text-xl">
|
||||
<DialogTitle className="font-semi-bold text-center text-2xl">
|
||||
Introducing public profile!
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-center">
|
||||
<DialogDescription className="text-muted-foreground/60 text-center text-sm">
|
||||
Reserve your Documenso public profile username
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<Card className="relative px-6 py-6">
|
||||
<Card className="flex flex-col items-center px-6 py-6">
|
||||
<code className="bg-muted rounded-md px-1 py-1 text-sm">
|
||||
<span>documenso.com/u/timur</span>
|
||||
</code>
|
||||
<Avatar className="dark:border-border mt-2 h-12 w-12 border-2 border-solid border-white">
|
||||
<AvatarImage className="AvatarImage" src={Timur.src} alt="Timur" />
|
||||
<AvatarFallback className="text-xs text-gray-400">Timur</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-row gap-x-2">
|
||||
Timur Ercan <BadgeCheck fill="#A2E771" />
|
||||
</div>
|
||||
<span className="text-center">
|
||||
Hey I’m Timur <br /> Pick any of the following agreements below and start signing to
|
||||
get started
|
||||
</span>
|
||||
</Card>
|
||||
<Card className="mt-2 items-center">
|
||||
<CardHeader className="p-2">Documents</CardHeader>
|
||||
<Card className="relative flex flex-col items-center border-none bg-gray-50 px-6 py-6 pb-0 shadow-none">
|
||||
<code className="rounded-md border-2 border-gray-200 px-1 py-1 text-sm">
|
||||
<span>documenso.com/u/timur</span>
|
||||
</code>
|
||||
<Avatar className="dark:border-border mt-2 h-20 w-20 border-2 border-solid border-white bg-white">
|
||||
<AvatarImage className="AvatarImage" src={Timur.src} alt="Timur" />
|
||||
<AvatarFallback className="text-xs text-gray-400">Timur</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-row gap-x-2">
|
||||
Timur Ercan <Image alt="Check" src={Check} />
|
||||
</div>
|
||||
<span className="text-muted-foreground/60 text-center">
|
||||
Hey I’m Timur <br /> Pick any of the following agreements below and start signing to
|
||||
get started
|
||||
</span>
|
||||
<Card className="bg mt-2 w-full items-center shadow-none">
|
||||
<CardHeader className="p-4 text-gray-500">Documents</CardHeader>
|
||||
<hr className="mb-2" />
|
||||
<div className="mb-2 flex flex-row items-center justify-between">
|
||||
<div className="flex flex-row items-center gap-x-2">
|
||||
<File className="ml-3" />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-md">NDA.pdf</span>
|
||||
<span className="text-muted-foregroun mt-0.5 text-xs">
|
||||
<span className="text-muted-foreground mt-0.5 text-xs">
|
||||
Like to discuss about my work?
|
||||
</span>
|
||||
</div>
|
||||
@ -135,6 +136,12 @@ export const PublicProfileIntro = ({ user }: PublicProfileIntroProps) => {
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<div
|
||||
className="fade-overlay bg-black-100 absolute bottom-0 h-1/4 w-full"
|
||||
style={{
|
||||
background: `linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, white 75%, white 100%)`,
|
||||
}}
|
||||
></div>
|
||||
</Card>
|
||||
|
||||
<Form {...form}>
|
||||
@ -173,7 +180,7 @@ export const PublicProfileIntro = ({ user }: PublicProfileIntroProps) => {
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<Dialog open={showClaimedDialog} onOpenChange={setShowClaimedDialog}>
|
||||
<Dialog open={false} onOpenChange={setShowClaimedDialog}>
|
||||
<DialogContent position="center" className="pb-4">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="font-semi-bold text-center text-xl">All set!</DialogTitle>
|
||||
@ -192,7 +199,7 @@ export const PublicProfileIntro = ({ user }: PublicProfileIntroProps) => {
|
||||
<AvatarFallback className="text-xs text-gray-400">Timur</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-row gap-x-2">
|
||||
Lucas Smith <BadgeCheck fill="#A2E771" />
|
||||
Lucas Smith <Image alt="Check" src={Check} />
|
||||
</div>
|
||||
<div className="flex inline-flex h-full w-full flex-col items-center justify-center gap-3 py-2">
|
||||
<Skeleton className="w-75 h-4 animate-none rounded-full" />
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Card } from '@documenso/ui/primitives/card';
|
||||
|
||||
import ClaimUsernameCard from '../../../components/(dashboard)/claim-username-card/claim-username-card';
|
||||
import { NewHeader } from '../../../components/(dashboard)/layout/new/new-header';
|
||||
|
||||
type SignUpLayoutProps = {
|
||||
@ -13,13 +10,11 @@ export default function SignUpLayout({ children }: SignUpLayoutProps) {
|
||||
return (
|
||||
<>
|
||||
<NewHeader className="mx-auto h-16 max-w-screen-xl px-4 md:h-20 lg:px-8" />
|
||||
<main className="bg-sand-100 flex flex-col items-center justify-center overflow-hidden px-4 py-12 md:p-12 lg:p-[7.2rem]">
|
||||
<div className="flex w-full items-center gap-x-8">
|
||||
<ClaimUsernameCard />
|
||||
<Card className="px-6 py-6">
|
||||
<div className="w-full">{children}</div>
|
||||
</Card>
|
||||
</div>
|
||||
<main
|
||||
className="bg-sand-100 scale-90 items-center justify-center px-4 md:h-20 lg:mx-28 lg:px-8"
|
||||
style={{ height: 'calc(100vh - 80px)' }}
|
||||
>
|
||||
<div className="grid grid-cols-12 gap-y-8 overflow-hidden p-2 lg:gap-x-8">{children}</div>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { IS_GOOGLE_SSO_ENABLED } from '@documenso/lib/constants/auth';
|
||||
import { decryptSecondaryData } from '@documenso/lib/server-only/crypto/decrypt';
|
||||
|
||||
import { SignUpForm } from '~/components/forms/signup';
|
||||
@ -31,25 +29,7 @@ export default function SignUpPage({ searchParams }: SignUpPageProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className="text-3xl font-semibold">Create a new account</h1>
|
||||
|
||||
<p className="text-muted-foreground/60 mt-2 text-sm">
|
||||
Create your account and start using state-of-the-art document signing. Open and beautiful
|
||||
signing is within your grasp.
|
||||
</p>
|
||||
|
||||
<SignUpForm
|
||||
className="mt-1"
|
||||
initialEmail={email || undefined}
|
||||
isGoogleSSOEnabled={IS_GOOGLE_SSO_ENABLED}
|
||||
/>
|
||||
|
||||
<p className="text-muted-foreground mt-6 text-center text-sm">
|
||||
Already have an account?{' '}
|
||||
<Link href="/signin" className="text-primary duration-200 hover:opacity-70">
|
||||
Sign in instead
|
||||
</Link>
|
||||
</p>
|
||||
<SignUpForm className="mt-1" initialEmail={email || undefined} isGoogleSSOEnabled={true} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -4,8 +4,9 @@ import React from 'react';
|
||||
|
||||
import Image from 'next/image';
|
||||
|
||||
import { BadgeCheck, File } from 'lucide-react';
|
||||
import { File } from 'lucide-react';
|
||||
|
||||
import Check from '@documenso/assets/Check.svg';
|
||||
import Timur from '@documenso/assets/images/Timur.png';
|
||||
import backgroundPattern from '@documenso/assets/images/background-blog-og.png';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
@ -13,68 +14,71 @@ import { Avatar, AvatarFallback, AvatarImage } from '@documenso/ui/primitives/av
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Card, CardFooter, CardHeader } from '@documenso/ui/primitives/card';
|
||||
|
||||
export default function ClaimUsernameCard() {
|
||||
type ClaimUsernameCardProps = {
|
||||
className: string;
|
||||
};
|
||||
|
||||
export default function ClaimUsernameCard({ className }: ClaimUsernameCardProps) {
|
||||
const onSignUpClick = () => {};
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="absolute -inset-96 -z-[1] flex items-center justify-center bg-contain opacity-50">
|
||||
<div className={cn('relative', className)}>
|
||||
<Card className={cn('relative h-full overflow-hidden px-16 py-16 shadow-none')}>
|
||||
<Image
|
||||
src={backgroundPattern}
|
||||
alt="background pattern"
|
||||
className="dark:brightness-95 dark:contrast-[100%] dark:invert"
|
||||
className="absolute left-0 top-0 h-full w-full bg-cover opacity-50 dark:brightness-95 dark:contrast-[100%] dark:invert"
|
||||
/>
|
||||
</div>
|
||||
<Card className={cn('relative px-16 py-16')}>
|
||||
<Card className="flex flex-col items-center px-6 py-6">
|
||||
<code className="bg-muted rounded-md px-1 py-1 text-sm">
|
||||
<Card className="mt-28 flex flex-col items-center px-6 py-6 shadow-none">
|
||||
<code className="rounded-md border-2 border-gray-200 px-1 py-1 text-sm">
|
||||
<span>documenso.com/u/timur</span>
|
||||
</code>
|
||||
<Avatar className="dark:border-border mt-2 h-12 w-12 border-2 border-solid border-white">
|
||||
<Avatar className="dark:border-border mt-2 h-20 w-20 border-2 border-solid border-white">
|
||||
<AvatarImage className="AvatarImage" src={Timur.src} alt="Timur" />
|
||||
<AvatarFallback className="text-xs text-gray-400">Timur</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-row gap-x-2">
|
||||
Timur Ercan <BadgeCheck fill="#A2E771" />
|
||||
<div className="mb-2 flex flex-row gap-x-2">
|
||||
Timur Ercan <Image alt="Check" src={Check} />
|
||||
</div>
|
||||
<span className="text-center">
|
||||
Hey I’m Timur <br /> Pick any of the following agreements below and start signing to get
|
||||
started
|
||||
<span className="text-muted-foreground/60 text-center ">
|
||||
Hey I’m Timur <br /> Pick any of the following agreements below and <br /> start signing
|
||||
to get started
|
||||
</span>
|
||||
</Card>
|
||||
<Card className="mt-2 items-center">
|
||||
<CardHeader className="p-2">Documents</CardHeader>
|
||||
<hr className="mb-2" />
|
||||
<div className="mb-2 flex flex-row items-center justify-between">
|
||||
<div className="flex flex-row items-center gap-x-2">
|
||||
<File className="ml-3" />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-md">NDA.pdf</span>
|
||||
<span className="text-muted-foregroun mt-0.5 text-xs">
|
||||
Like to discuss about my work?
|
||||
</span>
|
||||
<Card className="mt-2 w-full items-center shadow-none">
|
||||
<CardHeader className="p-4 text-gray-500">Documents</CardHeader>
|
||||
<hr className="mb-2" />
|
||||
<div className="mb-2 flex flex-row items-center justify-between">
|
||||
<div className="flex flex-row items-center gap-x-2">
|
||||
<File className="text-muted-foreground ml-3" />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-md">NDA.pdf</span>
|
||||
<span className="text-muted-foreground mt-0.5 text-xs">
|
||||
Like to discuss about my work?
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button className="mr-3 px-6" variant="default">
|
||||
Sign
|
||||
</Button>
|
||||
</div>
|
||||
<Button className="mr-3" variant="default">
|
||||
Sign
|
||||
</Button>
|
||||
</div>
|
||||
<hr className="mb-2" />
|
||||
<div className="mb-2 flex flex-row items-center justify-between">
|
||||
<div className="flex flex-row items-center gap-x-2">
|
||||
<File className="ml-3" />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-md">NDA.pdf</span>
|
||||
<span className="text-muted-foregroun mt-0.5 text-xs">
|
||||
Like to discuss about my work?
|
||||
</span>
|
||||
<hr className="mb-2" />
|
||||
<div className="mb-2 flex flex-row items-center justify-between">
|
||||
<div className="flex flex-row items-center gap-x-2">
|
||||
<File className="text-muted-foreground ml-3" />
|
||||
<div className="flex flex-col">
|
||||
<span className="text-md">NDA.pdf</span>
|
||||
<span className="text-muted-foreground mt-0.5 text-xs">
|
||||
Like to discuss about my work?
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button className="mr-3 px-6" variant="default">
|
||||
Sign
|
||||
</Button>
|
||||
</div>
|
||||
<Button className="mr-3" variant="default">
|
||||
Sign
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</Card>
|
||||
<CardFooter className="mt-20 justify-center">
|
||||
|
||||
<CardFooter className="mt-32 justify-center">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
@ -14,6 +17,7 @@ import { trpc } from '@documenso/trpc/react';
|
||||
import { ZPasswordSchema } from '@documenso/trpc/server/auth-router/schema';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
import { Card } from '@documenso/ui/primitives/card';
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
@ -27,6 +31,16 @@ import { PasswordInput } from '@documenso/ui/primitives/password-input';
|
||||
import { SignaturePad } from '@documenso/ui/primitives/signature-pad';
|
||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||
|
||||
import ClaimUsernameCard from '../(dashboard)/claim-username-card/claim-username-card';
|
||||
|
||||
export const STEP = {
|
||||
SIGNUP: 'SIGNUP',
|
||||
CLAIM: 'CLAIM',
|
||||
} as const;
|
||||
|
||||
type StepKeys = keyof typeof STEP;
|
||||
type StepValues = (typeof STEP)[StepKeys];
|
||||
|
||||
const SIGN_UP_REDIRECT_PATH = '/documents';
|
||||
|
||||
export const ZSignUpFormSchema = z
|
||||
@ -35,6 +49,7 @@ export const ZSignUpFormSchema = z
|
||||
email: z.string().email().min(1),
|
||||
password: ZPasswordSchema,
|
||||
signature: z.string().min(1, { message: 'We need your signature to sign documents' }),
|
||||
profileURL: z.string().trim().min(1, { message: 'Please enter a valid URL slug.' }),
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
@ -58,6 +73,7 @@ export const SignUpForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
||||
const { toast } = useToast();
|
||||
const analytics = useAnalytics();
|
||||
const searchParams = useSearchParams();
|
||||
const [step, setStep] = useState<StepValues>(STEP.SIGNUP);
|
||||
|
||||
let src: string | null = null;
|
||||
if (searchParams) {
|
||||
@ -70,18 +86,33 @@ export const SignUpForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
||||
email: initialEmail ?? '',
|
||||
password: '',
|
||||
signature: '',
|
||||
profileURL: '',
|
||||
},
|
||||
resolver: zodResolver(ZSignUpFormSchema),
|
||||
});
|
||||
|
||||
const isSubmitting = form.formState.isSubmitting;
|
||||
const isValid = form.formState.isValid;
|
||||
|
||||
const signature = form.watch('signature');
|
||||
|
||||
const { mutateAsync: signup } = trpc.auth.signup.useMutation();
|
||||
const { mutateAsync: updatePublicProfile } = trpc.profile.updatePublicProfile.useMutation();
|
||||
|
||||
const onFormSubmit = async ({ name, email, password, signature }: TSignUpFormSchema) => {
|
||||
const onFormSubmit = async ({
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
signature,
|
||||
profileURL,
|
||||
}: TSignUpFormSchema) => {
|
||||
try {
|
||||
await signup({ name, email, password, signature });
|
||||
|
||||
await updatePublicProfile({
|
||||
profileURL,
|
||||
});
|
||||
|
||||
await signIn('credentials', {
|
||||
email,
|
||||
password,
|
||||
@ -111,6 +142,16 @@ export const SignUpForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
||||
}
|
||||
};
|
||||
|
||||
const onNextStepClick = () => {
|
||||
if (step === STEP.SIGNUP) {
|
||||
setStep(STEP.CLAIM);
|
||||
|
||||
setTimeout(() => {
|
||||
document.querySelector<HTMLElement>('#signature')?.focus();
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
const onSignUpWithGoogleClick = async () => {
|
||||
try {
|
||||
await signIn('google', { callbackUrl: SIGN_UP_REDIRECT_PATH });
|
||||
@ -124,107 +165,199 @@ export const SignUpForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
||||
}
|
||||
};
|
||||
|
||||
const stepsRemaining = useMemo(() => {
|
||||
if (step === STEP.CLAIM) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}, [step]);
|
||||
|
||||
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}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Full Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<>
|
||||
<ClaimUsernameCard className="col-span-12 gap-y-4 lg:col-span-7" />
|
||||
<Card className="col-span-12 gap-y-4 bg-gray-50 px-6 py-6 shadow-none lg:col-span-5">
|
||||
<div className="w-full">
|
||||
{step === STEP.SIGNUP && (
|
||||
<>
|
||||
<h1 className="text-3xl font-semibold">Create a new account</h1>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email Address</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="email" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<p className="text-muted-foreground/60 mt-2 text-sm">
|
||||
Create your account and start using state-of-the-art document signing. Open and
|
||||
beautiful signing is within your grasp.
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
{step === STEP.CLAIM && (
|
||||
<>
|
||||
<h1 className="text-3xl font-semibold">Claim your username now</h1>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="signature"
|
||||
render={({ field: { onChange } }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Sign Here</FormLabel>
|
||||
<FormControl>
|
||||
<SignaturePad
|
||||
className="h-36 w-full"
|
||||
disabled={isSubmitting}
|
||||
containerClassName="mt-2 rounded-lg border bg-background"
|
||||
onChange={(v) => onChange(v ?? '')}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</fieldset>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
size="lg"
|
||||
loading={isSubmitting}
|
||||
className="dark:bg-documenso dark:hover:opacity-90"
|
||||
>
|
||||
{isSubmitting ? 'Signing up...' : 'Sign Up'}
|
||||
</Button>
|
||||
|
||||
{isGoogleSSOEnabled && (
|
||||
<>
|
||||
<div className="relative flex items-center justify-center gap-x-4 py-2 text-xs uppercase">
|
||||
<div className="bg-border h-px flex-1" />
|
||||
<span className="text-muted-foreground bg-transparent">Or</span>
|
||||
<div className="bg-border h-px flex-1" />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
size="lg"
|
||||
variant={'outline'}
|
||||
className="bg-background text-muted-foreground border"
|
||||
disabled={isSubmitting}
|
||||
onClick={onSignUpWithGoogleClick}
|
||||
<p className="text-muted-foreground/60 mt-2 text-sm">
|
||||
You will get notified & be able to set up your documenso public profile when we
|
||||
launch the feature
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
<hr className="mb-6 mt-4" />
|
||||
<Form {...form}>
|
||||
<form
|
||||
className={cn('flex h-full w-full flex-col gap-y-4', className)}
|
||||
onSubmit={form.handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<FcGoogle className="mr-2 h-5 w-5" />
|
||||
Sign Up with Google
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
</Form>
|
||||
<fieldset className="flex w-full flex-col gap-y-4" disabled={isSubmitting}>
|
||||
<div className={cn(step === STEP.SIGNUP && 'hidden')}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="profileURL"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Public profile URL</FormLabel>
|
||||
<FormControl>
|
||||
<>
|
||||
<Input id="username" type="text" className="mb-2 mt-2" {...field} />
|
||||
<div className="mt-2">
|
||||
<code className="bg-muted rounded-md px-1 py-1 text-sm">
|
||||
documenso.com/u/
|
||||
</code>
|
||||
</div>
|
||||
</>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className={cn('space-y-2', step === STEP.CLAIM && 'invisible')}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Full Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" className="bg-white" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email Address</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="email" className="bg-white" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormControl>
|
||||
<PasswordInput className="bg-white" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="signature"
|
||||
render={({ field: { onChange } }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Sign Here</FormLabel>
|
||||
<FormControl>
|
||||
<SignaturePad
|
||||
id="signatureText"
|
||||
className="w-full"
|
||||
disabled={isSubmitting}
|
||||
containerClassName="mt-2 rounded-lg border bg-background"
|
||||
onChange={(v) => onChange(v ?? '')}
|
||||
height={200}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{isGoogleSSOEnabled && (
|
||||
<>
|
||||
<div className="relative flex items-center justify-center gap-x-4 py-2 text-xs uppercase">
|
||||
<div className="bg-border h-px flex-1" />
|
||||
<span className="text-muted-foreground bg-transparent">Or</span>
|
||||
<div className="bg-border h-px flex-1" />
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
size="lg"
|
||||
variant={'outline'}
|
||||
className="bg-background text-muted-foreground border"
|
||||
disabled={isSubmitting}
|
||||
onClick={onSignUpWithGoogleClick}
|
||||
>
|
||||
<FcGoogle className="mr-2 h-5 w-5" />
|
||||
Sign Up with Google
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<p className="text-muted-foreground text-left text-sm">
|
||||
Already have an account?{' '}
|
||||
<Link href="/signin" className="text-primary duration-200 hover:opacity-70">
|
||||
Sign in instead
|
||||
</Link>
|
||||
</p>
|
||||
<div className="mt-6 flex items-center justify-between">
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{isValid ? 'Claim username' : `Basic details ${stepsRemaining}/2`}
|
||||
</p>
|
||||
|
||||
<p className="text-muted-foreground block text-xs md:hidden">Minimise contract</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-background relative h-[2px] w-full">
|
||||
<div
|
||||
className={cn('bg-primary/60 absolute inset-y-0 left-0 duration-200', {
|
||||
'w-1/2': stepsRemaining === 1,
|
||||
'w-full': isValid,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
{!isValid && (
|
||||
<Button
|
||||
loading={isSubmitting}
|
||||
className="dark:bg-documenso ml-auto w-52 dark:hover:opacity-90"
|
||||
onClick={() => onNextStepClick()}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
{isValid && (
|
||||
<Button
|
||||
type="submit"
|
||||
loading={isSubmitting}
|
||||
className="dark:bg-documenso ml-auto w-52 dark:hover:opacity-90"
|
||||
>
|
||||
Complete
|
||||
</Button>
|
||||
)}
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user