Skip to content

Commit

Permalink
feat: endorsement card (#19)
Browse files Browse the repository at this point in the history
Co-authored-by: martines3000 <[email protected]>
  • Loading branch information
andyv09 and martines3000 authored Jul 3, 2024
1 parent d15e93b commit a64c541
Show file tree
Hide file tree
Showing 12 changed files with 577 additions and 29 deletions.
Binary file modified packages/dapp/public/images/endorsement_card_bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 changes: 110 additions & 1 deletion packages/dapp/src/app/api/og/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { getAggregatedAccountData } from '@/lib/ees';
import { DEFAULT_CHAIN_ID } from '@/lib/contracts';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { getAttestation } from '@/lib/eas';
import { getPropertyValue } from '@/utils/getPropertyValue';

export const runtime = 'nodejs';
export const revalidate = 0;
Expand All @@ -30,7 +32,7 @@ export async function GET(req: NextRequest) {
// Read search params
const { searchParams } = new URL(req.url);
const values = Object.fromEntries(searchParams);
const { platform, account } = values;
const { platform, account, endorsementId } = values;

const _platform = validateOrGetDefaultPlatform(platform);

Expand All @@ -51,6 +53,113 @@ export async function GET(req: NextRequest) {
});
}

if (endorsementId) {
const attestation = await getAttestation({
chainId: DEFAULT_CHAIN_ID,
id: endorsementId,
});

if (!attestation) {
throw new Error('Attestation not found');
}

const attestationData = JSON.parse(attestation?.decodedDataJson || '{}');
const endorser = getPropertyValue(
attestationData,
'endorser'
) as `0x${string}`;
const endorsementType = getPropertyValue(
attestationData,
'endorsementType'
);
const endorserData = await getMinimalProfileFromAddress(endorser);
const endorserAvatar = endorserData.avatar;
const endorserDisplayName =
endorserData.displayName ?? formatAddress(endorser);

return new ImageResponse(
<div
style={{
height: '100%',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
backgroundImage: `url(${APP_URL}/images/endorsement_card_bg_sharp.png)`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
}}
>
<div
style={{
position: 'absolute',
top: 32,
left: 32,
}}
tw="text-black text-3xl flex items-center"
>
<div>Endorsed by</div>
<div tw="flex items-center ml-4">
<img
style={{ objectFit: 'cover' }}
width={48}
height={48}
tw="rounded-full"
alt="Avatar"
src={endorserAvatar ?? blo(endorser, 160)}
/>
<h2 tw="text-3xl font-medium text-blue-500 ml-2">
{endorserDisplayName}
</h2>
</div>
</div>
<div tw="flex flex-col w-full px-8">
<div tw="flex items-center">
<img
style={{ objectFit: 'cover' }}
width={120}
height={120}
tw="rounded-full"
alt="Avatar"
src={avatar ?? blo(address, 160)}
/>
<h2 tw="text-6xl text-blue-500 ml-8">
{displayName ?? formatAddress(address)}
</h2>
</div>
<h2 tw="text-4xl font-medium">for</h2>
<h2 tw="text-6xl text-blue-500">{endorsementType}</h2>
</div>
</div>,
// ImageResponse options
{
width: 1200,
height: 630,
fonts: [
{
name: 'Inter',
data: fontRegular,
weight: 400,
style: 'normal',
},
{
name: 'Inter',
data: fontMedium,
weight: 600,
style: 'normal',
},
{
name: 'Inter',
data: fontBold,
weight: 800,
style: 'normal',
},
],
}
);
}

