feat: web i18n (#1286)

This commit is contained in:
David Nguyen
2024-08-27 20:34:39 +09:00
committed by GitHub
parent 0829311214
commit 75c8772a02
294 changed files with 14846 additions and 2229 deletions

View File

@ -1,8 +1,13 @@
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { Button } from '@documenso/ui/primitives/button';
export default function SignatureDisclosure() {
setupI18nSSR();
return (
<div>
<article className="prose dark:prose-invert">
@ -100,7 +105,9 @@ export default function SignatureDisclosure() {
<div className="mt-8">
<Button asChild>
<Link href="/documents">Back to Documents</Link>
<Link href="/documents">
<Trans>Back to Documents</Trans>
</Link>
</Button>
</div>
</div>

View File

@ -1,6 +1,9 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { Button } from '@documenso/ui/primitives/button';
export const metadata: Metadata = {
@ -8,18 +11,26 @@ export const metadata: Metadata = {
};
export default function ForgotPasswordPage() {
setupI18nSSR();
return (
<div className="w-screen max-w-lg px-4">
<div className="w-full">
<h1 className="text-4xl font-semibold">Email sent!</h1>
<h1 className="text-4xl font-semibold">
<Trans>Email sent!</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
A password reset email has been sent, if you have an account you should see it in your
inbox shortly.
<Trans>
A password reset email has been sent, if you have an account you should see it in your
inbox shortly.
</Trans>
</p>
<Button asChild>
<Link href="/signin">Return to sign in</Link>
<Link href="/signin">
<Trans>Return to sign in</Trans>
</Link>
</Button>
</div>
</div>

View File

@ -1,6 +1,10 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { ForgotPasswordForm } from '~/components/forms/forgot-password';
export const metadata: Metadata = {
@ -8,23 +12,31 @@ export const metadata: Metadata = {
};
export default function ForgotPasswordPage() {
setupI18nSSR();
return (
<div className="w-screen max-w-lg px-4">
<div className="w-full">
<h1 className="text-3xl font-semibold">Forgot your password?</h1>
<h1 className="text-3xl font-semibold">
<Trans>Forgot your password?</Trans>
</h1>
<p className="text-muted-foreground mt-2 text-sm">
No worries, it happens! Enter your email and we'll email you a special link to reset your
password.
<Trans>
No worries, it happens! Enter your email and we'll email you a special link to reset
your password.
</Trans>
</p>
<ForgotPasswordForm className="mt-4" />
<p className="text-muted-foreground mt-6 text-center text-sm">
Remembered your password?{' '}
<Link href="/signin" className="text-primary duration-200 hover:opacity-70">
Sign In
</Link>
<Trans>
Remembered your password?{' '}
<Link href="/signin" className="text-primary duration-200 hover:opacity-70">
Sign In
</Link>
</Trans>
</p>
</div>
</div>

View File

@ -3,12 +3,15 @@ import React from 'react';
import Image from 'next/image';
import backgroundPattern from '@documenso/assets/images/background-pattern.png';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
type UnauthenticatedLayoutProps = {
children: React.ReactNode;
};
export default function UnauthenticatedLayout({ children }: UnauthenticatedLayoutProps) {
setupI18nSSR();
return (
<main className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden px-4 py-12 md:p-12 lg:p-24">
<div>

View File

@ -1,6 +1,9 @@
import Link from 'next/link';
import { redirect } from 'next/navigation';
import { Trans } from '@lingui/macro';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { getResetTokenValidity } from '@documenso/lib/server-only/user/get-reset-token-validity';
import { ResetPasswordForm } from '~/components/forms/reset-password';
@ -12,6 +15,8 @@ type ResetPasswordPageProps = {
};
export default async function ResetPasswordPage({ params: { token } }: ResetPasswordPageProps) {
setupI18nSSR();
const isValid = await getResetTokenValidity({ token });
if (!isValid) {
@ -21,17 +26,23 @@ export default async function ResetPasswordPage({ params: { token } }: ResetPass
return (
<div className="w-screen max-w-lg px-4">
<div className="w-full">
<h1 className="text-4xl font-semibold">Reset Password</h1>
<h1 className="text-4xl font-semibold">
<Trans>Reset Password</Trans>
</h1>
<p className="text-muted-foreground mt-2 text-sm">Please choose your new password </p>
<p className="text-muted-foreground mt-2 text-sm">
<Trans>Please choose your new password</Trans>
</p>
<ResetPasswordForm token={token} className="mt-4" />
<p className="text-muted-foreground mt-6 text-center text-sm">
Don't have an account?{' '}
<Link href="/signup" className="text-primary duration-200 hover:opacity-70">
Sign up
</Link>
<Trans>
Don't have an account?{' '}
<Link href="/signup" className="text-primary duration-200 hover:opacity-70">
Sign up
</Link>
</Trans>
</p>
</div>
</div>

View File

@ -1,6 +1,9 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { Button } from '@documenso/ui/primitives/button';
export const metadata: Metadata = {
@ -8,18 +11,26 @@ export const metadata: Metadata = {
};
export default function ResetPasswordPage() {
setupI18nSSR();
return (
<div className="w-screen max-w-lg px-4">
<div className="w-full">
<h1 className="text-3xl font-semibold">Unable to reset password</h1>
<h1 className="text-3xl font-semibold">
<Trans>Unable to reset password</Trans>
</h1>
<p className="text-muted-foreground mt-2 text-sm">
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.
<Trans>
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.
</Trans>
</p>
<Button className="mt-4" asChild>
<Link href="/signin">Return to sign in</Link>
<Link href="/signin">
<Trans>Return to sign in</Trans>
</Link>
</Button>
</div>
</div>

View File

@ -2,8 +2,10 @@ import type { Metadata } from 'next';
import Link from 'next/link';
import { redirect } from 'next/navigation';
import { Trans } from '@lingui/macro';
import { env } from 'next-runtime-env';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import {
IS_GOOGLE_SSO_ENABLED,
IS_OIDC_SSO_ENABLED,
@ -24,6 +26,8 @@ type SignInPageProps = {
};
export default function SignInPage({ searchParams }: SignInPageProps) {
setupI18nSSR();
const NEXT_PUBLIC_DISABLE_SIGNUP = env('NEXT_PUBLIC_DISABLE_SIGNUP');
const rawEmail = typeof searchParams.email === 'string' ? searchParams.email : undefined;
@ -36,10 +40,12 @@ export default function SignInPage({ searchParams }: SignInPageProps) {
return (
<div className="w-screen max-w-lg px-4">
<div className="border-border dark:bg-background z-10 rounded-xl border bg-neutral-100 p-6">
<h1 className="text-2xl font-semibold">Sign in to your account</h1>
<h1 className="text-2xl font-semibold">
<Trans>Sign in to your account</Trans>
</h1>
<p className="text-muted-foreground mt-2 text-sm">
Welcome back, we are lucky to have you.
<Trans>Welcome back, we are lucky to have you.</Trans>
</p>
<hr className="-mx-6 my-4" />
@ -52,10 +58,12 @@ export default function SignInPage({ searchParams }: SignInPageProps) {
{NEXT_PUBLIC_DISABLE_SIGNUP !== 'true' && (
<p className="text-muted-foreground mt-6 text-center text-sm">
Don't have an account?{' '}
<Link href="/signup" className="text-documenso-700 duration-200 hover:opacity-70">
Sign up
</Link>
<Trans>
Don't have an account?{' '}
<Link href="/signup" className="text-documenso-700 duration-200 hover:opacity-70">
Sign up
</Link>
</Trans>
</p>
)}
</div>

View File

@ -3,6 +3,7 @@ import { redirect } from 'next/navigation';
import { env } from 'next-runtime-env';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { IS_GOOGLE_SSO_ENABLED, IS_OIDC_SSO_ENABLED } from '@documenso/lib/constants/auth';
import { decryptSecondaryData } from '@documenso/lib/server-only/crypto/decrypt';
@ -19,6 +20,8 @@ type SignUpPageProps = {
};
export default function SignUpPage({ searchParams }: SignUpPageProps) {
setupI18nSSR();
const NEXT_PUBLIC_DISABLE_SIGNUP = env('NEXT_PUBLIC_DISABLE_SIGNUP');
if (NEXT_PUBLIC_DISABLE_SIGNUP === 'true') {

View File

@ -1,7 +1,9 @@
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { DateTime } from 'luxon';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { getServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
import { declineTeamInvitation } from '@documenso/lib/server-only/team/decline-team-invitation';
@ -19,6 +21,8 @@ type DeclineInvitationPageProps = {
export default async function DeclineInvitationPage({
params: { token },
}: DeclineInvitationPageProps) {
setupI18nSSR();
const session = await getServerComponentSession();
const teamMemberInvite = await prisma.teamMemberInvite.findUnique({
@ -31,14 +35,18 @@ export default async function DeclineInvitationPage({
return (
<div className="w-screen max-w-lg px-4">
<div className="w-full">
<h1 className="text-4xl font-semibold">Invalid token</h1>
<h1 className="text-4xl font-semibold">
<Trans>Invalid token</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
This token is invalid or has expired. No action is needed.
<Trans>This token is invalid or has expired. No action is needed.</Trans>
</p>
<Button asChild>
<Link href="/">Return</Link>
<Link href="/">
<Trans>Return</Trans>
</Link>
</Button>
</div>
</div>
@ -79,18 +87,24 @@ export default async function DeclineInvitationPage({
if (!user) {
return (
<div>
<h1 className="text-4xl font-semibold">Team invitation</h1>
<h1 className="text-4xl font-semibold">
<Trans>Team invitation</Trans>
</h1>
<p className="text-muted-foreground mt-2 text-sm">
You have been invited by <strong>{team.name}</strong> to join their team.
<Trans>
You have been invited by <strong>{team.name}</strong> to join their team.
</Trans>
</p>
<p className="text-muted-foreground mb-4 mt-1 text-sm">
To decline this invitation you must create an account.
<Trans>To decline this invitation you must create an account.</Trans>
</p>
<Button asChild>
<Link href={`/signup?email=${encodeURIComponent(email)}`}>Create account</Link>
<Link href={`/signup?email=${encodeURIComponent(email)}`}>
<Trans>Create account</Trans>
</Link>
</Button>
</div>
);
@ -100,19 +114,27 @@ export default async function DeclineInvitationPage({
return (
<div className="w-screen max-w-lg px-4">
<h1 className="text-4xl font-semibold">Invitation declined</h1>
<h1 className="text-4xl font-semibold">
<Trans>Invitation declined</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
You have declined the invitation from <strong>{team.name}</strong> to join their team.
<Trans>
You have declined the invitation from <strong>{team.name}</strong> to join their team.
</Trans>
</p>
{isSessionUserTheInvitedUser ? (
<Button asChild>
<Link href="/">Return to Dashboard</Link>
<Link href="/">
<Trans>Return to Dashboard</Trans>
</Link>
</Button>
) : (
<Button asChild>
<Link href="/">Return to Home</Link>
<Link href="/">
<Trans>Return to Home</Trans>
</Link>
</Button>
)}
</div>

View File

@ -1,7 +1,9 @@
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { DateTime } from 'luxon';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { getServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
import { acceptTeamInvitation } from '@documenso/lib/server-only/team/accept-team-invitation';
@ -19,6 +21,8 @@ type AcceptInvitationPageProps = {
export default async function AcceptInvitationPage({
params: { token },
}: AcceptInvitationPageProps) {
setupI18nSSR();
const session = await getServerComponentSession();
const teamMemberInvite = await prisma.teamMemberInvite.findUnique({
@ -31,14 +35,20 @@ export default async function AcceptInvitationPage({
return (
<div className="w-screen max-w-lg px-4">
<div className="w-full">
<h1 className="text-4xl font-semibold">Invalid token</h1>
<h1 className="text-4xl font-semibold">
<Trans>Invalid token</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
This token is invalid or has expired. Please contact your team for a new invitation.
<Trans>
This token is invalid or has expired. Please contact your team for a new invitation.
</Trans>
</p>
<Button asChild>
<Link href="/">Return</Link>
<Link href="/">
<Trans>Return</Trans>
</Link>
</Button>
</div>
</div>
@ -82,18 +92,24 @@ export default async function AcceptInvitationPage({
if (!user) {
return (
<div>
<h1 className="text-4xl font-semibold">Team invitation</h1>
<h1 className="text-4xl font-semibold">
<Trans>Team invitation</Trans>
</h1>
<p className="text-muted-foreground mt-2 text-sm">
You have been invited by <strong>{team.name}</strong> to join their team.
<Trans>
You have been invited by <strong>{team.name}</strong> to join their team.
</Trans>
</p>
<p className="text-muted-foreground mb-4 mt-1 text-sm">
To accept this invitation you must create an account.
<Trans>To accept this invitation you must create an account.</Trans>
</p>
<Button asChild>
<Link href={`/signup?email=${encodeURIComponent(email)}`}>Create account</Link>
<Link href={`/signup?email=${encodeURIComponent(email)}`}>
<Trans>Create account</Trans>
</Link>
</Button>
</div>
);
@ -103,19 +119,27 @@ export default async function AcceptInvitationPage({
return (
<div>
<h1 className="text-4xl font-semibold">Invitation accepted!</h1>
<h1 className="text-4xl font-semibold">
<Trans>Invitation accepted!</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
You have accepted an invitation from <strong>{team.name}</strong> to join their team.
<Trans>
You have accepted an invitation from <strong>{team.name}</strong> to join their team.
</Trans>
</p>
{isSessionUserTheInvitedUser ? (
<Button asChild>
<Link href="/">Continue</Link>
<Link href="/">
<Trans>Continue</Trans>
</Link>
</Button>
) : (
<Button asChild>
<Link href={`/signin?email=${encodeURIComponent(email)}`}>Continue to login</Link>
<Link href={`/signin?email=${encodeURIComponent(email)}`}>
<Trans>Continue to login</Trans>
</Link>
</Button>
)}
</div>

View File

@ -1,5 +1,8 @@
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { isTokenExpired } from '@documenso/lib/utils/token-verification';
import { prisma } from '@documenso/prisma';
import { Button } from '@documenso/ui/primitives/button';
@ -11,6 +14,8 @@ type VerifyTeamEmailPageProps = {
};
export default async function VerifyTeamEmailPage({ params: { token } }: VerifyTeamEmailPageProps) {
setupI18nSSR();
const teamEmailVerification = await prisma.teamEmailVerification.findUnique({
where: {
token,
@ -24,14 +29,21 @@ export default async function VerifyTeamEmailPage({ params: { token } }: VerifyT
return (
<div className="w-screen max-w-lg px-4">
<div className="w-full">
<h1 className="text-4xl font-semibold">Invalid link</h1>
<h1 className="text-4xl font-semibold">
<Trans>Invalid link</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
This link is invalid or has expired. Please contact your team to resend a verification.
<Trans>
This link is invalid or has expired. Please contact your team to resend a
verification.
</Trans>
</p>
<Button asChild>
<Link href="/">Return</Link>
<Link href="/">
<Trans>Return</Trans>
</Link>
</Button>
</div>
</div>
@ -65,11 +77,15 @@ export default async function VerifyTeamEmailPage({ params: { token } }: VerifyT
if (isTeamEmailVerificationError) {
return (
<div>
<h1 className="text-4xl font-semibold">Team email verification</h1>
<h1 className="text-4xl font-semibold">
<Trans>Team email verification</Trans>
</h1>
<p className="text-muted-foreground mt-2 text-sm">
Something went wrong while attempting to verify your email address for{' '}
<strong>{team.name}</strong>. Please try again later.
<Trans>
Something went wrong while attempting to verify your email address for{' '}
<strong>{team.name}</strong>. Please try again later.
</Trans>
</p>
</div>
);
@ -77,14 +93,20 @@ export default async function VerifyTeamEmailPage({ params: { token } }: VerifyT
return (
<div>
<h1 className="text-4xl font-semibold">Team email verified!</h1>
<h1 className="text-4xl font-semibold">
<Trans>Team email verified!</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
You have verified your email address for <strong>{team.name}</strong>.
<Trans>
You have verified your email address for <strong>{team.name}</strong>.
</Trans>
</p>
<Button asChild>
<Link href="/">Continue</Link>
<Link href="/">
<Trans>Continue</Trans>
</Link>
</Button>
</div>
);

View File

@ -1,5 +1,8 @@
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { transferTeamOwnership } from '@documenso/lib/server-only/team/transfer-team-ownership';
import { isTokenExpired } from '@documenso/lib/utils/token-verification';
import { prisma } from '@documenso/prisma';
@ -14,6 +17,8 @@ type VerifyTeamTransferPage = {
export default async function VerifyTeamTransferPage({
params: { token },
}: VerifyTeamTransferPage) {
setupI18nSSR();
const teamTransferVerification = await prisma.teamTransferVerification.findUnique({
where: {
token,
@ -27,15 +32,21 @@ export default async function VerifyTeamTransferPage({
return (
<div className="w-screen max-w-lg px-4">
<div className="w-full">
<h1 className="text-4xl font-semibold">Invalid link</h1>
<h1 className="text-4xl font-semibold">
<Trans>Invalid link</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
This link is invalid or has expired. Please contact your team to resend a transfer
request.
<Trans>
This link is invalid or has expired. Please contact your team to resend a transfer
request.
</Trans>
</p>
<Button asChild>
<Link href="/">Return</Link>
<Link href="/">
<Trans>Return</Trans>
</Link>
</Button>
</div>
</div>
@ -56,11 +67,15 @@ export default async function VerifyTeamTransferPage({
if (isTransferError) {
return (
<div>
<h1 className="text-4xl font-semibold">Team ownership transfer</h1>
<h1 className="text-4xl font-semibold">
<Trans>Team ownership transfer</Trans>
</h1>
<p className="text-muted-foreground mt-2 text-sm">
Something went wrong while attempting to transfer the ownership of team{' '}
<strong>{team.name}</strong> to your. Please try again later or contact support.
<Trans>
Something went wrong while attempting to transfer the ownership of team{' '}
<strong>{team.name}</strong> to your. Please try again later or contact support.
</Trans>
</p>
</div>
);
@ -68,14 +83,21 @@ export default async function VerifyTeamTransferPage({
return (
<div>
<h1 className="text-4xl font-semibold">Team ownership transferred!</h1>
<h1 className="text-4xl font-semibold">
<Trans>Team ownership transferred!</Trans>
</h1>
<p className="text-muted-foreground mb-4 mt-2 text-sm">
The ownership of team <strong>{team.name}</strong> has been successfully transferred to you.
<Trans>
The ownership of team <strong>{team.name}</strong> has been successfully transferred to
you.
</Trans>
</p>
<Button asChild>
<Link href={`/t/${team.url}/settings`}>Continue</Link>
<Link href={`/t/${team.url}/settings`}>
<Trans>Continue</Trans>
</Link>
</Button>
</div>
);

View File

@ -1,8 +1,13 @@
import { Trans } from '@lingui/macro';
import { Mails } from 'lucide-react';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { SendConfirmationEmailForm } from '~/components/forms/send-confirmation-email';
export default function UnverifiedAccount() {
setupI18nSSR();
return (
<div className="w-screen max-w-lg px-4">
<div className="flex items-start">
@ -10,15 +15,22 @@ export default function UnverifiedAccount() {
<Mails className="text-primary h-10 w-10" strokeWidth={2} />
</div>
<div className="">
<h2 className="text-2xl font-bold md:text-4xl">Confirm email</h2>
<h2 className="text-2xl font-bold md:text-4xl">
<Trans>Confirm email</Trans>
</h2>
<p className="text-muted-foreground mt-4">
To gain access to your account, please confirm your email address by clicking on the
confirmation link from your inbox.
<Trans>
To gain access to your account, please confirm your email address by clicking on the
confirmation link from your inbox.
</Trans>
</p>
<p className="text-muted-foreground mt-4">
If you don't find the confirmation link in your inbox, you can request a new one below.
<Trans>
If you don't find the confirmation link in your inbox, you can request a new one
below.
</Trans>
</p>
<SendConfirmationEmailForm />

View File

@ -1,7 +1,9 @@
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { AlertTriangle, CheckCircle2, XCircle, XOctagon } from 'lucide-react';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { verifyEmail } from '@documenso/lib/server-only/user/verify-email';
import { Button } from '@documenso/ui/primitives/button';
@ -12,6 +14,8 @@ export type PageProps = {
};
export default async function VerifyEmailPage({ params: { token } }: PageProps) {
setupI18nSSR();
if (!token) {
return (
<div className="w-screen max-w-lg px-4">
@ -20,9 +24,13 @@ export default async function VerifyEmailPage({ params: { token } }: PageProps)
<XOctagon />
</div>
<h2 className="text-4xl font-semibold">No token provided</h2>
<h2 className="text-4xl font-semibold">
<Trans>No token provided</Trans>
</h2>
<p className="text-muted-foreground mt-2 text-base">
It seems that there is no token provided. Please check your email and try again.
<Trans>
It seems that there is no token provided. Please check your email and try again.
</Trans>
</p>
</div>
</div>
@ -40,15 +48,21 @@ export default async function VerifyEmailPage({ params: { token } }: PageProps)
</div>
<div>
<h2 className="text-2xl font-bold md:text-4xl">Something went wrong</h2>
<h2 className="text-2xl font-bold md:text-4xl">
<Trans>Something went wrong</Trans>
</h2>
<p className="text-muted-foreground mt-4">
We were unable to verify your email. If your email is not verified already, please try
again.
<Trans>
We were unable to verify your email. If your email is not verified already, please
try again.
</Trans>
</p>
<Button className="mt-4" asChild>
<Link href="/">Go back home</Link>
<Link href="/">
<Trans>Go back home</Trans>
</Link>
</Button>
</div>
</div>
@ -65,15 +79,21 @@ export default async function VerifyEmailPage({ params: { token } }: PageProps)
</div>
<div>
<h2 className="text-2xl font-bold md:text-4xl">Your token has expired!</h2>
<h2 className="text-2xl font-bold md:text-4xl">
<Trans>Your token has expired!</Trans>
</h2>
<p className="text-muted-foreground mt-4">
It seems that the provided token has expired. We've just sent you another token,
please check your email and try again.
<Trans>
It seems that the provided token has expired. We've just sent you another token,
please check your email and try again.
</Trans>
</p>
<Button className="mt-4" asChild>
<Link href="/">Go back home</Link>
<Link href="/">
<Trans>Go back home</Trans>
</Link>
</Button>
</div>
</div>
@ -89,14 +109,20 @@ export default async function VerifyEmailPage({ params: { token } }: PageProps)
</div>
<div>
<h2 className="text-2xl font-bold md:text-4xl">Email Confirmed!</h2>
<h2 className="text-2xl font-bold md:text-4xl">
<Trans>Email Confirmed!</Trans>
</h2>
<p className="text-muted-foreground mt-4">
Your email has been successfully confirmed! You can now use all features of Documenso.
<Trans>
Your email has been successfully confirmed! You can now use all features of Documenso.
</Trans>
</p>
<Button className="mt-4" asChild>
<Link href="/">Go back home</Link>
<Link href="/">
<Trans>Go back home</Trans>
</Link>
</Button>
</div>
</div>

View File

@ -1,8 +1,10 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import { Trans } from '@lingui/macro';
import { XCircle } from 'lucide-react';
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
import { Button } from '@documenso/ui/primitives/button';
export const metadata: Metadata = {
@ -10,6 +12,8 @@ export const metadata: Metadata = {
};
export default function EmailVerificationWithoutTokenPage() {
setupI18nSSR();
return (
<div className="w-screen max-w-lg px-4">
<div className="flex w-full items-start">
@ -19,16 +23,20 @@ export default function EmailVerificationWithoutTokenPage() {
<div>
<h2 className="text-2xl font-bold md:text-4xl">
Uh oh! Looks like you're missing a token
<Trans>Uh oh! Looks like you're missing a token</Trans>
</h2>
<p className="text-muted-foreground mt-4">
It seems that there is no token provided, if you are trying to verify your email please
follow the link in your email.
<Trans>
It seems that there is no token provided, if you are trying to verify your email
please follow the link in your email.
</Trans>
</p>
<Button className="mt-4" asChild>
<Link href="/">Go back home</Link>
<Link href="/">
<Trans>Go back home</Trans>
</Link>
</Button>
</div>
</div>