diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..f80dc7f80 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,7 @@ +# Config files +*.config.js +*.config.cjs + +# Statically hosted javascript files +apps/*/public/*.js +apps/*/public/*.cjs diff --git a/apps/marketing/src/app/(marketing)/[content]/page.tsx b/apps/marketing/src/app/(marketing)/[content]/page.tsx index f32765024..37d6d1b63 100644 --- a/apps/marketing/src/app/(marketing)/[content]/page.tsx +++ b/apps/marketing/src/app/(marketing)/[content]/page.tsx @@ -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 } }) => { diff --git a/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx b/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx index 68f22e734..5192dec32 100644 --- a/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx +++ b/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx @@ -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 } }) => { diff --git a/apps/marketing/src/app/(marketing)/open/page.tsx b/apps/marketing/src/app/(marketing)/open/page.tsx index 539e624c6..2d5bc2aa4 100644 --- a/apps/marketing/src/app/(marketing)/open/page.tsx +++ b/apps/marketing/src/app/(marketing)/open/page.tsx @@ -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 ( diff --git a/apps/marketing/src/app/(marketing)/page.tsx b/apps/marketing/src/app/(marketing)/page.tsx index 09e9e3dec..377384701 100644 --- a/apps/marketing/src/app/(marketing)/page.tsx +++ b/apps/marketing/src/app/(marketing)/page.tsx @@ -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); diff --git a/apps/marketing/src/components/(marketing)/claim-plan-dialog.tsx b/apps/marketing/src/components/(marketing)/claim-plan-dialog.tsx index f350a7e01..7de30bba3 100644 --- a/apps/marketing/src/components/(marketing)/claim-plan-dialog.tsx +++ b/apps/marketing/src/components/(marketing)/claim-plan-dialog.tsx @@ -63,7 +63,9 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog const onFormSubmit = async ({ name, email }: TClaimPlanDialogFormSchema) => { try { - const delay = new Promise((resolve) => setTimeout(resolve, 1000)); + const delay = new Promise((resolve) => { + setTimeout(resolve, 1000); + }); const [redirectUrl] = await Promise.all([ claimPlan({ name, email, planId, signatureText: name, signatureDataUrl: null }), diff --git a/apps/marketing/src/components/(marketing)/password-reveal.tsx b/apps/marketing/src/components/(marketing)/password-reveal.tsx index 7e1cb72a3..b31765943 100644 --- a/apps/marketing/src/components/(marketing)/password-reveal.tsx +++ b/apps/marketing/src/components/(marketing)/password-reveal.tsx @@ -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.', diff --git a/apps/marketing/src/components/(marketing)/widget.tsx b/apps/marketing/src/components/(marketing)/widget.tsx index 1a15069e9..15e15d04c 100644 --- a/apps/marketing/src/components/(marketing)/widget.tsx +++ b/apps/marketing/src/components/(marketing)/widget.tsx @@ -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((resolve) => setTimeout(resolve, 1000)); + const delay = new Promise((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; diff --git a/apps/web/package.json b/apps/web/package.json index c0a3035ea..8e7dd2be7 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -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" diff --git a/apps/web/src/app/(dashboard)/dashboard/page.tsx b/apps/web/src/app/(dashboard)/dashboard/page.tsx index 4fcf867ec..a83b2e8cc 100644 --- a/apps/web/src/app/(dashboard)/dashboard/page.tsx +++ b/apps/web/src/app/(dashboard)/dashboard/page.tsx @@ -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, }), ]); diff --git a/apps/web/src/app/(dashboard)/documents/data-table-action-button.tsx b/apps/web/src/app/(dashboard)/documents/data-table-action-button.tsx new file mode 100644 index 000000000..7c1d42d2b --- /dev/null +++ b/apps/web/src/app/(dashboard)/documents/data-table-action-button.tsx @@ -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; + 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 }, () => ( + + )) + .with({ isRecipient: true, isPending: true, isSigned: false }, () => ( + + )) + .otherwise(() => ( + + )); +}; diff --git a/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx b/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx new file mode 100644 index 000000000..b1d5832f8 --- /dev/null +++ b/apps/web/src/app/(dashboard)/documents/data-table-action-dropdown.tsx @@ -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; + 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 ( + + + + + + + Action + + + + + Sign + + + + + + + Edit + + + + + + Download + + + + + Duplicate + + + + + Void + + + + + Delete + + + Share + + + + Resend + + + + + Share + + + + ); +}; diff --git a/apps/web/src/app/(dashboard)/documents/data-table.tsx b/apps/web/src/app/(dashboard)/documents/data-table.tsx index 35fdfb4b1..1d6c08e73 100644 --- a/apps/web/src/app/(dashboard)/documents/data-table.tsx +++ b/apps/web/src/app/(dashboard)/documents/data-table.tsx @@ -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; + results: FindResultSet< + Document & { + Recipient: Recipient[]; + User: Pick; + } + >; }; export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => { @@ -45,7 +53,11 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => { { header: 'Title', cell: ({ row }) => ( - + {row.original.title} ), @@ -67,6 +79,15 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => { accessorKey: 'created', cell: ({ row }) => , }, + { + header: 'Actions', + cell: ({ row }) => ( +
+ + +
+ ), + }, ]} data={results.data} perPage={results.perPage} diff --git a/apps/web/src/app/(dashboard)/documents/page.tsx b/apps/web/src/app/(dashboard)/documents/page.tsx index 76675f573..4ea55936b 100644 --- a/apps/web/src/app/(dashboard)/documents/page.tsx +++ b/apps/web/src/app/(dashboard)/documents/page.tsx @@ -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

