From ca325cc90ba83fc3584613bfc6a97d5b4f359a7e Mon Sep 17 00:00:00 2001 From: Mythie Date: Tue, 19 Sep 2023 13:34:54 +0000 Subject: [PATCH] fix: add layout and minor updates --- .devcontainer/devcontainer.json | 46 ++++++++++------ .../(unauthenticated)/check-email/page.tsx | 36 ++++-------- .../forgot-password/page.tsx | 41 +++++--------- apps/web/src/app/(unauthenticated)/layout.tsx | 27 +++++++++ .../reset-password/[token]/page.tsx | 53 +++++++++--------- .../(unauthenticated)/reset-password/page.tsx | 36 ++++-------- .../src/app/(unauthenticated)/signin/page.tsx | 52 +++++++----------- .../src/app/(unauthenticated)/signup/page.tsx | 47 +++++----------- .../src/components/forms/forgot-password.tsx | 45 +++++---------- apps/web/src/components/forms/password.tsx | 4 +- apps/web/src/components/forms/profile.tsx | 6 +- .../src/components/forms/reset-password.tsx | 19 +++---- apps/web/src/components/forms/signin.tsx | 15 ++--- packages/email/templates/reset-password.tsx | 2 +- .../server-only/auth/send-forgot-password.ts | 4 +- .../server-only/auth/send-reset-password.ts | 8 +-- .../lib/server-only/user/forgot-password.ts | 55 +++++++++---------- .../user/get-reset-token-validity.ts | 18 ++++++ .../lib/server-only/user/reset-password.ts | 11 +--- packages/trpc/server/profile-router/router.ts | 11 +--- 20 files changed, 238 insertions(+), 298 deletions(-) create mode 100644 apps/web/src/app/(unauthenticated)/layout.tsx create mode 100644 packages/lib/server-only/user/get-reset-token-validity.ts diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 59a318b7f..a2ba921f5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,20 +1,32 @@ { - "name": "Documenso", - "image": "mcr.microsoft.com/devcontainers/base:bullseye", - "features": { - "ghcr.io/devcontainers/features/docker-in-docker:2": { - "version": "latest", - "enableNonRootDocker": "true", - "moby": "true" - }, - "ghcr.io/devcontainers/features/node:1": {} - }, + "name": "Documenso", + "image": "mcr.microsoft.com/devcontainers/base:bullseye", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": { + "version": "latest", + "enableNonRootDocker": "true", + "moby": "true" + }, + "ghcr.io/devcontainers/features/node:1": {} + }, "onCreateCommand": "./.devcontainer/on-create.sh", - "forwardPorts": [ - 3000, - 54320, - 9000, - 2500, - 1100 - ] + "forwardPorts": [3000, 54320, 9000, 2500, 1100], + "customizations": { + "vscode": { + "extensions": [ + "GitHub.vscode-pull-request-github", + "GitHub.copilot-labs", + "GitHub.copilot-chat", + "GitHub.copilot", + "aaron-bond.better-comments", + "mikestead.dotenv", + "VisualStudioExptTeam.vscodeintellicode", + "Prisma.prisma", + "bradlc.vscode-tailwindcss", + "dbaeumer.vscode-eslint", + "unifiedjs.vscode-mdx", + "esbenp.prettier-vscode" + ] + } + } } diff --git a/apps/web/src/app/(unauthenticated)/check-email/page.tsx b/apps/web/src/app/(unauthenticated)/check-email/page.tsx index 26039f4ae..fffbc44c1 100644 --- a/apps/web/src/app/(unauthenticated)/check-email/page.tsx +++ b/apps/web/src/app/(unauthenticated)/check-email/page.tsx @@ -1,34 +1,20 @@ -import Image from 'next/image'; import Link from 'next/link'; -import backgroundPattern from '~/assets/background-pattern.png'; +import { Button } from '@documenso/ui/primitives/button'; export default function ForgotPasswordPage() { return ( -
-
-
- background pattern -
+
+

Email sent!

-
-

Reset Pasword

+

+ A password reset email has been sent, if you have an account you should see it in your inbox + shortly. +

-

- Please check your email for reset instructions -

- -

- - Sign in - -

-
-
-
+ + ); } diff --git a/apps/web/src/app/(unauthenticated)/forgot-password/page.tsx b/apps/web/src/app/(unauthenticated)/forgot-password/page.tsx index af1c96e6f..4f0617f7c 100644 --- a/apps/web/src/app/(unauthenticated)/forgot-password/page.tsx +++ b/apps/web/src/app/(unauthenticated)/forgot-password/page.tsx @@ -1,38 +1,25 @@ -import Image from 'next/image'; import Link from 'next/link'; -import backgroundPattern from '~/assets/background-pattern.png'; import { ForgotPasswordForm } from '~/components/forms/forgot-password'; export default function ForgotPasswordPage() { return ( -
-
-
- background pattern -
+
+

Forgotten your password?

-
-

Forgot Password?

+

+ No worries, it happens! Enter your email and we'll email you a special link to reset your + password. +

-

- No worries, we'll send you reset instructions. -

+ - - -

- Don't have an account?{' '} - - Sign up - -

-
-
-
+

+ Remembered your password?{' '} + + Sign In + +

+ ); } diff --git a/apps/web/src/app/(unauthenticated)/layout.tsx b/apps/web/src/app/(unauthenticated)/layout.tsx new file mode 100644 index 000000000..c88b9fb2e --- /dev/null +++ b/apps/web/src/app/(unauthenticated)/layout.tsx @@ -0,0 +1,27 @@ +import React from 'react'; + +import Image from 'next/image'; + +import backgroundPattern from '~/assets/background-pattern.png'; + +type UnauthenticatedLayoutProps = { + children: React.ReactNode; +}; + +export default function UnauthenticatedLayout({ children }: UnauthenticatedLayoutProps) { + return ( +
+
+
+ background pattern +
+ +
{children}
+
+
+ ); +} diff --git a/apps/web/src/app/(unauthenticated)/reset-password/[token]/page.tsx b/apps/web/src/app/(unauthenticated)/reset-password/[token]/page.tsx index 0e8492030..04afd2c4d 100644 --- a/apps/web/src/app/(unauthenticated)/reset-password/[token]/page.tsx +++ b/apps/web/src/app/(unauthenticated)/reset-password/[token]/page.tsx @@ -1,36 +1,37 @@ -import Image from 'next/image'; import Link from 'next/link'; +import { redirect } from 'next/navigation'; + +import { getResetTokenValidity } from '@documenso/lib/server-only/user/get-reset-token-validity'; -import backgroundPattern from '~/assets/background-pattern.png'; import { ResetPasswordForm } from '~/components/forms/reset-password'; -export default function ResetPasswordPage({ params }: { params: { token: string } }) { +type ResetPasswordPageProps = { + params: { + token: string; + }; +}; + +export default async function ResetPasswordPage({ params: { token } }: ResetPasswordPageProps) { + const isValid = await getResetTokenValidity({ token }); + + if (!isValid) { + redirect('/reset-password'); + } + return ( -
-
-
- background pattern -
+
+

Reset Password

-
-

Reset Password

+

Please choose your new password

-

Please choose your new password

+ - - -

- Don't have an account?{' '} - - Sign up - -

-
-
-
+

+ Don't have an account?{' '} + + Sign up + +

+ ); } diff --git a/apps/web/src/app/(unauthenticated)/reset-password/page.tsx b/apps/web/src/app/(unauthenticated)/reset-password/page.tsx index 982fe54c4..c4f521363 100644 --- a/apps/web/src/app/(unauthenticated)/reset-password/page.tsx +++ b/apps/web/src/app/(unauthenticated)/reset-password/page.tsx @@ -1,34 +1,20 @@ -import Image from 'next/image'; import Link from 'next/link'; -import backgroundPattern from '~/assets/background-pattern.png'; +import { Button } from '@documenso/ui/primitives/button'; export default function ResetPasswordPage() { return ( -
-
-
- background pattern -
+
+

Unable to reset password

-
-

Reset Password

+

+ The token you have used to reset your password is either expired or it never existed. If you + have still forgotten your password, please request a new reset link. +

-

- The token you provided is invalid. Please try again. -

- -

- - Sign in - -

-
-
-
+ + ); } diff --git a/apps/web/src/app/(unauthenticated)/signin/page.tsx b/apps/web/src/app/(unauthenticated)/signin/page.tsx index 800ff9b9a..868b0471d 100644 --- a/apps/web/src/app/(unauthenticated)/signin/page.tsx +++ b/apps/web/src/app/(unauthenticated)/signin/page.tsx @@ -1,43 +1,33 @@ -import Image from 'next/image'; import Link from 'next/link'; -import backgroundPattern from '~/assets/background-pattern.png'; -import connections from '~/assets/card-sharing-figure.png'; import { SignInForm } from '~/components/forms/signin'; export default function SignInPage() { return ( -
-
-
- background pattern -
+
+

Sign in to your account

-
-

Sign in to your account

+

+ Welcome back, we are lucky to have you. +

-

- Welcome back, we are lucky to have you. -

+ - +

+ Don't have an account?{' '} + + Sign up + +

-

- Don't have an account?{' '} - - Sign up - -

-
- -
- documenso connections -
-
-
+

+ + Forgotten your password? + +

+ ); } diff --git a/apps/web/src/app/(unauthenticated)/signup/page.tsx b/apps/web/src/app/(unauthenticated)/signup/page.tsx index b398e6990..0d82e5c4f 100644 --- a/apps/web/src/app/(unauthenticated)/signup/page.tsx +++ b/apps/web/src/app/(unauthenticated)/signup/page.tsx @@ -1,44 +1,25 @@ -import Image from 'next/image'; import Link from 'next/link'; -import backgroundPattern from '~/assets/background-pattern.png'; -import connections from '~/assets/connections.png'; import { SignUpForm } from '~/components/forms/signup'; export default function SignUpPage() { return ( -
-
-
- background pattern -
+
+

Create a new account

-
-

Create a shiny, new Documenso 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 - -

-
- -
- documenso connections -
-
-
+

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

+ ); } diff --git a/apps/web/src/components/forms/forgot-password.tsx b/apps/web/src/components/forms/forgot-password.tsx index 1dcd0f2b1..449d346e4 100644 --- a/apps/web/src/components/forms/forgot-password.tsx +++ b/apps/web/src/components/forms/forgot-password.tsx @@ -3,14 +3,13 @@ import { useRouter } from 'next/navigation'; import { zodResolver } from '@hookform/resolvers/zod'; -import { Loader } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; -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 { FormErrorMessage } from '@documenso/ui/primitives/form/form-error-message'; import { Input } from '@documenso/ui/primitives/input'; import { Label } from '@documenso/ui/primitives/label'; import { useToast } from '@documenso/ui/primitives/use-toast'; @@ -44,33 +43,18 @@ export const ForgotPasswordForm = ({ className }: ForgotPasswordFormProps) => { const { mutateAsync: forgotPassword } = trpc.profile.forgotPassword.useMutation(); const onFormSubmit = async ({ email }: TForgotPasswordFormSchema) => { - try { - await forgotPassword({ email }); + await forgotPassword({ email }).catch(() => null); - toast({ - title: 'Reset email sent', - description: 'Your password reset mail has been sent successfully.', - duration: 5000, - }); + toast({ + title: 'Reset email sent', + description: + 'A password reset email has been sent, if you have an account you should see it in your inbox shortly.', + duration: 5000, + }); - reset(); - router.push('/check-email'); - } 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 send your email. Please try again later.', - }); - } - } + reset(); + + router.push('/check-email'); }; return ( @@ -79,17 +63,16 @@ export const ForgotPasswordForm = ({ className }: ForgotPasswordFormProps) => { onSubmit={handleSubmit(onFormSubmit)} >
-
- diff --git a/apps/web/src/components/forms/password.tsx b/apps/web/src/components/forms/password.tsx index 508579b78..dfbe77b4c 100644 --- a/apps/web/src/components/forms/password.tsx +++ b/apps/web/src/components/forms/password.tsx @@ -88,7 +88,7 @@ export const PasswordForm = ({ className }: PasswordFormProps) => { onSubmit={handleSubmit(onFormSubmit)} >
-
-