diff --git a/apps/web/src/app/(share)/share/[slug]/opengraph-image.tsx b/apps/web/src/app/(share)/share/[slug]/opengraph/route.tsx
similarity index 94%
rename from apps/web/src/app/(share)/share/[slug]/opengraph-image.tsx
rename to apps/web/src/app/(share)/share/[slug]/opengraph/route.tsx
index 8751f407e..d6a2c6397 100644
--- a/apps/web/src/app/(share)/share/[slug]/opengraph-image.tsx
+++ b/apps/web/src/app/(share)/share/[slug]/opengraph/route.tsx
@@ -1,4 +1,4 @@
-import { ImageResponse } from 'next/server';
+import { ImageResponse, NextResponse } from 'next/server';
import { P, match } from 'ts-pattern';
@@ -21,7 +21,7 @@ type SharePageOpenGraphImageProps = {
params: { slug: string };
};
-export default async function Image({ params: { slug } }: SharePageOpenGraphImageProps) {
+export async function GET(_request: Request, { params: { slug } }: SharePageOpenGraphImageProps) {
const [interSemiBold, interRegular, caveatRegular, shareFrameImage] = await Promise.all([
getAssetBuffer('/fonts/inter-semibold.ttf'),
getAssetBuffer('/fonts/inter-regular.ttf'),
@@ -32,7 +32,7 @@ export default async function Image({ params: { slug } }: SharePageOpenGraphImag
const recipientOrSender = await getRecipientOrSenderByShareLinkSlug({ slug }).catch(() => null);
if (!recipientOrSender) {
- return null;
+ return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
const isRecipient = 'Signature' in recipientOrSender;
diff --git a/apps/web/src/app/(share)/share/[slug]/page.tsx b/apps/web/src/app/(share)/share/[slug]/page.tsx
index 63449f29f..2f9369f60 100644
--- a/apps/web/src/app/(share)/share/[slug]/page.tsx
+++ b/apps/web/src/app/(share)/share/[slug]/page.tsx
@@ -1,11 +1,30 @@
import { Metadata } from 'next';
+import { headers } from 'next/headers';
+import { redirect } from 'next/navigation';
-import { Redirect } from './redirect';
+import { APP_BASE_URL } from '@documenso/lib/constants/app';
-export const metadata: Metadata = {
- title: 'Documenso - Share',
+type SharePageProps = {
+ params: { slug: string };
};
-export default function SharePage() {
- return ;
+export function generateMetadata({ params: { slug } }: SharePageProps) {
+ return {
+ title: 'Documenso - Share',
+ description: 'I just signed a document with Documenso!',
+ openGraph: {
+ images: [`${APP_BASE_URL}/share/${slug}/opengraph`],
+ },
+ } satisfies Metadata;
+}
+
+export default function SharePage() {
+ const userAgent = headers().get('User-Agent') ?? '';
+
+ // https://stackoverflow.com/questions/47026171/how-to-detect-bots-for-open-graph-with-user-agent
+ if (/bot|facebookexternalhit|WhatsApp|google|bing|duckduckbot|MetaInspector/i.test(userAgent)) {
+ return null;
+ }
+
+ redirect(process.env.NEXT_PUBLIC_MARKETING_URL ?? 'http://localhost:3001');
}
diff --git a/apps/web/src/app/(share)/share/[slug]/redirect.tsx b/apps/web/src/app/(share)/share/[slug]/redirect.tsx
deleted file mode 100644
index 5b3af0771..000000000
--- a/apps/web/src/app/(share)/share/[slug]/redirect.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-'use client';
-
-import { useEffect } from 'react';
-
-export const Redirect = () => {
- useEffect(() => {
- window.location.href = process.env.NEXT_PUBLIC_MARKETING_URL ?? 'http://localhost:3001';
- }, []);
-
- return null;
-};
diff --git a/apps/web/src/app/(signing)/sign/[token]/complete/page.tsx b/apps/web/src/app/(signing)/sign/[token]/complete/page.tsx
index 0828bac40..e87b2fced 100644
--- a/apps/web/src/app/(signing)/sign/[token]/complete/page.tsx
+++ b/apps/web/src/app/(signing)/sign/[token]/complete/page.tsx
@@ -9,8 +9,7 @@ import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-f
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
import { DocumentStatus, FieldType } from '@documenso/prisma/client';
import { DocumentDownloadButton } from '@documenso/ui/components/document/document-download-button';
-import { SigningCard } from '@documenso/ui/components/signing-card';
-import { Button } from '@documenso/ui/primitives/button';
+import { SigningCard3D } from '@documenso/ui/components/signing-card';
import signingCelebration from '~/assets/signing-celebration.png';
@@ -54,7 +53,7 @@ export default async function CompletedSigningPage({
return (
{/* Card with recipient */}
-
+
{match(document.status)