Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a heatmap #1022

Merged
merged 9 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion apps/web/.env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ DATADOG_CLIENT_ID=
NEYNAR_API_KEY=

FARCASTER_DEVELOPER_FID=
FARCASTER_DEVELOPER_MNEMONIC=
FARCASTER_DEVELOPER_MNEMONIC=

ETHERSCAN_API_KEY=
BASESCAN_API_KEY=
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these keys need to be added to config service or are they already in there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these still need to be added via codeflow 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes proposed

TALENT_PROTOCOL_API_KEY=
3 changes: 3 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
"@heroicons/react": "^2.1.3",
"@lottiefiles/dotlottie-react": "^0.8.10",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.2",
"@rainbow-me/rainbowkit": "^2.1.5",
"@tanstack/react-query": "^5",
"@types/jsonwebtoken": "^9.0.6",
"@types/react-calendar-heatmap": "^1.6.7",
"@vercel/blob": "^0.23.4",
"@vercel/kv": "^1.0.1",
"@vercel/og": "^0.6.2",
Expand All @@ -49,6 +51,7 @@
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-blockies": "^1.4.1",
"react-calendar-heatmap": "^1.9.0",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.2.0",
"react-intersection-observer": "^9.10.2",
Expand Down
70 changes: 70 additions & 0 deletions apps/web/pages/api/proxy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { isAddress } from 'viem';

// Make sure the environment variables are properly set
const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY;
const BASESCAN_API_KEY = process.env.BASESCAN_API_KEY;
const TALENT_PROTOCOL_API_KEY = process.env.TALENT_PROTOCOL_API_KEY;

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { query, method } = req;
const address = query.address as string;
const apiType = query.apiType as string;
const body = req.body as Record<string, unknown>; // Explicitly type the body

if (!address || !isAddress(address)) {
return res.status(400).json({ error: 'Missing or invalid address parameter' });
}

let apiUrl: string;

try {
switch (apiType) {
case 'etherscan':
apiUrl = `https://api.etherscan.io/api?address=${address}&apikey=${ETHERSCAN_API_KEY}&module=account&action=txlist`;
break;
case 'base-sepolia':
apiUrl = `https://api-sepolia.basescan.org/api?address=${address}&apikey=${BASESCAN_API_KEY}&module=account&action=txlistinternal`;
break;
case 'basescan':
apiUrl = `https://api.basescan.org/api?address=${address}&apikey=${BASESCAN_API_KEY}&module=account&action=txlist`;
break;
case 'basescan-internal':
apiUrl = `https://api.basescan.org/api?address=${address}&apikey=${BASESCAN_API_KEY}&module=account&action=txlistinternal`;
break;
case 'talent':
apiUrl = `https://api.talentprotocol.com/api/v2/passports/${address}`;
break;
default:
return res.status(400).json({ error: 'Invalid apiType parameter' });
}

// Fetch from the external API using the constructed URL
const externalResponse = await fetch(apiUrl, {
method,
headers: {
'Content-Type': 'application/json',
'X-API-KEY': TALENT_PROTOCOL_API_KEY ?? '',
},
body: method !== 'GET' ? JSON.stringify(body) : undefined,
});
Dismissed Show dismissed Hide dismissed

// Handle the content type of the response
const contentType = externalResponse.headers.get('content-type');
let responseData;
if (contentType?.includes('application/json')) {
responseData = await externalResponse.json();
} else {
responseData = await externalResponse.text();
}

if (externalResponse.ok) {
return res.status(200).json({ data: responseData });
} else {
return res.status(externalResponse.status).json({ error: responseData });
}
} catch (error) {
console.error('Error in API proxy:', error);
return res.status(500).json({ error: 'Internal server error' });
}
}
Binary file added apps/web/public/images/base-loading.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions apps/web/src/components/Basenames/UsernameProfile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export default function UsernameProfile() {
);

return (
<div className="mx-auto flex min-h-screen flex-col justify-between gap-10 md:flex-row">
<div className="w-full md:max-w-[25rem]">
<div className="mx-auto grid min-h-screen grid-cols-1 gap-10 md:grid-cols-[25rem_minmax(0,1fr)]">
<div className="w-full">
<UsernameProfileSidebar />
</div>
<div className="w-full">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import UsernameProfileSectionBadges from 'apps/web/src/components/Basenames/UsernameProfileSectionBadges';
import UsernameProfileSectionExplore from 'apps/web/src/components/Basenames/UsernameProfileSectionExplore';
import UsernameProfileSectionHeatmap from 'apps/web/src/components/Basenames/UsernameProfileSectionHeatmap';
import BadgeContextProvider from 'apps/web/src/components/Basenames/UsernameProfileSectionBadges/BadgeContext';
import UsernameProfileSectionFrames from 'apps/web/src/components/Basenames/UsernameProfileSectionFrames';
import UsernameProfileCasts from 'apps/web/src/components/Basenames/UsernameProfileCasts';
Expand All @@ -9,6 +10,7 @@ export default function UsernameProfileContent() {
return (
<div className="flex flex-col gap-4 rounded-2xl border border-[#EBEBEB] p-4 shadow-lg sm:gap-8 sm:p-8 md:gap-10 md:p-10 lg:gap-12 lg:p-12">
<UsernameProfileSectionFrames />
<UsernameProfileSectionHeatmap />
{USERNAMES_PINNED_CASTS_ENABLED && <UsernameProfileCasts />}
<BadgeContextProvider>
<UsernameProfileSectionBadges />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.react-calendar-heatmap {
min-width: 780px;
height: auto;
width: 100%;
}

.react-calendar-heatmap text {
font-size: 10px;
fill: #aaa;
}

.react-calendar-heatmap .react-calendar-heatmap-small-text {
font-size: 5px;
}

.react-calendar-heatmap rect:hover {
stroke-width: 1;
stroke: #fff;
}
.react-calendar-heatmap rect {
stroke-width: 1;
stroke: #fff;
}
Loading
Loading