feat: i18n for emails (#1442)
## Description Support setting a document language that will control the language used for sending emails to recipients. Additional work has been done to convert all emails to using our i18n implementation so we can later add controls for sending other kinds of emails in a users target language. ## Related Issue N/A ## Changes Made - Added `<Trans>` and `msg` macros to emails - Introduced a new `renderEmailWithI18N` utility in the lib package - Updated all emails to use the `<Tailwind>` component at the top level due to rendering constraints - Updated the `i18n.server.tsx` file to not use a top level await ## Testing Performed - Configured document language and verified emails were sent in the expected language - Created a document from a template and verified that the templates language was transferred to the document
This commit is contained in:
@@ -30,8 +30,8 @@ const mdxComponents: MDXComponents = {
|
|||||||
*
|
*
|
||||||
* Will render the document if it exists, otherwise will return a 404.
|
* Will render the document if it exists, otherwise will return a 404.
|
||||||
*/
|
*/
|
||||||
export default function ContentPage({ params }: { params: { content: string } }) {
|
export default async function ContentPage({ params }: { params: { content: string } }) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const post = allDocuments.find((post) => post._raw.flattenedPath === params.content);
|
const post = allDocuments.find((post) => post._raw.flattenedPath === params.content);
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ const mdxComponents: MDXComponents = {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function BlogPostPage({ params }: { params: { post: string } }) {
|
export default async function BlogPostPage({ params }: { params: { post: string } }) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const post = allBlogPosts.find((post) => post._raw.flattenedPath === `blog/${params.post}`);
|
const post = allBlogPosts.find((post) => post._raw.flattenedPath === `blog/${params.post}`);
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Blog',
|
title: 'Blog',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function BlogPage() {
|
export default async function BlogPage() {
|
||||||
const { i18n } = setupI18nSSR();
|
const { i18n } = await setupI18nSSR();
|
||||||
|
|
||||||
const blogPosts = allBlogPosts.sort((a, b) => {
|
const blogPosts = allBlogPosts.sort((a, b) => {
|
||||||
const dateA = new Date(a.date);
|
const dateA = new Date(a.date);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
|
|
||||||
import { Trans, msg } from '@lingui/macro';
|
import { Trans, msg } from '@lingui/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
||||||
@@ -131,9 +130,9 @@ const fetchEarlyAdopters = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function OpenPage() {
|
export default async function OpenPage() {
|
||||||
setupI18nSSR();
|
const { i18n } = await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = i18n;
|
||||||
|
|
||||||
const [
|
const [
|
||||||
{ forks_count: forksCount, stargazers_count: stargazersCount },
|
{ forks_count: forksCount, stargazers_count: stargazersCount },
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const fontCaveat = Caveat({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default async function IndexPage() {
|
export default async function IndexPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const starCount = await fetch('https://api.github.com/repos/documenso/documenso', {
|
const starCount = await fetch('https://api.github.com/repos/documenso/documenso', {
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export type PricingPageProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PricingPage() {
|
export default async function PricingPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-6 sm:mt-12">
|
<div className="mt-6 sm:mt-12">
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ export const dynamic = 'force-dynamic';
|
|||||||
// !: This entire file is a hack to get around failed prerendering of
|
// !: This entire file is a hack to get around failed prerendering of
|
||||||
// !: the Single Player Mode page. This regression was introduced during
|
// !: the Single Player Mode page. This regression was introduced during
|
||||||
// !: the upgrade of Next.js to v13.5.x.
|
// !: the upgrade of Next.js to v13.5.x.
|
||||||
export default function SingleplayerPage() {
|
export default async function SingleplayerPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return <SinglePlayerClient />;
|
return <SinglePlayerClient />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export function generateMetadata() {
|
|||||||
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
||||||
const flags = await getAllAnonymousFlags();
|
const flags = await getAllAnonymousFlags();
|
||||||
|
|
||||||
const { lang, locales, i18n } = setupI18nSSR();
|
const { lang, locales, i18n } = await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ type AdminDocumentDetailsPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function AdminDocumentDetailsPage({ params }: AdminDocumentDetailsPageProps) {
|
export default async function AdminDocumentDetailsPage({ params }: AdminDocumentDetailsPageProps) {
|
||||||
const { i18n } = setupI18nSSR();
|
const { i18n } = await setupI18nSSR();
|
||||||
|
|
||||||
const document = await getEntireDocument({ id: Number(params.id) });
|
const document = await getEntireDocument({ id: Number(params.id) });
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
|||||||
|
|
||||||
import { AdminDocumentResults } from './document-results';
|
import { AdminDocumentResults } from './document-results';
|
||||||
|
|
||||||
export default function AdminDocumentsPage() {
|
export default async function AdminDocumentsPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export type AdminSectionLayoutProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function AdminSectionLayout({ children }: AdminSectionLayoutProps) {
|
export default async function AdminSectionLayout({ children }: AdminSectionLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { user } = await getRequiredServerComponentSession();
|
const { user } = await getRequiredServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { BannerForm } from './banner-form';
|
|||||||
// import { BannerForm } from './banner-form';
|
// import { BannerForm } from './banner-form';
|
||||||
|
|
||||||
export default async function AdminBannerPage() {
|
export default async function AdminBannerPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { SignerConversionChart } from './signer-conversion-chart';
|
|||||||
import { UserWithDocumentChart } from './user-with-document';
|
import { UserWithDocumentChart } from './user-with-document';
|
||||||
|
|
||||||
export default async function AdminStatsPage() {
|
export default async function AdminStatsPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
} from '@documenso/ui/primitives/table';
|
} from '@documenso/ui/primitives/table';
|
||||||
|
|
||||||
export default async function Subscriptions() {
|
export default async function Subscriptions() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const subscriptions = await findSubscriptions();
|
const subscriptions = await findSubscriptions();
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ type AdminManageUsersProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function AdminManageUsers({ searchParams = {} }: AdminManageUsersProps) {
|
export default async function AdminManageUsers({ searchParams = {} }: AdminManageUsersProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const page = Number(searchParams.page) || 1;
|
const page = Number(searchParams.page) || 1;
|
||||||
const perPage = Number(searchParams.perPage) || 10;
|
const perPage = Number(searchParams.perPage) || 10;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { useRouter, useSearchParams } from 'next/navigation';
|
|||||||
import { msg } from '@lingui/macro';
|
import { msg } from '@lingui/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
|
import { isValidLanguageCode } from '@documenso/lib/constants/i18n';
|
||||||
import {
|
import {
|
||||||
DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
||||||
SKIP_QUERY_BATCH_META,
|
SKIP_QUERY_BATCH_META,
|
||||||
@@ -201,7 +202,7 @@ export const EditDocumentForm = ({
|
|||||||
|
|
||||||
const onAddSettingsFormSubmit = async (data: TAddSettingsFormSchema) => {
|
const onAddSettingsFormSubmit = async (data: TAddSettingsFormSchema) => {
|
||||||
try {
|
try {
|
||||||
const { timezone, dateFormat, redirectUrl } = data.meta;
|
const { timezone, dateFormat, redirectUrl, language } = data.meta;
|
||||||
|
|
||||||
await setSettingsForDocument({
|
await setSettingsForDocument({
|
||||||
documentId: document.id,
|
documentId: document.id,
|
||||||
@@ -217,6 +218,7 @@ export const EditDocumentForm = ({
|
|||||||
timezone,
|
timezone,
|
||||||
dateFormat,
|
dateFormat,
|
||||||
redirectUrl,
|
redirectUrl,
|
||||||
|
language: isValidLanguageCode(language) ? language : undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export type DocumentPageProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DocumentEditPage({ params }: DocumentPageProps) {
|
export default async function DocumentEditPage({ params }: DocumentPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return <DocumentEditPageView params={params} />;
|
return <DocumentEditPageView params={params} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { ChevronLeft, Loader } from 'lucide-react';
|
|||||||
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
||||||
import { Skeleton } from '@documenso/ui/primitives/skeleton';
|
import { Skeleton } from '@documenso/ui/primitives/skeleton';
|
||||||
|
|
||||||
export default function Loading() {
|
export default async function Loading() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto -mt-4 flex w-full max-w-screen-xl flex-col px-4 md:px-8">
|
<div className="mx-auto -mt-4 flex w-full max-w-screen-xl flex-col px-4 md:px-8">
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export type DocumentsLogsPageProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DocumentsLogsPage({ params }: DocumentsLogsPageProps) {
|
export default async function DocumentsLogsPage({ params }: DocumentsLogsPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return <DocumentLogsPageView params={params} />;
|
return <DocumentLogsPageView params={params} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export type DocumentPageProps = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DocumentPage({ params }: DocumentPageProps) {
|
export default async function DocumentPage({ params }: DocumentPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return <DocumentPageView params={params} />;
|
return <DocumentPageView params={params} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { ChevronLeft } from 'lucide-react';
|
|||||||
|
|
||||||
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
||||||
|
|
||||||
export default function DocumentSentPage() {
|
export default async function DocumentSentPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto -mt-4 flex w-full max-w-screen-xl flex-col px-4 md:px-8">
|
<div className="mx-auto -mt-4 flex w-full max-w-screen-xl flex-col px-4 md:px-8">
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function DocumentsPage({ searchParams = {} }: DocumentsPageProps) {
|
export default async function DocumentsPage({ searchParams = {} }: DocumentsPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { user } = await getRequiredServerComponentSession();
|
const { user } = await getRequiredServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export type AuthenticatedDashboardLayoutProps = {
|
|||||||
export default async function AuthenticatedDashboardLayout({
|
export default async function AuthenticatedDashboardLayout({
|
||||||
children,
|
children,
|
||||||
}: AuthenticatedDashboardLayoutProps) {
|
}: AuthenticatedDashboardLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const session = await getServerSession(NEXT_AUTH_OPTIONS);
|
const session = await getServerSession(NEXT_AUTH_OPTIONS);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function BillingSettingsPage() {
|
export default async function BillingSettingsPage() {
|
||||||
const { i18n } = setupI18nSSR();
|
const { i18n } = await setupI18nSSR();
|
||||||
|
|
||||||
let { user } = await getRequiredServerComponentSession();
|
let { user } = await getRequiredServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ export type DashboardSettingsLayoutProps = {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DashboardSettingsLayout({ children }: DashboardSettingsLayoutProps) {
|
export default async function DashboardSettingsLayout({ children }: DashboardSettingsLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-screen-xl px-4 md:px-8">
|
<div className="mx-auto w-full max-w-screen-xl px-4 md:px-8">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function ProfileSettingsPage() {
|
export default async function ProfileSettingsPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
const { user } = await getRequiredServerComponentSession();
|
const { user } = await getRequiredServerComponentSession();
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { getUserPublicProfile } from '@documenso/lib/server-only/user/get-user-p
|
|||||||
import { PublicProfilePageView } from './public-profile-page-view';
|
import { PublicProfilePageView } from './public-profile-page-view';
|
||||||
|
|
||||||
export default async function Page() {
|
export default async function Page() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { user } = await getRequiredServerComponentSession();
|
const { user } = await getRequiredServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Security activity',
|
title: 'Security activity',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SettingsSecurityActivityPage() {
|
export default async function SettingsSecurityActivityPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function SecuritySettingsPage() {
|
export default async function SecuritySettingsPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
const { user } = await getRequiredServerComponentSession();
|
const { user } = await getRequiredServerComponentSession();
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function SettingsManagePasskeysPage() {
|
export default async function SettingsManagePasskeysPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
const isPasskeyEnabled = await getServerComponentFlag('app_passkey');
|
const isPasskeyEnabled = await getServerComponentFlag('app_passkey');
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import DeleteTokenDialog from '~/components/(dashboard)/settings/token/delete-to
|
|||||||
import { ApiTokenForm } from '~/components/forms/token';
|
import { ApiTokenForm } from '~/components/forms/token';
|
||||||
|
|
||||||
export default async function ApiTokensPage() {
|
export default async function ApiTokensPage() {
|
||||||
const { i18n } = setupI18nSSR();
|
const { i18n } = await setupI18nSSR();
|
||||||
|
|
||||||
const { user } = await getRequiredServerComponentSession();
|
const { user } = await getRequiredServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { useRouter } from 'next/navigation';
|
|||||||
import { msg } from '@lingui/macro';
|
import { msg } from '@lingui/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
|
import { isValidLanguageCode } from '@documenso/lib/constants/i18n';
|
||||||
import {
|
import {
|
||||||
DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
DO_NOT_INVALIDATE_QUERY_ON_MUTATION,
|
||||||
SKIP_QUERY_BATCH_META,
|
SKIP_QUERY_BATCH_META,
|
||||||
@@ -151,7 +152,10 @@ export const EditTemplateForm = ({
|
|||||||
globalAccessAuth: data.globalAccessAuth ?? null,
|
globalAccessAuth: data.globalAccessAuth ?? null,
|
||||||
globalActionAuth: data.globalActionAuth ?? null,
|
globalActionAuth: data.globalActionAuth ?? null,
|
||||||
},
|
},
|
||||||
meta: data.meta,
|
meta: {
|
||||||
|
...data.meta,
|
||||||
|
language: isValidLanguageCode(data.meta.language) ? data.meta.language : undefined,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Router refresh is here to clear the router cache for when navigating to /documents.
|
// Router refresh is here to clear the router cache for when navigating to /documents.
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { TemplatePageView } from './template-page-view';
|
|||||||
|
|
||||||
type TemplatePageProps = Pick<TemplatePageViewProps, 'params'>;
|
type TemplatePageProps = Pick<TemplatePageViewProps, 'params'>;
|
||||||
|
|
||||||
export default function TemplatePage({ params }: TemplatePageProps) {
|
export default async function TemplatePage({ params }: TemplatePageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return <TemplatePageView params={params} />;
|
return <TemplatePageView params={params} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Templates',
|
title: 'Templates',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function TemplatesPage({ searchParams = {} }: TemplatesPageProps) {
|
export default async function TemplatesPage({ searchParams = {} }: TemplatesPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return <TemplatesPageView searchParams={searchParams} />;
|
return <TemplatesPageView searchParams={searchParams} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type PublicProfileLayoutProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function PublicProfileLayout({ children }: PublicProfileLayoutProps) {
|
export default async function PublicProfileLayout({ children }: PublicProfileLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { user, session } = await getServerComponentSession();
|
const { user, session } = await getServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const BADGE_DATA = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function PublicProfilePage({ params }: PublicProfilePageProps) {
|
export default async function PublicProfilePage({ params }: PublicProfilePageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { url: profileUrl } = params;
|
const { url: profileUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export type TemplatesDirectPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function TemplatesDirectPage({ params }: TemplatesDirectPageProps) {
|
export default async function TemplatesDirectPage({ params }: TemplatesDirectPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { token } = params;
|
const { token } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type RecipientLayoutProps = {
|
|||||||
* Such as direct template access, or signing.
|
* Such as direct template access, or signing.
|
||||||
*/
|
*/
|
||||||
export default async function RecipientLayout({ children }: RecipientLayoutProps) {
|
export default async function RecipientLayout({ children }: RecipientLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { user, session } = await getServerComponentSession();
|
const { user, session } = await getServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export type SigningLayoutProps = {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SigningLayout({ children }: SigningLayoutProps) {
|
export default async function SigningLayout({ children }: SigningLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export type CompletedSigningPageProps = {
|
|||||||
export default async function CompletedSigningPage({
|
export default async function CompletedSigningPage({
|
||||||
params: { token },
|
params: { token },
|
||||||
}: CompletedSigningPageProps) {
|
}: CompletedSigningPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export type SigningLayoutProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function SigningLayout({ children }: SigningLayoutProps) {
|
export default async function SigningLayout({ children }: SigningLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { user, session } = await getServerComponentSession();
|
const { user, session } = await getServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export type SigningPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function SigningPage({ params: { token } }: SigningPageProps) {
|
export default async function SigningPage({ params: { token } }: SigningPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return notFound();
|
return notFound();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type WaitingForTurnToSignPageProps = {
|
|||||||
export default async function WaitingForTurnToSignPage({
|
export default async function WaitingForTurnToSignPage({
|
||||||
params: { token },
|
params: { token },
|
||||||
}: WaitingForTurnToSignPageProps) {
|
}: WaitingForTurnToSignPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return notFound();
|
return notFound();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export type DocumentPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function TeamsDocumentEditPage({ params }: DocumentPageProps) {
|
export default async function TeamsDocumentEditPage({ params }: DocumentPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export type TeamDocumentsLogsPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function TeamsDocumentsLogsPage({ params }: TeamDocumentsLogsPageProps) {
|
export default async function TeamsDocumentsLogsPage({ params }: TeamDocumentsLogsPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export type DocumentPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function DocumentPage({ params }: DocumentPageProps) {
|
export default async function DocumentPage({ params }: DocumentPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export default async function TeamsDocumentPage({
|
|||||||
params,
|
params,
|
||||||
searchParams = {},
|
searchParams = {},
|
||||||
}: TeamsDocumentPageProps) {
|
}: TeamsDocumentPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default async function AuthenticatedTeamsLayout({
|
|||||||
children,
|
children,
|
||||||
params,
|
params,
|
||||||
}: AuthenticatedTeamsLayoutProps) {
|
}: AuthenticatedTeamsLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { session, user } = await getServerComponentSession();
|
const { session, user } = await getServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export type TeamsSettingsBillingPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function TeamsSettingBillingPage({ params }: TeamsSettingsBillingPageProps) {
|
export default async function TeamsSettingBillingPage({ params }: TeamsSettingsBillingPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export default async function TeamsSettingsLayout({
|
|||||||
children,
|
children,
|
||||||
params: { teamUrl },
|
params: { teamUrl },
|
||||||
}: TeamSettingsLayoutProps) {
|
}: TeamSettingsLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const session = await getRequiredServerComponentSession();
|
const session = await getRequiredServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export type TeamsSettingsMembersPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function TeamsSettingsMembersPage({ params }: TeamsSettingsMembersPageProps) {
|
export default async function TeamsSettingsMembersPage({ params }: TeamsSettingsMembersPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export type TeamsSettingsPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function TeamsSettingsPage({ params }: TeamsSettingsPageProps) {
|
export default async function TeamsSettingsPage({ params }: TeamsSettingsPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export type TeamsSettingsPublicProfilePageProps = {
|
|||||||
export default async function TeamsSettingsPublicProfilePage({
|
export default async function TeamsSettingsPublicProfilePage({
|
||||||
params,
|
params,
|
||||||
}: TeamsSettingsPublicProfilePageProps) {
|
}: TeamsSettingsPublicProfilePageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type ApiTokensPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function ApiTokensPage({ params }: ApiTokensPageProps) {
|
export default async function ApiTokensPage({ params }: ApiTokensPageProps) {
|
||||||
const { i18n } = setupI18nSSR();
|
const { i18n } = await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type TeamTemplatePageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function TeamTemplatePage({ params }: TeamTemplatePageProps) {
|
export default async function TeamTemplatePage({ params }: TeamTemplatePageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default async function TeamTemplatesPage({
|
|||||||
searchParams = {},
|
searchParams = {},
|
||||||
params,
|
params,
|
||||||
}: TeamTemplatesPageProps) {
|
}: TeamTemplatesPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { teamUrl } = params;
|
const { teamUrl } = params;
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { Button } from '@documenso/ui/primitives/button';
|
|||||||
|
|
||||||
const SUPPORT_EMAIL = 'support@documenso.com';
|
const SUPPORT_EMAIL = 'support@documenso.com';
|
||||||
|
|
||||||
export default function SignatureDisclosure() {
|
export default async function SignatureDisclosure() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Forgot password',
|
title: 'Forgot password',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ForgotPasswordPage() {
|
export default async function ForgotPasswordPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen max-w-lg px-4">
|
<div className="w-screen max-w-lg px-4">
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Forgot Password',
|
title: 'Forgot Password',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ForgotPasswordPage() {
|
export default async function ForgotPasswordPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen max-w-lg px-4">
|
<div className="w-screen max-w-lg px-4">
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ type UnauthenticatedLayoutProps = {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function UnauthenticatedLayout({ children }: UnauthenticatedLayoutProps) {
|
export default async function UnauthenticatedLayout({ children }: UnauthenticatedLayoutProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
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">
|
<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">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type ResetPasswordPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function ResetPasswordPage({ params: { token } }: ResetPasswordPageProps) {
|
export default async function ResetPasswordPage({ params: { token } }: ResetPasswordPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const isValid = await getResetTokenValidity({ token });
|
const isValid = await getResetTokenValidity({ token });
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Reset Password',
|
title: 'Reset Password',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ResetPasswordPage() {
|
export default async function ResetPasswordPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen max-w-lg px-4">
|
<div className="w-screen max-w-lg px-4">
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Sign In',
|
title: 'Sign In',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SignInPage() {
|
export default async function SignInPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const NEXT_PUBLIC_DISABLE_SIGNUP = env('NEXT_PUBLIC_DISABLE_SIGNUP');
|
const NEXT_PUBLIC_DISABLE_SIGNUP = env('NEXT_PUBLIC_DISABLE_SIGNUP');
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Sign Up',
|
title: 'Sign Up',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SignUpPage() {
|
export default async function SignUpPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const NEXT_PUBLIC_DISABLE_SIGNUP = env('NEXT_PUBLIC_DISABLE_SIGNUP');
|
const NEXT_PUBLIC_DISABLE_SIGNUP = env('NEXT_PUBLIC_DISABLE_SIGNUP');
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type DeclineInvitationPageProps = {
|
|||||||
export default async function DeclineInvitationPage({
|
export default async function DeclineInvitationPage({
|
||||||
params: { token },
|
params: { token },
|
||||||
}: DeclineInvitationPageProps) {
|
}: DeclineInvitationPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const session = await getServerComponentSession();
|
const session = await getServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type AcceptInvitationPageProps = {
|
|||||||
export default async function AcceptInvitationPage({
|
export default async function AcceptInvitationPage({
|
||||||
params: { token },
|
params: { token },
|
||||||
}: AcceptInvitationPageProps) {
|
}: AcceptInvitationPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const session = await getServerComponentSession();
|
const session = await getServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ type VerifyTeamEmailPageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function VerifyTeamEmailPage({ params: { token } }: VerifyTeamEmailPageProps) {
|
export default async function VerifyTeamEmailPage({ params: { token } }: VerifyTeamEmailPageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const teamEmailVerification = await prisma.teamEmailVerification.findUnique({
|
const teamEmailVerification = await prisma.teamEmailVerification.findUnique({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ type VerifyTeamTransferPage = {
|
|||||||
export default async function VerifyTeamTransferPage({
|
export default async function VerifyTeamTransferPage({
|
||||||
params: { token },
|
params: { token },
|
||||||
}: VerifyTeamTransferPage) {
|
}: VerifyTeamTransferPage) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const teamTransferVerification = await prisma.teamTransferVerification.findUnique({
|
const teamTransferVerification = await prisma.teamTransferVerification.findUnique({
|
||||||
where: {
|
where: {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
|||||||
|
|
||||||
import { SendConfirmationEmailForm } from '~/components/forms/send-confirmation-email';
|
import { SendConfirmationEmailForm } from '~/components/forms/send-confirmation-email';
|
||||||
|
|
||||||
export default function UnverifiedAccount() {
|
export default async function UnverifiedAccount() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen max-w-lg px-4">
|
<div className="w-screen max-w-lg px-4">
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export type PageProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function VerifyEmailPage({ params: { token } }: PageProps) {
|
export default async function VerifyEmailPage({ params: { token } }: PageProps) {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ export const metadata: Metadata = {
|
|||||||
title: 'Verify Email',
|
title: 'Verify Email',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function EmailVerificationWithoutTokenPage() {
|
export default async function EmailVerificationWithoutTokenPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen max-w-lg px-4">
|
<div className="w-screen max-w-lg px-4">
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export function generateMetadata() {
|
|||||||
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
||||||
const flags = await getServerComponentAllFlags();
|
const flags = await getServerComponentAllFlags();
|
||||||
|
|
||||||
const { i18n, lang, locales } = setupI18nSSR();
|
const { i18n, lang, locales } = await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html
|
<html
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Button } from '@documenso/ui/primitives/button';
|
|||||||
import NotFoundPartial from '~/components/partials/not-found';
|
import NotFoundPartial from '~/components/partials/not-found';
|
||||||
|
|
||||||
export default async function NotFound() {
|
export default async function NotFound() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
const { session } = await getServerComponentSession();
|
const { session } = await getServerComponentSession();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
||||||
|
|
||||||
export default function DashboardPage() {
|
export default async function DashboardPage() {
|
||||||
setupI18nSSR();
|
await setupI18nSSR();
|
||||||
|
|
||||||
return <div>Documenso</div>;
|
return <div>Documenso</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const config: LinguiConfig = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '<rootDir>/packages/lib/translations/{locale}/common',
|
path: '<rootDir>/packages/lib/translations/{locale}/common',
|
||||||
include: ['packages/ui', 'packages/lib'],
|
include: ['packages/ui', 'packages/lib', 'packages/email'],
|
||||||
exclude: ['**/node_modules/**'],
|
exclude: ['**/node_modules/**'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
3
package-lock.json
generated
3
package-lock.json
generated
@@ -36774,6 +36774,9 @@
|
|||||||
"@documenso/email": "*",
|
"@documenso/email": "*",
|
||||||
"@documenso/prisma": "*",
|
"@documenso/prisma": "*",
|
||||||
"@documenso/signing": "*",
|
"@documenso/signing": "*",
|
||||||
|
"@lingui/core": "^4.11.3",
|
||||||
|
"@lingui/macro": "^4.11.3",
|
||||||
|
"@lingui/react": "^4.11.3",
|
||||||
"@next-auth/prisma-adapter": "1.0.7",
|
"@next-auth/prisma-adapter": "1.0.7",
|
||||||
"@noble/ciphers": "0.4.0",
|
"@noble/ciphers": "0.4.0",
|
||||||
"@noble/hashes": "1.3.2",
|
"@noble/hashes": "1.3.2",
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
|||||||
dateFormat: dateFormat?.value,
|
dateFormat: dateFormat?.value,
|
||||||
redirectUrl: body.meta.redirectUrl,
|
redirectUrl: body.meta.redirectUrl,
|
||||||
signingOrder: body.meta.signingOrder,
|
signingOrder: body.meta.signingOrder,
|
||||||
|
language: body.meta.language,
|
||||||
requestMetadata: extractNextApiRequestMetadata(args.req),
|
requestMetadata: extractNextApiRequestMetadata(args.req),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { extendZodWithOpenApi } from '@anatine/zod-openapi';
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { DATE_FORMATS, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
import { DATE_FORMATS, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||||
|
import { SUPPORTED_LANGUAGE_CODES } from '@documenso/lib/constants/i18n';
|
||||||
import '@documenso/lib/constants/time-zones';
|
import '@documenso/lib/constants/time-zones';
|
||||||
import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones';
|
import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones';
|
||||||
import { ZUrlSchema } from '@documenso/lib/schemas/common';
|
import { ZUrlSchema } from '@documenso/lib/schemas/common';
|
||||||
@@ -127,6 +128,7 @@ export const ZCreateDocumentMutationSchema = z.object({
|
|||||||
}),
|
}),
|
||||||
redirectUrl: z.string(),
|
redirectUrl: z.string(),
|
||||||
signingOrder: z.nativeEnum(DocumentSigningOrder).optional(),
|
signingOrder: z.nativeEnum(DocumentSigningOrder).optional(),
|
||||||
|
language: z.enum(SUPPORTED_LANGUAGE_CODES).optional(),
|
||||||
})
|
})
|
||||||
.partial(),
|
.partial(),
|
||||||
authOptions: z
|
authOptions: z
|
||||||
@@ -181,6 +183,7 @@ export const ZCreateDocumentFromTemplateMutationSchema = z.object({
|
|||||||
dateFormat: z.string(),
|
dateFormat: z.string(),
|
||||||
redirectUrl: z.string(),
|
redirectUrl: z.string(),
|
||||||
signingOrder: z.nativeEnum(DocumentSigningOrder).optional(),
|
signingOrder: z.nativeEnum(DocumentSigningOrder).optional(),
|
||||||
|
language: z.enum(SUPPORTED_LANGUAGE_CODES).optional(),
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.optional(),
|
.optional(),
|
||||||
@@ -247,6 +250,7 @@ export const ZGenerateDocumentFromTemplateMutationSchema = z.object({
|
|||||||
dateFormat: z.string(),
|
dateFormat: z.string(),
|
||||||
redirectUrl: ZUrlSchema,
|
redirectUrl: ZUrlSchema,
|
||||||
signingOrder: z.nativeEnum(DocumentSigningOrder).optional(),
|
signingOrder: z.nativeEnum(DocumentSigningOrder).optional(),
|
||||||
|
language: z.enum(SUPPORTED_LANGUAGE_CODES).optional(),
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.optional(),
|
.optional(),
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export { render, renderAsync } from '@react-email/render';
|
|
||||||
39
packages/email/render.tsx
Normal file
39
packages/email/render.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import * as reactEmail from '@react-email/render';
|
||||||
|
|
||||||
|
import config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
import { Tailwind } from './components';
|
||||||
|
|
||||||
|
export const render: typeof reactEmail.render = (element, options) => {
|
||||||
|
return reactEmail.render(
|
||||||
|
<Tailwind
|
||||||
|
config={{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: config.theme.extend.colors,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{element}
|
||||||
|
</Tailwind>,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const renderAsync: typeof reactEmail.renderAsync = async (element, options) => {
|
||||||
|
return reactEmail.renderAsync(
|
||||||
|
<Tailwind
|
||||||
|
config={{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: config.theme.extend.colors,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{element}
|
||||||
|
</Tailwind>,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { Button, Section, Text } from '../components';
|
import { Button, Section, Text } from '../components';
|
||||||
import { TemplateDocumentImage } from './template-document-image';
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
@@ -10,17 +13,21 @@ export const TemplateConfirmationEmail = ({
|
|||||||
confirmationLink,
|
confirmationLink,
|
||||||
assetBaseUrl,
|
assetBaseUrl,
|
||||||
}: TemplateConfirmationEmailProps) => {
|
}: TemplateConfirmationEmailProps) => {
|
||||||
|
const { _ } = useLingui();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
|
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
|
||||||
|
|
||||||
<Section className="flex-row items-center justify-center">
|
<Section className="flex-row items-center justify-center">
|
||||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
Welcome to Documenso!
|
<Trans>Welcome to Documenso!</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
|
<Trans>
|
||||||
Before you get started, please confirm your email address by clicking the button below:
|
Before you get started, please confirm your email address by clicking the button below:
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Section className="mb-6 mt-8 text-center">
|
<Section className="mb-6 mt-8 text-center">
|
||||||
@@ -28,11 +35,13 @@ export const TemplateConfirmationEmail = ({
|
|||||||
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||||
href={confirmationLink}
|
href={confirmationLink}
|
||||||
>
|
>
|
||||||
Confirm email
|
<Trans>Confirm email</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
<Text className="mt-8 text-center text-sm italic text-slate-400">
|
<Text className="mt-8 text-center text-sm italic text-slate-400">
|
||||||
|
<Trans>
|
||||||
You can also copy and paste this link into your browser: {confirmationLink} (link
|
You can also copy and paste this link into your browser: {confirmationLink} (link
|
||||||
expires in 1 hour)
|
expires in 1 hour)
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
|
||||||
import { Section, Text } from '../components';
|
import { Section, Text } from '../components';
|
||||||
import { TemplateDocumentImage } from './template-document-image';
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
@@ -19,16 +21,18 @@ export const TemplateDocumentCancel = ({
|
|||||||
|
|
||||||
<Section>
|
<Section>
|
||||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
|
<Trans>
|
||||||
{inviterName} has cancelled the document
|
{inviterName} has cancelled the document
|
||||||
<br />"{documentName}"
|
<br />"{documentName}"
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
All signatures have been voided.
|
<Trans>All signatures have been voided.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
You don't need to sign it anymore.
|
<Trans>You don't need to sign it anymore.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</Section>
|
</Section>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
|
||||||
import { Button, Column, Img, Section, Text } from '../components';
|
import { Button, Column, Img, Section, Text } from '../components';
|
||||||
import { TemplateDocumentImage } from './template-document-image';
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
@@ -30,17 +32,17 @@ export const TemplateDocumentCompleted = ({
|
|||||||
src={getAssetUrl('/static/completed.png')}
|
src={getAssetUrl('/static/completed.png')}
|
||||||
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
||||||
/>
|
/>
|
||||||
Completed
|
<Trans>Completed</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</Column>
|
</Column>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||||
{customBody ?? `“${documentName}” was signed by all signers`}
|
<Trans>{customBody ?? `“${documentName}” was signed by all signers`}</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
Continue by downloading the document.
|
<Trans>Continue by downloading the document.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Section className="mb-6 mt-8 text-center">
|
<Section className="mb-6 mt-8 text-center">
|
||||||
@@ -59,7 +61,7 @@ export const TemplateDocumentCompleted = ({
|
|||||||
src={getAssetUrl('/static/download.png')}
|
src={getAssetUrl('/static/download.png')}
|
||||||
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
||||||
/>
|
/>
|
||||||
Download
|
<Trans>Download</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles';
|
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles';
|
||||||
import type { RecipientRole } from '@documenso/prisma/client';
|
import type { RecipientRole } from '@documenso/prisma/client';
|
||||||
|
|
||||||
@@ -26,6 +29,8 @@ export const TemplateDocumentInvite = ({
|
|||||||
isTeamInvite,
|
isTeamInvite,
|
||||||
teamName,
|
teamName,
|
||||||
}: TemplateDocumentInviteProps) => {
|
}: TemplateDocumentInviteProps) => {
|
||||||
|
const { _ } = useLingui();
|
||||||
|
|
||||||
const { actionVerb, progressiveVerb } = RECIPIENT_ROLES_DESCRIPTION_ENG[role];
|
const { actionVerb, progressiveVerb } = RECIPIENT_ROLES_DESCRIPTION_ENG[role];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -35,28 +40,30 @@ export const TemplateDocumentInvite = ({
|
|||||||
<Section>
|
<Section>
|
||||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
{selfSigner ? (
|
{selfSigner ? (
|
||||||
<>
|
<Trans>
|
||||||
{`Please ${actionVerb.toLowerCase()} your document`}
|
{`Please ${_(actionVerb).toLowerCase()} your document`}
|
||||||
<br />
|
<br />
|
||||||
{`"${documentName}"`}
|
{`"${documentName}"`}
|
||||||
</>
|
</Trans>
|
||||||
) : isTeamInvite ? (
|
) : isTeamInvite ? (
|
||||||
<>
|
<Trans>
|
||||||
{`${inviterName} on behalf of ${teamName} has invited you to ${actionVerb.toLowerCase()}`}
|
{`${inviterName} on behalf of ${teamName} has invited you to ${_(
|
||||||
|
actionVerb,
|
||||||
|
).toLowerCase()}`}
|
||||||
<br />
|
<br />
|
||||||
{`"${documentName}"`}
|
{`"${documentName}"`}
|
||||||
</>
|
</Trans>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<Trans>
|
||||||
{`${inviterName} has invited you to ${actionVerb.toLowerCase()}`}
|
{`${inviterName} has invited you to ${_(actionVerb).toLowerCase()}`}
|
||||||
<br />
|
<br />
|
||||||
{`"${documentName}"`}
|
{`"${documentName}"`}
|
||||||
</>
|
</Trans>
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
Continue by {progressiveVerb.toLowerCase()} the document.
|
<Trans>Continue by {_(progressiveVerb).toLowerCase()} the document.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Section className="mb-6 mt-8 text-center">
|
<Section className="mb-6 mt-8 text-center">
|
||||||
@@ -64,7 +71,7 @@ export const TemplateDocumentInvite = ({
|
|||||||
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||||
href={signDocumentLink}
|
href={signDocumentLink}
|
||||||
>
|
>
|
||||||
{actionVerb} Document
|
<Trans>{_(actionVerb)} Document</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
|
||||||
import { Column, Img, Section, Text } from '../components';
|
import { Column, Img, Section, Text } from '../components';
|
||||||
import { TemplateDocumentImage } from './template-document-image';
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
@@ -26,19 +28,21 @@ export const TemplateDocumentPending = ({
|
|||||||
src={getAssetUrl('/static/clock.png')}
|
src={getAssetUrl('/static/clock.png')}
|
||||||
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
||||||
/>
|
/>
|
||||||
Waiting for others
|
<Trans>Waiting for others</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</Column>
|
</Column>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||||
“{documentName}” has been signed
|
<Trans>“{documentName}” has been signed</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
||||||
|
<Trans>
|
||||||
We're still waiting for other signers to sign this document.
|
We're still waiting for other signers to sign this document.
|
||||||
<br />
|
<br />
|
||||||
We'll notify you as soon as it's ready.
|
We'll notify you as soon as it's ready.
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</Section>
|
</Section>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
import { env } from 'next-runtime-env';
|
import { env } from 'next-runtime-env';
|
||||||
|
|
||||||
import { Button, Column, Img, Link, Section, Text } from '../components';
|
import { Button, Column, Img, Link, Section, Text } from '../components';
|
||||||
@@ -32,16 +33,17 @@ export const TemplateDocumentSelfSigned = ({
|
|||||||
src={getAssetUrl('/static/completed.png')}
|
src={getAssetUrl('/static/completed.png')}
|
||||||
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
||||||
/>
|
/>
|
||||||
Completed
|
<Trans>Completed</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</Column>
|
</Column>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Text className="text-primary mb-0 mt-6 text-center text-lg font-semibold">
|
<Text className="text-primary mb-0 mt-6 text-center text-lg font-semibold">
|
||||||
You have signed “{documentName}”
|
<Trans>You have signed “{documentName}”</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
||||||
|
<Trans>
|
||||||
Create a{' '}
|
Create a{' '}
|
||||||
<Link
|
<Link
|
||||||
href={signUpUrl}
|
href={signUpUrl}
|
||||||
@@ -51,6 +53,7 @@ export const TemplateDocumentSelfSigned = ({
|
|||||||
free account
|
free account
|
||||||
</Link>{' '}
|
</Link>{' '}
|
||||||
to access your signed documents at any time.
|
to access your signed documents at any time.
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Section className="mb-6 mt-8 text-center">
|
<Section className="mb-6 mt-8 text-center">
|
||||||
@@ -62,7 +65,7 @@ export const TemplateDocumentSelfSigned = ({
|
|||||||
src={getAssetUrl('/static/user-plus.png')}
|
src={getAssetUrl('/static/user-plus.png')}
|
||||||
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
||||||
/>
|
/>
|
||||||
Create account
|
<Trans>Create account</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
@@ -73,7 +76,7 @@ export const TemplateDocumentSelfSigned = ({
|
|||||||
src={getAssetUrl('/static/review.png')}
|
src={getAssetUrl('/static/review.png')}
|
||||||
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
||||||
/>
|
/>
|
||||||
View plans
|
<Trans>View plans</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
|
||||||
import { Section, Text } from '../components';
|
import { Section, Text } from '../components';
|
||||||
import { TemplateDocumentImage } from './template-document-image';
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
@@ -18,20 +20,22 @@ export const TemplateDocumentDelete = ({
|
|||||||
|
|
||||||
<Section>
|
<Section>
|
||||||
<Text className="text-primary mb-0 mt-6 text-left text-lg font-semibold">
|
<Text className="text-primary mb-0 mt-6 text-left text-lg font-semibold">
|
||||||
Your document has been deleted by an admin!
|
<Trans>Your document has been deleted by an admin!</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="mx-auto mb-6 mt-1 text-left text-base text-slate-400">
|
<Text className="mx-auto mb-6 mt-1 text-left text-base text-slate-400">
|
||||||
"{documentName}" has been deleted by an admin.
|
<Trans>"{documentName}" has been deleted by an admin.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="mx-auto mb-6 mt-1 text-left text-base text-slate-400">
|
<Text className="mx-auto mb-6 mt-1 text-left text-base text-slate-400">
|
||||||
|
<Trans>
|
||||||
This document can not be recovered, if you would like to dispute the reason for future
|
This document can not be recovered, if you would like to dispute the reason for future
|
||||||
documents please contact support.
|
documents please contact support.
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="mx-auto mt-1 text-left text-base text-slate-400">
|
<Text className="mx-auto mt-1 text-left text-base text-slate-400">
|
||||||
The reason provided for deletion is the following:
|
<Trans>The reason provided for deletion is the following:</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="mx-auto mb-6 mt-1 text-left text-base italic text-slate-400">
|
<Text className="mx-auto mb-6 mt-1 text-left text-base italic text-slate-400">
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
|
||||||
import { Link, Section, Text } from '../components';
|
import { Link, Section, Text } from '../components';
|
||||||
|
|
||||||
export type TemplateFooterProps = {
|
export type TemplateFooterProps = {
|
||||||
@@ -9,10 +11,12 @@ export const TemplateFooter = ({ isDocument = true }: TemplateFooterProps) => {
|
|||||||
<Section>
|
<Section>
|
||||||
{isDocument && (
|
{isDocument && (
|
||||||
<Text className="my-4 text-base text-slate-400">
|
<Text className="my-4 text-base text-slate-400">
|
||||||
|
<Trans>
|
||||||
This document was sent using{' '}
|
This document was sent using{' '}
|
||||||
<Link className="text-[#7AC455]" href="https://documen.so/mail-footer">
|
<Link className="text-[#7AC455]" href="https://documen.so/mail-footer">
|
||||||
Documenso.
|
Documenso.
|
||||||
</Link>
|
</Link>
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
|
|
||||||
import { Button, Section, Text } from '../components';
|
import { Button, Section, Text } from '../components';
|
||||||
import { TemplateDocumentImage } from './template-document-image';
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
@@ -16,11 +18,11 @@ export const TemplateForgotPassword = ({
|
|||||||
|
|
||||||
<Section className="flex-row items-center justify-center">
|
<Section className="flex-row items-center justify-center">
|
||||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
Forgot your password?
|
<Trans>Forgot your password?</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
That's okay, it happens! Click the button below to reset your password.
|
<Trans>That's okay, it happens! Click the button below to reset your password.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Section className="mb-6 mt-8 text-center">
|
<Section className="mb-6 mt-8 text-center">
|
||||||
@@ -28,7 +30,7 @@ export const TemplateForgotPassword = ({
|
|||||||
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||||
href={resetPasswordLink}
|
href={resetPasswordLink}
|
||||||
>
|
>
|
||||||
Reset Password
|
<Trans>Reset Password</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Trans } from '@lingui/macro';
|
||||||
import { env } from 'next-runtime-env';
|
import { env } from 'next-runtime-env';
|
||||||
|
|
||||||
import { Button, Section, Text } from '../components';
|
import { Button, Section, Text } from '../components';
|
||||||
@@ -18,11 +19,11 @@ export const TemplateResetPassword = ({ assetBaseUrl }: TemplateResetPasswordPro
|
|||||||
|
|
||||||
<Section className="flex-row items-center justify-center">
|
<Section className="flex-row items-center justify-center">
|
||||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
Password updated!
|
<Trans>Password updated!</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
Your password has been updated.
|
<Trans>Your password has been updated.</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Section className="mb-6 mt-8 text-center">
|
<Section className="mb-6 mt-8 text-center">
|
||||||
@@ -30,7 +31,7 @@ export const TemplateResetPassword = ({ assetBaseUrl }: TemplateResetPasswordPro
|
|||||||
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||||
href={`${NEXT_PUBLIC_WEBAPP_URL ?? 'http://localhost:3000'}/signin`}
|
href={`${NEXT_PUBLIC_WEBAPP_URL ?? 'http://localhost:3000'}/signin`}
|
||||||
>
|
>
|
||||||
Sign In
|
<Trans>Sign In</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import config from '@documenso/tailwind-config';
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { Body, Container, Head, Html, Img, Preview, Section, Tailwind } from '../components';
|
import { Body, Container, Head, Html, Img, Preview, Section } from '../components';
|
||||||
import type { TemplateConfirmationEmailProps } from '../template-components/template-confirmation-email';
|
import type { TemplateConfirmationEmailProps } from '../template-components/template-confirmation-email';
|
||||||
import { TemplateConfirmationEmail } from '../template-components/template-confirmation-email';
|
import { TemplateConfirmationEmail } from '../template-components/template-confirmation-email';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
@@ -9,7 +10,9 @@ export const ConfirmEmailTemplate = ({
|
|||||||
confirmationLink,
|
confirmationLink,
|
||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
}: TemplateConfirmationEmailProps) => {
|
}: TemplateConfirmationEmailProps) => {
|
||||||
const previewText = `Please confirm your email address`;
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const previewText = msg`Please confirm your email address`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -18,16 +21,7 @@ export const ConfirmEmailTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto bg-white font-sans">
|
<Body className="mx-auto my-auto bg-white font-sans">
|
||||||
<Section>
|
<Section>
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||||
@@ -51,7 +45,6 @@ export const ConfirmEmailTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { formatTeamUrl } from '@documenso/lib/utils/teams';
|
import { formatTeamUrl } from '@documenso/lib/utils/teams';
|
||||||
import config from '@documenso/tailwind-config';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Body,
|
Body,
|
||||||
@@ -11,7 +13,6 @@ import {
|
|||||||
Link,
|
Link,
|
||||||
Preview,
|
Preview,
|
||||||
Section,
|
Section,
|
||||||
Tailwind,
|
|
||||||
Text,
|
Text,
|
||||||
} from '../components';
|
} from '../components';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
@@ -32,21 +33,15 @@ export const ConfirmTeamEmailTemplate = ({
|
|||||||
teamUrl = 'demo',
|
teamUrl = 'demo',
|
||||||
token = '',
|
token = '',
|
||||||
}: ConfirmTeamEmailProps) => {
|
}: ConfirmTeamEmailProps) => {
|
||||||
const previewText = `Accept team email request for ${teamName} on Documenso`;
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const previewText = msg`Accept team email request for ${teamName} on Documenso`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto font-sans">
|
<Body className="mx-auto my-auto font-sans">
|
||||||
<Section className="bg-white">
|
<Section className="bg-white">
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 px-2 pt-2 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 px-2 pt-2 backdrop-blur-sm">
|
||||||
@@ -80,8 +75,8 @@ export const ConfirmTeamEmailTemplate = ({
|
|||||||
|
|
||||||
<Section className="mt-6">
|
<Section className="mt-6">
|
||||||
<Text className="my-0 text-sm">
|
<Text className="my-0 text-sm">
|
||||||
By accepting this request, you will be granting <strong>{teamName}</strong>{' '}
|
By accepting this request, you will be granting <strong>{teamName}</strong> access
|
||||||
access to:
|
to:
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<ul className="mb-0 mt-2">
|
<ul className="mb-0 mt-2">
|
||||||
@@ -122,7 +117,6 @@ export const ConfirmTeamEmailTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import config from '@documenso/tailwind-config';
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { Body, Container, Head, Hr, Html, Img, Preview, Section, Tailwind } from '../components';
|
import { Body, Container, Head, Hr, Html, Img, Preview, Section } from '../components';
|
||||||
import type { TemplateDocumentCancelProps } from '../template-components/template-document-cancel';
|
import type { TemplateDocumentCancelProps } from '../template-components/template-document-cancel';
|
||||||
import { TemplateDocumentCancel } from '../template-components/template-document-cancel';
|
import { TemplateDocumentCancel } from '../template-components/template-document-cancel';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
@@ -13,7 +14,9 @@ export const DocumentCancelTemplate = ({
|
|||||||
documentName = 'Open Source Pledge.pdf',
|
documentName = 'Open Source Pledge.pdf',
|
||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
}: DocumentCancelEmailTemplateProps) => {
|
}: DocumentCancelEmailTemplateProps) => {
|
||||||
const previewText = `${inviterName} has cancelled the document ${documentName}, you don't need to sign it anymore.`;
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const previewText = msg`${inviterName} has cancelled the document ${documentName}, you don't need to sign it anymore.`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -22,16 +25,8 @@ export const DocumentCancelTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto bg-white font-sans">
|
<Body className="mx-auto my-auto bg-white font-sans">
|
||||||
<Section>
|
<Section>
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||||
@@ -58,7 +53,6 @@ export const DocumentCancelTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import config from '@documenso/tailwind-config';
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { Body, Container, Head, Html, Img, Preview, Section, Tailwind } from '../components';
|
import { Body, Container, Head, Html, Img, Preview, Section } from '../components';
|
||||||
import type { TemplateDocumentCompletedProps } from '../template-components/template-document-completed';
|
import type { TemplateDocumentCompletedProps } from '../template-components/template-document-completed';
|
||||||
import { TemplateDocumentCompleted } from '../template-components/template-document-completed';
|
import { TemplateDocumentCompleted } from '../template-components/template-document-completed';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
@@ -15,7 +16,9 @@ export const DocumentCompletedEmailTemplate = ({
|
|||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
customBody,
|
customBody,
|
||||||
}: DocumentCompletedEmailTemplateProps) => {
|
}: DocumentCompletedEmailTemplateProps) => {
|
||||||
const previewText = `Completed Document`;
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const previewText = msg`Completed Document`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -24,16 +27,8 @@ export const DocumentCompletedEmailTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto font-sans">
|
<Body className="mx-auto my-auto font-sans">
|
||||||
<Section className="bg-white">
|
<Section className="bg-white">
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||||
@@ -58,7 +53,6 @@ export const DocumentCompletedEmailTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,9 @@
|
|||||||
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles';
|
import { Trans, msg } from '@lingui/macro';
|
||||||
import config from '@documenso/tailwind-config';
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import {
|
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles';
|
||||||
Body,
|
|
||||||
Button,
|
import { Body, Button, Container, Head, Html, Img, Preview, Section, Text } from '../components';
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from '../components';
|
|
||||||
import TemplateDocumentImage from '../template-components/template-document-image';
|
import TemplateDocumentImage from '../template-components/template-document-image';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
import { RecipientRole } from '.prisma/client';
|
import { RecipientRole } from '.prisma/client';
|
||||||
@@ -32,9 +23,11 @@ export const DocumentCreatedFromDirectTemplateEmailTemplate = ({
|
|||||||
documentName = 'Open Source Pledge.pdf',
|
documentName = 'Open Source Pledge.pdf',
|
||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
}: DocumentCompletedEmailTemplateProps) => {
|
}: DocumentCompletedEmailTemplateProps) => {
|
||||||
const action = RECIPIENT_ROLES_DESCRIPTION_ENG[recipientRole].actioned.toLowerCase();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
const previewText = `Document created from direct template`;
|
const action = _(RECIPIENT_ROLES_DESCRIPTION_ENG[recipientRole].actioned).toLowerCase();
|
||||||
|
|
||||||
|
const previewText = msg`Document created from direct template`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -43,16 +36,8 @@ export const DocumentCreatedFromDirectTemplateEmailTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto font-sans">
|
<Body className="mx-auto my-auto font-sans">
|
||||||
<Section className="bg-white">
|
<Section className="bg-white">
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||||
@@ -67,7 +52,9 @@ export const DocumentCreatedFromDirectTemplateEmailTemplate = ({
|
|||||||
|
|
||||||
<Section>
|
<Section>
|
||||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||||
|
<Trans>
|
||||||
{recipientName} {action} a document by using one of your direct links
|
{recipientName} {action} a document by using one of your direct links
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<div className="mx-auto my-2 w-fit rounded-lg bg-gray-50 px-4 py-2 text-sm text-slate-600">
|
<div className="mx-auto my-2 w-fit rounded-lg bg-gray-50 px-4 py-2 text-sm text-slate-600">
|
||||||
@@ -79,7 +66,7 @@ export const DocumentCreatedFromDirectTemplateEmailTemplate = ({
|
|||||||
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||||
href={documentLink}
|
href={documentLink}
|
||||||
>
|
>
|
||||||
View document
|
<Trans>View document</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
@@ -91,7 +78,6 @@ export const DocumentCreatedFromDirectTemplateEmailTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
|
import { Trans, msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles';
|
import { RECIPIENT_ROLES_DESCRIPTION_ENG } from '@documenso/lib/constants/recipient-roles';
|
||||||
import type { RecipientRole } from '@documenso/prisma/client';
|
import type { RecipientRole } from '@documenso/prisma/client';
|
||||||
import config from '@documenso/tailwind-config';
|
|
||||||
|
|
||||||
import {
|
import { Body, Container, Head, Hr, Html, Img, Link, Preview, Section, Text } from '../components';
|
||||||
Body,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Hr,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Link,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from '../components';
|
|
||||||
import type { TemplateDocumentInviteProps } from '../template-components/template-document-invite';
|
import type { TemplateDocumentInviteProps } from '../template-components/template-document-invite';
|
||||||
import { TemplateDocumentInvite } from '../template-components/template-document-invite';
|
import { TemplateDocumentInvite } from '../template-components/template-document-invite';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
@@ -40,13 +30,15 @@ export const DocumentInviteEmailTemplate = ({
|
|||||||
isTeamInvite = false,
|
isTeamInvite = false,
|
||||||
teamName,
|
teamName,
|
||||||
}: DocumentInviteEmailTemplateProps) => {
|
}: DocumentInviteEmailTemplateProps) => {
|
||||||
const action = RECIPIENT_ROLES_DESCRIPTION_ENG[role].actionVerb.toLowerCase();
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const action = _(RECIPIENT_ROLES_DESCRIPTION_ENG[role].actionVerb).toLowerCase();
|
||||||
|
|
||||||
const previewText = selfSigner
|
const previewText = selfSigner
|
||||||
? `Please ${action} your document ${documentName}`
|
? msg`Please ${action} your document ${documentName}`
|
||||||
: isTeamInvite
|
: isTeamInvite
|
||||||
? `${inviterName} on behalf of ${teamName} has invited you to ${action} ${documentName}`
|
? msg`${inviterName} on behalf of ${teamName} has invited you to ${action} ${documentName}`
|
||||||
: `${inviterName} has invited you to ${action} ${documentName}`;
|
: msg`${inviterName} has invited you to ${action} ${documentName}`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -55,16 +47,8 @@ export const DocumentInviteEmailTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto bg-white font-sans">
|
<Body className="mx-auto my-auto bg-white font-sans">
|
||||||
<Section>
|
<Section>
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||||
@@ -92,17 +76,21 @@ export const DocumentInviteEmailTemplate = ({
|
|||||||
<Container className="mx-auto mt-12 max-w-xl">
|
<Container className="mx-auto mt-12 max-w-xl">
|
||||||
<Section>
|
<Section>
|
||||||
<Text className="my-4 text-base font-semibold">
|
<Text className="my-4 text-base font-semibold">
|
||||||
|
<Trans>
|
||||||
{inviterName}{' '}
|
{inviterName}{' '}
|
||||||
<Link className="font-normal text-slate-400" href="mailto:{inviterEmail}">
|
<Link className="font-normal text-slate-400" href="mailto:{inviterEmail}">
|
||||||
({inviterEmail})
|
({inviterEmail})
|
||||||
</Link>
|
</Link>
|
||||||
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="mt-2 text-base text-slate-400">
|
<Text className="mt-2 text-base text-slate-400">
|
||||||
{customBody ? (
|
{customBody ? (
|
||||||
<pre className="font-sans text-base text-slate-400">{customBody}</pre>
|
<pre className="font-sans text-base text-slate-400">{customBody}</pre>
|
||||||
) : (
|
) : (
|
||||||
|
<Trans>
|
||||||
`${inviterName} has invited you to ${action} the document "${documentName}".`
|
`${inviterName} has invited you to ${action} the document "${documentName}".`
|
||||||
|
</Trans>
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</Section>
|
</Section>
|
||||||
@@ -115,7 +103,6 @@ export const DocumentInviteEmailTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import config from '@documenso/tailwind-config';
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { Body, Container, Head, Html, Img, Preview, Section, Tailwind } from '../components';
|
import { Body, Container, Head, Html, Img, Preview, Section } from '../components';
|
||||||
import type { TemplateDocumentPendingProps } from '../template-components/template-document-pending';
|
import type { TemplateDocumentPendingProps } from '../template-components/template-document-pending';
|
||||||
import { TemplateDocumentPending } from '../template-components/template-document-pending';
|
import { TemplateDocumentPending } from '../template-components/template-document-pending';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
@@ -11,7 +12,9 @@ export const DocumentPendingEmailTemplate = ({
|
|||||||
documentName = 'Open Source Pledge.pdf',
|
documentName = 'Open Source Pledge.pdf',
|
||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
}: DocumentPendingEmailTemplateProps) => {
|
}: DocumentPendingEmailTemplateProps) => {
|
||||||
const previewText = `Pending Document`;
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const previewText = msg`Pending Document`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -20,16 +23,8 @@ export const DocumentPendingEmailTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto font-sans">
|
<Body className="mx-auto my-auto font-sans">
|
||||||
<Section className="bg-white">
|
<Section className="bg-white">
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||||
@@ -49,7 +44,6 @@ export const DocumentPendingEmailTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import config from '@documenso/tailwind-config';
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { Body, Container, Head, Html, Img, Preview, Section, Tailwind } from '../components';
|
import { Body, Container, Head, Html, Img, Preview, Section } from '../components';
|
||||||
import type { TemplateDocumentSelfSignedProps } from '../template-components/template-document-self-signed';
|
import type { TemplateDocumentSelfSignedProps } from '../template-components/template-document-self-signed';
|
||||||
import { TemplateDocumentSelfSigned } from '../template-components/template-document-self-signed';
|
import { TemplateDocumentSelfSigned } from '../template-components/template-document-self-signed';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
@@ -11,7 +12,9 @@ export const DocumentSelfSignedEmailTemplate = ({
|
|||||||
documentName = 'Open Source Pledge.pdf',
|
documentName = 'Open Source Pledge.pdf',
|
||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
}: DocumentSelfSignedTemplateProps) => {
|
}: DocumentSelfSignedTemplateProps) => {
|
||||||
const previewText = `Completed Document`;
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const previewText = msg`Completed Document`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -20,16 +23,8 @@ export const DocumentSelfSignedEmailTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto font-sans">
|
<Body className="mx-auto my-auto font-sans">
|
||||||
<Section className="bg-white">
|
<Section className="bg-white">
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||||
@@ -40,10 +35,7 @@ export const DocumentSelfSignedEmailTemplate = ({
|
|||||||
className="mb-4 h-6"
|
className="mb-4 h-6"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TemplateDocumentSelfSigned
|
<TemplateDocumentSelfSigned documentName={documentName} assetBaseUrl={assetBaseUrl} />
|
||||||
documentName={documentName}
|
|
||||||
assetBaseUrl={assetBaseUrl}
|
|
||||||
/>
|
|
||||||
</Section>
|
</Section>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
@@ -52,7 +44,6 @@ export const DocumentSelfSignedEmailTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import config from '@documenso/tailwind-config';
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { Body, Container, Head, Hr, Html, Img, Preview, Section, Tailwind } from '../components';
|
import { Body, Container, Head, Hr, Html, Img, Preview, Section } from '../components';
|
||||||
import {
|
import {
|
||||||
TemplateDocumentDelete,
|
TemplateDocumentDelete,
|
||||||
type TemplateDocumentDeleteProps,
|
type TemplateDocumentDeleteProps,
|
||||||
@@ -14,7 +15,9 @@ export const DocumentSuperDeleteEmailTemplate = ({
|
|||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
reason = 'Unknown',
|
reason = 'Unknown',
|
||||||
}: DocumentDeleteEmailTemplateProps) => {
|
}: DocumentDeleteEmailTemplateProps) => {
|
||||||
const previewText = `An admin has deleted your document "${documentName}".`;
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const previewText = msg`An admin has deleted your document "${documentName}".`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -23,16 +26,8 @@ export const DocumentSuperDeleteEmailTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto bg-white font-sans">
|
<Body className="mx-auto my-auto bg-white font-sans">
|
||||||
<Section>
|
<Section>
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||||
@@ -58,7 +53,6 @@ export const DocumentSuperDeleteEmailTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import config from '@documenso/tailwind-config';
|
import { msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
|
|
||||||
import { Body, Container, Head, Html, Img, Preview, Section, Tailwind } from '../components';
|
import { Body, Container, Head, Html, Img, Preview, Section } from '../components';
|
||||||
import { TemplateFooter } from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
import type { TemplateForgotPasswordProps } from '../template-components/template-forgot-password';
|
import type { TemplateForgotPasswordProps } from '../template-components/template-forgot-password';
|
||||||
import { TemplateForgotPassword } from '../template-components/template-forgot-password';
|
import { TemplateForgotPassword } from '../template-components/template-forgot-password';
|
||||||
@@ -11,7 +12,9 @@ export const ForgotPasswordTemplate = ({
|
|||||||
resetPasswordLink = 'https://documenso.com',
|
resetPasswordLink = 'https://documenso.com',
|
||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
}: ForgotPasswordTemplateProps) => {
|
}: ForgotPasswordTemplateProps) => {
|
||||||
const previewText = `Password Reset Requested`;
|
const { _ } = useLingui();
|
||||||
|
|
||||||
|
const previewText = msg`Password Reset Requested`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
@@ -20,16 +23,8 @@ export const ForgotPasswordTemplate = ({
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{_(previewText)}</Preview>
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: config.theme.extend.colors,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="mx-auto my-auto bg-white font-sans">
|
<Body className="mx-auto my-auto bg-white font-sans">
|
||||||
<Section>
|
<Section>
|
||||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||||
@@ -54,7 +49,6 @@ export const ForgotPasswordTemplate = ({
|
|||||||
</Container>
|
</Container>
|
||||||
</Section>
|
</Section>
|
||||||
</Body>
|
</Body>
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user