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

Base #3

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# FRONTEND
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=bab3792638df5214933091cdfc569452
NEXT_PUBLIC_WHITELABEL_ENV="OPTIMISM"
NEXT_PUBLIC_ROUND_NAME="OP Citizen Grants Council"

# BACKEND
SYNAPS_SESSION_ID="<placeholder>"

# RAILWAY
RAILWAY_ENVIRONMENT_NAME="LOCAL_DEV"
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,8 @@ The OP Claim Tool is a web application for Optimism grant recipients to claim an
- `pnpm format`: Run Biome formatter

For more details, refer to the project documentation.

## Testing
- For testing use sepolia
- [Mint PLBR token](https://eth-sepolia.blockscout.com/token/0xdF0A43D15B036c065f6895734B878fD31269Bfa3?tab=read_write_contract)
- Create a hedgey token grant
2 changes: 2 additions & 0 deletions config/contracts/addresses.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
base,
mainnet,
optimism,
sepolia,
Expand All @@ -10,6 +11,7 @@ export const hedgeyContractAddresses = {
[optimism.id]: '0x8A2725a6f04816A5274dDD9FEaDd3bd0C253C1A6',
[mainnet.id]: '0x8A2725a6f04816A5274dDD9FEaDd3bd0C253C1A6',
[sepolia.id]: '0x8A2725a6f04816A5274dDD9FEaDd3bd0C253C1A6',
[base.id]: '0x8A2725a6f04816A5274dDD9FEaDd3bd0C253C1A6',
// TODO: Add correct contract addresses for zkSync once they have been deployed
[zksync.id]: '0x83FD45623D1627258D5e336e8BaeE3796F47a1C5',
[zksyncSepoliaTestnet.id]: '0xUnknown',
Expand Down
27 changes: 24 additions & 3 deletions config/features.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import colors from 'tailwindcss/colors';
import {
base,
mainnet,
optimism,
optimismSepolia,
Expand All @@ -8,23 +9,26 @@ import {
zksyncSepoliaTestnet,
} from 'wagmi/chains';

type WHITELABEL_ENV = 'OPTIMISM' | 'ZK_SYNC';
type WHITELABEL_ENV = 'OPTIMISM' | 'ZK_SYNC' | 'BASE';

const _WHITELABEL_ENV = process.env.NEXT_PUBLIC_WHITELABEL_ENV;

if (!_WHITELABEL_ENV) {
throw new Error('NEXT_PUBLIC_WHITELABEL_ENV is not set');
}

if (!(_WHITELABEL_ENV === 'OPTIMISM' || _WHITELABEL_ENV === 'ZK_SYNC')) {
if (!['OPTIMISM', 'ZK_SYNC', 'BASE'].includes(_WHITELABEL_ENV)) {
throw new Error('NEXT_PUBLIC_WHITELABEL_ENV is not set to a valid value');
}

export const WHITELABEL_ENV = _WHITELABEL_ENV;

export const ROUND_NAME =
process.env.NEXT_PUBLIC_ROUND_NAME || `${WHITELABEL_ENV} Round`;

interface Features {
APP_NAME: string;
BG_IMAGE: {
BG_IMAGE?: {
src: string;
};
DELEGATION_REQUIRED: boolean;
Expand Down Expand Up @@ -54,6 +58,12 @@ const featureMatrix: Record<WHITELABEL_ENV, Features> = {
DELEGATES_URL: 'https://vote.zknation.io/dao/delegates',
CONFIRMATION_CHECKMARK_BG_COLOR: 'black',
},
BASE: {
APP_NAME: 'Base Claim Tool',
DELEGATION_REQUIRED: false,
DELEGATION_ENABLED: false,
CONFIRMATION_CHECKMARK_BG_COLOR: '#0052FF',
},
};

export const FEATURES = featureMatrix[_WHITELABEL_ENV];
Expand All @@ -76,6 +86,11 @@ export const getChainConfig = () => {
appName: 'ZKsync Claim Tool',
chains: [mainnet, zksync, zksyncSepoliaTestnet],
};
case 'BASE':
return {
appName: 'Base Claim Tool',
chains: [base, sepolia],
};
}
};

Expand All @@ -99,5 +114,11 @@ export const getWhitelabelThemeColors = (): WhitelabelThemeColors => {
primaryAction: colors.blue[500],
primaryActionButtonBg: colors.blue[900],
};
case 'BASE':
return {
bgClaimcardHeader: colors.blue[100],
primaryAction: colors.blue[400],
primaryActionButtonBg: colors.blue[700],
};
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@rainbow-me/rainbowkit": "^2.1.7",
"@rainbow-me/rainbowkit-siwe-next-auth": "^0.5.0",
"@remixicon/react": "^4.3.0",
"@synaps-io/verify-sdk": "^4.0.48",
"@tanstack/react-query": "^5.59.0",
"@tanstack/react-query-devtools": "5.62.11",
"@types/lodash": "^4.17.14",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions public/base-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion src/app/api/grants/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export async function GET(req: NextRequest) {
);
const sheetNames = await sheetNamesResponse.json();
const title: string = sheetNames?.sheets[0]?.properties?.title;

if (!title) {
return Response.json({
success: false,
Expand Down
3 changes: 2 additions & 1 deletion src/app/claim-history/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ const ClaimHistory = () => {
<p>Remaining: </p>
<CurrencySymbol token={grant.campaign.token} />
<p className="font-semibold text-black">
{Math.round(grant.grantAmount - grant.claimed)}{' '}
{Math.round(grant.grantAmount - grant.claimed) ||
0}{' '}
{grant.campaign.token?.ticker}
</p>
</div>
Expand Down
8 changes: 5 additions & 3 deletions src/app/grants/[grantId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ const GrantPage = () => {
<ChevronLeft className="" />
<span>Back to all grants</span>
</Link>
<h2 className="text-lg font-semibold mb-4">You're claiming</h2>
<h2 className="text-4xl font-bold mb-6">You're claiming for</h2>
<h1 className="text-4xl font-bold flex items-center gap-2">
<span className="bg-neutral-200 rounded-md p-3">{grant?.title}</span>
<span className="bg-neutral-200 rounded-full py-3 px-5">
{grant?.title}
</span>
with
<span className="bg-neutral-200 rounded-md p-3 flex items-center gap-2 w-fit">
<span className="bg-neutral-200 rounded-full py-3 px-5 flex items-center gap-2 w-fit">
<CurrencySymbol token={grant?.campaign.token} />
{grant?.grantAmount} {grant?.campaign.token?.ticker}
</span>
Expand Down
41 changes: 18 additions & 23 deletions src/app/grants/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import WalletConnectButton from '@/components/auth/ConnectButton';
import GrantsList from '@/components/common/GrantList';
import { GrantCardSkeleton } from '@/components/common/skeletons/GrantCardSkeleton';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import {
Select,
Expand All @@ -16,15 +15,15 @@ import {
import { FilterOption, useGrants } from '@/context/GrantsContext';
import { Search } from 'lucide-react';
import { useMemo, useState } from 'react';
import { useAccount, useConnectorClient } from 'wagmi';
import { useAccount } from 'wagmi';
import { ROUND_NAME } from '../../../config/features';

const Grants = () => {
const { displayedGrants, loadMore, grants, isLoading, isFetched } =
useGrants();
const [searchTerm, setSearchTerm] = useState('');
const [filter, setFilter] = useState<FilterOption>(FilterOption.Highest);

const { isFetched: isFetchedConnector } = useConnectorClient();
const { isConnected } = useAccount();

const filteredAndSortedGrants = useMemo(() => {
Expand Down Expand Up @@ -60,18 +59,6 @@ const Grants = () => {
return filtered;
}, [displayedGrants, searchTerm, filter]);

if (isFetchedConnector && !isConnected) {
// Display a card to connect wallet, with connect button
return (
<Card>
<CardContent className="py-8 flex flex-col items-center justify-center gap-4">
Connect your wallet to view grants
<WalletConnectButton />
</CardContent>
</Card>
);
}

if (!isFetched && !isLoading) {
return null;
}
Expand All @@ -81,17 +68,24 @@ const Grants = () => {
<div className="flex flex-col gap-6 items-start">
<h1 className="text-4xl font-bold">Grants</h1>
<p>
Explore all grants from the OP Citizen Grants Council and who they've
delegated to. For grantees, this claiming tool offers a self-serve
interface to claim and delegate your grant.
Explore all grants from the {ROUND_NAME} and who they've delegated to.
For grantees, this claiming tool offers a self-serve interface to
claim and delegate your grant.
</p>

{!isConnected && (
<WalletConnectButton
text="Connect to claim"
classNames="py-6 font-normal"
/>
)}
</div>
<div className="flex items-center gap-2 my-6">
<div className="relative w-full">
<Input
type="text"
placeholder="Search grant"
className="w-full pl-10 pr-4 py-2"
className="w-full pl-10 pr-4 py-2 rounded-full"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
Expand All @@ -101,7 +95,7 @@ const Grants = () => {
value={filter}
onValueChange={(value) => setFilter(value as FilterOption)}
>
<SelectTrigger className="w-[180px] bg-neutral-200">
<SelectTrigger className="px-4 w-[180px] rounded-full bg-[#eff0f3]">
<SelectValue placeholder="Select filter" />
</SelectTrigger>
<SelectContent>
Expand All @@ -112,15 +106,16 @@ const Grants = () => {
</SelectContent>
</Select>
</div>
<div className="bg-white w-full flex items-center justify-between py-3 px-10 rounded-lg mb-4">
<p className="font-semibold">
<div className="bg-bgClaimcardHeader w-full flex items-center justify-between py-3 px-10 rounded-lg mb-6">
<p className="font-medium">
{isLoading ? 'Loading' : grants.length} Projects
</p>
<p className="font-semibold">
<p className="font-medium">
<span>Claimed</span> /{' '}
<span className="text-gray-500">Grant amount</span>
</p>
</div>

{isLoading ? (
<div className="space-y-4">
<GrantCardSkeleton />
Expand Down
10 changes: 6 additions & 4 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ export default function RootLayout({
}: { children: React.ReactNode }) {
return (
<html lang="en" className={`${inter.variable} ${sora.variable}`}>
<body className="bg-secondary">
<body>
<ContextProvider>
<ClientLayout>{children}</ClientLayout>
</ContextProvider>
<div className="fixed inset-0 w-full h-full -z-10 flex items-center justify-center">
<BackgroundImage src={FEATURES.BG_IMAGE.src} />
</div>
{FEATURES.BG_IMAGE && (
<div className="fixed inset-0 w-full h-full -z-10 flex items-center justify-center">
<BackgroundImage src={FEATURES.BG_IMAGE.src} />
</div>
)}
<Toaster />
</body>
</html>
Expand Down
17 changes: 13 additions & 4 deletions src/components/auth/ConnectButton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use client';

import { useDisconnect } from '@/hooks/useAuth';
import { cn } from '@/lib/utils';
import { ConnectButton } from '@rainbow-me/rainbowkit';
import { RiFileHistoryLine, RiLogoutBoxRLine } from '@remixicon/react';
import { useRouter } from 'next/navigation';
Expand All @@ -11,8 +12,13 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from '../ui/dropdown-menu';

const WalletConnectButton = () => {
const WalletConnectButton = ({
text,
classNames,
}: {
text?: string;
classNames?: string;
}) => {
const { disconnect } = useDisconnect();
return (
<ConnectButton.Custom>
Expand Down Expand Up @@ -49,11 +55,14 @@ const WalletConnectButton = () => {
return (
<Button
variant="outline"
className="border-secondary-foreground"
className={cn(
'bg-primaryActionButtonBg text-white rounded-full',
classNames,
)}
onClick={openConnectModal}
type="button"
>
Connect Wallet
{text || 'Connect Wallet'}
</Button>
);
}
Expand Down
Loading