fix: resolve issues with open graph asset loading

This commit is contained in:
Mythie
2023-09-21 05:37:04 +00:00
parent 15fd819132
commit 53db1a5d19
18 changed files with 367 additions and 171 deletions

View File

@ -4,7 +4,8 @@ import { P, match } from 'ts-pattern';
import { getRecipientOrSenderByShareLinkSlug } from '@documenso/lib/server-only/share/get-recipient-or-sender-by-share-link-slug';
export const runtime = 'edge';
import { Logo } from '~/components/branding/logo';
import { getAssetBuffer } from '~/helpers/get-asset-buffer';
const CARD_OFFSET_TOP = 152;
const CARD_OFFSET_LEFT = 350;
@ -21,12 +22,21 @@ type SharePageOpenGraphImageProps = {
};
export default async function Image({ params: { slug } }: SharePageOpenGraphImageProps) {
const [interSemiBold, interRegular, caveatRegular, shareFrameImage] = await Promise.all([
getAssetBuffer('/fonts/inter-semibold.ttf'),
getAssetBuffer('/fonts/inter-regular.ttf'),
getAssetBuffer('/fonts/caveat-regular.ttf'),
getAssetBuffer('/static/og-share-frame.png'),
]);
const recipientOrSender = await getRecipientOrSenderByShareLinkSlug({ slug }).catch(() => null);
if (!recipientOrSender) {
return null;
}
const isRecipient = 'Signature' in recipientOrSender;
const signatureImage = match(recipientOrSender)
.with({ Signature: P.array(P._) }, (recipient) => {
return recipient.Signature?.[0]?.signatureImageAsBase64 || null;
@ -43,30 +53,20 @@ export default async function Image({ params: { slug } }: SharePageOpenGraphImag
return sender.name || sender.email;
});
const [interSemiBold, interRegular, caveatRegular, shareFrameImage] = await Promise.all([
fetch(new URL('./../../../../assets/inter-semibold.ttf', import.meta.url)).then(async (res) =>
res.arrayBuffer(),
),
fetch(new URL('./../../../../assets/inter-regular.ttf', import.meta.url)).then(async (res) =>
res.arrayBuffer(),
),
fetch(new URL('./../../../../assets/caveat-regular.ttf', import.meta.url)).then(async (res) =>
res.arrayBuffer(),
),
fetch(new URL('./../../../../assets/og-share-frame.png', import.meta.url)).then(async (res) =>
res.arrayBuffer(),
),
]);
return new ImageResponse(
(
<div tw="relative flex h-full w-full">
{/* @ts-expect-error Lack of typing from ImageResponse */}
<img src={shareFrameImage} alt="og-share-frame" tw="absolute inset-0 w-full h-full" />
<div tw="absolute top-20 flex w-full items-center justify-center">
{/* @ts-expect-error Lack of typing from ImageResponse */}
<Logo tw="h-8 w-60" />
</div>
{signatureImage ? (
<div
tw="absolute py-6 px-12 -mt-2 flex items-center justify-center text-center"
tw="absolute py-6 px-12 flex items-center justify-center text-center"
style={{
top: `${CARD_OFFSET_TOP}px`,
left: `${CARD_OFFSET_LEFT}px`,
@ -74,11 +74,11 @@ export default async function Image({ params: { slug } }: SharePageOpenGraphImag
height: `${CARD_HEIGHT}px`,
}}
>
<img src={signatureImage} alt="signature" tw="w-full h-full" />
<img src={signatureImage} alt="signature" tw="opacity-60 h-full max-w-[100%]" />
</div>
) : (
<p
tw="absolute py-6 px-12 -mt-2 flex items-center justify-center text-center"
tw="absolute py-6 px-12 -mt-2 flex items-center justify-center text-center text-slate-500"
style={{
fontFamily: 'Caveat',
fontSize: `${Math.max(
@ -95,20 +95,34 @@ export default async function Image({ params: { slug } }: SharePageOpenGraphImag
</p>
)}
{/* <div
tw="absolute flex items-center justify-center text-slate-500"
style={{
top: `${CARD_OFFSET_TOP + CARD_HEIGHT - 45}px`,
left: `${CARD_OFFSET_LEFT}`,
width: `${CARD_WIDTH}px`,
fontSize: '30px',
}}
>
{signatureName}
</div> */}
<div
tw="absolute absolute flex flex-col items-center justify-center pt-2.5 w-full"
tw="absolute flex flex-col items-center justify-center pt-12 w-full"
style={{
top: `${CARD_OFFSET_TOP + CARD_HEIGHT}px`,
}}
>
<h2
tw="text-2xl text-slate-900/60"
tw="text-3xl text-slate-500"
style={{
fontFamily: 'Inter',
fontWeight: 600,
}}
>
I just signed with Documenso
{isRecipient
? 'I just signed with Documenso and you can too!'
: 'I just sent a document with Documenso and you can too!'}
</h2>
</div>
</div>

View File

@ -1,38 +1,11 @@
import React from 'react';
import { Metadata } from 'next';
import { notFound } from 'next/navigation';
import { getShareLinkBySlug } from '@documenso/lib/server-only/share/get-share-link-by-slug';
import Redirect from './redirect';
import { Redirect } from './redirect';
export const metadata: Metadata = {
title: 'Documenso - Share',
};
export type SharePageProps = {
params: {
slug?: string;
};
};
export default async function SharePage({ params: { slug } }: SharePageProps) {
if (!slug) {
return notFound();
}
const share = await getShareLinkBySlug({ slug }).catch(() => null);
if (!share) {
return notFound();
}
return (
<div className="flex h-screen flex-col items-center justify-center">
<h1 className="my-2 text-4xl font-semibold">Share Page</h1>
<p className="my-2 text-xl">Redirecting...</p>
<Redirect />
</div>
);
export default function SharePage() {
return <Redirect />;
}

View File

@ -2,18 +2,10 @@
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
export default function Redirect() {
const { push } = useRouter();
export const Redirect = () => {
useEffect(() => {
const timer = setTimeout(() => {
push('/');
}, 3000);
window.location.href = process.env.NEXT_PUBLIC_MARKETING_URL ?? 'http://localhost:3001';
}, []);
return () => clearTimeout(timer);
}, [push]);
return <div></div>;
}
return null;
};

View File

@ -2,12 +2,13 @@
import { HTMLAttributes } from 'react';
import { useRouter } from 'next/navigation';
import { Share } from 'lucide-react';
import { trpc } from '@documenso/trpc/react';
import { Button } from '@documenso/ui/primitives/button';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { useCopyToClipboard } from '~/hooks/use-copy-to-clipboard';
export type ShareButtonProps = HTMLAttributes<HTMLButtonElement> & {
token: string;
@ -15,29 +16,35 @@ export type ShareButtonProps = HTMLAttributes<HTMLButtonElement> & {
};
export const ShareButton = ({ token, documentId }: ShareButtonProps) => {
const { toast } = useToast();
const [, copyToClipboard] = useCopyToClipboard();
const { mutateAsync: createOrGetShareLink, isLoading } =
trpc.shareLink.createOrGetShareLink.useMutation();
const router = useRouter();
const onShareClick = async () => {
const { slug } = await createOrGetShareLink({
token: token,
documentId,
});
await copyToClipboard(`${window.location.origin}/share/${slug}`).catch(() => null);
toast({
title: 'Copied to clipboard',
description: 'The sharing link has been copied to your clipboard.',
});
};
return (
<Button
variant="outline"
className="flex-1"
disabled={!token || !documentId || isLoading}
onClick={async () => {
console.log('Signing Clicked');
const { slug } = await createOrGetShareLink({
token,
documentId,
});
// TODO: Router delaying...
return router.push(`/share/${slug}`);
}}
disabled={!token || !documentId}
loading={isLoading}
onClick={onShareClick}
>
<Share className="mr-2 h-5 w-5" />
{!isLoading && <Share className="mr-2 h-5 w-5" />}
Share
</Button>
);

View File

@ -0,0 +1,14 @@
/**
* getAssetBuffer is used to retrieve array buffers for various assets
* that are hosted in the `public` folder.
*
* This exists due to a breakage with `import.meta.url` imports and open graph images,
* once we can identify a fix for this, we can remove this helper.
*
* @param path The path to the asset, relative to the `public` folder.
*/
export const getAssetBuffer = async (path: string) => {
const baseUrl = process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000';
return fetch(new URL(path, baseUrl)).then(async (res) => res.arrayBuffer());
};