Compare commits
20 Commits
openpage-a
...
v1.7.2-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de880aa821 | ||
|
|
dc5723c386 | ||
|
|
c57d1dc55d | ||
|
|
4dd95016b1 | ||
|
|
04b1ce1aab | ||
|
|
885349ad94 | ||
|
|
28514ba2e7 | ||
|
|
8aa6d8e602 | ||
|
|
378e515843 | ||
|
|
f42e600e3f | ||
|
|
88eaec91c9 | ||
|
|
f199183c78 | ||
|
|
0cee07aed3 | ||
|
|
f76f87ff1c | ||
|
|
6020336792 | ||
|
|
634b30aa54 | ||
|
|
7fc497a642 | ||
|
|
e30ceeb038 | ||
|
|
872762661a | ||
|
|
5fcd8610c9 |
2
.github/workflows/translations-upload.yml
vendored
2
.github/workflows/translations-upload.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.ref }}
|
token: ${{ secrets.GH_PAT }}
|
||||||
|
|
||||||
- uses: ./.github/actions/node-install
|
- uses: ./.github/actions/node-install
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,36 @@
|
|||||||
# @documenso/documentation
|
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3002](http://localhost:3002) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@documenso/marketing",
|
"name": "@documenso/marketing",
|
||||||
"version": "1.7.2-rc.1",
|
"version": "1.7.2-rc.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3001",
|
"dev": "next dev -p 3001",
|
||||||
"build": "turbo run translate:extract && turbo run translate:compile && next build",
|
"build": "npm run translate:extract --prefix ../../ && turbo run translate:compile && next build",
|
||||||
"start": "next start -p 3001",
|
"start": "next start -p 3001",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"lint:fix": "next lint --fix",
|
"lint:fix": "next lint --fix",
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
40
apps/openpage-api/.gitignore
vendored
40
apps/openpage-api/.gitignore
vendored
@@ -1,40 +0,0 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.*
|
|
||||||
.yarn/*
|
|
||||||
!.yarn/patches
|
|
||||||
!.yarn/plugins
|
|
||||||
!.yarn/releases
|
|
||||||
!.yarn/versions
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# env files (can opt-in for commiting if needed)
|
|
||||||
.env*
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
||||||
|
|
||||||
# typescript
|
|
||||||
*.tsbuildinfo
|
|
||||||
next-env.d.ts
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
# @documenso/openpage-api
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import type { NextRequest } from 'next/server';
|
|
||||||
|
|
||||||
import cors from '@/lib/cors';
|
|
||||||
|
|
||||||
const paths = [
|
|
||||||
{ path: '/total-prs', description: 'Total GitHub Merged PRs' },
|
|
||||||
{ path: '/total-stars', description: 'Total GitHub Stars' },
|
|
||||||
{ path: '/total-forks', description: 'Total GitHub Forks' },
|
|
||||||
{ path: '/total-issues', description: 'Total GitHub Issues' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function GET(request: NextRequest) {
|
|
||||||
const url = request.nextUrl.toString();
|
|
||||||
const apis = paths.map(({ path, description }) => {
|
|
||||||
return { path: url + path, description };
|
|
||||||
});
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(apis), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
import { transformRepoStats } from '@/lib/transform-repo-stats';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const res = await fetch('https://stargrazer-live.onrender.com/api/stats');
|
|
||||||
const data = await res.json();
|
|
||||||
const transformedData = transformRepoStats(data, 'forks');
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(transformedData), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
import { transformRepoStats } from '@/lib/transform-repo-stats';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const res = await fetch('https://stargrazer-live.onrender.com/api/stats');
|
|
||||||
const data = await res.json();
|
|
||||||
const transformedData = transformRepoStats(data, 'openIssues');
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(transformedData), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
import { transformRepoStats } from '@/lib/transform-repo-stats';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const res = await fetch('https://stargrazer-live.onrender.com/api/stats');
|
|
||||||
const data = await res.json();
|
|
||||||
const transformedData = transformRepoStats(data, 'mergedPRs');
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(transformedData), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
import { transformRepoStats } from '@/lib/transform-repo-stats';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const res = await fetch('https://stargrazer-live.onrender.com/api/stats');
|
|
||||||
const data = await res.json();
|
|
||||||
const transformedData = transformRepoStats(data, 'stars');
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(transformedData), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const res = await fetch('https://api.github.com/repos/documenso/documenso');
|
|
||||||
const { forks_count } = await res.json();
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify({ data: forks_count }), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const res = await fetch(
|
|
||||||
'https://api.github.com/search/issues?q=repo:documenso/documenso+type:issue+state:open&page=0&per_page=1',
|
|
||||||
);
|
|
||||||
const { total_count } = await res.json();
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify({ data: total_count }), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const res = await fetch(
|
|
||||||
'https://api.github.com/search/issues?q=repo:documenso/documenso/+is:pr+merged:>=2010-01-01&page=0&per_page=1',
|
|
||||||
);
|
|
||||||
const { total_count } = await res.json();
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify({ data: total_count }), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import type { NextRequest } from 'next/server';
|
|
||||||
|
|
||||||
import cors from '@/lib/cors';
|
|
||||||
|
|
||||||
const paths = [
|
|
||||||
{ path: '/forks', description: 'GitHub Forks' },
|
|
||||||
{ path: '/stars', description: 'GitHub Stars' },
|
|
||||||
{ path: '/issues', description: 'GitHub Merged Issues' },
|
|
||||||
{ path: '/prs', description: 'GitHub Pull Request' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function GET(request: NextRequest) {
|
|
||||||
const url = request.nextUrl.toString();
|
|
||||||
const apis = paths.map(({ path, description }) => {
|
|
||||||
return { path: url + path, description };
|
|
||||||
});
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(apis), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const res = await fetch('https://api.github.com/repos/documenso/documenso');
|
|
||||||
const { stargazers_count } = await res.json();
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify({ data: stargazers_count }), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
import { getUserMonthlyGrowth } from '@/lib/growth/get-user-monthly-growth';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const monthlyUsers = await getUserMonthlyGrowth();
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(monthlyUsers), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import type { NextRequest } from 'next/server';
|
|
||||||
|
|
||||||
import cors from '@/lib/cors';
|
|
||||||
|
|
||||||
const paths = [
|
|
||||||
{ path: '/total-customers', description: 'Total Customers' },
|
|
||||||
{ path: '/total-users', description: 'Total Users' },
|
|
||||||
{ path: '/new-users', description: 'New Users' },
|
|
||||||
{ path: '/completed-documents', description: 'Completed Documents per Month' },
|
|
||||||
{ path: '/total-completed-documents', description: 'Total Completed Documents' },
|
|
||||||
{ path: '/twitter', description: 'Twitter' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function GET(request: NextRequest) {
|
|
||||||
const url = request.nextUrl.toString();
|
|
||||||
const apis = paths.map(({ path, description }) => {
|
|
||||||
return { path: url + path, description };
|
|
||||||
});
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(apis), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import cors from '@/lib/cors';
|
|
||||||
import { getUserMonthlyGrowth } from '@/lib/growth/get-user-monthly-growth';
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const totalUsers = await getUserMonthlyGrowth();
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(totalUsers), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import type { NextRequest } from 'next/server';
|
|
||||||
|
|
||||||
import cors from '@/lib/cors';
|
|
||||||
|
|
||||||
const paths = [
|
|
||||||
{ path: 'github', description: 'GitHub Data' },
|
|
||||||
{ path: 'community', description: 'Community Data' },
|
|
||||||
{ path: 'growth', description: 'Growth Data' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function GET(request: NextRequest) {
|
|
||||||
const url = request.nextUrl.toString();
|
|
||||||
const apis = paths.map(({ path, description }) => {
|
|
||||||
return { path: url + path, description };
|
|
||||||
});
|
|
||||||
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(JSON.stringify(apis), {
|
|
||||||
status: 200,
|
|
||||||
headers: {
|
|
||||||
'content-type': 'application/json',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OPTIONS(request: Request) {
|
|
||||||
return cors(
|
|
||||||
request,
|
|
||||||
new Response(null, {
|
|
||||||
status: 204,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
/**
|
|
||||||
* Multi purpose CORS lib.
|
|
||||||
* Note: Based on the `cors` package in npm but using only web APIs.
|
|
||||||
* Taken from: https://github.com/vercel/examples/blob/main/edge-functions/cors/lib/cors.ts
|
|
||||||
*/
|
|
||||||
|
|
||||||
type StaticOrigin = boolean | string | RegExp | (boolean | string | RegExp)[];
|
|
||||||
|
|
||||||
type OriginFn = (origin: string | undefined, req: Request) => StaticOrigin | Promise<StaticOrigin>;
|
|
||||||
|
|
||||||
interface CorsOptions {
|
|
||||||
origin?: StaticOrigin | OriginFn;
|
|
||||||
methods?: string | string[];
|
|
||||||
allowedHeaders?: string | string[];
|
|
||||||
exposedHeaders?: string | string[];
|
|
||||||
credentials?: boolean;
|
|
||||||
maxAge?: number;
|
|
||||||
preflightContinue?: boolean;
|
|
||||||
optionsSuccessStatus?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultOptions: CorsOptions = {
|
|
||||||
origin: '*',
|
|
||||||
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
|
||||||
preflightContinue: false,
|
|
||||||
optionsSuccessStatus: 204,
|
|
||||||
};
|
|
||||||
|
|
||||||
function isOriginAllowed(origin: string, allowed: StaticOrigin): boolean {
|
|
||||||
return Array.isArray(allowed)
|
|
||||||
? allowed.some((o) => isOriginAllowed(origin, o))
|
|
||||||
: typeof allowed === 'string'
|
|
||||||
? origin === allowed
|
|
||||||
: allowed instanceof RegExp
|
|
||||||
? allowed.test(origin)
|
|
||||||
: !!allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOriginHeaders(reqOrigin: string | undefined, origin: StaticOrigin) {
|
|
||||||
const headers = new Headers();
|
|
||||||
|
|
||||||
if (origin === '*') {
|
|
||||||
// Allow any origin
|
|
||||||
headers.set('Access-Control-Allow-Origin', '*');
|
|
||||||
} else if (typeof origin === 'string') {
|
|
||||||
// Fixed origin
|
|
||||||
headers.set('Access-Control-Allow-Origin', origin);
|
|
||||||
headers.append('Vary', 'Origin');
|
|
||||||
} else {
|
|
||||||
const allowed = isOriginAllowed(reqOrigin ?? '', origin);
|
|
||||||
|
|
||||||
if (allowed && reqOrigin) {
|
|
||||||
headers.set('Access-Control-Allow-Origin', reqOrigin);
|
|
||||||
}
|
|
||||||
headers.append('Vary', 'Origin');
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function originHeadersFromReq(req: Request, origin: StaticOrigin | OriginFn) {
|
|
||||||
const reqOrigin = req.headers.get('Origin') || undefined;
|
|
||||||
const value = typeof origin === 'function' ? await origin(reqOrigin, req) : origin;
|
|
||||||
|
|
||||||
if (!value) return;
|
|
||||||
return getOriginHeaders(reqOrigin, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAllowedHeaders(req: Request, allowed?: string | string[]) {
|
|
||||||
const headers = new Headers();
|
|
||||||
|
|
||||||
if (!allowed) {
|
|
||||||
allowed = req.headers.get('Access-Control-Request-Headers')!;
|
|
||||||
headers.append('Vary', 'Access-Control-Request-Headers');
|
|
||||||
} else if (Array.isArray(allowed)) {
|
|
||||||
// If the allowed headers is an array, turn it into a string
|
|
||||||
allowed = allowed.join(',');
|
|
||||||
}
|
|
||||||
if (allowed) {
|
|
||||||
headers.set('Access-Control-Allow-Headers', allowed);
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function cors(req: Request, res: Response, options?: CorsOptions) {
|
|
||||||
const opts = { ...defaultOptions, ...options };
|
|
||||||
const { headers } = res;
|
|
||||||
const originHeaders = await originHeadersFromReq(req, opts.origin ?? false);
|
|
||||||
const mergeHeaders = (v: string, k: string) => {
|
|
||||||
if (k === 'Vary') headers.append(k, v);
|
|
||||||
else headers.set(k, v);
|
|
||||||
};
|
|
||||||
|
|
||||||
// If there's no origin we won't touch the response
|
|
||||||
if (!originHeaders) return res;
|
|
||||||
|
|
||||||
originHeaders.forEach(mergeHeaders);
|
|
||||||
|
|
||||||
if (opts.credentials) {
|
|
||||||
headers.set('Access-Control-Allow-Credentials', 'true');
|
|
||||||
}
|
|
||||||
|
|
||||||
const exposed = Array.isArray(opts.exposedHeaders)
|
|
||||||
? opts.exposedHeaders.join(',')
|
|
||||||
: opts.exposedHeaders;
|
|
||||||
|
|
||||||
if (exposed) {
|
|
||||||
headers.set('Access-Control-Expose-Headers', exposed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the preflight request
|
|
||||||
if (req.method === 'OPTIONS') {
|
|
||||||
if (opts.methods) {
|
|
||||||
const methods = Array.isArray(opts.methods) ? opts.methods.join(',') : opts.methods;
|
|
||||||
|
|
||||||
headers.set('Access-Control-Allow-Methods', methods);
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllowedHeaders(req, opts.allowedHeaders).forEach(mergeHeaders);
|
|
||||||
|
|
||||||
if (typeof opts.maxAge === 'number') {
|
|
||||||
headers.set('Access-Control-Max-Age', String(opts.maxAge));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.preflightContinue) return res;
|
|
||||||
|
|
||||||
headers.set('Content-Length', '0');
|
|
||||||
return new Response(null, { status: opts.optionsSuccessStatus, headers });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we got here, it's a normal request
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initCors(options?: CorsOptions) {
|
|
||||||
return async (req: Request, res: Response) => cors(req, res, options);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import { DateTime } from 'luxon';
|
|
||||||
|
|
||||||
import { kyselyPrisma, sql } from '@documenso/prisma';
|
|
||||||
|
|
||||||
export const getUserMonthlyGrowth = async (type: 'count' | 'cumulative' = 'count') => {
|
|
||||||
const qb = kyselyPrisma.$kysely
|
|
||||||
.selectFrom('User')
|
|
||||||
.select(({ fn }) => [
|
|
||||||
fn<Date>('DATE_TRUNC', [sql.lit('MONTH'), 'User.createdAt']).as('month'),
|
|
||||||
fn.count('id').as('count'),
|
|
||||||
fn
|
|
||||||
.sum(fn.count('id'))
|
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
|
|
||||||
.over((ob) => ob.orderBy(fn('DATE_TRUNC', [sql.lit('MONTH'), 'User.createdAt']) as any))
|
|
||||||
.as('cume_count'),
|
|
||||||
])
|
|
||||||
.groupBy('month')
|
|
||||||
.orderBy('month', 'desc')
|
|
||||||
.limit(12);
|
|
||||||
|
|
||||||
const result = await qb.execute();
|
|
||||||
|
|
||||||
const transformedData = {
|
|
||||||
labels: result.map((row) => DateTime.fromJSDate(row.month).toFormat('MMM yyyy')).reverse(),
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: type === 'count' ? 'New Users' : 'Total Users',
|
|
||||||
data: result
|
|
||||||
.map((row) => (type === 'count' ? Number(row.count) : Number(row.cume_count)))
|
|
||||||
.reverse(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
return transformedData;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type GetUserMonthlyGrowthResult = Awaited<ReturnType<typeof getUserMonthlyGrowth>>;
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
type RepoStats = {
|
|
||||||
stars: number;
|
|
||||||
forks: number;
|
|
||||||
mergedPRs: number;
|
|
||||||
openIssues: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
type DataEntry = {
|
|
||||||
[key: string]: RepoStats;
|
|
||||||
};
|
|
||||||
|
|
||||||
type TransformedData = {
|
|
||||||
labels: string[];
|
|
||||||
datasets: {
|
|
||||||
label: string;
|
|
||||||
data: number[];
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
|
|
||||||
type MonthNames = {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MetricKey = keyof RepoStats;
|
|
||||||
|
|
||||||
const FRIENDLY_METRIC_NAMES: { [key in MetricKey]: string } = {
|
|
||||||
stars: 'Stars',
|
|
||||||
forks: 'Forks',
|
|
||||||
mergedPRs: 'Merged PRs',
|
|
||||||
openIssues: 'Open Issues',
|
|
||||||
};
|
|
||||||
|
|
||||||
export function transformRepoStats(data: DataEntry, metric: MetricKey): TransformedData {
|
|
||||||
const sortedEntries = Object.entries(data).sort(([dateA], [dateB]) => {
|
|
||||||
const [yearA, monthA] = dateA.split('-').map(Number);
|
|
||||||
const [yearB, monthB] = dateB.split('-').map(Number);
|
|
||||||
return new Date(yearA, monthA - 1).getTime() - new Date(yearB, monthB - 1).getTime();
|
|
||||||
});
|
|
||||||
|
|
||||||
const monthNames: MonthNames = {
|
|
||||||
'1': 'Jan',
|
|
||||||
'2': 'Feb',
|
|
||||||
'3': 'Mar',
|
|
||||||
'4': 'Apr',
|
|
||||||
'5': 'May',
|
|
||||||
'6': 'Jun',
|
|
||||||
'7': 'Jul',
|
|
||||||
'8': 'Aug',
|
|
||||||
'9': 'Sep',
|
|
||||||
'10': 'Oct',
|
|
||||||
'11': 'Nov',
|
|
||||||
'12': 'Dec',
|
|
||||||
};
|
|
||||||
|
|
||||||
const labels = sortedEntries.map(([date]) => {
|
|
||||||
const [year, month] = date.split('-');
|
|
||||||
const monthIndex = parseInt(month);
|
|
||||||
return `${monthNames[monthIndex.toString()]} ${year}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
labels,
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: `Total ${FRIENDLY_METRIC_NAMES[metric]}`,
|
|
||||||
data: sortedEntries.map(([_, stats]) => stats[metric]),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
|
||||||
const nextConfig = {};
|
|
||||||
|
|
||||||
module.exports = nextConfig;
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@documenso/openpage-api",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
|
||||||
"dev": "next dev -p 3003",
|
|
||||||
"build": "next build",
|
|
||||||
"start": "next start",
|
|
||||||
"lint:fix": "next lint --fix",
|
|
||||||
"clean": "rimraf .next && rimraf node_modules",
|
|
||||||
"copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@documenso/prisma": "*",
|
|
||||||
"next": "14.2.6"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "20.16.5",
|
|
||||||
"@types/react": "18.3.5",
|
|
||||||
"typescript": "5.5.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES2017",
|
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
|
||||||
"allowJs": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"strict": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"module": "esnext",
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"jsx": "preserve",
|
|
||||||
"incremental": true,
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "next"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["./*"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
||||||
"exclude": ["node_modules"]
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@documenso/web",
|
"name": "@documenso/web",
|
||||||
"version": "1.7.2-rc.1",
|
"version": "1.7.2-rc.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3000",
|
"dev": "next dev -p 3000",
|
||||||
"build": "turbo run translate:extract && turbo run translate:compile && next build",
|
"build": "npm run translate:extract --prefix ../../ && turbo run translate:compile && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"e2e:prepare": "next build && next start",
|
"e2e:prepare": "next build && next start",
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export const DeleteDocumentDialog = ({
|
|||||||
|
|
||||||
const onInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const onInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setInputValue(event.target.value);
|
setInputValue(event.target.value);
|
||||||
setIsDeleteEnabled(event.target.value === 'delete');
|
setIsDeleteEnabled(event.target.value === _(msg`delete`));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -117,10 +117,10 @@ export const MoveDocumentDialog = ({ documentId, open, onOpenChange }: MoveDocum
|
|||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="secondary" onClick={() => onOpenChange(false)}>
|
<Button variant="secondary" onClick={() => onOpenChange(false)}>
|
||||||
Cancel
|
<Trans>Cancel</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onMove} loading={isLoading} disabled={!selectedTeamId || isLoading}>
|
<Button onClick={onMove} loading={isLoading} disabled={!selectedTeamId || isLoading}>
|
||||||
{isLoading ? 'Moving...' : 'Move'}
|
{isLoading ? <Trans>Moving...</Trans> : <Trans>Move</Trans>}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { Trans } from '@lingui/macro';
|
import { Trans, msg } from '@lingui/macro';
|
||||||
import { useLingui } from '@lingui/react';
|
import { useLingui } from '@lingui/react';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
@@ -77,7 +77,7 @@ export const ConfigureDirectTemplateFormPartial = ({
|
|||||||
if (template.Recipient.map((recipient) => recipient.email).includes(items.email)) {
|
if (template.Recipient.map((recipient) => recipient.email).includes(items.email)) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
message: 'Email cannot already exist in the template',
|
message: _(msg`Email cannot already exist in the template`),
|
||||||
path: ['email'],
|
path: ['email'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
@@ -222,7 +222,7 @@ export default async function CompletedSigningPage({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{isLoggedIn && (
|
{isLoggedIn && (
|
||||||
<Link href="/documents" className="text-documenso-700 hover:text-documenso-600">
|
<Link href="/documents" className="text-documenso-700 hover:text-documenso-600 mt-2">
|
||||||
<Trans>Go Back Home</Trans>
|
<Trans>Go Back Home</Trans>
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -124,9 +124,9 @@ export const SigningForm = ({
|
|||||||
>
|
>
|
||||||
<div className={cn('flex flex-1 flex-col')}>
|
<div className={cn('flex flex-1 flex-col')}>
|
||||||
<h3 className="text-foreground text-2xl font-semibold">
|
<h3 className="text-foreground text-2xl font-semibold">
|
||||||
{recipient.role === RecipientRole.VIEWER && 'View Document'}
|
{recipient.role === RecipientRole.VIEWER && <Trans>View Document</Trans>}
|
||||||
{recipient.role === RecipientRole.SIGNER && 'Sign Document'}
|
{recipient.role === RecipientRole.SIGNER && <Trans>Sign Document</Trans>}
|
||||||
{recipient.role === RecipientRole.APPROVER && 'Approve Document'}
|
{recipient.role === RecipientRole.APPROVER && <Trans>Approve Document</Trans>}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{recipient.role === RecipientRole.VIEWER ? (
|
{recipient.role === RecipientRole.VIEWER ? (
|
||||||
@@ -166,7 +166,7 @@ export const SigningForm = ({
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<p className="text-muted-foreground mt-2 text-sm">
|
<p className="text-muted-foreground mt-2 text-sm">
|
||||||
Please review the document before signing.
|
<Trans>Please review the document before signing.</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr className="border-border mb-8 mt-4" />
|
<hr className="border-border mb-8 mt-4" />
|
||||||
@@ -174,7 +174,9 @@ export const SigningForm = ({
|
|||||||
<div className="-mx-2 flex flex-1 flex-col gap-4 overflow-y-auto px-2">
|
<div className="-mx-2 flex flex-1 flex-col gap-4 overflow-y-auto px-2">
|
||||||
<div className="flex flex-1 flex-col gap-y-4">
|
<div className="flex flex-1 flex-col gap-y-4">
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="full-name">Full Name</Label>
|
<Label htmlFor="full-name">
|
||||||
|
<Trans>Full Name</Trans>
|
||||||
|
</Label>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -186,7 +188,9 @@ export const SigningForm = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label htmlFor="Signature">Signature</Label>
|
<Label htmlFor="Signature">
|
||||||
|
<Trans>Signature</Trans>
|
||||||
|
</Label>
|
||||||
|
|
||||||
<Card className="mt-2" gradient degrees={-120}>
|
<Card className="mt-2" gradient degrees={-120}>
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
@@ -213,7 +217,7 @@ export const SigningForm = ({
|
|||||||
disabled={typeof window !== 'undefined' && window.history.length <= 1}
|
disabled={typeof window !== 'undefined' && window.history.length <= 1}
|
||||||
onClick={() => router.back()}
|
onClick={() => router.back()}
|
||||||
>
|
>
|
||||||
Cancel
|
<Trans>Cancel</Trans>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<SignDialog
|
<SignDialog
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { useTransition } from 'react';
|
|||||||
|
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
|
||||||
|
import { Trans, msg } from '@lingui/macro';
|
||||||
|
import { useLingui } from '@lingui/react';
|
||||||
import { Loader } from 'lucide-react';
|
import { Loader } from 'lucide-react';
|
||||||
|
|
||||||
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
|
import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc';
|
||||||
@@ -37,6 +39,7 @@ export const InitialsField = ({
|
|||||||
}: InitialsFieldProps) => {
|
}: InitialsFieldProps) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const { _ } = useLingui();
|
||||||
|
|
||||||
const { fullName } = useRequiredSigningContext();
|
const { fullName } = useRequiredSigningContext();
|
||||||
const initials = extractInitials(fullName);
|
const initials = extractInitials(fullName);
|
||||||
@@ -83,8 +86,8 @@ export const InitialsField = ({
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: 'Error',
|
title: _(msg`Error`),
|
||||||
description: 'An error occurred while signing the document.',
|
description: _(msg`An error occurred while signing the document.`),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -109,8 +112,8 @@ export const InitialsField = ({
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: 'Error',
|
title: _(msg`Error`),
|
||||||
description: 'An error occurred while removing the signature.',
|
description: _(msg`An error occurred while removing the field.`),
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -126,7 +129,7 @@ export const InitialsField = ({
|
|||||||
|
|
||||||
{!field.inserted && (
|
{!field.inserted && (
|
||||||
<p className="group-hover:text-primary text-muted-foreground duration-200 group-hover:text-yellow-300">
|
<p className="group-hover:text-primary text-muted-foreground duration-200 group-hover:text-yellow-300">
|
||||||
Initials
|
<Trans>Initials</Trans>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -43,12 +43,6 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
|
|||||||
|
|
||||||
const requestMetadata = extractNextHeaderRequestMetadata(requestHeaders);
|
const requestMetadata = extractNextHeaderRequestMetadata(requestHeaders);
|
||||||
|
|
||||||
const isRecipientsTurn = await getIsRecipientsTurnToSign({ token });
|
|
||||||
|
|
||||||
if (!isRecipientsTurn) {
|
|
||||||
return redirect(`/sign/${token}/waiting`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const [document, fields, recipient, completedFields] = await Promise.all([
|
const [document, fields, recipient, completedFields] = await Promise.all([
|
||||||
getDocumentAndSenderByToken({
|
getDocumentAndSenderByToken({
|
||||||
token,
|
token,
|
||||||
@@ -69,6 +63,12 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
|
|||||||
return notFound();
|
return notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isRecipientsTurn = await getIsRecipientsTurnToSign({ token });
|
||||||
|
|
||||||
|
if (!isRecipientsTurn) {
|
||||||
|
return redirect(`/sign/${token}/waiting`);
|
||||||
|
}
|
||||||
|
|
||||||
const { derivedRecipientAccessAuth } = extractDocumentAuthMethods({
|
const { derivedRecipientAccessAuth } = extractDocumentAuthMethods({
|
||||||
documentAuth: document.authOptions,
|
documentAuth: document.authOptions,
|
||||||
recipientAuth: recipient.authOptions,
|
recipientAuth: recipient.authOptions,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
@@ -97,17 +97,11 @@ export default async function ApiTokensPage({ params }: ApiTokensPageProps) {
|
|||||||
<h5 className="text-base">{token.name}</h5>
|
<h5 className="text-base">{token.name}</h5>
|
||||||
|
|
||||||
<p className="text-muted-foreground mt-2 text-xs">
|
<p className="text-muted-foreground mt-2 text-xs">
|
||||||
<Trans>
|
<Trans>Created on {i18n.date(token.createdAt, DateTime.DATETIME_FULL)}</Trans>
|
||||||
Created on
|
|
||||||
{i18n.date(token.createdAt, DateTime.DATETIME_FULL)}
|
|
||||||
</Trans>
|
|
||||||
</p>
|
</p>
|
||||||
{token.expires ? (
|
{token.expires ? (
|
||||||
<p className="text-muted-foreground mt-1 text-xs">
|
<p className="text-muted-foreground mt-1 text-xs">
|
||||||
<Trans>
|
<Trans>Expires on {i18n.date(token.expires, DateTime.DATETIME_FULL)}</Trans>
|
||||||
Expires on
|
|
||||||
{i18n.date(token.expires, DateTime.DATETIME_FULL)}
|
|
||||||
</Trans>
|
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-muted-foreground mt-1 text-xs">
|
<p className="text-muted-foreground mt-1 text-xs">
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -5,101 +5,156 @@ import { Trans } from '@lingui/macro';
|
|||||||
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
import { setupI18nSSR } from '@documenso/lib/client-only/providers/i18n.server';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
|
|
||||||
export default function SignatureDisclosure() {
|
const SUPPORT_EMAIL = 'support@documenso.com';
|
||||||
setupI18nSSR();
|
|
||||||
|
export default async function SignatureDisclosure() {
|
||||||
|
await setupI18nSSR();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<article className="prose dark:prose-invert">
|
<article className="prose dark:prose-invert">
|
||||||
<h1>Electronic Signature Disclosure</h1>
|
<h1>
|
||||||
|
<Trans>Electronic Signature Disclosure</Trans>
|
||||||
|
</h1>
|
||||||
|
|
||||||
<h2>Welcome</h2>
|
<h2>
|
||||||
|
<Trans>Welcome</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
Thank you for using Documenso to perform your electronic document signing. The purpose of
|
<Trans>
|
||||||
this disclosure is to inform you about the process, legality, and your rights regarding
|
Thank you for using Documenso to perform your electronic document signing. The purpose
|
||||||
the use of electronic signatures on our platform. By opting to use an electronic
|
of this disclosure is to inform you about the process, legality, and your rights
|
||||||
signature, you are agreeing to the terms and conditions outlined below.
|
regarding the use of electronic signatures on our platform. By opting to use an
|
||||||
|
electronic signature, you are agreeing to the terms and conditions outlined below.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Acceptance and Consent</h2>
|
<h2>
|
||||||
|
<Trans>Acceptance and Consent</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
|
<Trans>
|
||||||
When you use our platform to affix your electronic signature to documents, you are
|
When you use our platform to affix your electronic signature to documents, you are
|
||||||
consenting to do so under the Electronic Signatures in Global and National Commerce Act
|
consenting to do so under the Electronic Signatures in Global and National Commerce Act
|
||||||
(E-Sign Act) and other applicable laws. This action indicates your agreement to use
|
(E-Sign Act) and other applicable laws. This action indicates your agreement to use
|
||||||
electronic means to sign documents and receive notifications.
|
electronic means to sign documents and receive notifications.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Legality of Electronic Signatures</h2>
|
<h2>
|
||||||
|
<Trans>Legality of Electronic Signatures</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
An electronic signature provided by you on our platform, achieved through clicking through
|
<Trans>
|
||||||
to a document and entering your name, or any other electronic signing method we provide,
|
An electronic signature provided by you on our platform, achieved through clicking
|
||||||
is legally binding. It carries the same weight and enforceability as a manual signature
|
through to a document and entering your name, or any other electronic signing method we
|
||||||
written with ink on paper.
|
provide, is legally binding. It carries the same weight and enforceability as a manual
|
||||||
|
signature written with ink on paper.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>System Requirements</h2>
|
<h2>
|
||||||
<p>To use our electronic signature service, you must have access to:</p>
|
<Trans>System Requirements</Trans>
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
<Trans>To use our electronic signature service, you must have access to:</Trans>
|
||||||
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>A stable internet connection</li>
|
<li>
|
||||||
<li>An email account</li>
|
<Trans>A stable internet connection</Trans>
|
||||||
<li>A device capable of accessing, opening, and reading documents</li>
|
</li>
|
||||||
<li>A means to print or download documents for your records</li>
|
<li>
|
||||||
|
<Trans>An email account</Trans>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Trans>A device capable of accessing, opening, and reading documents</Trans>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Trans>A means to print or download documents for your records</Trans>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Electronic Delivery of Documents</h2>
|
<h2>
|
||||||
|
<Trans>Electronic Delivery of Documents</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
|
<Trans>
|
||||||
All documents related to the electronic signing process will be provided to you
|
All documents related to the electronic signing process will be provided to you
|
||||||
electronically through our platform or via email. It is your responsibility to ensure that
|
electronically through our platform or via email. It is your responsibility to ensure
|
||||||
your email address is current and that you can receive and open our emails.
|
that your email address is current and that you can receive and open our emails.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Consent to Electronic Transactions</h2>
|
<h2>
|
||||||
|
<Trans>Consent to Electronic Transactions</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
By using the electronic signature feature, you are consenting to conduct transactions and
|
<Trans>
|
||||||
receive disclosures electronically. You acknowledge that your electronic signature on
|
By using the electronic signature feature, you are consenting to conduct transactions
|
||||||
documents is binding and that you accept the terms outlined in the documents you are
|
and receive disclosures electronically. You acknowledge that your electronic signature
|
||||||
|
on documents is binding and that you accept the terms outlined in the documents you are
|
||||||
signing.
|
signing.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Withdrawing Consent</h2>
|
<h2>
|
||||||
|
<Trans>Withdrawing Consent</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
|
<Trans>
|
||||||
You have the right to withdraw your consent to use electronic signatures at any time
|
You have the right to withdraw your consent to use electronic signatures at any time
|
||||||
before completing the signing process. To withdraw your consent, please contact the sender
|
before completing the signing process. To withdraw your consent, please contact the
|
||||||
of the document. In failing to contact the sender you may reach out to{' '}
|
sender of the document. In failing to contact the sender you may reach out to{' '}
|
||||||
<a href="mailto:support@documenso.com">support@documenso.com</a> for assistance. Be aware
|
<a href={`mailto:${SUPPORT_EMAIL}`}>{SUPPORT_EMAIL}</a> for assistance. Be aware that
|
||||||
that withdrawing consent may delay or halt the completion of the related transaction or
|
withdrawing consent may delay or halt the completion of the related transaction or
|
||||||
service.
|
service.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Updating Your Information</h2>
|
<h2>
|
||||||
|
<Trans>Updating Your Information</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
It is crucial to keep your contact information, especially your email address, up to date
|
<Trans>
|
||||||
with us. Please notify us immediately of any changes to ensure that you continue to
|
It is crucial to keep your contact information, especially your email address, up to
|
||||||
|
date with us. Please notify us immediately of any changes to ensure that you continue to
|
||||||
receive all necessary communications.
|
receive all necessary communications.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Retention of Documents</h2>
|
<h2>
|
||||||
|
<Trans>Retention of Documents</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
|
<Trans>
|
||||||
After signing a document electronically, you will be provided the opportunity to view,
|
After signing a document electronically, you will be provided the opportunity to view,
|
||||||
download, and print the document for your records. It is highly recommended that you
|
download, and print the document for your records. It is highly recommended that you
|
||||||
retain a copy of all electronically signed documents for your personal records. We will
|
retain a copy of all electronically signed documents for your personal records. We will
|
||||||
also retain a copy of the signed document for our records however we may not be able to
|
also retain a copy of the signed document for our records however we may not be able to
|
||||||
provide you with a copy of the signed document after a certain period of time.
|
provide you with a copy of the signed document after a certain period of time.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Acknowledgment</h2>
|
<h2>
|
||||||
|
<Trans>Acknowledgment</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
|
<Trans>
|
||||||
By proceeding to use the electronic signature service provided by Documenso, you affirm
|
By proceeding to use the electronic signature service provided by Documenso, you affirm
|
||||||
that you have read and understood this disclosure. You agree to all terms and conditions
|
that you have read and understood this disclosure. You agree to all terms and conditions
|
||||||
related to the use of electronic signatures and electronic transactions as outlined
|
related to the use of electronic signatures and electronic transactions as outlined
|
||||||
herein.
|
herein.
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Contact Information</h2>
|
<h2>
|
||||||
|
<Trans>Contact Information</Trans>
|
||||||
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
|
<Trans>
|
||||||
For any questions regarding this disclosure, electronic signatures, or any related
|
For any questions regarding this disclosure, electronic signatures, or any related
|
||||||
process, please contact us at:{' '}
|
process, please contact us at: <a href={`mailto:${SUPPORT_EMAIL}`}>{SUPPORT_EMAIL}</a>
|
||||||
<a href="mailto:support@documenso.com">support@documenso.com</a>
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user