diff --git a/apps/marketing/contentlayer.config.ts b/apps/marketing/contentlayer.config.ts index f1ba82b89..10999a408 100644 --- a/apps/marketing/contentlayer.config.ts +++ b/apps/marketing/contentlayer.config.ts @@ -12,6 +12,7 @@ export const BlogPost = defineDocumentType(() => ({ authorName: { type: 'string', required: true }, authorImage: { type: 'string', required: false }, authorRole: { type: 'string', required: true }, + cta: { type: 'boolean', required: false, default: true }, }, computedFields: { href: { type: 'string', resolve: (post) => `/${post._raw.flattenedPath}` }, diff --git a/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx b/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx index 14b8b2d8f..bd5fdb2da 100644 --- a/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx +++ b/apps/marketing/src/app/(marketing)/blog/[post]/page.tsx @@ -7,6 +7,8 @@ import { ChevronLeft } from 'lucide-react'; import type { MDXComponents } from 'mdx/types'; import { useMDXComponent } from 'next-contentlayer/hooks'; +import { CallToAction } from '~/components/(marketing)/call-to-action'; + export const dynamic = 'force-dynamic'; export const generateMetadata = ({ params }: { params: { post: string } }) => { @@ -42,53 +44,57 @@ export default function BlogPostPage({ params }: { params: { post: string } }) { const MDXContent = useMDXComponent(post.body.code); return ( -
-
- +
+
+
+ -

{post.title}

+

{post.title}

-
-
- {post.authorImage && ( - {`Image - )} -
+
+
+ {post.authorImage && ( + {`Image + )} +
-
-

{post.authorName}

-

{post.authorRole}

+
+

{post.authorName}

+

{post.authorRole}

+
-
- + - {post.tags.length > 0 && ( -
    - {post.tags.map((tag, i) => ( -
  • - {tag} -
  • - ))} -
- )} + {post.tags.length > 0 && ( +
    + {post.tags.map((tag, i) => ( +
  • + {tag} +
  • + ))} +
+ )} -
+
- - - Back to all posts - -
+ + + Back to all posts + +
+ + {post.cta && } + ); } diff --git a/apps/marketing/src/app/(marketing)/open/page.tsx b/apps/marketing/src/app/(marketing)/open/page.tsx index 8fef81134..10ab71aa7 100644 --- a/apps/marketing/src/app/(marketing)/open/page.tsx +++ b/apps/marketing/src/app/(marketing)/open/page.tsx @@ -7,6 +7,7 @@ import { getUserMonthlyGrowth } from '@documenso/lib/server-only/user/get-user-m import { FUNDING_RAISED } from '~/app/(marketing)/open/data'; import { MetricCard } from '~/app/(marketing)/open/metric-card'; import { SalaryBands } from '~/app/(marketing)/open/salary-bands'; +import { CallToAction } from '~/components/(marketing)/call-to-action'; import { BarMetric } from './bar-metrics'; import { CapTable } from './cap-table'; @@ -141,114 +142,118 @@ export default async function OpenPage() { const MONTHLY_USERS = await getUserMonthlyGrowth(); return ( -
-
-

Open Startup

+
+
+
+

Open Startup

-

- All our metrics, finances, and learnings are public. We believe in transparency and want - to share our journey with you. You can read more about why here:{' '} - - Announcing Open Metrics - -

-
- -
-
- - - - -
- - - - - - - - - - - data={EARLY_ADOPTERS_DATA} - metricKey="earlyAdopters" - title="Early Adopters" - label="Early Adopters" - className="col-span-12 lg:col-span-6" - extraInfo={} - /> - - - data={STARGAZERS_DATA} - metricKey="stars" - title="Github: Total Stars" - label="Stars" - className="col-span-12 lg:col-span-6" - /> - - - data={STARGAZERS_DATA} - metricKey="mergedPRs" - title="Github: Total Merged PRs" - label="Merged PRs" - chartHeight={300} - className="col-span-12 lg:col-span-6" - /> - - - data={STARGAZERS_DATA} - metricKey="forks" - title="Github: Total Forks" - label="Forks" - chartHeight={300} - className="col-span-12 lg:col-span-6" - /> - - - data={STARGAZERS_DATA} - metricKey="openIssues" - title="Github: Total Open Issues" - label="Open Issues" - chartHeight={300} - className="col-span-12 lg:col-span-6" - /> - - - - - - -
-

Where's the rest?

- -

- We're still working on getting all our metrics together. We'll update this page as soon - as we have more to share. +

+ All our metrics, finances, and learnings are public. We believe in transparency and want + to share our journey with you. You can read more about why here:{' '} + + Announcing Open Metrics +

+ +
+
+ + + + +
+ + + + + + + + + + + data={EARLY_ADOPTERS_DATA} + metricKey="earlyAdopters" + title="Early Adopters" + label="Early Adopters" + className="col-span-12 lg:col-span-6" + extraInfo={} + /> + + + data={STARGAZERS_DATA} + metricKey="stars" + title="Github: Total Stars" + label="Stars" + className="col-span-12 lg:col-span-6" + /> + + + data={STARGAZERS_DATA} + metricKey="mergedPRs" + title="Github: Total Merged PRs" + label="Merged PRs" + chartHeight={300} + className="col-span-12 lg:col-span-6" + /> + + + data={STARGAZERS_DATA} + metricKey="forks" + title="Github: Total Forks" + label="Forks" + chartHeight={300} + className="col-span-12 lg:col-span-6" + /> + + + data={STARGAZERS_DATA} + metricKey="openIssues" + title="Github: Total Open Issues" + label="Open Issues" + chartHeight={300} + className="col-span-12 lg:col-span-6" + /> + + + + + + +
+

Where's the rest?

+ +

+ We're still working on getting all our metrics together. We'll update this page as + soon as we have more to share. +

+
+
+ +
); } diff --git a/apps/marketing/src/components/(marketing)/call-to-action.tsx b/apps/marketing/src/components/(marketing)/call-to-action.tsx new file mode 100644 index 000000000..3d1f51b23 --- /dev/null +++ b/apps/marketing/src/components/(marketing)/call-to-action.tsx @@ -0,0 +1,31 @@ +import Link from 'next/link'; + +import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app'; +import { Button } from '@documenso/ui/primitives/button'; +import { Card, CardContent } from '@documenso/ui/primitives/card'; + +type CallToActionProps = { + className?: string; + utmSource?: string; +}; + +export const CallToAction = ({ className, utmSource = 'generic-cta' }: CallToActionProps) => { + return ( + + +

Join the Open Signing Movement

+ +

+ Create your account and start using state-of-the-art document signing. Open and beautiful + signing is within your grasp. +

+ + +
+
+ ); +}; diff --git a/apps/web/src/app/(dashboard)/settings/profile/delete-account-dialog.tsx b/apps/web/src/app/(dashboard)/settings/profile/delete-account-dialog.tsx index e9cc885e9..2e1087380 100644 --- a/apps/web/src/app/(dashboard)/settings/profile/delete-account-dialog.tsx +++ b/apps/web/src/app/(dashboard)/settings/profile/delete-account-dialog.tsx @@ -1,5 +1,7 @@ 'use client'; +import { useState } from 'react'; + import { signOut } from 'next-auth/react'; import type { User } from '@documenso/prisma/client'; @@ -16,6 +18,8 @@ import { DialogTitle, DialogTrigger, } from '@documenso/ui/primitives/dialog'; +import { Input } from '@documenso/ui/primitives/input'; +import { Label } from '@documenso/ui/primitives/label'; import { useToast } from '@documenso/ui/primitives/use-toast'; export type DeleteAccountDialogProps = { @@ -28,6 +32,8 @@ export const DeleteAccountDialog = ({ className, user }: DeleteAccountDialogProp const hasTwoFactorAuthentication = user.twoFactorEnabled; + const [enteredEmail, setEnteredEmail] = useState(''); + const { mutateAsync: deleteAccount, isLoading: isDeletingAccount } = trpc.profile.deleteAccount.useMutation(); @@ -76,10 +82,11 @@ export const DeleteAccountDialog = ({ className, user }: DeleteAccountDialogProp
- + setEnteredEmail('')}> + Delete Account @@ -105,12 +112,29 @@ export const DeleteAccountDialog = ({ className, user }: DeleteAccountDialogProp + {!hasTwoFactorAuthentication && ( +
+ + + setEnteredEmail(e.target.value)} + /> +
+ )} diff --git a/packages/app-tests/e2e/test-delete-user.spec.ts b/packages/app-tests/e2e/test-delete-user.spec.ts index beae6eb09..6eb72bad9 100644 --- a/packages/app-tests/e2e/test-delete-user.spec.ts +++ b/packages/app-tests/e2e/test-delete-user.spec.ts @@ -16,6 +16,8 @@ test('delete user', async ({ page }) => { }); await page.getByRole('button', { name: 'Delete Account' }).click(); + await page.getByLabel('Confirm Email').fill(user.email); + await expect(page.getByRole('button', { name: 'Confirm Deletion' })).not.toBeDisabled(); await page.getByRole('button', { name: 'Confirm Deletion' }).click(); await page.waitForURL(`${WEBAPP_BASE_URL}/signin`); diff --git a/packages/lib/constants/url-regex.ts b/packages/lib/constants/url-regex.ts index 259ce070d..1dfb70ad3 100644 --- a/packages/lib/constants/url-regex.ts +++ b/packages/lib/constants/url-regex.ts @@ -1,2 +1,2 @@ export const URL_REGEX = - /^(https?):\/\/(?:www\.)?[a-zA-Z0-9-]+\.[a-zA-Z0-9()]{2,}(?:\/[a-zA-Z0-9-._?&=/]*)?$/i; + /^(https?):\/\/(?:www\.)?(?:[a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z0-9()]{2,}(?:\/[a-zA-Z0-9-._?&=/]*)?$/i;