Documents

-
- +
+ - - - + {[ + ExtendedDocumentStatus.INBOX, + ExtendedDocumentStatus.PENDING, + ExtendedDocumentStatus.COMPLETED, + ExtendedDocumentStatus.DRAFT, + ExtendedDocumentStatus.ALL, + ].map((value) => ( + + + - - {Math.min(stats.PENDING, 99)} - - - - - - - - - - {Math.min(stats.COMPLETED, 99)} - - - - - - - - - - {Math.min(stats.DRAFT, 99)} - - - - - - - All - - + {value !== ExtendedDocumentStatus.ALL && ( + + {Math.min(stats[value], 99)} + + )} + + + ))} diff --git a/apps/web/src/app/(dashboard)/settings/billing/page.tsx b/apps/web/src/app/(dashboard)/settings/billing/page.tsx index 256f682fb..e9966b9ac 100644 --- a/apps/web/src/app/(dashboard)/settings/billing/page.tsx +++ b/apps/web/src/app/(dashboard)/settings/billing/page.tsx @@ -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 (

Billing

- 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{' '} + + + + . + + )}


- + {billingPortalUrl && ( + + )} + + {!billingPortalUrl && ( +

+ You do not currently have a customer record, this should not happen. Please contact + support for assistance. +

+ )}
); } diff --git a/apps/web/src/app/(signing)/sign/[token]/name-field.tsx b/apps/web/src/app/(signing)/sign/[token]/name-field.tsx index f200d94cd..9688619fa 100644 --- a/apps/web/src/app/(signing)/sign/[token]/name-field.tsx +++ b/apps/web/src/app/(signing)/sign/[token]/name-field.tsx @@ -149,7 +149,7 @@ export const NameField = ({ field, recipient }: NameFieldProps) => { disabled={!localFullName} onClick={() => { setShowFullNameModal(false); - onSign('local'); + void onSign('local'); }} > Sign diff --git a/apps/web/src/app/(signing)/sign/[token]/signature-field.tsx b/apps/web/src/app/(signing)/sign/[token]/signature-field.tsx index 921b4f51f..cada25e06 100644 --- a/apps/web/src/app/(signing)/sign/[token]/signature-field.tsx +++ b/apps/web/src/app/(signing)/sign/[token]/signature-field.tsx @@ -182,7 +182,7 @@ export const SignatureField = ({ field, recipient }: SignatureFieldProps) => { disabled={!localSignature} onClick={() => { setShowSignatureModal(false); - onSign('local'); + void onSign('local'); }} > Sign diff --git a/apps/web/src/components/(dashboard)/layout/desktop-nav.tsx b/apps/web/src/components/(dashboard)/layout/desktop-nav.tsx index 9b64baf58..2c6165a05 100644 --- a/apps/web/src/components/(dashboard)/layout/desktop-nav.tsx +++ b/apps/web/src/components/(dashboard)/layout/desktop-nav.tsx @@ -7,13 +7,15 @@ import { cn } from '@documenso/ui/lib/utils'; export type DesktopNavProps = HTMLAttributes; export const DesktopNav = ({ className, ...props }: DesktopNavProps) => { + // const pathname = usePathname(); + return ( diff --git a/apps/web/src/components/(dashboard)/layout/profile-dropdown.tsx b/apps/web/src/components/(dashboard)/layout/profile-dropdown.tsx index f7d14c39d..02af86d70 100644 --- a/apps/web/src/components/(dashboard)/layout/profile-dropdown.tsx +++ b/apps/web/src/components/(dashboard)/layout/profile-dropdown.tsx @@ -118,7 +118,7 @@ export const ProfileDropdown = ({ user }: ProfileDropdownProps) => { - signOut({ + void signOut({ callbackUrl: '/', }) } diff --git a/apps/web/src/components/(marketing)/claim-plan-dialog.tsx b/apps/web/src/components/(marketing)/claim-plan-dialog.tsx index 06bfd5ced..1f78c5292 100644 --- a/apps/web/src/components/(marketing)/claim-plan-dialog.tsx +++ b/apps/web/src/components/(marketing)/claim-plan-dialog.tsx @@ -63,7 +63,9 @@ export const ClaimPlanDialog = ({ className, planId, children }: ClaimPlanDialog const onFormSubmit = async ({ name, email }: TClaimPlanDialogFormSchema) => { try { - const delay = new Promise((resolve) => setTimeout(resolve, 1000)); + const delay = new Promise((resolve) => { + setTimeout(resolve, 1000); + }); const [redirectUrl] = await Promise.all([ claimPlan({ name, email, planId, signatureText: name, signatureDataUrl: null }), diff --git a/apps/web/src/components/(marketing)/password-reveal.tsx b/apps/web/src/components/(marketing)/password-reveal.tsx index 7e1cb72a3..b31765943 100644 --- a/apps/web/src/components/(marketing)/password-reveal.tsx +++ b/apps/web/src/components/(marketing)/password-reveal.tsx @@ -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.', diff --git a/apps/web/src/components/(marketing)/widget.tsx b/apps/web/src/components/(marketing)/widget.tsx index 1a15069e9..15e15d04c 100644 --- a/apps/web/src/components/(marketing)/widget.tsx +++ b/apps/web/src/components/(marketing)/widget.tsx @@ -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((resolve) => setTimeout(resolve, 1000)); + const delay = new Promise((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; diff --git a/apps/web/src/components/formatter/document-status.tsx b/apps/web/src/components/formatter/document-status.tsx index 4e1ccf742..126a52f4f 100644 --- a/apps/web/src/components/formatter/document-status.tsx +++ b/apps/web/src/components/formatter/document-status.tsx @@ -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 = { +const FRIENDLY_STATUS_MAP: Record = { PENDING: { label: 'Pending', icon: Clock, @@ -28,10 +29,19 @@ const FRIENDLY_STATUS_MAP: Record = { 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 & { - status: InternalDocumentStatus; + status: ExtendedDocumentStatus; inheritColor?: boolean; }; @@ -45,11 +55,13 @@ export const DocumentStatus = ({ return ( - + {Icon && ( + + )} {label} ); diff --git a/apps/web/src/components/forms/password.tsx b/apps/web/src/components/forms/password.tsx index 7c595421e..508579b78 100644 --- a/apps/web/src/components/forms/password.tsx +++ b/apps/web/src/components/forms/password.tsx @@ -39,6 +39,7 @@ export const PasswordForm = ({ className }: PasswordFormProps) => { const { register, handleSubmit, + reset, formState: { errors, isSubmitting }, } = useForm({ 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.', }); } } diff --git a/apps/web/src/components/forms/signin.tsx b/apps/web/src/components/forms/signin.tsx index 9e9a01976..2ffb2798e 100644 --- a/apps/web/src/components/forms/signin.tsx +++ b/apps/web/src/components/forms/signin.tsx @@ -76,10 +76,7 @@ export const SignInForm = ({ className }: SignInFormProps) => { return (
{ - e.preventDefault(); - handleSubmit(onFormSubmit)(); - }} + onSubmit={handleSubmit(onFormSubmit)} >