diff --git a/apps/marketing/src/app/(marketing)/layout.tsx b/apps/marketing/src/app/(marketing)/layout.tsx index 75baefd99..ab9de03d5 100644 --- a/apps/marketing/src/app/(marketing)/layout.tsx +++ b/apps/marketing/src/app/(marketing)/layout.tsx @@ -2,8 +2,10 @@ import React, { useEffect, useState } from 'react'; +import Image from 'next/image'; import { usePathname } from 'next/navigation'; +import backgroundPattern from '@documenso/assets/images/background-lw-2.png'; import { cn } from '@documenso/ui/lib/utils'; import { AnnouncementBar } from '@documenso/ui/primitives/announcement-bar'; @@ -39,7 +41,14 @@ export default function MarketingLayout({ children }: MarketingLayoutProps) { 'bg-background/50 backdrop-blur-md': scrollY > 5, })} > - +
+ background pattern +
+
diff --git a/apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx b/apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx index ee123d7ad..b80b2fe8c 100644 --- a/apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx +++ b/apps/marketing/src/components/(marketing)/faster-smarter-beautiful-bento.tsx @@ -1,4 +1,4 @@ -import { HTMLAttributes } from 'react'; +import type { HTMLAttributes } from 'react'; import Image from 'next/image'; diff --git a/apps/web/src/app/(dashboard)/documents/page.tsx b/apps/web/src/app/(dashboard)/documents/page.tsx index 67f432a13..487378823 100644 --- a/apps/web/src/app/(dashboard)/documents/page.tsx +++ b/apps/web/src/app/(dashboard)/documents/page.tsx @@ -1,7 +1,10 @@ import type { Metadata } from 'next'; +import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session'; + import type { DocumentsPageViewProps } from './documents-page-view'; import { DocumentsPageView } from './documents-page-view'; +import { PublicProfileIntro } from './username-claim/public-profile-intro'; export type DocumentsPageProps = { searchParams?: DocumentsPageViewProps['searchParams']; @@ -11,6 +14,12 @@ export const metadata: Metadata = { title: 'Documents', }; -export default function DocumentsPage({ searchParams = {} }: DocumentsPageProps) { - return ; +export default async function DocumentsPage({ searchParams = {} }: DocumentsPageProps) { + const { user } = await getRequiredServerComponentSession(); + return ( + <> + + + + ); } diff --git a/apps/web/src/app/(dashboard)/documents/username-claim/public-profile-intro.tsx b/apps/web/src/app/(dashboard)/documents/username-claim/public-profile-intro.tsx new file mode 100644 index 000000000..c14f6c99d --- /dev/null +++ b/apps/web/src/app/(dashboard)/documents/username-claim/public-profile-intro.tsx @@ -0,0 +1,225 @@ +'use client'; + +import React, { useRef, useState } from 'react'; + +import { zodResolver } from '@hookform/resolvers/zod'; +import { BadgeCheck, File } from 'lucide-react'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; + +import Lucas from '@documenso/assets/images/Lucas.png'; +import Timur from '@documenso/assets/images/Timur.png'; +import type { User } from '@documenso/prisma/client'; +import { TRPCClientError } from '@documenso/trpc/client'; +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 { Card, CardHeader } from '@documenso/ui/primitives/card'; +import { + Dialog, + DialogContent, + DialogDescription, + 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 { Skeleton } from '@documenso/ui/primitives/skeleton'; +import { useToast } from '@documenso/ui/primitives/use-toast'; + +export const ZPublicProfileFormSchema = z.object({ + profileURL: z.string().trim().min(1, { message: 'Please enter a valid URL slug.' }), +}); + +export type TPublicProfileFormSchema = z.infer; + +export type PublicProfileIntroProps = { + user: User; +}; + +export const PublicProfileIntro = ({ user }: PublicProfileIntroProps) => { + const form = useForm({ + values: { + profileURL: user.profileURL || '', + }, + resolver: zodResolver(ZPublicProfileFormSchema), + }); + const textRef = useRef(null); + + const { toast } = useToast(); + const { mutateAsync: updatePublicProfile } = trpc.profile.updatePublicProfile.useMutation(); + const isSaving = form.formState.isSubmitting; + + const isProfileURLClaimed = user.profileURL ? false : true; + const [showClaimingDialog, setShowClaimingDialog] = useState(isProfileURLClaimed); + const [showClaimedDialog, setShowClaimedDialog] = useState(false); + + const onFormSubmit = async ({ profileURL }: TPublicProfileFormSchema) => { + try { + await updatePublicProfile({ + profileURL, + }); + setShowClaimingDialog(false); + setShowClaimedDialog(true); + } catch (err) { + if (err instanceof TRPCClientError && err.data?.code === 'BAD_REQUEST') { + toast({ + title: 'An error occurred', + description: err.message, + variant: 'destructive', + }); + } else { + toast({ + title: 'An unknown error occurred', + variant: 'destructive', + description: + 'We encountered an unknown error while attempting to save your details. Please try again later.', + }); + } + } + }; + + return ( + <> + + + + + Introducing public profile! + + + Reserve your Documenso public profile username + + + + + + + documenso.com/u/timur + + + + Timur + +
+ Timur Ercan +
+ + Hey I’m Timur
Pick any of the following agreements below and start signing to + get started +
+
+ + Documents +
+
+
+ +
+ NDA.pdf + + Like to discuss about my work? + +
+
+ +
+
+
+ +
+ +
+ ( + + Public profile URL + + <> + +
+ + + documenso.com/u/ + + +
+ +
+ +
+ )} + /> +
+ +
+ +
+
+ +
+
+ + + + All set! + + We will let you know as soon as this feature is launched + + + + + + + documenso.com/u/lucas + + + + Timur + +
+ Lucas Smith +
+
+ + +
+
+ + Documents +
+
+
+ +
+ NDA.pdf + + Like to discuss about my work? + +
+
+ +
+
+
+
+
+ + ); +}; diff --git a/apps/web/src/app/(dashboard)/settings/public-profile/page.tsx b/apps/web/src/app/(dashboard)/settings/public-profile/page.tsx index ddba9386e..bcac9471a 100644 --- a/apps/web/src/app/(dashboard)/settings/public-profile/page.tsx +++ b/apps/web/src/app/(dashboard)/settings/public-profile/page.tsx @@ -1,30 +1,30 @@ import * as React from 'react'; import type { Metadata } from 'next'; - -import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session'; -import { Switch } from '@documenso/ui/primitives/switch'; +import Link from 'next/link'; import { SettingsHeader } from '~/components/(dashboard)/settings/layout/header'; -import { PublicProfileForm } from '~/components/forms/public-profile'; export const metadata: Metadata = { title: 'Public Profile', }; -export default async function PublicProfilePage() { - const { user } = await getRequiredServerComponentSession(); - +export default function PublicProfilePage() { return ( <> } + subtitle="" className="max-w-xl" + titleChildren={ + + Coming soon! + + } /> - - ); } diff --git a/apps/web/src/app/(unauthenticated)/signin/layout.tsx b/apps/web/src/app/(unauthenticated)/signin/layout.tsx index 2524e7b5d..6bea6e7ab 100644 --- a/apps/web/src/app/(unauthenticated)/signin/layout.tsx +++ b/apps/web/src/app/(unauthenticated)/signin/layout.tsx @@ -20,7 +20,7 @@ export default function SignInLayout({ children }: SignInLayoutProps) { background pattern
diff --git a/apps/web/src/app/(unauthenticated)/signup/layout.tsx b/apps/web/src/app/(unauthenticated)/signup/layout.tsx new file mode 100644 index 000000000..2f75e0617 --- /dev/null +++ b/apps/web/src/app/(unauthenticated)/signup/layout.tsx @@ -0,0 +1,26 @@ +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 = { + children: React.ReactNode; +}; + +export default function SignUpLayout({ children }: SignUpLayoutProps) { + return ( + <> + +
+
+ + +
{children}
+
+
+
+ + ); +} diff --git a/apps/web/src/app/(unauthenticated)/signup/page.tsx b/apps/web/src/app/(unauthenticated)/signup/page.tsx index ed7477041..a475e6064 100644 --- a/apps/web/src/app/(unauthenticated)/signup/page.tsx +++ b/apps/web/src/app/(unauthenticated)/signup/page.tsx @@ -9,8 +9,6 @@ import { decryptSecondaryData } from '@documenso/lib/server-only/crypto/decrypt' import { SignUpForm } from '~/components/forms/signup'; -import SignUpLayout from '../signup-layout'; - export const metadata: Metadata = { title: 'Sign Up', }; @@ -36,28 +34,26 @@ export default function SignUpPage({ searchParams }: SignUpPageProps) { } return ( - - <> -

Create a new account

+ <> +

Create a new account

-

- 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. +

- + -

- Already have an account?{' '} - - Sign in instead - -

- -
+

+ Already have an account?{' '} + + Sign in instead + +

+ ); } diff --git a/apps/web/src/components/(dashboard)/claim-username-card/claim-username-card.tsx b/apps/web/src/components/(dashboard)/claim-username-card/claim-username-card.tsx new file mode 100644 index 000000000..d215e91f0 --- /dev/null +++ b/apps/web/src/components/(dashboard)/claim-username-card/claim-username-card.tsx @@ -0,0 +1,93 @@ +'use client'; + +import React from 'react'; + +import Image from 'next/image'; + +import { BadgeCheck, File } from 'lucide-react'; + +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'; +import { Avatar, AvatarFallback, AvatarImage } from '@documenso/ui/primitives/avatar'; +import { Button } from '@documenso/ui/primitives/button'; +import { Card, CardFooter, CardHeader } from '@documenso/ui/primitives/card'; + +export default function ClaimUsernameCard() { + const onSignUpClick = () => {}; + return ( +
+
+ background pattern +
+ + + + documenso.com/u/timur + + + + Timur + +
+ Timur Ercan +
+ + Hey I’m Timur
Pick any of the following agreements below and start signing to get + started +
+
+ + Documents +
+
+
+ +
+ NDA.pdf + + Like to discuss about my work? + +
+
+ +
+
+
+
+ +
+ NDA.pdf + + Like to discuss about my work? + +
+
+ +
+
+ + + +
+
+ ); +} diff --git a/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx b/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx index 17147305f..08e258f4b 100644 --- a/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx +++ b/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx @@ -92,7 +92,7 @@ export const DesktopNav = ({ className, ...props }: DesktopNavProps) => { )} - +
diff --git a/apps/web/src/components/(dashboard)/settings/layout/mobile-nav.tsx b/apps/web/src/components/(dashboard)/settings/layout/mobile-nav.tsx index 152eb59a6..c607fc175 100644 --- a/apps/web/src/components/(dashboard)/settings/layout/mobile-nav.tsx +++ b/apps/web/src/components/(dashboard)/settings/layout/mobile-nav.tsx @@ -95,7 +95,7 @@ export const MobileNav = ({ className, ...props }: MobileNavProps) => { )} - + diff --git a/apps/web/src/components/forms/public-profile.tsx b/apps/web/src/components/forms/public-profile.tsx deleted file mode 100644 index 5ceb2c6a5..000000000 --- a/apps/web/src/components/forms/public-profile.tsx +++ /dev/null @@ -1,165 +0,0 @@ -'use client'; - -import { useRef } from 'react'; - -import { useRouter } from 'next/navigation'; - -import { zodResolver } from '@hookform/resolvers/zod'; -import { Copy } from 'lucide-react'; -import { useForm } from 'react-hook-form'; -import { z } from 'zod'; - -import type { User } from '@documenso/prisma/client'; -import { TRPCClientError } from '@documenso/trpc/client'; -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 { Textarea } from '@documenso/ui/primitives/textarea'; -import { useToast } from '@documenso/ui/primitives/use-toast'; - -export const ZPublicProfileFormSchema = z.object({ - profileURL: z.string().trim().min(1, { message: 'Please enter a valid URL slug.' }), - profileBio: z - .string() - .max(256, { message: 'Profile bio must not exceed 256 characters' }) - .optional(), -}); - -export type TPublicProfileFormSchema = z.infer; - -export type PublicProfileFormProps = { - className?: string; - user: User; -}; - -export const PublicProfileForm = ({ user, className }: PublicProfileFormProps) => { - const textRef = useRef(null); - - const { toast } = useToast(); - const router = useRouter(); - - const form = useForm({ - values: { - profileURL: user.profileURL || '', - }, - resolver: zodResolver(ZPublicProfileFormSchema), - }); - - const isSaving = form.formState.isSubmitting; - - const { mutateAsync: updatePublicProfile, data: profileURL } = - trpc.profile.updatePublicProfile.useMutation(); - - const copyTextToClipboard = async () => { - if (textRef.current) { - try { - await navigator.clipboard.writeText(textRef.current.textContent || ''); - } catch (err) { - console.log('Failed to copy: ', err); - } - } - }; - - const onFormSubmit = async ({ profileURL, profileBio }: TPublicProfileFormSchema) => { - try { - await updatePublicProfile({ - profileURL, - profileBio: profileBio || '', - }); - - toast({ - title: 'Public profile updated', - description: 'Your public profile has been updated successfully.', - duration: 5000, - }); - - router.refresh(); - } catch (err) { - if (err instanceof TRPCClientError && err.data?.code === 'BAD_REQUEST') { - toast({ - title: 'An error occurred', - description: err.message, - variant: 'destructive', - }); - } else { - toast({ - title: 'An unknown error occurred', - variant: 'destructive', - description: - 'We encountered an unknown error while attempting to save your details. Please try again later.', - }); - } - } - }; - - return ( -
- -
- ( - - Public profile URL - - <> - - {profileURL && ( - - - {profileURL} - - - - )} - - - - - )} - /> - - ( - - Bio - -