mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
Merge branch 'feat/refresh' into feat/improve-readability
This commit is contained in:
7
.eslintignore
Normal file
7
.eslintignore
Normal file
@ -0,0 +1,7 @@
|
||||
# Config files
|
||||
*.config.js
|
||||
*.config.cjs
|
||||
|
||||
# Statically hosted javascript files
|
||||
apps/*/public/*.js
|
||||
apps/*/public/*.cjs
|
||||
@ -5,7 +5,7 @@ import { allDocuments } from 'contentlayer/generated';
|
||||
import type { MDXComponents } from 'mdx/types';
|
||||
import { useMDXComponent } from 'next-contentlayer/hooks';
|
||||
|
||||
export const generateStaticParams = async () =>
|
||||
export const generateStaticParams = () =>
|
||||
allDocuments.map((post) => ({ post: post._raw.flattenedPath }));
|
||||
|
||||
export const generateMetadata = ({ params }: { params: { content: string } }) => {
|
||||
|
||||
@ -7,7 +7,7 @@ import { ChevronLeft } from 'lucide-react';
|
||||
import type { MDXComponents } from 'mdx/types';
|
||||
import { useMDXComponent } from 'next-contentlayer/hooks';
|
||||
|
||||
export const generateStaticParams = async () =>
|
||||
export const generateStaticParams = () =>
|
||||
allBlogPosts.map((post) => ({ post: post._raw.flattenedPath }));
|
||||
|
||||
export const generateMetadata = ({ params }: { params: { post: string } }) => {
|
||||
|
||||
@ -43,7 +43,7 @@ export default async function OpenPage() {
|
||||
accept: 'application/vnd.github.v3+json',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(async (res) => res.json())
|
||||
.then((res) => ZGithubStatsResponse.parse(res));
|
||||
|
||||
const { total_count: mergedPullRequests } = await fetch(
|
||||
@ -54,7 +54,7 @@ export default async function OpenPage() {
|
||||
},
|
||||
},
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then(async (res) => res.json())
|
||||
.then((res) => ZMergedPullRequestsResponse.parse(res));
|
||||
|
||||
const STARGAZERS_DATA = await fetch('https://stargrazer-live.onrender.com/api/stats', {
|
||||
@ -62,7 +62,7 @@ export default async function OpenPage() {
|
||||
accept: 'application/json',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(async (res) => res.json())
|
||||
.then((res) => ZStargazersLiveResponse.parse(res));
|
||||
|
||||
return (
|
||||
|
||||
@ -24,7 +24,7 @@ export default async function IndexPage() {
|
||||
accept: 'application/vnd.github.v3+json',
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(async (res) => res.json())
|
||||
.then((res) => (typeof res.stargazers_count === 'number' ? res.stargazers_count : undefined))
|
||||
.catch(() => undefined);
|
||||
|
||||
|
||||
@ -63,7 +63,9 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog
|
||||
|
||||
const onFormSubmit = async ({ name, email }: TClaimPlanDialogFormSchema) => {
|
||||
try {
|
||||
const delay = new Promise<void>((resolve) => setTimeout(resolve, 1000));
|
||||
const delay = new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 1000);
|
||||
});
|
||||
|
||||
const [redirectUrl] = await Promise.all([
|
||||
claimPlan({ name, email, planId, signatureText: name, signatureDataUrl: null }),
|
||||
|
||||
@ -13,7 +13,7 @@ export const PasswordReveal = ({ password }: PasswordRevealProps) => {
|
||||
const [, copy] = useCopyToClipboard();
|
||||
|
||||
const onCopyClick = () => {
|
||||
copy(password).then(() => {
|
||||
void copy(password).then(() => {
|
||||
toast({
|
||||
title: 'Copied to clipboard',
|
||||
description: 'Your password has been copied to your clipboard.',
|
||||
|
||||
@ -124,7 +124,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
|
||||
setValue('signatureDataUrl', draftSignatureDataUrl);
|
||||
setValue('signatureText', '');
|
||||
|
||||
trigger('signatureDataUrl');
|
||||
void trigger('signatureDataUrl');
|
||||
setShowSigningDialog(false);
|
||||
};
|
||||
|
||||
@ -135,7 +135,9 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
|
||||
signatureText,
|
||||
}: TWidgetFormSchema) => {
|
||||
try {
|
||||
const delay = new Promise<void>((resolve) => setTimeout(resolve, 1000));
|
||||
const delay = new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 1000);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const planId = process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID;
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
"copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@documenso/ee": "*",
|
||||
"@documenso/lib": "*",
|
||||
"@documenso/prisma": "*",
|
||||
"@documenso/tailwind-config": "*",
|
||||
@ -21,6 +22,7 @@
|
||||
"formidable": "^2.1.1",
|
||||
"framer-motion": "^10.12.8",
|
||||
"lucide-react": "^0.214.0",
|
||||
"luxon": "^3.4.0",
|
||||
"micro": "^10.0.1",
|
||||
"nanoid": "^4.0.2",
|
||||
"next": "13.4.12",
|
||||
@ -43,6 +45,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/formidable": "^2.0.6",
|
||||
"@types/luxon": "^3.3.1",
|
||||
"@types/node": "20.1.0",
|
||||
"@types/react": "18.2.18",
|
||||
"@types/react-dom": "18.2.7"
|
||||
|
||||
@ -22,14 +22,14 @@ import { LocaleDate } from '~/components/formatter/locale-date';
|
||||
import { UploadDocument } from './upload-document';
|
||||
|
||||
export default async function DashboardPage() {
|
||||
const session = await getRequiredServerComponentSession();
|
||||
const user = await getRequiredServerComponentSession();
|
||||
|
||||
const [stats, results] = await Promise.all([
|
||||
getStats({
|
||||
userId: session.id,
|
||||
user,
|
||||
}),
|
||||
findDocuments({
|
||||
userId: session.id,
|
||||
userId: user.id,
|
||||
perPage: 10,
|
||||
}),
|
||||
]);
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
|
||||
import { Edit, Pencil, Share } from 'lucide-react';
|
||||
import { useSession } from 'next-auth/react';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { Document, DocumentStatus, Recipient, SigningStatus, User } from '@documenso/prisma/client';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
|
||||
export type DataTableActionButtonProps = {
|
||||
row: Document & {
|
||||
User: Pick<User, 'id' | 'name' | 'email'>;
|
||||
Recipient: Recipient[];
|
||||
};
|
||||
};
|
||||
|
||||
export const DataTableActionButton = ({ row }: DataTableActionButtonProps) => {
|
||||
const { data: session } = useSession();
|
||||
|
||||
if (!session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const recipient = row.Recipient.find((recipient) => recipient.email === session.user.email);
|
||||
|
||||
const isOwner = row.User.id === session.user.id;
|
||||
const isRecipient = !!recipient;
|
||||
const isDraft = row.status === DocumentStatus.DRAFT;
|
||||
const isPending = row.status === DocumentStatus.PENDING;
|
||||
const isComplete = row.status === DocumentStatus.COMPLETED;
|
||||
const isSigned = recipient?.signingStatus === SigningStatus.SIGNED;
|
||||
|
||||
return match({
|
||||
isOwner,
|
||||
isRecipient,
|
||||
isDraft,
|
||||
isPending,
|
||||
isComplete,
|
||||
isSigned,
|
||||
})
|
||||
.with({ isOwner: true, isDraft: true }, () => (
|
||||
<Button className="w-24" asChild>
|
||||
<Link href={`/documents/${row.id}`}>
|
||||
<Edit className="-ml-1 mr-2 h-4 w-4" />
|
||||
Edit
|
||||
</Link>
|
||||
</Button>
|
||||
))
|
||||
.with({ isRecipient: true, isPending: true, isSigned: false }, () => (
|
||||
<Button className="w-24" asChild>
|
||||
<Link href={`/sign/${recipient?.token}`}>
|
||||
<Pencil className="-ml-1 mr-2 h-4 w-4" />
|
||||
Sign
|
||||
</Link>
|
||||
</Button>
|
||||
))
|
||||
.otherwise(() => (
|
||||
<Button className="w-24" disabled>
|
||||
<Share className="-ml-1 mr-2 h-4 w-4" />
|
||||
Share
|
||||
</Button>
|
||||
));
|
||||
};
|
||||
@ -0,0 +1,133 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
|
||||
import {
|
||||
Copy,
|
||||
Download,
|
||||
Edit,
|
||||
History,
|
||||
MoreHorizontal,
|
||||
Pencil,
|
||||
Share,
|
||||
Trash2,
|
||||
XCircle,
|
||||
} from 'lucide-react';
|
||||
import { useSession } from 'next-auth/react';
|
||||
|
||||
import { Document, DocumentStatus, Recipient, User } from '@documenso/prisma/client';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuTrigger,
|
||||
} from '@documenso/ui/primitives/dropdown-menu';
|
||||
|
||||
export type DataTableActionDropdownProps = {
|
||||
row: Document & {
|
||||
User: Pick<User, 'id' | 'name' | 'email'>;
|
||||
Recipient: Recipient[];
|
||||
};
|
||||
};
|
||||
|
||||
export const DataTableActionDropdown = ({ row }: DataTableActionDropdownProps) => {
|
||||
const { data: session } = useSession();
|
||||
|
||||
if (!session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const recipient = row.Recipient.find((recipient) => recipient.email === session.user.email);
|
||||
|
||||
const isOwner = row.User.id === session.user.id;
|
||||
// const isRecipient = !!recipient;
|
||||
// const isDraft = row.status === DocumentStatus.DRAFT;
|
||||
// const isPending = row.status === DocumentStatus.PENDING;
|
||||
const isComplete = row.status === DocumentStatus.COMPLETED;
|
||||
// const isSigned = recipient?.signingStatus === SigningStatus.SIGNED;
|
||||
|
||||
const onDownloadClick = () => {
|
||||
let decodedDocument = row.document;
|
||||
|
||||
try {
|
||||
decodedDocument = atob(decodedDocument);
|
||||
} catch (err) {
|
||||
// We're just going to ignore this error and try to download the document
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
const documentBytes = Uint8Array.from(decodedDocument.split('').map((c) => c.charCodeAt(0)));
|
||||
|
||||
const blob = new Blob([documentBytes], {
|
||||
type: 'application/pdf',
|
||||
});
|
||||
|
||||
const link = window.document.createElement('a');
|
||||
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = row.title || 'document.pdf';
|
||||
|
||||
link.click();
|
||||
|
||||
window.URL.revokeObjectURL(link.href);
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<MoreHorizontal className="h-5 w-5 text-gray-500" />
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent className="w-52" align="start" forceMount>
|
||||
<DropdownMenuLabel>Action</DropdownMenuLabel>
|
||||
|
||||
<DropdownMenuItem disabled={!recipient} asChild>
|
||||
<Link href={`/sign/${recipient?.token}`}>
|
||||
<Pencil className="mr-2 h-4 w-4" />
|
||||
Sign
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem disabled={!isOwner} asChild>
|
||||
<Link href={`/documents/${row.id}`}>
|
||||
<Edit className="mr-2 h-4 w-4" />
|
||||
Edit
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem disabled={!isComplete} onClick={onDownloadClick}>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
Download
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem disabled>
|
||||
<Copy className="mr-2 h-4 w-4" />
|
||||
Duplicate
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem disabled>
|
||||
<XCircle className="mr-2 h-4 w-4" />
|
||||
Void
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem disabled>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuLabel>Share</DropdownMenuLabel>
|
||||
|
||||
<DropdownMenuItem disabled>
|
||||
<History className="mr-2 h-4 w-4" />
|
||||
Resend
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem disabled>
|
||||
<Share className="mr-2 h-4 w-4" />
|
||||
Share
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
@ -8,7 +8,7 @@ import { Loader } from 'lucide-react';
|
||||
|
||||
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
|
||||
import { FindResultSet } from '@documenso/lib/types/find-result-set';
|
||||
import { DocumentWithReciepient } from '@documenso/prisma/types/document-with-recipient';
|
||||
import { Document, Recipient, User } from '@documenso/prisma/client';
|
||||
import { DataTable } from '@documenso/ui/primitives/data-table';
|
||||
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
|
||||
|
||||
@ -16,8 +16,16 @@ import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-a
|
||||
import { DocumentStatus } from '~/components/formatter/document-status';
|
||||
import { LocaleDate } from '~/components/formatter/locale-date';
|
||||
|
||||
import { DataTableActionButton } from './data-table-action-button';
|
||||
import { DataTableActionDropdown } from './data-table-action-dropdown';
|
||||
|
||||
export type DocumentsDataTableProps = {
|
||||
results: FindResultSet<DocumentWithReciepient>;
|
||||
results: FindResultSet<
|
||||
Document & {
|
||||
Recipient: Recipient[];
|
||||
User: Pick<User, 'id' | 'name' | 'email'>;
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => {
|
||||
@ -45,7 +53,11 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => {
|
||||
{
|
||||
header: 'Title',
|
||||
cell: ({ row }) => (
|
||||
<Link href={`/documents/${row.original.id}`} className="font-medium hover:underline">
|
||||
<Link
|
||||
href={`/documents/${row.original.id}`}
|
||||
title={row.original.title}
|
||||
className="block max-w-[10rem] truncate font-medium hover:underline md:max-w-[20rem]"
|
||||
>
|
||||
{row.original.title}
|
||||
</Link>
|
||||
),
|
||||
@ -67,6 +79,15 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => {
|
||||
accessorKey: 'created',
|
||||
cell: ({ row }) => <LocaleDate date={row.getValue('created')} />,
|
||||
},
|
||||
{
|
||||
header: 'Actions',
|
||||
cell: ({ row }) => (
|
||||
<div className="flex items-center gap-x-4">
|
||||
<DataTableActionButton row={row.original} />
|
||||
<DataTableActionDropdown row={row.original} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
data={results.data}
|
||||
perPage={results.perPage}
|
||||
|
||||
@ -3,8 +3,8 @@ import Link from 'next/link';
|
||||
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-session';
|
||||
import { findDocuments } from '@documenso/lib/server-only/document/find-documents';
|
||||
import { getStats } from '@documenso/lib/server-only/document/get-stats';
|
||||
import { isDocumentStatus } from '@documenso/lib/types/is-document-status';
|
||||
import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/client';
|
||||
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
|
||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||
import { Tabs, TabsList, TabsTrigger } from '@documenso/ui/primitives/tabs';
|
||||
|
||||
import { PeriodSelector } from '~/components/(dashboard)/period-selector/period-selector';
|
||||
@ -16,7 +16,7 @@ import { DocumentsDataTable } from './data-table';
|
||||
|
||||
export type DocumentsPageProps = {
|
||||
searchParams?: {
|
||||
status?: InternalDocumentStatus | 'ALL';
|
||||
status?: ExtendedDocumentStatus;
|
||||
period?: PeriodSelectorValue;
|
||||
page?: string;
|
||||
perPage?: string;
|
||||
@ -24,22 +24,20 @@ export type DocumentsPageProps = {
|
||||
};
|
||||
|
||||
export default async function DocumentsPage({ searchParams = {} }: DocumentsPageProps) {
|
||||
const session = await getRequiredServerComponentSession();
|
||||
const user = await getRequiredServerComponentSession();
|
||||
|
||||
const stats = await getStats({
|
||||
userId: session.id,
|
||||
user,
|
||||
});
|
||||
|
||||
const status = isDocumentStatus(searchParams.status) ? searchParams.status : 'ALL';
|
||||
const status = isExtendedDocumentStatus(searchParams.status) ? searchParams.status : 'ALL';
|
||||
// const period = isPeriodSelectorValue(searchParams.period) ? searchParams.period : '';
|
||||
const page = Number(searchParams.page) || 1;
|
||||
const perPage = Number(searchParams.perPage) || 20;
|
||||
|
||||
const shouldDefaultToPending = status === 'ALL' && stats.PENDING > 0;
|
||||
|
||||
const results = await findDocuments({
|
||||
userId: session.id,
|
||||
status: status === 'ALL' ? undefined : status,
|
||||
userId: user.id,
|
||||
status,
|
||||
orderBy: {
|
||||
column: 'created',
|
||||
direction: 'desc',
|
||||
@ -57,10 +55,6 @@ export default async function DocumentsPage({ searchParams = {} }: DocumentsPage
|
||||
params.delete('page');
|
||||
}
|
||||
|
||||
if (value === 'ALL') {
|
||||
params.delete('status');
|
||||
}
|
||||
|
||||
return `/documents?${params.toString()}`;
|
||||
};
|
||||
|
||||
@ -70,47 +64,28 @@ export default async function DocumentsPage({ searchParams = {} }: DocumentsPage
|
||||
|
||||
<h1 className="mt-12 text-4xl font-semibold">Documents</h1>
|
||||
|
||||
<div className="mt-8 flex flex-wrap gap-x-4 gap-y-6 ">
|
||||
<Tabs
|
||||
className="overflow-x-auto"
|
||||
defaultValue={shouldDefaultToPending ? InternalDocumentStatus.PENDING : status}
|
||||
>
|
||||
<div className="mt-8 flex flex-wrap gap-x-4 gap-y-6">
|
||||
<Tabs defaultValue={status} className="overflow-x-auto">
|
||||
<TabsList>
|
||||
<TabsTrigger className="min-w-[60px]" value={InternalDocumentStatus.PENDING} asChild>
|
||||
<Link href={getTabHref(InternalDocumentStatus.PENDING)} scroll={false}>
|
||||
<DocumentStatus status={InternalDocumentStatus.PENDING} />
|
||||
{[
|
||||
ExtendedDocumentStatus.INBOX,
|
||||
ExtendedDocumentStatus.PENDING,
|
||||
ExtendedDocumentStatus.COMPLETED,
|
||||
ExtendedDocumentStatus.DRAFT,
|
||||
ExtendedDocumentStatus.ALL,
|
||||
].map((value) => (
|
||||
<TabsTrigger key={value} className="min-w-[60px]" value={value} asChild>
|
||||
<Link href={getTabHref(value)} scroll={false}>
|
||||
<DocumentStatus status={value} />
|
||||
|
||||
<span className="ml-1 hidden opacity-50 md:inline-block">
|
||||
{Math.min(stats.PENDING, 99)}
|
||||
</span>
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
|
||||
<TabsTrigger className="min-w-[60px]" value={InternalDocumentStatus.COMPLETED} asChild>
|
||||
<Link href={getTabHref(InternalDocumentStatus.COMPLETED)} scroll={false}>
|
||||
<DocumentStatus status={InternalDocumentStatus.COMPLETED} />
|
||||
|
||||
<span className="ml-1 hidden opacity-50 md:inline-block">
|
||||
{Math.min(stats.COMPLETED, 99)}
|
||||
</span>
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
|
||||
<TabsTrigger className="min-w-[60px]" value={InternalDocumentStatus.DRAFT} asChild>
|
||||
<Link href={getTabHref(InternalDocumentStatus.DRAFT)} scroll={false}>
|
||||
<DocumentStatus status={InternalDocumentStatus.DRAFT} />
|
||||
|
||||
<span className="ml-1 hidden opacity-50 md:inline-block">
|
||||
{Math.min(stats.DRAFT, 99)}
|
||||
</span>
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
|
||||
<TabsTrigger className="min-w-[60px]" value="ALL" asChild>
|
||||
<Link href={getTabHref('ALL')} scroll={false}>
|
||||
All
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
{value !== ExtendedDocumentStatus.ALL && (
|
||||
<span className="ml-1 hidden opacity-50 md:inline-block">
|
||||
{Math.min(stats[value], 99)}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
import Link from 'next/link';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { createCustomer } from '@documenso/ee/server-only/stripe/create-customer';
|
||||
import { getPortalSession } from '@documenso/ee/server-only/stripe/get-portal-session';
|
||||
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-session';
|
||||
import { getSubscriptionByUserId } from '@documenso/lib/server-only/subscription/get-subscription-by-user-id';
|
||||
import { SubscriptionStatus } from '@documenso/prisma/client';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
|
||||
import { PasswordForm } from '~/components/forms/password';
|
||||
import { LocaleDate } from '~/components/formatter/locale-date';
|
||||
import { getServerComponentFlag } from '~/helpers/get-server-component-feature-flag';
|
||||
|
||||
export default async function BillingSettingsPage() {
|
||||
@ -15,17 +21,55 @@ export default async function BillingSettingsPage() {
|
||||
redirect('/settings/profile');
|
||||
}
|
||||
|
||||
let subscription = await getSubscriptionByUserId({ userId: user.id });
|
||||
|
||||
// If we don't have a customer record, create one as well as an empty subscription.
|
||||
if (!subscription?.customerId) {
|
||||
subscription = await createCustomer({ user });
|
||||
}
|
||||
|
||||
let billingPortalUrl = '';
|
||||
|
||||
if (subscription?.customerId) {
|
||||
billingPortalUrl = await getPortalSession({
|
||||
customerId: subscription.customerId,
|
||||
returnUrl: `${process.env.NEXT_PUBLIC_SITE_URL}/settings/billing`,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">Billing</h3>
|
||||
|
||||
<p className="mt-2 text-sm text-slate-500">
|
||||
Here you can update and manage your subscription.
|
||||
Your subscription is{' '}
|
||||
{subscription.status !== SubscriptionStatus.INACTIVE ? 'active' : 'inactive'}.
|
||||
{subscription?.periodEnd && (
|
||||
<>
|
||||
{' '}
|
||||
Your next payment is due on{' '}
|
||||
<span className="font-semibold">
|
||||
<LocaleDate date={subscription.periodEnd} />
|
||||
</span>
|
||||
.
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
|
||||
<hr className="my-4" />
|
||||
|
||||
<PasswordForm user={user} className="max-w-xl" />
|
||||
{billingPortalUrl && (
|
||||
<Button asChild>
|
||||
<Link href={billingPortalUrl}>Manage Subscription</Link>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!billingPortalUrl && (
|
||||
<p className="max-w-[60ch] text-base text-slate-500">
|
||||
You do not currently have a customer record, this should not happen. Please contact
|
||||
support for assistance.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ export const NameField = ({ field, recipient }: NameFieldProps) => {
|
||||
disabled={!localFullName}
|
||||
onClick={() => {
|
||||
setShowFullNameModal(false);
|
||||
onSign('local');
|
||||
void onSign('local');
|
||||
}}
|
||||
>
|
||||
Sign
|
||||
|
||||
@ -182,7 +182,7 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => {
|
||||
disabled={!localSignature}
|
||||
onClick={() => {
|
||||
setShowSignatureModal(false);
|
||||
onSign('local');
|
||||
void onSign('local');
|
||||
}}
|
||||
>
|
||||
Sign
|
||||
|
||||
@ -7,13 +7,15 @@ import { cn } from '@documenso/ui/lib/utils';
|
||||
export type DesktopNavProps = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
export const DesktopNav = ({ className, ...props }: DesktopNavProps) => {
|
||||
// const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<div className={cn('ml-8 hidden flex-1 gap-x-6 md:flex', className)} {...props}>
|
||||
{/* No Nav tabs while there is only one main page */}
|
||||
{/* We have no other subpaths rn */}
|
||||
{/* <Link
|
||||
href="/documents"
|
||||
className={cn(
|
||||
'text-muted-foreground focus-visible:ring-ring ring-offset-background rounded-md font-medium leading-5 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2 ',
|
||||
'text-muted-foreground focus-visible:ring-ring ring-offset-background rounded-md font-medium leading-5 hover:opacity-80 focus-visible:outline-none focus-visible:ring-2',
|
||||
{
|
||||
'text-foreground': pathname?.startsWith('/documents'),
|
||||
},
|
||||
|
||||
@ -4,11 +4,8 @@ import { HTMLAttributes } from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
|
||||
import { Menu } from 'lucide-react';
|
||||
|
||||
import { User } from '@documenso/prisma/client';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
import { Button } from '@documenso/ui/primitives/button';
|
||||
|
||||
import { Logo } from '~/components/branding/logo';
|
||||
|
||||
@ -23,7 +20,7 @@ export const Header = ({ className, user, ...props }: HeaderProps) => {
|
||||
return (
|
||||
<header
|
||||
className={cn(
|
||||
'supports-backdrop-blur:bg-background/60 bg-background/95 sticky top-0 z-40 flex h-16 w-full items-center border-b backdrop-blur',
|
||||
'supports-backdrop-blur:bg-background/60 bg-background/95 sticky top-0 z-50 flex h-16 w-full items-center border-b backdrop-blur',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
@ -41,9 +38,9 @@ export const Header = ({ className, user, ...props }: HeaderProps) => {
|
||||
<div className="flex gap-x-4">
|
||||
<ProfileDropdown user={user} />
|
||||
|
||||
<Button variant="outline" size="sm" className="h-10 w-10 p-0.5 md:hidden">
|
||||
{/* <Button variant="outline" size="sm" className="h-10 w-10 p-0.5 md:hidden">
|
||||
<Menu className="h-6 w-6" />
|
||||
</Button>
|
||||
</Button> */}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@ -118,7 +118,7 @@ export const ProfileDropdown = ({ user }: ProfileDropdownProps) => {
|
||||
|
||||
<DropdownMenuItem
|
||||
onSelect={() =>
|
||||
signOut({
|
||||
void signOut({
|
||||
callbackUrl: '/',
|
||||
})
|
||||
}
|
||||
|
||||
@ -63,7 +63,9 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog
|
||||
|
||||
const onFormSubmit = async ({ name, email }: TClaimPlanDialogFormSchema) => {
|
||||
try {
|
||||
const delay = new Promise<void>((resolve) => setTimeout(resolve, 1000));
|
||||
const delay = new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 1000);
|
||||
});
|
||||
|
||||
const [redirectUrl] = await Promise.all([
|
||||
claimPlan({ name, email, planId, signatureText: name, signatureDataUrl: null }),
|
||||
|
||||
@ -13,7 +13,7 @@ export const PasswordReveal = ({ password }: PasswordRevealProps) => {
|
||||
const [, copy] = useCopyToClipboard();
|
||||
|
||||
const onCopyClick = () => {
|
||||
copy(password).then(() => {
|
||||
void copy(password).then(() => {
|
||||
toast({
|
||||
title: 'Copied to clipboard',
|
||||
description: 'Your password has been copied to your clipboard.',
|
||||
|
||||
@ -124,7 +124,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
|
||||
setValue('signatureDataUrl', draftSignatureDataUrl);
|
||||
setValue('signatureText', '');
|
||||
|
||||
trigger('signatureDataUrl');
|
||||
void trigger('signatureDataUrl');
|
||||
setShowSigningDialog(false);
|
||||
};
|
||||
|
||||
@ -135,7 +135,9 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {
|
||||
signatureText,
|
||||
}: TWidgetFormSchema) => {
|
||||
try {
|
||||
const delay = new Promise<void>((resolve) => setTimeout(resolve, 1000));
|
||||
const delay = new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 1000);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const planId = process.env.NEXT_PUBLIC_STRIPE_COMMUNITY_PLAN_MONTHLY_PRICE_ID;
|
||||
|
||||
@ -3,16 +3,17 @@ import { HTMLAttributes } from 'react';
|
||||
import { CheckCircle2, Clock, File } from 'lucide-react';
|
||||
import type { LucideIcon } from 'lucide-react/dist/lucide-react';
|
||||
|
||||
import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/client';
|
||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||
import { SignatureIcon } from '@documenso/ui/icons/signature';
|
||||
import { cn } from '@documenso/ui/lib/utils';
|
||||
|
||||
type FriendlyStatus = {
|
||||
label: string;
|
||||
icon: LucideIcon;
|
||||
icon?: LucideIcon;
|
||||
color: string;
|
||||
};
|
||||
|
||||
const FRIENDLY_STATUS_MAP: Record<InternalDocumentStatus, FriendlyStatus> = {
|
||||
const FRIENDLY_STATUS_MAP: Record<ExtendedDocumentStatus, FriendlyStatus> = {
|
||||
PENDING: {
|
||||
label: 'Pending',
|
||||
icon: Clock,
|
||||
@ -28,10 +29,19 @@ const FRIENDLY_STATUS_MAP: Record<InternalDocumentStatus, FriendlyStatus> = {
|
||||
icon: File,
|
||||
color: 'text-yellow-500',
|
||||
},
|
||||
INBOX: {
|
||||
label: 'Inbox',
|
||||
icon: SignatureIcon,
|
||||
color: 'text-muted-foreground',
|
||||
},
|
||||
ALL: {
|
||||
label: 'All',
|
||||
color: 'text-muted-foreground',
|
||||
},
|
||||
};
|
||||
|
||||
export type DocumentStatusProps = HTMLAttributes<HTMLSpanElement> & {
|
||||
status: InternalDocumentStatus;
|
||||
status: ExtendedDocumentStatus;
|
||||
inheritColor?: boolean;
|
||||
};
|
||||
|
||||
@ -45,11 +55,13 @@ export const DocumentStatus = ({
|
||||
|
||||
return (
|
||||
<span className={cn('flex items-center', className)} {...props}>
|
||||
<Icon
|
||||
className={cn('mr-2 inline-block h-4 w-4', {
|
||||
[color]: !inheritColor,
|
||||
})}
|
||||
/>
|
||||
{Icon && (
|
||||
<Icon
|
||||
className={cn('mr-2 inline-block h-4 w-4', {
|
||||
[color]: !inheritColor,
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
|
||||
@ -39,6 +39,7 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
reset,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<TPasswordFormSchema>({
|
||||
values: {
|
||||
@ -56,6 +57,8 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
|
||||
password,
|
||||
});
|
||||
|
||||
reset();
|
||||
|
||||
toast({
|
||||
title: 'Password updated',
|
||||
description: 'Your password has been updated successfully.',
|
||||
@ -73,7 +76,7 @@ export const PasswordForm = ({ className }: PasswordFormProps) => {
|
||||
title: 'An unknown error occurred',
|
||||
variant: 'destructive',
|
||||
description:
|
||||
'We encountered an unknown error while attempting to sign you In. Please try again later.',
|
||||
'We encountered an unknown error while attempting to update your password. Please try again later.',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,10 +76,7 @@ export const SignInForm = ({ className }: SignInFormProps) => {
|
||||
return (
|
||||
<form
|
||||
className={cn('flex w-full flex-col gap-y-4', className)}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
handleSubmit(onFormSubmit)();
|
||||
}}
|
||||
onSubmit={handleSubmit(onFormSubmit)}
|
||||
>
|
||||
<div>
|
||||
<Label htmlFor="email" className="text-slate-500">
|
||||
|
||||
@ -2,7 +2,7 @@ import { z } from 'zod';
|
||||
|
||||
import { LOCAL_FEATURE_FLAGS, isFeatureFlagEnabled } from '@documenso/lib/constants/feature-flags';
|
||||
|
||||
import { TFeatureFlagValue, ZFeatureFlagValueSchema } from '~/providers/feature-flag';
|
||||
import { TFeatureFlagValue, ZFeatureFlagValueSchema } from '~/providers/feature-flag.types';
|
||||
|
||||
/**
|
||||
* Evaluate whether a flag is enabled for the current user.
|
||||
@ -32,7 +32,7 @@ export const getFlag = async (
|
||||
revalidate: 60,
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(async (res) => res.json())
|
||||
.then((res) => ZFeatureFlagValueSchema.parse(res))
|
||||
.catch(() => false);
|
||||
|
||||
@ -64,7 +64,7 @@ export const getAllFlags = async (
|
||||
revalidate: 60,
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then(async (res) => res.json())
|
||||
.then((res) => z.record(z.string(), ZFeatureFlagValueSchema).parse(res))
|
||||
.catch(() => LOCAL_FEATURE_FLAGS);
|
||||
};
|
||||
|
||||
@ -11,6 +11,6 @@ export default function PostHogServerClient() {
|
||||
|
||||
return new PostHog(postHogConfig.key, {
|
||||
host: postHogConfig.host,
|
||||
fetch: (...args) => fetch(...args),
|
||||
fetch: async (...args) => fetch(...args),
|
||||
});
|
||||
}
|
||||
|
||||
18
apps/web/src/hooks/use-debounced-value.ts
Normal file
18
apps/web/src/hooks/use-debounced-value.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function useDebouncedValue<T>(value: T, delay: number) {
|
||||
// State and setters for debounced value
|
||||
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedValue(value);
|
||||
}, delay);
|
||||
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
};
|
||||
}, [value, delay]);
|
||||
|
||||
return debouncedValue;
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
export default async function middleware(req: NextRequest) {
|
||||
export default function middleware(req: NextRequest) {
|
||||
if (req.nextUrl.pathname === '/') {
|
||||
const redirectUrl = new URL('/documents', req.url);
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
|
||||
import formidable from 'formidable';
|
||||
import { type File } from 'formidable';
|
||||
import formidable, { type File } from 'formidable';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
import { getServerSession } from '@documenso/lib/next-auth/get-server-session';
|
||||
|
||||
@ -4,7 +4,7 @@ import { appRouter } from '@documenso/trpc/server/router';
|
||||
|
||||
export default trpcNext.createNextApiHandler({
|
||||
router: appRouter,
|
||||
createContext: ({ req, res }) => createTrpcContext({ req, res }),
|
||||
createContext: async ({ req, res }) => createTrpcContext({ req, res }),
|
||||
});
|
||||
|
||||
// export default async function handler(_req: NextApiRequest, res: NextApiResponse) {
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
|
||||
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
FEATURE_FLAG_POLL_INTERVAL,
|
||||
LOCAL_FEATURE_FLAGS,
|
||||
@ -12,14 +10,7 @@ import {
|
||||
|
||||
import { getAllFlags } from '~/helpers/get-feature-flag';
|
||||
|
||||
export const ZFeatureFlagValueSchema = z.union([
|
||||
z.boolean(),
|
||||
z.string(),
|
||||
z.number(),
|
||||
z.undefined(),
|
||||
]);
|
||||
|
||||
export type TFeatureFlagValue = z.infer<typeof ZFeatureFlagValueSchema>;
|
||||
import { TFeatureFlagValue } from './feature-flag.types';
|
||||
|
||||
export type FeatureFlagContextValue = {
|
||||
getFlag: (_key: string) => TFeatureFlagValue;
|
||||
@ -67,7 +58,7 @@ export function FeatureFlagProvider({
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (document.hasFocus()) {
|
||||
getAllFlags().then((newFlags) => setFlags(newFlags));
|
||||
void getAllFlags().then((newFlags) => setFlags(newFlags));
|
||||
}
|
||||
}, FEATURE_FLAG_POLL_INTERVAL);
|
||||
|
||||
@ -84,7 +75,7 @@ export function FeatureFlagProvider({
|
||||
return;
|
||||
}
|
||||
|
||||
const onFocus = () => getAllFlags().then((newFlags) => setFlags(newFlags));
|
||||
const onFocus = () => void getAllFlags().then((newFlags) => setFlags(newFlags));
|
||||
|
||||
window.addEventListener('focus', onFocus);
|
||||
|
||||
|
||||
10
apps/web/src/providers/feature-flag.types.ts
Normal file
10
apps/web/src/providers/feature-flag.types.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZFeatureFlagValueSchema = z.union([
|
||||
z.boolean(),
|
||||
z.string(),
|
||||
z.number(),
|
||||
z.undefined(),
|
||||
]);
|
||||
|
||||
export type TFeatureFlagValue = z.infer<typeof ZFeatureFlagValueSchema>;
|
||||
@ -7,5 +7,6 @@ module.exports = {
|
||||
content: [
|
||||
...baseConfig.content,
|
||||
`${path.join(require.resolve('@documenso/ui'), '..')}/**/*.{ts,tsx}`,
|
||||
`${path.join(require.resolve('@documenso/email'), '..')}/**/*.{ts,tsx}`,
|
||||
],
|
||||
};
|
||||
|
||||
616
package-lock.json
generated
616
package-lock.json
generated
@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "documenso.next",
|
||||
"name": "@documenso/root",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "documenso.next",
|
||||
"name": "@documenso/root",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
@ -17,7 +17,7 @@
|
||||
"@commitlint/config-conventional": "^17.7.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"dotenv-cli": "^7.2.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-config-custom": "*",
|
||||
"husky": "^8.0.0",
|
||||
"lint-staged": "^14.0.0",
|
||||
@ -68,6 +68,7 @@
|
||||
"version": "0.1.0",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@documenso/ee": "*",
|
||||
"@documenso/lib": "*",
|
||||
"@documenso/prisma": "*",
|
||||
"@documenso/tailwind-config": "*",
|
||||
@ -78,6 +79,7 @@
|
||||
"formidable": "^2.1.1",
|
||||
"framer-motion": "^10.12.8",
|
||||
"lucide-react": "^0.214.0",
|
||||
"luxon": "^3.4.0",
|
||||
"micro": "^10.0.1",
|
||||
"nanoid": "^4.0.2",
|
||||
"next": "13.4.12",
|
||||
@ -100,6 +102,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/formidable": "^2.0.6",
|
||||
"@types/luxon": "^3.3.1",
|
||||
"@types/node": "20.1.0",
|
||||
"@types/react": "18.2.18",
|
||||
"@types/react-dom": "18.2.7"
|
||||
@ -133,6 +136,7 @@
|
||||
"version": "7.12.11",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
|
||||
"integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.10.4"
|
||||
}
|
||||
@ -1073,6 +1077,10 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@documenso/ee": {
|
||||
"resolved": "packages/ee",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@documenso/email": {
|
||||
"resolved": "packages/email",
|
||||
"link": true
|
||||
@ -1553,36 +1561,47 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
|
||||
"integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
|
||||
"integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.1.1",
|
||||
"espree": "^7.3.0",
|
||||
"globals": "^13.9.0",
|
||||
"ignore": "^4.0.6",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^9.6.0",
|
||||
"globals": "^13.19.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"minimatch": "^3.0.4",
|
||||
"js-yaml": "^4.1.0",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/ignore": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
|
||||
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
"node_modules/@eslint/eslintrc/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.46.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz",
|
||||
"integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==",
|
||||
"version": "8.48.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz",
|
||||
"integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
@ -1665,13 +1684,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
|
||||
"integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
|
||||
"version": "0.11.11",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
|
||||
"integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^1.2.0",
|
||||
"@humanwhocodes/object-schema": "^1.2.1",
|
||||
"debug": "^4.1.1",
|
||||
"minimatch": "^3.0.4"
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.10.0"
|
||||
@ -4848,6 +4867,9 @@
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
||||
"integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@ -5118,14 +5140,6 @@
|
||||
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
|
||||
"integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag=="
|
||||
},
|
||||
"node_modules/astral-regex": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
|
||||
"integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/astring": {
|
||||
"version": "1.8.6",
|
||||
"resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz",
|
||||
@ -6807,6 +6821,29 @@
|
||||
"resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
|
||||
"integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ=="
|
||||
},
|
||||
"node_modules/disparity": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/disparity/-/disparity-3.2.0.tgz",
|
||||
"integrity": "sha512-8cl9ouncFYE7OQsYwJNiy2e15S0xN80X1Jj/N/YkoiM+VGWSyg1YzPToecKyYx2DQiJapt5IC8yi43GW23TUHQ==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.2.1",
|
||||
"diff": "^4.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"disparity": "bin/disparity"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/disparity/node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
@ -7009,6 +7046,9 @@
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
|
||||
"integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-colors": "^4.1.1",
|
||||
"strip-ansi": "^6.0.1"
|
||||
@ -7182,56 +7222,53 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "7.32.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
|
||||
"integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
|
||||
"version": "8.48.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz",
|
||||
"integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.12.11",
|
||||
"@eslint/eslintrc": "^0.4.3",
|
||||
"@humanwhocodes/config-array": "^0.5.0",
|
||||
"ajv": "^6.10.0",
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.2",
|
||||
"@eslint/js": "8.48.0",
|
||||
"@humanwhocodes/config-array": "^0.11.10",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"ajv": "^6.12.4",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
"debug": "^4.0.1",
|
||||
"debug": "^4.3.2",
|
||||
"doctrine": "^3.0.0",
|
||||
"enquirer": "^2.3.5",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^2.1.0",
|
||||
"eslint-visitor-keys": "^2.0.0",
|
||||
"espree": "^7.3.1",
|
||||
"esquery": "^1.4.0",
|
||||
"eslint-scope": "^7.2.2",
|
||||
"eslint-visitor-keys": "^3.4.3",
|
||||
"espree": "^9.6.1",
|
||||
"esquery": "^1.4.2",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"file-entry-cache": "^6.0.1",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"glob-parent": "^5.1.2",
|
||||
"globals": "^13.6.0",
|
||||
"ignore": "^4.0.6",
|
||||
"import-fresh": "^3.0.0",
|
||||
"find-up": "^5.0.0",
|
||||
"glob-parent": "^6.0.2",
|
||||
"globals": "^13.19.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"is-path-inside": "^3.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.0.4",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
"progress": "^2.0.0",
|
||||
"regexpp": "^3.1.0",
|
||||
"semver": "^7.2.1",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"strip-json-comments": "^3.1.0",
|
||||
"table": "^6.0.9",
|
||||
"text-table": "^0.2.0",
|
||||
"v8-compile-cache": "^2.0.3"
|
||||
"optionator": "^0.9.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"text-table": "^0.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"eslint": "bin/eslint.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
@ -7591,9 +7628,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import": {
|
||||
"version": "2.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz",
|
||||
"integrity": "sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==",
|
||||
"version": "2.28.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz",
|
||||
"integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==",
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.6",
|
||||
"array.prototype.findlastindex": "^1.2.2",
|
||||
@ -7604,13 +7641,12 @@
|
||||
"eslint-import-resolver-node": "^0.3.7",
|
||||
"eslint-module-utils": "^2.8.0",
|
||||
"has": "^1.0.3",
|
||||
"is-core-module": "^2.12.1",
|
||||
"is-core-module": "^2.13.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^3.1.2",
|
||||
"object.fromentries": "^2.0.6",
|
||||
"object.groupby": "^1.0.0",
|
||||
"object.values": "^1.1.6",
|
||||
"resolve": "^1.22.3",
|
||||
"semver": "^6.3.1",
|
||||
"tsconfig-paths": "^3.14.2"
|
||||
},
|
||||
@ -7640,22 +7676,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import/node_modules/resolve": {
|
||||
"version": "1.22.3",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
|
||||
"integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.12.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
@ -7701,6 +7721,22 @@
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-package-json": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-package-json/-/eslint-plugin-package-json-0.1.4.tgz",
|
||||
"integrity": "sha512-qdb9LUBFR3tM9OZM1AaYCkxoZnRx7PX2xqvLm49D0JbUu+EkbDur9ug+tCS2xlA1Lbt12Wff5qES81ttc/VBdg==",
|
||||
"dependencies": {
|
||||
"disparity": "^3.0.0",
|
||||
"package-json-validator": "^0.6.3",
|
||||
"requireindex": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=4.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-prettier": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
|
||||
@ -7834,32 +7870,10 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-utils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
|
||||
"integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
|
||||
"dependencies": {
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mysticatea"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-visitor-keys": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz",
|
||||
"integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==",
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
||||
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
@ -7867,41 +7881,73 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/eslint-visitor-keys": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
|
||||
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
|
||||
"node_modules/eslint/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"node_modules/eslint/node_modules/eslint-scope": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
|
||||
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
|
||||
"dependencies": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/ignore": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
|
||||
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
|
||||
"node_modules/eslint/node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/espree": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
|
||||
"integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
|
||||
"version": "9.6.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
||||
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
|
||||
"dependencies": {
|
||||
"acorn": "^7.4.0",
|
||||
"acorn-jsx": "^5.3.1",
|
||||
"eslint-visitor-keys": "^1.3.0"
|
||||
"acorn": "^8.9.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/espree/node_modules/eslint-visitor-keys": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
|
||||
"node_modules/espree/node_modules/acorn": {
|
||||
"version": "8.10.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
|
||||
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esprima": {
|
||||
@ -8453,11 +8499,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/functional-red-black-tree": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
|
||||
"integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g=="
|
||||
},
|
||||
"node_modules/functions-have-names": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||
@ -9345,9 +9386,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
|
||||
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
|
||||
"version": "2.13.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
|
||||
"integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
|
||||
"dependencies": {
|
||||
"has": "^1.0.3"
|
||||
},
|
||||
@ -10198,11 +10239,6 @@
|
||||
"integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lodash.truncate": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
|
||||
"integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="
|
||||
},
|
||||
"node_modules/lodash.uniq": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
|
||||
@ -12115,6 +12151,20 @@
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/optimist": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
"integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==",
|
||||
"dependencies": {
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/optimist/node_modules/minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw=="
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
|
||||
@ -12168,6 +12218,17 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/package-json-validator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/package-json-validator/-/package-json-validator-0.6.3.tgz",
|
||||
"integrity": "sha512-juKiFboV4UKUvWQ+OSxstnyukhuluyuEoFmgZw1Rx21XzmwlgDWLcbl3qzjA3789IRORYhVFs7cmAO0YFGwHCg==",
|
||||
"dependencies": {
|
||||
"optimist": "~0.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"pjv": "bin/pjv"
|
||||
}
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
@ -12864,14 +12925,6 @@
|
||||
"node": ">=16.13"
|
||||
}
|
||||
},
|
||||
"node_modules/progress": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
@ -13570,17 +13623,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/regexpp": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
|
||||
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mysticatea"
|
||||
}
|
||||
},
|
||||
"node_modules/rehype-stringify": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-9.0.3.tgz",
|
||||
@ -13711,10 +13753,19 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/requireindex": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz",
|
||||
"integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==",
|
||||
"engines": {
|
||||
"node": ">=0.10.5"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.2",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
|
||||
@ -14259,22 +14310,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/slice-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
|
||||
"integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"astral-regex": "^2.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
@ -14721,41 +14756,6 @@
|
||||
"url": "https://opencollective.com/unts"
|
||||
}
|
||||
},
|
||||
"node_modules/table": {
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
|
||||
"integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
|
||||
"dependencies": {
|
||||
"ajv": "^8.0.1",
|
||||
"lodash.truncate": "^4.4.2",
|
||||
"slice-ansi": "^4.0.0",
|
||||
"string-width": "^4.2.3",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/table/node_modules/ajv": {
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/table/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "1.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz",
|
||||
@ -16017,11 +16017,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
|
||||
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA=="
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
@ -16203,6 +16198,14 @@
|
||||
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||
}
|
||||
},
|
||||
"node_modules/wordwrap": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
@ -16315,6 +16318,14 @@
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"packages/ee": {
|
||||
"version": "1.0.0",
|
||||
"license": "COMMERCIAL",
|
||||
"dependencies": {
|
||||
"@documenso/lib": "*",
|
||||
"@documenso/prisma": "*"
|
||||
}
|
||||
},
|
||||
"packages/email": {
|
||||
"name": "@documenso/email",
|
||||
"version": "1.0.0",
|
||||
@ -16342,172 +16353,16 @@
|
||||
"eslint-config-next": "13.4.12",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-turbo": "^1.9.3",
|
||||
"eslint-plugin-package-json": "^0.1.4",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config/node_modules/@eslint/eslintrc": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz",
|
||||
"integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^9.6.0",
|
||||
"globals": "^13.19.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config/node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
|
||||
"integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^1.2.1",
|
||||
"debug": "^4.1.1",
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.10.0"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config/node_modules/acorn": {
|
||||
"version": "8.10.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
|
||||
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"packages/eslint-config/node_modules/eslint": {
|
||||
"version": "8.46.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz",
|
||||
"integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.1",
|
||||
"@eslint/js": "^8.46.0",
|
||||
"@humanwhocodes/config-array": "^0.11.10",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"ajv": "^6.12.4",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
"debug": "^4.3.2",
|
||||
"doctrine": "^3.0.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^7.2.2",
|
||||
"eslint-visitor-keys": "^3.4.2",
|
||||
"espree": "^9.6.1",
|
||||
"esquery": "^1.4.2",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"file-entry-cache": "^6.0.1",
|
||||
"find-up": "^5.0.0",
|
||||
"glob-parent": "^6.0.2",
|
||||
"globals": "^13.19.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"is-path-inside": "^3.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"text-table": "^0.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"eslint": "bin/eslint.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config/node_modules/eslint-scope": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
|
||||
"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
|
||||
"dependencies": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config/node_modules/espree": {
|
||||
"version": "9.6.1",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
||||
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
|
||||
"dependencies": {
|
||||
"acorn": "^8.9.0",
|
||||
"acorn-jsx": "^5.3.2",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config/node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"packages/eslint-config/node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"packages/lib": {
|
||||
"name": "@documenso/lib",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"dependencies": {
|
||||
"@documenso/email": "*",
|
||||
"@documenso/prisma": "*",
|
||||
@ -16561,7 +16416,6 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"autoprefixer": "^10.4.13",
|
||||
"eslint": "7.32.0",
|
||||
"postcss": "^8.4.21",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"tailwindcss-animate": "^1.0.5"
|
||||
|
||||
@ -18,14 +18,14 @@
|
||||
"@commitlint/config-conventional": "^17.7.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"dotenv-cli": "^7.2.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-config-custom": "*",
|
||||
"husky": "^8.0.0",
|
||||
"lint-staged": "^14.0.0",
|
||||
"prettier": "^2.5.1",
|
||||
"turbo": "^1.9.3"
|
||||
},
|
||||
"name": "documenso.next",
|
||||
"name": "@documenso/root",
|
||||
"packageManager": "npm@8.19.2",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
|
||||
40
packages/ee/LICENSE
Normal file
40
packages/ee/LICENSE
Normal file
@ -0,0 +1,40 @@
|
||||
The Documenso Commercial License (the “Commercial License”)
|
||||
Copyright (c) 2023 Documenso, Inc
|
||||
|
||||
With regard to the Documenso Software:
|
||||
|
||||
This software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, an agreement governing
|
||||
the use of the Software, as mutually agreed by you and Documenso, Inc ("Documenso"),
|
||||
and otherwise have a valid Documenso Enterprise Edition subscription ("Commercial Subscription").
|
||||
Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software.
|
||||
You agree that Documenso and/or its licensors (as applicable) retain all right, title and interest in
|
||||
and to all such modifications and/or patches, and all such modifications and/or
|
||||
patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid Commercial Subscription for the correct number of hosts.
|
||||
Notwithstanding the foregoing, you may copy and modify the Software for development
|
||||
and testing purposes, without requiring a subscription. You agree that Documenso and/or
|
||||
its licensors (as applicable) retain all right, title and interest in and to all such
|
||||
modifications. You are not granted any other rights beyond what is expressly stated herein.
|
||||
Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense,
|
||||
and/or sell the Software.
|
||||
|
||||
This Commercial License applies only to the part of this Software that is not distributed under
|
||||
the AGPLv3 license. Any part of this Software distributed under the MIT license or which
|
||||
is served client-side as an image, font, cascading stylesheet (CSS), file which produces
|
||||
or is compiled, arranged, augmented, or combined into client-side JavaScript, in whole or
|
||||
in part, is copyrighted under the AGPLv3 license. The full text of this Commercial License shall
|
||||
be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the Documenso Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
||||
1
packages/ee/index.ts
Normal file
1
packages/ee/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export {};
|
||||
17
packages/ee/package.json
Normal file
17
packages/ee/package.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@documenso/ee",
|
||||
"version": "1.0.0",
|
||||
"main": "./index.ts",
|
||||
"types": "./index.ts",
|
||||
"license": "COMMERCIAL",
|
||||
"files": [
|
||||
"client-only/",
|
||||
"server-only/",
|
||||
"universal/"
|
||||
],
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"@documenso/lib": "*",
|
||||
"@documenso/prisma": "*"
|
||||
}
|
||||
}
|
||||
31
packages/ee/server-only/stripe/create-customer.ts
Normal file
31
packages/ee/server-only/stripe/create-customer.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { stripe } from '@documenso/lib/server-only/stripe';
|
||||
import { getSubscriptionByUserId } from '@documenso/lib/server-only/subscription/get-subscription-by-user-id';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { User } from '@documenso/prisma/client';
|
||||
|
||||
export type CreateCustomerOptions = {
|
||||
user: User;
|
||||
};
|
||||
|
||||
export const createCustomer = async ({ user }: CreateCustomerOptions) => {
|
||||
const existingSubscription = await getSubscriptionByUserId({ userId: user.id });
|
||||
|
||||
if (existingSubscription) {
|
||||
throw new Error('User already has a subscription');
|
||||
}
|
||||
|
||||
const customer = await stripe.customers.create({
|
||||
name: user.name ?? undefined,
|
||||
email: user.email,
|
||||
metadata: {
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
return await prisma.subscription.create({
|
||||
data: {
|
||||
userId: user.id,
|
||||
customerId: customer.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
19
packages/ee/server-only/stripe/get-portal-session.ts
Normal file
19
packages/ee/server-only/stripe/get-portal-session.ts
Normal file
@ -0,0 +1,19 @@
|
||||
'use server';
|
||||
|
||||
import { stripe } from '@documenso/lib/server-only/stripe';
|
||||
|
||||
export type GetPortalSessionOptions = {
|
||||
customerId: string;
|
||||
returnUrl: string;
|
||||
};
|
||||
|
||||
export const getPortalSession = async ({ customerId, returnUrl }: GetPortalSessionOptions) => {
|
||||
'use server';
|
||||
|
||||
const session = await stripe.billingPortal.sessions.create({
|
||||
customer: customerId,
|
||||
return_url: returnUrl,
|
||||
});
|
||||
|
||||
return session.url;
|
||||
};
|
||||
5
packages/ee/tsconfig.json
Normal file
5
packages/ee/tsconfig.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "@documenso/tsconfig/react-library.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "**/*.d.ts"],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
import { Button, Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
export interface TemplateDocumentCompletedProps {
|
||||
downloadLink: string;
|
||||
reviewLink: string;
|
||||
documentName: string;
|
||||
assetBaseUrl: string;
|
||||
}
|
||||
|
||||
export const TemplateDocumentCompleted = ({
|
||||
downloadLink,
|
||||
reviewLink,
|
||||
documentName,
|
||||
assetBaseUrl,
|
||||
}: TemplateDocumentCompletedProps) => {
|
||||
const getAssetUrl = (path: string) => {
|
||||
return new URL(path, assetBaseUrl).toString();
|
||||
};
|
||||
|
||||
return (
|
||||
<Tailwind
|
||||
config={{
|
||||
theme: {
|
||||
extend: {
|
||||
colors: config.theme.extend.colors,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Section className="flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
||||
</div>
|
||||
|
||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-[#7AC455]">
|
||||
<Img src={getAssetUrl('/static/completed.png')} className="-mb-0.5 mr-2 inline h-7 w-7" />
|
||||
Completed
|
||||
</Text>
|
||||
|
||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||
“{documentName}” was signed by all signers
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
Continue by downloading or reviewing the document.
|
||||
</Text>
|
||||
|
||||
<Section className="mb-6 mt-8 text-center">
|
||||
<Button
|
||||
className="mr-4 inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||
href={reviewLink}
|
||||
>
|
||||
<Img src={getAssetUrl('/static/review.png')} className="-mb-1 mr-2 inline h-5 w-5" />
|
||||
Review
|
||||
</Button>
|
||||
<Button
|
||||
className="inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||
href={downloadLink}
|
||||
>
|
||||
<Img src={getAssetUrl('/static/download.png')} className="-mb-1 mr-2 inline h-5 w-5" />
|
||||
Download
|
||||
</Button>
|
||||
</Section>
|
||||
</Section>
|
||||
</Tailwind>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateDocumentCompleted;
|
||||
@ -0,0 +1,59 @@
|
||||
import { Button, Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
export interface TemplateDocumentInviteProps {
|
||||
inviterName: string;
|
||||
inviterEmail: string;
|
||||
documentName: string;
|
||||
signDocumentLink: string;
|
||||
assetBaseUrl: string;
|
||||
}
|
||||
|
||||
export const TemplateDocumentInvite = ({
|
||||
inviterName,
|
||||
documentName,
|
||||
signDocumentLink,
|
||||
assetBaseUrl,
|
||||
}: TemplateDocumentInviteProps) => {
|
||||
const getAssetUrl = (path: string) => {
|
||||
return new URL(path, assetBaseUrl).toString();
|
||||
};
|
||||
|
||||
return (
|
||||
<Tailwind
|
||||
config={{
|
||||
theme: {
|
||||
extend: {
|
||||
colors: config.theme.extend.colors,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Section className="mt-4 flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
||||
</div>
|
||||
|
||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||
{inviterName} has invited you to sign "{documentName}"
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
Continue by signing the document.
|
||||
</Text>
|
||||
|
||||
<Section className="mb-6 mt-8 text-center">
|
||||
<Button
|
||||
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}
|
||||
>
|
||||
Sign Document
|
||||
</Button>
|
||||
</Section>
|
||||
</Section>
|
||||
</Tailwind>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateDocumentInvite;
|
||||
@ -0,0 +1,52 @@
|
||||
import { Img, Section, Tailwind, Text } from '@react-email/components';
|
||||
|
||||
import * as config from '@documenso/tailwind-config';
|
||||
|
||||
export interface TemplateDocumentPendingProps {
|
||||
documentName: string;
|
||||
assetBaseUrl: string;
|
||||
}
|
||||
|
||||
export const TemplateDocumentPending = ({
|
||||
documentName,
|
||||
assetBaseUrl,
|
||||
}: TemplateDocumentPendingProps) => {
|
||||
const getAssetUrl = (path: string) => {
|
||||
return new URL(path, assetBaseUrl).toString();
|
||||
};
|
||||
|
||||
return (
|
||||
<Tailwind
|
||||
config={{
|
||||
theme: {
|
||||
extend: {
|
||||
colors: config.theme.extend.colors,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Section className="flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
||||
</div>
|
||||
|
||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-blue-500">
|
||||
<Img src={getAssetUrl('/static/clock.png')} className="-mb-0.5 mr-2 inline h-7 w-7" />
|
||||
Waiting for others
|
||||
</Text>
|
||||
|
||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||
“{documentName}” has been signed
|
||||
</Text>
|
||||
|
||||
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
||||
We're still waiting for other signers to sign this document.
|
||||
<br />
|
||||
We'll notify you as soon as it's ready.
|
||||
</Text>
|
||||
</Section>
|
||||
</Tailwind>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateDocumentPending;
|
||||
22
packages/email/template-components/template-footer.tsx
Normal file
22
packages/email/template-components/template-footer.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { Link, Section, Text } from '@react-email/components';
|
||||
|
||||
export const TemplateFooter = () => {
|
||||
return (
|
||||
<Section>
|
||||
<Text className="my-4 text-base text-slate-400">
|
||||
This document was sent using{' '}
|
||||
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||
Documenso.
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
<Text className="my-8 text-sm text-slate-400">
|
||||
Documenso
|
||||
<br />
|
||||
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||
</Text>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default TemplateFooter;
|
||||
@ -1,25 +1,23 @@
|
||||
import {
|
||||
Body,
|
||||
Button,
|
||||
Container,
|
||||
Head,
|
||||
Html,
|
||||
Img,
|
||||
Link,
|
||||
Preview,
|
||||
Section,
|
||||
Tailwind,
|
||||
Text,
|
||||
} from '@react-email/components';
|
||||
|
||||
import config from '@documenso/tailwind-config';
|
||||
|
||||
interface DocumentCompletedEmailTemplateProps {
|
||||
downloadLink?: string;
|
||||
reviewLink?: string;
|
||||
documentName?: string;
|
||||
assetBaseUrl?: string;
|
||||
}
|
||||
import {
|
||||
TemplateDocumentCompleted,
|
||||
TemplateDocumentCompletedProps,
|
||||
} from '../template-components/template-document-completed';
|
||||
import TemplateFooter from '../template-components/template-footer';
|
||||
|
||||
export type DocumentCompletedEmailTemplateProps = Partial<TemplateDocumentCompletedProps>;
|
||||
|
||||
export const DocumentCompletedEmailTemplate = ({
|
||||
downloadLink = 'https://documenso.com',
|
||||
@ -50,74 +48,23 @@ export const DocumentCompletedEmailTemplate = ({
|
||||
<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">
|
||||
<Section className="p-2">
|
||||
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||
<Img
|
||||
src={getAssetUrl('/static/logo.png')}
|
||||
alt="Documenso Logo"
|
||||
className="mb-4 h-6"
|
||||
/>
|
||||
|
||||
<Section className="mt-4 flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img
|
||||
className="h-42"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-[#7AC455]">
|
||||
<Img
|
||||
src={getAssetUrl('/static/completed.png')}
|
||||
className="-mb-0.5 mr-2 inline h-7 w-7"
|
||||
/>
|
||||
Completed
|
||||
</Text>
|
||||
|
||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||
“{documentName}” was signed by all signers
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
Continue by downloading or reviewing the document.
|
||||
</Text>
|
||||
|
||||
<Section className="mb-6 mt-8 text-center">
|
||||
<Button
|
||||
className="mr-4 inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||
href={reviewLink}
|
||||
>
|
||||
<Img
|
||||
src={getAssetUrl('/static/review.png')}
|
||||
className="-mb-1 mr-2 inline h-5 w-5"
|
||||
/>
|
||||
Review
|
||||
</Button>
|
||||
<Button
|
||||
className="inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||
href={downloadLink}
|
||||
>
|
||||
<Img
|
||||
src={getAssetUrl('/static/download.png')}
|
||||
className="-mb-1 mr-2 inline h-5 w-5"
|
||||
/>
|
||||
Download
|
||||
</Button>
|
||||
</Section>
|
||||
</Section>
|
||||
<TemplateDocumentCompleted
|
||||
downloadLink={downloadLink}
|
||||
reviewLink={reviewLink}
|
||||
documentName={documentName}
|
||||
assetBaseUrl={assetBaseUrl}
|
||||
/>
|
||||
</Section>
|
||||
</Container>
|
||||
|
||||
<Container className="mx-auto max-w-xl">
|
||||
<Section>
|
||||
<Text className="my-4 text-base text-slate-400">
|
||||
This document was sent using{' '}
|
||||
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||
Documenso.
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
<Text className="my-8 text-sm text-slate-400">
|
||||
Documenso
|
||||
<br />
|
||||
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||
</Text>
|
||||
</Section>
|
||||
<TemplateFooter />
|
||||
</Container>
|
||||
</Section>
|
||||
</Body>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import {
|
||||
Body,
|
||||
Button,
|
||||
Container,
|
||||
Head,
|
||||
Hr,
|
||||
@ -15,13 +14,13 @@ import {
|
||||
|
||||
import config from '@documenso/tailwind-config';
|
||||
|
||||
interface DocumentInviteEmailTemplateProps {
|
||||
inviterName?: string;
|
||||
inviterEmail?: string;
|
||||
documentName?: string;
|
||||
signDocumentLink?: string;
|
||||
assetBaseUrl?: string;
|
||||
}
|
||||
import {
|
||||
TemplateDocumentInvite,
|
||||
TemplateDocumentInviteProps,
|
||||
} from '../template-components/template-document-invite';
|
||||
import TemplateFooter from '../template-components/template-footer';
|
||||
|
||||
export type DocumentInviteEmailTemplateProps = Partial<TemplateDocumentInviteProps>;
|
||||
|
||||
export const DocumentInviteEmailTemplate = ({
|
||||
inviterName = 'Lucas Smith',
|
||||
@ -51,36 +50,21 @@ export const DocumentInviteEmailTemplate = ({
|
||||
>
|
||||
<Body className="mx-auto my-auto bg-white font-sans">
|
||||
<Section>
|
||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||
<Section className="p-2">
|
||||
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||
<Section>
|
||||
<Img
|
||||
src={getAssetUrl('/static/logo.png')}
|
||||
alt="Documenso Logo"
|
||||
className="mb-4 h-6"
|
||||
/>
|
||||
|
||||
<Section className="mt-4 flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img
|
||||
className="h-42"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||
{inviterName} has invited you to sign "{documentName}"
|
||||
</Text>
|
||||
|
||||
<Text className="my-1 text-center text-base text-slate-400">
|
||||
Continue by signing the document.
|
||||
</Text>
|
||||
|
||||
<Section className="mb-6 mt-8 text-center">
|
||||
<Button
|
||||
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}
|
||||
>
|
||||
Sign Document
|
||||
</Button>
|
||||
</Section>
|
||||
</Section>
|
||||
<TemplateDocumentInvite
|
||||
inviterName={inviterName}
|
||||
inviterEmail={inviterEmail}
|
||||
documentName={documentName}
|
||||
signDocumentLink={signDocumentLink}
|
||||
assetBaseUrl={assetBaseUrl}
|
||||
/>
|
||||
</Section>
|
||||
</Container>
|
||||
|
||||
@ -102,20 +86,7 @@ export const DocumentInviteEmailTemplate = ({
|
||||
<Hr className="mx-auto mt-12 max-w-xl" />
|
||||
|
||||
<Container className="mx-auto max-w-xl">
|
||||
<Section>
|
||||
<Text className="my-4 text-base text-slate-400">
|
||||
This document was sent using{' '}
|
||||
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||
Documenso.
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
<Text className="my-8 text-sm text-slate-400">
|
||||
Documenso
|
||||
<br />
|
||||
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||
</Text>
|
||||
</Section>
|
||||
<TemplateFooter />
|
||||
</Container>
|
||||
</Section>
|
||||
</Body>
|
||||
|
||||
@ -4,19 +4,20 @@ import {
|
||||
Head,
|
||||
Html,
|
||||
Img,
|
||||
Link,
|
||||
Preview,
|
||||
Section,
|
||||
Tailwind,
|
||||
Text,
|
||||
} from '@react-email/components';
|
||||
|
||||
import config from '@documenso/tailwind-config';
|
||||
|
||||
interface DocumentPendingEmailTemplateProps {
|
||||
documentName?: string;
|
||||
assetBaseUrl?: string;
|
||||
}
|
||||
import {
|
||||
TemplateDocumentPending,
|
||||
TemplateDocumentPendingProps,
|
||||
} from '../template-components/template-document-pending';
|
||||
import { TemplateFooter } from '../template-components/template-footer';
|
||||
|
||||
export type DocumentPendingEmailTemplateProps = Partial<TemplateDocumentPendingProps>;
|
||||
|
||||
export const DocumentPendingEmailTemplate = ({
|
||||
documentName = 'Open Source Pledge.pdf',
|
||||
@ -43,55 +44,20 @@ export const DocumentPendingEmailTemplate = ({
|
||||
>
|
||||
<Body className="mx-auto my-auto font-sans">
|
||||
<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">
|
||||
<Section className="p-2">
|
||||
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-4 backdrop-blur-sm">
|
||||
<Section>
|
||||
<Img
|
||||
src={getAssetUrl('/static/logo.png')}
|
||||
alt="Documenso Logo"
|
||||
className="mb-4 h-6"
|
||||
/>
|
||||
|
||||
<Section className="mt-4 flex-row items-center justify-center">
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<Img
|
||||
className="h-42"
|
||||
src={getAssetUrl('/static/document.png')}
|
||||
alt="Documenso"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-blue-500">
|
||||
<Img
|
||||
src={getAssetUrl('/static/clock.png')}
|
||||
className="-mb-0.5 mr-2 inline h-7 w-7"
|
||||
/>
|
||||
Waiting for others
|
||||
</Text>
|
||||
|
||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||
“{documentName}” has been signed
|
||||
</Text>
|
||||
|
||||
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
||||
We're still waiting for other signers to sign this document.
|
||||
<br />
|
||||
We'll notify you as soon as it's ready.
|
||||
</Text>
|
||||
</Section>
|
||||
<TemplateDocumentPending documentName={documentName} assetBaseUrl={assetBaseUrl} />
|
||||
</Section>
|
||||
</Container>
|
||||
|
||||
<Container className="mx-auto max-w-xl">
|
||||
<Section>
|
||||
<Text className="my-4 text-base text-slate-400">
|
||||
This document was sent using{' '}
|
||||
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||
Documenso.
|
||||
</Link>
|
||||
</Text>
|
||||
|
||||
<Text className="my-8 text-sm text-slate-400">
|
||||
Documenso
|
||||
<br />
|
||||
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||
</Text>
|
||||
</Section>
|
||||
<TemplateFooter />
|
||||
</Container>
|
||||
</Section>
|
||||
</Body>
|
||||
|
||||
@ -110,9 +110,10 @@ export class MailChannelsTransport implements Transport<SentMessageInfo> {
|
||||
});
|
||||
}
|
||||
|
||||
res.json().then((data) => {
|
||||
return callback(new Error(`MailChannels error: ${data.message}`), null);
|
||||
});
|
||||
res
|
||||
.json()
|
||||
.then((data) => callback(new Error(`MailChannels error: ${data.message}`), null))
|
||||
.catch((err) => callback(err, null));
|
||||
})
|
||||
.catch((err) => {
|
||||
return callback(err, null);
|
||||
|
||||
@ -6,9 +6,10 @@ module.exports = {
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
'plugin:package-json/recommended',
|
||||
],
|
||||
|
||||
plugins: ['prettier'],
|
||||
plugins: ['prettier', 'package-json'],
|
||||
|
||||
env: {
|
||||
node: true,
|
||||
@ -19,6 +20,8 @@ module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['../../apps/*/tsconfig.json', '../../packages/*/tsconfig.json'],
|
||||
ecmaVersion: 2022,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
@ -32,6 +35,32 @@ module.exports = {
|
||||
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
||||
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
||||
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-multi-spaces': [
|
||||
'error',
|
||||
{
|
||||
ignoreEOLComments: false,
|
||||
exceptions: {
|
||||
BinaryExpression: false,
|
||||
VariableDeclarator: false,
|
||||
ImportDeclaration: false,
|
||||
Property: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// Safety with promises so we aren't running with scissors
|
||||
'no-promise-executor-return': 'error',
|
||||
'prefer-promise-reject-errors': 'error',
|
||||
'require-atomic-updates': 'error',
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-misused-promises': [
|
||||
'error',
|
||||
{ checksVoidReturn: { attributes: false } },
|
||||
],
|
||||
'@typescript-eslint/promise-function-async': 'error',
|
||||
'@typescript-eslint/require-await': 'error',
|
||||
|
||||
// We never want to use `as` but are required to on occasion to handle
|
||||
// shortcomings in third-party and generated types.
|
||||
//
|
||||
|
||||
@ -9,9 +9,10 @@
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-config-next": "13.4.12",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-turbo": "^1.9.3",
|
||||
"eslint-plugin-package-json": "^0.1.4",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-config-turbo": "^1.9.3",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
}
|
||||
|
||||
9
packages/eslint-config/tsconfig.json
Normal file
9
packages/eslint-config/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "@documenso/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
},
|
||||
"include": ["**/*.cjs", "**/*.js"],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@ -89,7 +89,7 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = {
|
||||
};
|
||||
},
|
||||
|
||||
async session({ token, session }) {
|
||||
session({ token, session }) {
|
||||
if (token && token.email) {
|
||||
return {
|
||||
...session,
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
import { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next';
|
||||
import { headers } from 'next/headers';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
import { getServerSession as getNextAuthServerSession } from 'next-auth';
|
||||
import { getToken } from 'next-auth/jwt';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
@ -30,18 +27,6 @@ export const getServerSession = async ({ req, res }: GetServerSessionOptions) =>
|
||||
return user;
|
||||
};
|
||||
|
||||
export const getServerComponentToken = async () => {
|
||||
const requestHeaders = Object.fromEntries(headers().entries());
|
||||
|
||||
const req = new NextRequest('http://example.com', {
|
||||
headers: requestHeaders,
|
||||
});
|
||||
|
||||
const token = await getToken({
|
||||
req,
|
||||
});
|
||||
};
|
||||
|
||||
export const getServerComponentSession = async () => {
|
||||
const session = await getNextAuthServerSession(NEXT_AUTH_OPTIONS);
|
||||
|
||||
|
||||
@ -87,6 +87,6 @@ export const completeDocumentWithToken = async ({
|
||||
|
||||
if (documents.count > 0) {
|
||||
console.log('sealing document');
|
||||
sealDocument({ documentId: document.id });
|
||||
await sealDocument({ documentId: document.id });
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { Document, DocumentStatus, Prisma } from '@documenso/prisma/client';
|
||||
import { DocumentWithReciepient } from '@documenso/prisma/types/document-with-recipient';
|
||||
import { Document, Prisma, SigningStatus } from '@documenso/prisma/client';
|
||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||
|
||||
import { FindResultSet } from '../../types/find-result-set';
|
||||
|
||||
export interface FindDocumentsOptions {
|
||||
userId: number;
|
||||
term?: string;
|
||||
status?: DocumentStatus;
|
||||
status?: ExtendedDocumentStatus;
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
orderBy?: {
|
||||
@ -19,29 +21,102 @@ export interface FindDocumentsOptions {
|
||||
export const findDocuments = async ({
|
||||
userId,
|
||||
term,
|
||||
status,
|
||||
status = ExtendedDocumentStatus.ALL,
|
||||
page = 1,
|
||||
perPage = 10,
|
||||
orderBy,
|
||||
}: FindDocumentsOptions): Promise<FindResultSet<DocumentWithReciepient>> => {
|
||||
}: FindDocumentsOptions) => {
|
||||
const user = await prisma.user.findFirstOrThrow({
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
});
|
||||
|
||||
const orderByColumn = orderBy?.column ?? 'created';
|
||||
const orderByDirection = orderBy?.direction ?? 'desc';
|
||||
|
||||
const filters: Prisma.DocumentWhereInput = {
|
||||
status,
|
||||
userId,
|
||||
};
|
||||
const termFilters = !term
|
||||
? undefined
|
||||
: ({
|
||||
title: {
|
||||
contains: term,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
} as const);
|
||||
|
||||
if (term) {
|
||||
filters.title = {
|
||||
contains: term,
|
||||
mode: 'insensitive',
|
||||
};
|
||||
}
|
||||
const filters = match<ExtendedDocumentStatus, Prisma.DocumentWhereInput>(status)
|
||||
.with(ExtendedDocumentStatus.ALL, () => ({
|
||||
OR: [
|
||||
{
|
||||
userId,
|
||||
},
|
||||
{
|
||||
status: {
|
||||
not: ExtendedDocumentStatus.DRAFT,
|
||||
},
|
||||
Recipient: {
|
||||
some: {
|
||||
email: user.email,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}))
|
||||
.with(ExtendedDocumentStatus.INBOX, () => ({
|
||||
status: {
|
||||
not: ExtendedDocumentStatus.DRAFT,
|
||||
},
|
||||
Recipient: {
|
||||
some: {
|
||||
email: user.email,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
},
|
||||
},
|
||||
}))
|
||||
.with(ExtendedDocumentStatus.DRAFT, () => ({
|
||||
userId,
|
||||
status: ExtendedDocumentStatus.DRAFT,
|
||||
}))
|
||||
.with(ExtendedDocumentStatus.PENDING, () => ({
|
||||
OR: [
|
||||
{
|
||||
userId,
|
||||
status: ExtendedDocumentStatus.PENDING,
|
||||
},
|
||||
{
|
||||
status: ExtendedDocumentStatus.PENDING,
|
||||
|
||||
Recipient: {
|
||||
some: {
|
||||
email: user.email,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}))
|
||||
.with(ExtendedDocumentStatus.COMPLETED, () => ({
|
||||
OR: [
|
||||
{
|
||||
userId,
|
||||
status: ExtendedDocumentStatus.COMPLETED,
|
||||
},
|
||||
{
|
||||
status: ExtendedDocumentStatus.COMPLETED,
|
||||
Recipient: {
|
||||
some: {
|
||||
email: user.email,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}))
|
||||
.exhaustive();
|
||||
|
||||
const [data, count] = await Promise.all([
|
||||
prisma.document.findMany({
|
||||
where: {
|
||||
...termFilters,
|
||||
...filters,
|
||||
},
|
||||
skip: Math.max(page - 1, 0) * perPage,
|
||||
@ -50,21 +125,37 @@ export const findDocuments = async ({
|
||||
[orderByColumn]: orderByDirection,
|
||||
},
|
||||
include: {
|
||||
User: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
Recipient: true,
|
||||
},
|
||||
}),
|
||||
prisma.document.count({
|
||||
where: {
|
||||
...termFilters,
|
||||
...filters,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
const maskedData = data.map((doc) => ({
|
||||
...doc,
|
||||
Recipient: doc.Recipient.map((recipient) => ({
|
||||
...recipient,
|
||||
token: recipient.email === user.email ? recipient.token : '',
|
||||
})),
|
||||
}));
|
||||
|
||||
return {
|
||||
data,
|
||||
data: maskedData,
|
||||
count,
|
||||
currentPage: Math.max(page, 1),
|
||||
perPage,
|
||||
totalPages: Math.ceil(count / perPage),
|
||||
};
|
||||
} satisfies FindResultSet<typeof maskedData>;
|
||||
};
|
||||
|
||||
@ -1,30 +1,88 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { DocumentStatus } from '@documenso/prisma/client';
|
||||
import { SigningStatus, User } from '@documenso/prisma/client';
|
||||
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
|
||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||
|
||||
export type GetStatsInput = {
|
||||
userId: number;
|
||||
user: User;
|
||||
};
|
||||
|
||||
export const getStats = async ({ userId }: GetStatsInput) => {
|
||||
const result = await prisma.document.groupBy({
|
||||
by: ['status'],
|
||||
_count: {
|
||||
_all: true,
|
||||
},
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
export const getStats = async ({ user }: GetStatsInput) => {
|
||||
const [ownerCounts, notSignedCounts, hasSignedCounts] = await Promise.all([
|
||||
prisma.document.groupBy({
|
||||
by: ['status'],
|
||||
_count: {
|
||||
_all: true,
|
||||
},
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
}),
|
||||
prisma.document.groupBy({
|
||||
by: ['status'],
|
||||
_count: {
|
||||
_all: true,
|
||||
},
|
||||
where: {
|
||||
status: ExtendedDocumentStatus.PENDING,
|
||||
Recipient: {
|
||||
some: {
|
||||
email: user.email,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.document.groupBy({
|
||||
by: ['status'],
|
||||
_count: {
|
||||
_all: true,
|
||||
},
|
||||
where: {
|
||||
status: {
|
||||
not: ExtendedDocumentStatus.DRAFT,
|
||||
},
|
||||
Recipient: {
|
||||
some: {
|
||||
email: user.email,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
const stats: Record<DocumentStatus, number> = {
|
||||
[DocumentStatus.DRAFT]: 0,
|
||||
[DocumentStatus.PENDING]: 0,
|
||||
[DocumentStatus.COMPLETED]: 0,
|
||||
const stats: Record<ExtendedDocumentStatus, number> = {
|
||||
[ExtendedDocumentStatus.DRAFT]: 0,
|
||||
[ExtendedDocumentStatus.PENDING]: 0,
|
||||
[ExtendedDocumentStatus.COMPLETED]: 0,
|
||||
[ExtendedDocumentStatus.INBOX]: 0,
|
||||
[ExtendedDocumentStatus.ALL]: 0,
|
||||
};
|
||||
|
||||
result.forEach((stat) => {
|
||||
ownerCounts.forEach((stat) => {
|
||||
stats[stat.status] = stat._count._all;
|
||||
});
|
||||
|
||||
notSignedCounts.forEach((stat) => {
|
||||
stats[ExtendedDocumentStatus.INBOX] += stat._count._all;
|
||||
});
|
||||
|
||||
hasSignedCounts.forEach((stat) => {
|
||||
if (stat.status === ExtendedDocumentStatus.COMPLETED) {
|
||||
stats[ExtendedDocumentStatus.COMPLETED] += stat._count._all;
|
||||
}
|
||||
|
||||
if (stat.status === ExtendedDocumentStatus.PENDING) {
|
||||
stats[ExtendedDocumentStatus.PENDING] += stat._count._all;
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(stats).forEach((key) => {
|
||||
if (key !== ExtendedDocumentStatus.ALL && isExtendedDocumentStatus(key)) {
|
||||
stats[ExtendedDocumentStatus.ALL] += stats[key];
|
||||
}
|
||||
});
|
||||
|
||||
return stats;
|
||||
};
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
'use server';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type GetSubscriptionByUserIdOptions = {
|
||||
userId: number;
|
||||
};
|
||||
|
||||
export const getSubscriptionByUserId = ({ userId }: GetSubscriptionByUserIdOptions) => {
|
||||
return prisma.subscription.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
import { hash } from 'bcrypt';
|
||||
import { compare, hash } from 'bcrypt';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
@ -11,7 +11,7 @@ export type UpdatePasswordOptions = {
|
||||
|
||||
export const updatePassword = async ({ userId, password }: UpdatePasswordOptions) => {
|
||||
// Existence check
|
||||
await prisma.user.findFirstOrThrow({
|
||||
const user = await prisma.user.findFirstOrThrow({
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
@ -19,6 +19,13 @@ export const updatePassword = async ({ userId, password }: UpdatePasswordOptions
|
||||
|
||||
const hashedPassword = await hash(password, SALT_ROUNDS);
|
||||
|
||||
// Compare the new password with the old password
|
||||
const isSamePassword = await compare(password, user.password as string);
|
||||
|
||||
if (isSamePassword) {
|
||||
throw new Error('Your new password cannot be the same as your old password.');
|
||||
}
|
||||
|
||||
const updatedUser = await prisma.user.update({
|
||||
where: {
|
||||
id: userId,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export type FindResultSet<T> = {
|
||||
data: T[];
|
||||
data: T extends Array<any> ? T : T[];
|
||||
count: number;
|
||||
currentPage: number;
|
||||
perPage: number;
|
||||
|
||||
11
packages/prisma/guards/is-extended-document-status.ts
Normal file
11
packages/prisma/guards/is-extended-document-status.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { ExtendedDocumentStatus } from '../types/extended-document-status';
|
||||
|
||||
export const isExtendedDocumentStatus = (value: unknown): value is ExtendedDocumentStatus => {
|
||||
if (typeof value !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're using the assertion for a type-guard so it's safe to ignore the eslint warning
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return Object.values(ExtendedDocumentStatus).includes(value as ExtendedDocumentStatus);
|
||||
};
|
||||
5
packages/prisma/tsconfig.json
Normal file
5
packages/prisma/tsconfig.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "@documenso/tsconfig/react-library.json",
|
||||
"include": ["."],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { Document, Recipient } from '@documenso/prisma/client';
|
||||
|
||||
export type DocumentWithReciepient = Document & {
|
||||
export type DocumentWithRecipient = Document & {
|
||||
Recipient: Recipient[];
|
||||
};
|
||||
|
||||
12
packages/prisma/types/document.ts
Normal file
12
packages/prisma/types/document.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Document, Recipient } from '@documenso/prisma/client';
|
||||
|
||||
export type DocumentWithRecipientAndSender = Omit<Document, 'document'> & {
|
||||
recipient: Recipient;
|
||||
sender: {
|
||||
id: number;
|
||||
name: string | null;
|
||||
email: string;
|
||||
};
|
||||
subject: string;
|
||||
description: string;
|
||||
};
|
||||
10
packages/prisma/types/extended-document-status.ts
Normal file
10
packages/prisma/types/extended-document-status.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { DocumentStatus } from '@prisma/client';
|
||||
|
||||
export const ExtendedDocumentStatus = {
|
||||
...DocumentStatus,
|
||||
INBOX: 'INBOX',
|
||||
ALL: 'ALL',
|
||||
} as const;
|
||||
|
||||
export type ExtendedDocumentStatus =
|
||||
(typeof ExtendedDocumentStatus)[keyof typeof ExtendedDocumentStatus];
|
||||
@ -115,6 +115,11 @@ module.exports = {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
},
|
||||
screens: {
|
||||
'3xl': '1920px',
|
||||
'4xl': '2560px',
|
||||
'5xl': '3840px',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')],
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"autoprefixer": "^10.4.13",
|
||||
"eslint": "7.32.0",
|
||||
"postcss": "^8.4.21",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"tailwindcss-animate": "^1.0.5"
|
||||
|
||||
9
packages/tailwind-config/tsconfig.json
Normal file
9
packages/tailwind-config/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "@documenso/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
},
|
||||
"include": ["**/*.cjs", "**/*.js"],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
import 'zod';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZSignUpMutationSchema = z.object({
|
||||
|
||||
@ -40,12 +40,16 @@ export const profileRouter = router({
|
||||
password,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
let message =
|
||||
'We were unable to update your profile. Please review the information you provided and try again.';
|
||||
|
||||
if (err instanceof Error) {
|
||||
message = err.message;
|
||||
}
|
||||
|
||||
throw new TRPCError({
|
||||
code: 'BAD_REQUEST',
|
||||
message:
|
||||
'We were unable to update your profile. Please review the information you provided and try again.',
|
||||
message,
|
||||
});
|
||||
}
|
||||
}),
|
||||
|
||||
@ -10,7 +10,7 @@ const t = initTRPC.context<TrpcContext>().create({
|
||||
/**
|
||||
* Middlewares
|
||||
*/
|
||||
export const authenticatedMiddleware = t.middleware(({ ctx, next }) => {
|
||||
export const authenticatedMiddleware = t.middleware(async ({ ctx, next }) => {
|
||||
if (!ctx.session) {
|
||||
throw new TRPCError({
|
||||
code: 'UNAUTHORIZED',
|
||||
@ -18,7 +18,7 @@ export const authenticatedMiddleware = t.middleware(({ ctx, next }) => {
|
||||
});
|
||||
}
|
||||
|
||||
return next({
|
||||
return await next({
|
||||
ctx: {
|
||||
...ctx,
|
||||
|
||||
|
||||
8
packages/tsconfig/tsconfig.json
Normal file
8
packages/tsconfig/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx", "**/*.d.ts", "**/*.json"],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
28
packages/ui/icons/signature.tsx
Normal file
28
packages/ui/icons/signature.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import type { LucideIcon } from 'lucide-react/dist/lucide-react';
|
||||
|
||||
export const SignatureIcon: LucideIcon = ({
|
||||
size = 24,
|
||||
color = 'currentColor',
|
||||
strokeWidth = 1.33,
|
||||
absoluteStrokeWidth,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M1.5 11H14.5M1.5 14C1.5 14 8.72 2 4.86938 2H4.875C2.01 2 1.97437 14.0694 8 6.51188V6.5C8 6.5 9 11.3631 11.5 7.52375V7.5C11.5 7.5 11.5 9 14.5 9"
|
||||
stroke={color}
|
||||
strokeWidth={absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@ -110,7 +110,7 @@ CardContent.displayName = 'CardContent';
|
||||
|
||||
const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn(' flex items-center p-6 pt-0', className)} {...props} />
|
||||
<div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props} />
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@ -86,7 +86,7 @@ export const DocumentDropzone = ({ className, onDrop, ...props }: DocumentDropzo
|
||||
multiple: false,
|
||||
onDrop: ([acceptedFile]) => {
|
||||
if (acceptedFile && onDrop) {
|
||||
onDrop(acceptedFile);
|
||||
void onDrop(acceptedFile);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@ -88,6 +88,8 @@ export const AddFieldsFormPartial = ({
|
||||
},
|
||||
});
|
||||
|
||||
const onFormSubmit = handleSubmit(onSubmit);
|
||||
|
||||
const {
|
||||
append,
|
||||
remove,
|
||||
@ -500,7 +502,7 @@ export const AddFieldsFormPartial = ({
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting}
|
||||
onGoBackClick={documentFlow.onBackStep}
|
||||
onGoNextClick={() => handleSubmit(onSubmit)()}
|
||||
onGoNextClick={() => void onFormSubmit()}
|
||||
/>
|
||||
</DocumentFlowFormContainerFooter>
|
||||
</>
|
||||
|
||||
@ -68,6 +68,8 @@ export const AddSignersFormPartial = ({
|
||||
},
|
||||
});
|
||||
|
||||
const onFormSubmit = handleSubmit(onSubmit);
|
||||
|
||||
const {
|
||||
append: appendSigner,
|
||||
fields: signers,
|
||||
@ -214,7 +216,7 @@ export const AddSignersFormPartial = ({
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting}
|
||||
onGoBackClick={documentFlow.onBackStep}
|
||||
onGoNextClick={() => handleSubmit(onSubmit)()}
|
||||
onGoNextClick={() => void onFormSubmit()}
|
||||
/>
|
||||
</DocumentFlowFormContainerFooter>
|
||||
</>
|
||||
|
||||
@ -47,6 +47,8 @@ export const AddSubjectFormPartial = ({
|
||||
},
|
||||
});
|
||||
|
||||
const onFormSubmit = handleSubmit(onSubmit);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DocumentFlowFormContainerContent>
|
||||
@ -130,7 +132,7 @@ export const AddSubjectFormPartial = ({
|
||||
disabled={isSubmitting}
|
||||
goNextLabel={document.status === DocumentStatus.DRAFT ? 'Send' : 'Update'}
|
||||
onGoBackClick={documentFlow.onBackStep}
|
||||
onGoNextClick={() => handleSubmit(onSubmit)()}
|
||||
onGoNextClick={() => void onFormSubmit()}
|
||||
/>
|
||||
</DocumentFlowFormContainerFooter>
|
||||
</>
|
||||
|
||||
@ -67,7 +67,7 @@ const NavigationMenuContent = React.forwardRef<
|
||||
<NavigationMenuPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 left-0 top-0 w-full md:absolute md:w-auto ',
|
||||
'data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 left-0 top-0 w-full md:absolute md:w-auto',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@ -66,7 +66,7 @@ export const PDFViewer = ({ className, document, onPageClick, ...props }: PDFVie
|
||||
const pageY = event.clientY - top;
|
||||
|
||||
if (onPageClick) {
|
||||
onPageClick({
|
||||
void onPageClick({
|
||||
pageNumber,
|
||||
numPages,
|
||||
originalEvent: event,
|
||||
|
||||
@ -302,8 +302,8 @@ export class Canvas {
|
||||
/**
|
||||
* Retrieves the signature as an image blob.
|
||||
*/
|
||||
public toBlob(type?: string, quality?: number): Promise<Blob> {
|
||||
return new Promise((resolve, reject) => {
|
||||
public async toBlob(type?: string, quality?: number): Promise<Blob> {
|
||||
const promise = new Promise<Blob>((resolve, reject) => {
|
||||
this.$canvas.toBlob(
|
||||
(blob) => {
|
||||
if (!blob) {
|
||||
@ -317,5 +317,7 @@ export class Canvas {
|
||||
quality,
|
||||
);
|
||||
});
|
||||
|
||||
return await promise;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user