return new ImageResponse(
<div
style={{
Expand Down
21 changes: 19 additions & 2 deletions packages/dapp/src/app/profile/[slug]/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import { ExplorerTable } from '@/components/ExplorerTable';
import { EndorsementView } from '@/components/EndorsementView';
import { EndorsementViewBackArrow } from './EndorsementVIewBackArrow';
import { Suspense } from 'react';
import { Skeleton } from '@/components/ui/skeleton';

type ExplorerProps = {
chainId: number;
account: `0x${string}`;
currentPage: number;
endorsementId?: string;
totalEndorsementsReceived: number;
avatar: string;
displayName: string;
endorsementTab?: string;
};

export const Explorer = ({
Expand All @@ -18,6 +22,9 @@ export const Explorer = ({
currentPage,
endorsementId,
totalEndorsementsReceived,
avatar,
displayName,
endorsementTab,
}: ExplorerProps) => {
return (
<div className="flex flex-col gap-y-4 overflow-auto px-2 pb-2">
Expand All @@ -43,9 +50,19 @@ export const Explorer = ({
{endorsementId && (
<Suspense
key={`${chainId}-${endorsementId}`}
fallback={<div>loading...</div>}
fallback={
<div className="mt-4 w-full">
<Skeleton className="w-full h-48 bg-gray-200 rounded-sm" />
</div>
}
>
<EndorsementView chainId={chainId} id={endorsementId} />
<EndorsementView
chainId={chainId}
id={endorsementId}
avatar={avatar}
displayName={displayName}
endorsementTab={endorsementTab}
/>
</Suspense>
)}
</CardContent>
Expand Down
7 changes: 6 additions & 1 deletion packages/dapp/src/app/profile/[slug]/Feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ const validateOrGetDefaultTab = (tab: string | undefined) => {
type FeedProps = {
account: `0x${string}`;
avatar: string | null;
displayName: string | null;
displayName: string;
tab?: string;
network: number;
currentPage: number;
endorsementId?: string;
totalEndorsementsReceived: number;
endorsementTab?: string;
};

export const Feed = ({
Expand All @@ -46,6 +47,7 @@ export const Feed = ({
currentPage,
endorsementId,
totalEndorsementsReceived,
endorsementTab,
}: FeedProps) => {
const _tab = validateOrGetDefaultTab(tab);

Expand All @@ -71,6 +73,9 @@ export const Feed = ({
currentPage={currentPage}
endorsementId={endorsementId}
totalEndorsementsReceived={totalEndorsementsReceived}
avatar={avatar ?? ''}
displayName={displayName}
endorsementTab={endorsementTab}
/>
)}
{_tab === 'graph' && (
Expand Down
54 changes: 50 additions & 4 deletions packages/dapp/src/app/profile/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Link from 'next/link';
import type { Metadata } from 'next';
import { Address } from '@/components/Address';
import { Container } from '@/components/Container';
import {
Expand All @@ -20,6 +19,7 @@ import { getAggregatedAccountData } from '@/lib/ees';
import { NetworkSelect } from './NetworkSelect';
import { cn } from '@/lib/utils';
import { validateOrGetDefaultPage } from '@/utils/validateOrGetDefaultPage';
import type { Metadata } from 'next';

type PageProps = {
params: { slug: string };
Expand All @@ -29,12 +29,13 @@ type PageProps = {
network?: string;
page?: string;
endorsementId?: string;
endorsementTab?: string;
};
};

export default async function Page({
params: { slug },
searchParams: { platform, tab, network, page, endorsementId },
searchParams: { platform, tab, endorsementTab, network, page, endorsementId },
}: PageProps) {
const _platform = validateOrGetDefaultPlatform(platform);
const _network = validateOrGetDefaultNetwork(network);
Expand Down Expand Up @@ -115,11 +116,12 @@ export default async function Page({
>
<Feed
account={mainAddress}
avatar={avatar}
displayName={basicProfileInfo.name}
displayName={basicProfileInfo.name ?? formatAddress(mainAddress)}
tab={tab}
endorsementTab={endorsementTab}
network={_network}
currentPage={_page}
avatar={avatar}
endorsementId={endorsementId}
totalEndorsementsReceived={
Number.isNaN(totalEndorsementsReceived)
Expand All @@ -141,3 +143,47 @@ export default async function Page({
</Container>
);
}

export async function generateMetadata({
params: { slug },
searchParams,
}: PageProps): Promise<Metadata> {
return {
title: `Profile | ${slug}`,
description: `Check out ${slug} on endorse.fun!`,
openGraph: {
siteName: 'endorse.fun',
description: 'The next upgrade for Web3 social layer.',
images: [
{
url: `/api/og?account=${slug}&platform=${searchParams.platform}&endorsementId=${searchParams.endorsementId}`,
width: 1200,
height: 630,
alt: 'Profile Page Image',
},
],
title: `Check out ${slug} on endorse.fun!`,
type: 'article',
url: `/profile/${slug}?platform=${searchParams.platform}`,
},
twitter: {
card: 'summary_large_image',
title: `Check out ${slug} on endorse.fun!`,
description: 'Profile Page',
images: [
{
url: `/api/og?account=${slug}${
searchParams.platform ? `&platform=${searchParams.platform}` : ''
}${
searchParams.endorsementId
? `&endorsementId=${searchParams.endorsementId}`
: ''
}`,
width: 1200,
height: 630,
alt: 'Profile Page Image',
},
],
},
};
}
Loading

0 comments on commit a64c541

Please sign in to comment.