From d74f196742d5294156d72ddc3e005518b963cb07 Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 09:44:32 +0100 Subject: [PATCH 01/11] update: breadcrumbs --- packages/dappkit | 2 +- src/components/composite/Hero.tsx | 49 +++++++--------- .../_merkl.opportunity.$chain.$type.$id.tsx | 7 ++- src/routes/_merkl.protocol.$id.tsx | 5 +- src/routes/_merkl.protocol.(all).tsx | 14 +++++ src/routes/_merkl.status.$status.tsx | 5 +- src/routes/_merkl.token.$symbol.tsx | 4 ++ src/routes/_merkl.user.$address.tsx | 4 ++ src/routes/_merkl.user.(none).tsx | 57 +++++++++++++++++++ 9 files changed, 115 insertions(+), 32 deletions(-) create mode 100644 src/routes/_merkl.protocol.(all).tsx create mode 100644 src/routes/_merkl.user.(none).tsx diff --git a/packages/dappkit b/packages/dappkit index 8ced032d..71bc4b81 160000 --- a/packages/dappkit +++ b/packages/dappkit @@ -1 +1 @@ -Subproject commit 8ced032d34bbd5186fabb31ecf741bff89d0bab4 +Subproject commit 71bc4b81aa0aa5eb4f1e857721cbd22633c78f86 diff --git a/src/components/composite/Hero.tsx b/src/components/composite/Hero.tsx index f72dede4..052baf14 100644 --- a/src/components/composite/Hero.tsx +++ b/src/components/composite/Hero.tsx @@ -10,6 +10,7 @@ import { formatUnits, parseUnits } from "viem"; export type HeroProps = PropsWithChildren<{ icons?: IconProps[]; title: ReactNode; + breadcrumbs?: { name: string; link: string; component?: ReactNode }[]; navigation?: { label: ReactNode; link: string }; description: ReactNode; tags?: ReactNode[]; @@ -17,7 +18,17 @@ export type HeroProps = PropsWithChildren<{ opportunity?: Opportunity; }>; -export default function Hero({ navigation, icons, title, description, tags, children, opportunity, tabs }: HeroProps) { +export default function Hero({ + navigation, + breadcrumbs, + icons, + title, + description, + tags, + tabs, + children, + campaigns, +}: HeroProps) { const location = useLocation(); const filteredCampaigns = useMemo(() => { @@ -49,34 +60,18 @@ export default function Hero({ navigation, icons, title, description, tags, chil {/* TODO: Build dynamic breadcrumbs */} {/** Disabled and set invisible when undefined to preserve layout height */} - - - {location.pathname.includes("opportunity") && ( - - )} - {location.pathname.includes("user") && ( - - )} - - {!location.pathname.includes("user") && ( - - )} + {breadcrumbs?.map(breadcrumb => { + if (breadcrumb.component) return breadcrumb.component; + return ( + + ); + })} diff --git a/src/routes/_merkl.opportunity.$chain.$type.$id.tsx b/src/routes/_merkl.opportunity.$chain.$type.$id.tsx index e08112a1..fad4c1aa 100644 --- a/src/routes/_merkl.opportunity.$chain.$type.$id.tsx +++ b/src/routes/_merkl.opportunity.$chain.$type.$id.tsx @@ -42,7 +42,7 @@ export default function Index() { const spaced = opportunity?.name.split(" "); return spaced - .map((str, index) => { + .map((str) => { const key = str + crypto.randomUUID(); if (!str.match(/[\p{Letter}\p{Mark}]+/gu)) return [ @@ -68,7 +68,10 @@ export default function Index() { ({ src: t.icon }))} - navigation={{ label: "Back to opportunities", link: "/" }} + breadcrumbs={[ + { link: "/", name: "Opportunities" }, + { link: "/", name: opportunity.name }, + ]} title={styleName} description={description} tabs={[ diff --git a/src/routes/_merkl.protocol.$id.tsx b/src/routes/_merkl.protocol.$id.tsx index 29cdc6b8..56d1c63e 100644 --- a/src/routes/_merkl.protocol.$id.tsx +++ b/src/routes/_merkl.protocol.$id.tsx @@ -15,8 +15,11 @@ export default function Index() { return ( + + + ); +} diff --git a/src/routes/_merkl.status.$status.tsx b/src/routes/_merkl.status.$status.tsx index 944ed524..6aa5b50c 100644 --- a/src/routes/_merkl.status.$status.tsx +++ b/src/routes/_merkl.status.$status.tsx @@ -18,7 +18,10 @@ export default function Index() { return ( t.icon && t.icon !== "")?.icon }]} navigation={{ label: "Back to opportunities", link: "/" }} title={ diff --git a/src/routes/_merkl.user.$address.tsx b/src/routes/_merkl.user.$address.tsx index ebd63f51..3bbeb147 100644 --- a/src/routes/_merkl.user.$address.tsx +++ b/src/routes/_merkl.user.$address.tsx @@ -9,6 +9,10 @@ export default function Index() { return ( diff --git a/src/routes/_merkl.user.(none).tsx b/src/routes/_merkl.user.(none).tsx new file mode 100644 index 00000000..81ba7783 --- /dev/null +++ b/src/routes/_merkl.user.(none).tsx @@ -0,0 +1,57 @@ +import { Outlet, useNavigate } from "@remix-run/react"; +import { Hash, Icon } from "dappkit"; +import { useWalletContext } from "packages/dappkit/src/context/Wallet.context"; +import { useEffect, useState } from "react"; +import Hero from "src/components/composite/Hero"; + +export default function Index() { + const [_isEditingAddress, setIsEditingAddress] = useState(false); + const { address } = useWalletContext(); + const navigate = useNavigate(); + + useEffect(() => { + if (address) navigate(`/user/${address}`); + }, [address]); + + return ( + + {address} + + } + tabs={[ + { + label: ( + <> + + Rewards + + ), + link: `/user/${address}`, + }, + { + label: ( + <> + + Liquidity + + ), + link: `/user/${address}/liquidity`, + }, + { + label: ( + <> + + Claims + + ), + link: `/user/${address}/claims`, + }, + ]}> + + + ); +} From f41304f0833576d1b83b2a82cc349aa571d55046 Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 10:19:23 +0100 Subject: [PATCH 02/11] restore: tabs --- merkl.config.ts | 39 +++++------ src/components/composite/Hero.tsx | 69 ++++++------------- src/components/element/Tag.tsx | 7 +- .../element/functions/SearchBar.tsx | 2 +- src/hooks/resources/useOpportunity.tsx | 2 +- ...merkl.actions.$action.(opportunities).tsx} | 0 ...$action.tsx => _merkl.actions.$action.tsx} | 2 +- src/routes/_merkl.campaign.$id.tsx | 9 --- ... => _merkl.chains.$id.(opportunities).tsx} | 0 ...kl.chain.$id.tsx => _merkl.chains.$id.tsx} | 0 ...rtunities.$chain.$type.$id.(overview).tsx} | 0 ...portunities.$chain.$type.$id.analytics.tsx | 10 +++ ...tunities.$chain.$type.$id.leaderboard.tsx} | 0 ..._merkl.opportunities.$chain.$type.$id.tsx} | 0 ... _merkl.protocols.$id.(opportunities).tsx} | 0 ...tocol.$id.tsx => _merkl.protocols.$id.tsx} | 6 +- ...l.(all).tsx => _merkl.protocols.(all).tsx} | 2 +- ..._merkl.tokens.$symbol.(opportunities).tsx} | 0 ....$symbol.tsx => _merkl.tokens.$symbol.tsx} | 0 ...sx => _merkl.users.$address.(rewards).tsx} | 0 ...s.tsx => _merkl.users.$address.claims.tsx} | 0 ...sx => _merkl.users.$address.liquidity.tsx} | 0 ...$address.tsx => _merkl.users.$address.tsx} | 0 ...ser.(none).tsx => _merkl.users.(none).tsx} | 0 src/shorthands.css | 0 25 files changed, 57 insertions(+), 91 deletions(-) rename src/routes/{_merkl.action.$action.(opportunities).tsx => _merkl.actions.$action.(opportunities).tsx} (100%) rename src/routes/{_merkl.action.$action.tsx => _merkl.actions.$action.tsx} (93%) delete mode 100644 src/routes/_merkl.campaign.$id.tsx rename src/routes/{_merkl.chain.$id.(opportunities).tsx => _merkl.chains.$id.(opportunities).tsx} (100%) rename src/routes/{_merkl.chain.$id.tsx => _merkl.chains.$id.tsx} (100%) rename src/routes/{_merkl.opportunity.$chain.$type.$id.(overview).tsx => _merkl.opportunities.$chain.$type.$id.(overview).tsx} (100%) create mode 100644 src/routes/_merkl.opportunities.$chain.$type.$id.analytics.tsx rename src/routes/{_merkl.opportunity.$chain.$type.$id.leaderboard.tsx => _merkl.opportunities.$chain.$type.$id.leaderboard.tsx} (100%) rename src/routes/{_merkl.opportunity.$chain.$type.$id.tsx => _merkl.opportunities.$chain.$type.$id.tsx} (100%) rename src/routes/{_merkl.protocol.$id.(opportunities).tsx => _merkl.protocols.$id.(opportunities).tsx} (100%) rename src/routes/{_merkl.protocol.$id.tsx => _merkl.protocols.$id.tsx} (80%) rename src/routes/{_merkl.protocol.(all).tsx => _merkl.protocols.(all).tsx} (81%) rename src/routes/{_merkl.token.$symbol.(opportunities).tsx => _merkl.tokens.$symbol.(opportunities).tsx} (100%) rename src/routes/{_merkl.token.$symbol.tsx => _merkl.tokens.$symbol.tsx} (100%) rename src/routes/{_merkl.user.$address.(rewards).tsx => _merkl.users.$address.(rewards).tsx} (100%) rename src/routes/{_merkl.user.$address.claims.tsx => _merkl.users.$address.claims.tsx} (100%) rename src/routes/{_merkl.user.$address.liquidity.tsx => _merkl.users.$address.liquidity.tsx} (100%) rename src/routes/{_merkl.user.$address.tsx => _merkl.users.$address.tsx} (100%) rename src/routes/{_merkl.user.(none).tsx => _merkl.users.(none).tsx} (100%) delete mode 100644 src/shorthands.css diff --git a/merkl.config.ts b/merkl.config.ts index 85a3eb38..0971b5dd 100644 --- a/merkl.config.ts +++ b/merkl.config.ts @@ -1,6 +1,6 @@ import { createColoring } from "dappkit"; import { createConfig } from "src/config/type"; -import { http } from "viem"; +import { createClient, custom, http } from "viem"; import { mainnet, optimism, @@ -37,6 +37,7 @@ import { } from "viem/chains"; import { coinbaseWallet, walletConnect } from "wagmi/connectors"; import hero from "src/customer/assets/images/hero.jpg?url"; +import { eip712WalletActions } from "viem/zksync"; export default createConfig({ appName: "Merkl", @@ -44,26 +45,11 @@ export default createConfig({ defaultTheme: "merkl", themes: { merkl: { - base: createColoring( - ["#1F2333", "#B8AAFD", "#131620"], - ["#FCF8F5", "#B8AAFD", "white"] - ), - info: createColoring( - ["#2ABDFF", "#2ABDFF", "#131620"], - ["#FFFFFF", "#40B66B", "white"] - ), - good: createColoring( - ["#40B66B", "#40B66B", "#131620"], - ["#FFFFFF", "#40B66B", "white"] - ), - warn: createColoring( - ["#ff9600", "#ff9600", "#131620"], - ["#FFFFFF", "#40B66B", "white"] - ), - harm: createColoring( - ["#d22e14", "#d22e14", "#131620"], - ["#FFFFFF", "#40B66B", "white"] - ), + base: createColoring(["#1F2333", "#B8AAFD", "#131620"], ["#FCF8F5", "#B8AAFD", "white"]), + info: createColoring(["#2ABDFF", "#2ABDFF", "#131620"], ["#FFFFFF", "#40B66B", "white"]), + good: createColoring(["#40B66B", "#40B66B", "#131620"], ["#FFFFFF", "#40B66B", "white"]), + warn: createColoring(["#ff9600", "#ff9600", "#131620"], ["#FFFFFF", "#40B66B", "white"]), + harm: createColoring(["#d22e14", "#d22e14", "#131620"], ["#FFFFFF", "#40B66B", "white"]), }, }, sizing: { @@ -82,7 +68,7 @@ export default createConfig({ }, dashboard: { icon: "RiDashboard2Fill", - route: "/user", + route: "/users", key: crypto.randomUUID(), }, opportunities: { @@ -156,6 +142,12 @@ export default createConfig({ taiko, scroll, ], + client({ chain }) { + if (chain.id === zksync.id) + return createClient({ chain, transport: custom(window.ethereum!) }).extend(eip712WalletActions()); + return createClient({ chain, transport: http() }); + }, + ssr: true, connectors: [ coinbaseWallet(), walletConnect({ @@ -169,9 +161,12 @@ export default createConfig({ }, }), ], +<<<<<<< HEAD transports: { [zksync.id]: http(), [optimism.id]: http(), }, +======= +>>>>>>> 6e48802 (restore: tabs) }, }); diff --git a/src/components/composite/Hero.tsx b/src/components/composite/Hero.tsx index 052baf14..cff284fe 100644 --- a/src/components/composite/Hero.tsx +++ b/src/components/composite/Hero.tsx @@ -1,11 +1,9 @@ -import type { Campaign, Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@angleprotocol/merkl-api"; import { useLocation } from "@remix-run/react"; -import { Box, Container, Divider, Group, Icon, type IconProps, Icons, Text, Title, Value } from "dappkit"; +import { Box, Container, Divider, Group, Icon, type IconProps, Icons, Text, Title } from "dappkit"; import { Button } from "dappkit"; import config from "merkl.config"; -import moment from "moment"; -import { type PropsWithChildren, type ReactNode, useMemo } from "react"; -import { formatUnits, parseUnits } from "viem"; +import type { PropsWithChildren, ReactNode } from "react"; export type HeroProps = PropsWithChildren<{ icons?: IconProps[]; @@ -18,42 +16,13 @@ export type HeroProps = PropsWithChildren<{ opportunity?: Opportunity; }>; -export default function Hero({ - navigation, - breadcrumbs, - icons, - title, - description, - tags, - tabs, - children, - campaigns, -}: HeroProps) { +export default function Hero({ navigation, breadcrumbs, icons, title, description, tags, tabs, children }: HeroProps) { const location = useLocation(); - const filteredCampaigns = useMemo(() => { - if (!opportunity?.campaigns) return null; - const now = moment().unix(); - return opportunity.campaigns?.filter((c: Campaign) => Number(c.endTimestamp) > now); - }, [opportunity]); - - const totalRewards = useMemo(() => { - const amounts = filteredCampaigns?.map(campaign => { - const duration = campaign.endTimestamp - campaign.startTimestamp; - const dayspan = BigInt(duration) / BigInt(3600 * 24); - - return parseUnits(campaign.amount, 0) / BigInt(dayspan); - }); - - const sum = amounts?.reduce((accumulator, currentValue) => accumulator + currentValue, 0n); - if (!sum) return "0.0"; - return formatUnits(sum, 18); - }, [filteredCampaigns]); - return ( <> @@ -66,7 +35,7 @@ export default function Hero({ {breadcrumbs?.map(breadcrumb => { if (breadcrumb.component) return breadcrumb.component; return ( - @@ -114,8 +83,8 @@ export default function Hero({ )} - {/* TODO: Show "Opportunities" or "Campaigns" according to the page */} - {!location?.pathname.includes("user") && ( + {/* TODO: Move this outside the Hero component */} + {/* {!location?.pathname.includes("user") && ( @@ -145,20 +114,22 @@ export default function Hero({ - )} + )} */} - {!!tabs && ( - - {tabs?.map(tab => ( - - ))} - - )} + + {!!tabs && ( + + {tabs?.map(tab => ( + + ))} + + )} +
{children}
); diff --git a/src/components/element/Tag.tsx b/src/components/element/Tag.tsx index d940a69e..42876e03 100644 --- a/src/components/element/Tag.tsx +++ b/src/components/element/Tag.tsx @@ -229,11 +229,10 @@ export default function Tag({ type, value, ...props }: {value?.name} - + + {/* {token?.description} */} - {/* {token?.description} */} - ); diff --git a/src/hooks/resources/useOpportunity.tsx b/src/hooks/resources/useOpportunity.tsx index 571478ce..023c28da 100644 --- a/src/hooks/resources/useOpportunity.tsx +++ b/src/hooks/resources/useOpportunity.tsx @@ -15,7 +15,7 @@ export default function useOpportunity(opportunity: Opportunity) { }, [opportunity]); const link = useMemo( - () => `/opportunity/${opportunity.chain?.name?.toLowerCase?.()}/${opportunity.type}/${opportunity.identifier}`, + () => `/opportunities/${opportunity.chain?.name?.toLowerCase?.()}/${opportunity.type}/${opportunity.identifier}`, [opportunity], ); diff --git a/src/routes/_merkl.action.$action.(opportunities).tsx b/src/routes/_merkl.actions.$action.(opportunities).tsx similarity index 100% rename from src/routes/_merkl.action.$action.(opportunities).tsx rename to src/routes/_merkl.actions.$action.(opportunities).tsx diff --git a/src/routes/_merkl.action.$action.tsx b/src/routes/_merkl.actions.$action.tsx similarity index 93% rename from src/routes/_merkl.action.$action.tsx rename to src/routes/_merkl.actions.$action.tsx index 4fc39661..a1abc487 100644 --- a/src/routes/_merkl.action.$action.tsx +++ b/src/routes/_merkl.actions.$action.tsx @@ -24,7 +24,7 @@ export default function Index() { tabs={[ { label: "Opportunities", - link: `/action/${action.label?.toLowerCase()}`, + link: `/actions/${action.label?.toLowerCase()}`, }, ]}> diff --git a/src/routes/_merkl.campaign.$id.tsx b/src/routes/_merkl.campaign.$id.tsx deleted file mode 100644 index f669caba..00000000 --- a/src/routes/_merkl.campaign.$id.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Group } from "dappkit"; - -export default function Index() { - return ( - - OP - - ); -} diff --git a/src/routes/_merkl.chain.$id.(opportunities).tsx b/src/routes/_merkl.chains.$id.(opportunities).tsx similarity index 100% rename from src/routes/_merkl.chain.$id.(opportunities).tsx rename to src/routes/_merkl.chains.$id.(opportunities).tsx diff --git a/src/routes/_merkl.chain.$id.tsx b/src/routes/_merkl.chains.$id.tsx similarity index 100% rename from src/routes/_merkl.chain.$id.tsx rename to src/routes/_merkl.chains.$id.tsx diff --git a/src/routes/_merkl.opportunity.$chain.$type.$id.(overview).tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx similarity index 100% rename from src/routes/_merkl.opportunity.$chain.$type.$id.(overview).tsx rename to src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.analytics.tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.analytics.tsx new file mode 100644 index 00000000..a6cedacd --- /dev/null +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.analytics.tsx @@ -0,0 +1,10 @@ +import { type LoaderFunctionArgs, json } from "@remix-run/node"; +import { Text } from "dappkit/src"; + +export async function loader({ params }: LoaderFunctionArgs) { + return json({ chain: params.chain }); +} + +export default function Index() { + return Analytics; +} diff --git a/src/routes/_merkl.opportunity.$chain.$type.$id.leaderboard.tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx similarity index 100% rename from src/routes/_merkl.opportunity.$chain.$type.$id.leaderboard.tsx rename to src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx diff --git a/src/routes/_merkl.opportunity.$chain.$type.$id.tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.tsx similarity index 100% rename from src/routes/_merkl.opportunity.$chain.$type.$id.tsx rename to src/routes/_merkl.opportunities.$chain.$type.$id.tsx diff --git a/src/routes/_merkl.protocol.$id.(opportunities).tsx b/src/routes/_merkl.protocols.$id.(opportunities).tsx similarity index 100% rename from src/routes/_merkl.protocol.$id.(opportunities).tsx rename to src/routes/_merkl.protocols.$id.(opportunities).tsx diff --git a/src/routes/_merkl.protocol.$id.tsx b/src/routes/_merkl.protocols.$id.tsx similarity index 80% rename from src/routes/_merkl.protocol.$id.tsx rename to src/routes/_merkl.protocols.$id.tsx index 56d1c63e..cc5b51a5 100644 --- a/src/routes/_merkl.protocol.$id.tsx +++ b/src/routes/_merkl.protocols.$id.tsx @@ -17,14 +17,14 @@ export default function Index() { icons={[{ src: protocol?.icon }]} title={protocol?.name} breadcrumbs={[ - { link: "/protocol", name: "Protocols" }, - { link: `/protocol/${protocol.name}`, name: protocol.name }, + { link: "/protocols", name: "Protocols" }, + { link: `/protocols/${protocol.name}`, name: protocol.name }, ]} description={"Protocol"} tabs={[ { label: "Opportunities", - link: `/protocol/${protocol.name?.toLowerCase()}`, + link: `/protocols/${protocol.name?.toLowerCase()}`, }, ]}> diff --git a/src/routes/_merkl.protocol.(all).tsx b/src/routes/_merkl.protocols.(all).tsx similarity index 81% rename from src/routes/_merkl.protocol.(all).tsx rename to src/routes/_merkl.protocols.(all).tsx index 2962641b..64de4b0e 100644 --- a/src/routes/_merkl.protocol.(all).tsx +++ b/src/routes/_merkl.protocols.(all).tsx @@ -6,7 +6,7 @@ export default function Index() { diff --git a/src/routes/_merkl.token.$symbol.(opportunities).tsx b/src/routes/_merkl.tokens.$symbol.(opportunities).tsx similarity index 100% rename from src/routes/_merkl.token.$symbol.(opportunities).tsx rename to src/routes/_merkl.tokens.$symbol.(opportunities).tsx diff --git a/src/routes/_merkl.token.$symbol.tsx b/src/routes/_merkl.tokens.$symbol.tsx similarity index 100% rename from src/routes/_merkl.token.$symbol.tsx rename to src/routes/_merkl.tokens.$symbol.tsx diff --git a/src/routes/_merkl.user.$address.(rewards).tsx b/src/routes/_merkl.users.$address.(rewards).tsx similarity index 100% rename from src/routes/_merkl.user.$address.(rewards).tsx rename to src/routes/_merkl.users.$address.(rewards).tsx diff --git a/src/routes/_merkl.user.$address.claims.tsx b/src/routes/_merkl.users.$address.claims.tsx similarity index 100% rename from src/routes/_merkl.user.$address.claims.tsx rename to src/routes/_merkl.users.$address.claims.tsx diff --git a/src/routes/_merkl.user.$address.liquidity.tsx b/src/routes/_merkl.users.$address.liquidity.tsx similarity index 100% rename from src/routes/_merkl.user.$address.liquidity.tsx rename to src/routes/_merkl.users.$address.liquidity.tsx diff --git a/src/routes/_merkl.user.$address.tsx b/src/routes/_merkl.users.$address.tsx similarity index 100% rename from src/routes/_merkl.user.$address.tsx rename to src/routes/_merkl.users.$address.tsx diff --git a/src/routes/_merkl.user.(none).tsx b/src/routes/_merkl.users.(none).tsx similarity index 100% rename from src/routes/_merkl.user.(none).tsx rename to src/routes/_merkl.users.(none).tsx diff --git a/src/shorthands.css b/src/shorthands.css deleted file mode 100644 index e69de29b..00000000 From cd405d9940097af9ebd8db5db489afa52cdbc672 Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 10:20:19 +0100 Subject: [PATCH 03/11] fix: layout --- src/components/composite/Hero.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/composite/Hero.tsx b/src/components/composite/Hero.tsx index cff284fe..80ce6e89 100644 --- a/src/components/composite/Hero.tsx +++ b/src/components/composite/Hero.tsx @@ -22,7 +22,7 @@ export default function Hero({ navigation, breadcrumbs, icons, title, descriptio return ( <> From 1ae295b51547479263aa84c768eb376e76900032 Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 10:42:25 +0100 Subject: [PATCH 04/11] fix: loaders --- merkl.config.ts | 11 ---- src/api/services/campaign.service.ts | 13 +++++ src/api/services/opportunity.service.ts | 7 ++- src/components/layout/Header.tsx | 55 ++++++++++++------- ..._merkl.actions.$action.(opportunities).tsx | 2 +- .../_merkl.chains.$id.(opportunities).tsx | 4 +- .../_merkl.protocols.$id.(opportunities).tsx | 2 +- .../_merkl.status.$status.(opportunities).tsx | 2 +- .../_merkl.users.$address.(rewards).tsx | 2 +- src/routes/_merkl.users.$address.tsx | 10 ++-- src/routes/_merkl.users.(none).tsx | 18 +++--- 11 files changed, 73 insertions(+), 53 deletions(-) diff --git a/merkl.config.ts b/merkl.config.ts index 0971b5dd..1032b023 100644 --- a/merkl.config.ts +++ b/merkl.config.ts @@ -66,11 +66,6 @@ export default createConfig({ route: "/", key: crypto.randomUUID(), }, - dashboard: { - icon: "RiDashboard2Fill", - route: "/users", - key: crypto.randomUUID(), - }, opportunities: { icon: "RiPlanetFill", route: "/opportunities", @@ -81,12 +76,6 @@ export default createConfig({ route: "/protocols", key: crypto.randomUUID(), }, - bridge: { - icon: "RiVipCrown2Fill", - route: "/bridge", - key: crypto.randomUUID(), - }, - faq: { icon: "RiQuestionFill", route: "/faq", key: crypto.randomUUID() }, terms: { icon: "RiCompassesLine", route: "/terms", diff --git a/src/api/services/campaign.service.ts b/src/api/services/campaign.service.ts index 00604e36..21539473 100644 --- a/src/api/services/campaign.service.ts +++ b/src/api/services/campaign.service.ts @@ -1,3 +1,4 @@ +<<<<<<< HEAD import type { Campaign } from "@angleprotocol/merkl-api"; import { api } from "../index.server"; @@ -51,4 +52,16 @@ export abstract class CampaignService { static async getByID(Id: string): Promise { return null; } +======= +class CampaignService { + // // ------ Fetch all campaigns + // async get(): Promise { + // const { data } = await api.v4.campaigns.index.get({ query: {} }); + // return data; + // } + // // ------ Fetch a campaign by ID + // async getByID(Id: string): Promise { + // return "To implements"; + // } +>>>>>>> 19f3164 (fix: loaders) } diff --git a/src/api/services/opportunity.service.ts b/src/api/services/opportunity.service.ts index 2b45abbf..839e2eea 100644 --- a/src/api/services/opportunity.service.ts +++ b/src/api/services/opportunity.service.ts @@ -48,8 +48,11 @@ export abstract class OpportunityService { return query; } - static async getManyFromRequest(request: Request) { - return OpportunityService.getMany(OpportunityService.#getQueryFromRequest(request)); + static async getManyFromRequest( + request: Request, + overrides?: Parameters[0]["query"], + ) { + return OpportunityService.getMany(Object.assign(OpportunityService.#getQueryFromRequest(request), overrides ?? {})); } static async getMany( diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 6dba0411..d9748950 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -6,7 +6,8 @@ import SearchBar from "../element/functions/SearchBar"; import { motion } from "framer-motion"; import config from "merkl.config"; -import { useState } from "react"; +import { useWalletContext } from "packages/dappkit/src/context/Wallet.context"; +import { useMemo, useState } from "react"; import { useMediaQuery } from "react-responsive"; import SCREENS from "../../../packages/dappkit/src/constants/SCREENS.json"; import SwitchMode from "../element/SwitchMode"; @@ -31,12 +32,29 @@ const item = { }; export default function Header() { - const { mode } = useTheme(); + const { mode, toggleMode } = useTheme(); + const { address: user } = useWalletContext(); const [open, setOpen] = useState(false); const mdScreens = useMediaQuery({ maxWidth: SCREENS.lg }); const smScreens = useMediaQuery({ maxWidth: SCREENS.md }); + const routes = useMemo(() => { + const { homepage, ...rest } = config.routes; + + return Object.assign( + { homepage }, + { + dashboard: { + icon: "RiPlanetFill", + route: user ? `/users/${user}` : "/users", + key: crypto.randomUUID(), + }, + }, + rest, + ); + }, [user]); + return ( } + content={} className="flex gap-sm md:gap-lg items-center"> ) : ( - - ); - })} - - - - + {!mdScreens && + Object.entries(routes) + .filter(([key]) => !["homepage", "privacy", "terms"].includes(key)) + .map(([key, { route }]) => { + return ( + + ); + })} + {canSwitchModes && ( + )} {!smScreens && } diff --git a/src/routes/_merkl.actions.$action.(opportunities).tsx b/src/routes/_merkl.actions.$action.(opportunities).tsx index 0d22b4cb..853d999b 100644 --- a/src/routes/_merkl.actions.$action.(opportunities).tsx +++ b/src/routes/_merkl.actions.$action.(opportunities).tsx @@ -11,7 +11,7 @@ export async function loader({ params: { action: _action }, request }: LoaderFun const action = getAction(_action ?? ""); if (!action) throw new Error("Unknown action"); - const { opportunities, count } = await OpportunityService.getMany({ action }); + const { opportunities, count } = await OpportunityService.getManyFromRequest(request, { action }); const chains = await ChainService.getAll(); return json({ opportunities, chains, count }); diff --git a/src/routes/_merkl.chains.$id.(opportunities).tsx b/src/routes/_merkl.chains.$id.(opportunities).tsx index 66d54621..1f144482 100644 --- a/src/routes/_merkl.chains.$id.(opportunities).tsx +++ b/src/routes/_merkl.chains.$id.(opportunities).tsx @@ -7,7 +7,9 @@ import OpportunityLibrary from "src/components/element/opportunity/OpportunityLi export async function loader({ params: { id: chainId }, request }: LoaderFunctionArgs) { const chain = await ChainService.get({ search: chainId }); - const { opportunities, count } = await OpportunityService.getMany({ chainId: chain.id.toString() }); + const { opportunities, count } = await OpportunityService.getManyFromRequest(request, { + chainId: chain.id.toString(), + }); return json({ opportunities, count }); } diff --git a/src/routes/_merkl.protocols.$id.(opportunities).tsx b/src/routes/_merkl.protocols.$id.(opportunities).tsx index 8d4ea9f5..21e8e827 100644 --- a/src/routes/_merkl.protocols.$id.(opportunities).tsx +++ b/src/routes/_merkl.protocols.$id.(opportunities).tsx @@ -8,7 +8,7 @@ import OpportunityLibrary from "src/components/element/opportunity/OpportunityLi export async function loader({ params: { id }, request }: LoaderFunctionArgs) { const protocol = await ProtocolService.get({ id: id ?? "" }); - const { opportunities, count } = await OpportunityService.getMany({ mainProtocolId: id }); + const { opportunities, count } = await OpportunityService.getManyFromRequest(request, { mainProtocolId: id }); const chains = await ChainService.getAll(); return json({ opportunities, chains, count, protocol }); diff --git a/src/routes/_merkl.status.$status.(opportunities).tsx b/src/routes/_merkl.status.$status.(opportunities).tsx index 844218af..0b274ac3 100644 --- a/src/routes/_merkl.status.$status.(opportunities).tsx +++ b/src/routes/_merkl.status.$status.(opportunities).tsx @@ -10,7 +10,7 @@ export async function loader({ params: { status: _status }, request }: LoaderFun const status = getStatus(_status ?? ""); if (!status) throw new Error("Unknown status"); - const { opportunities, count } = await OpportunityService.getMany({ status }); + const { opportunities, count } = await OpportunityService.getManyFromRequest(request, { status }); const chains = await ChainService.getAll(); return json({ opportunities, chains, count }); diff --git a/src/routes/_merkl.users.$address.(rewards).tsx b/src/routes/_merkl.users.$address.(rewards).tsx index aa0134ee..ad94dac3 100644 --- a/src/routes/_merkl.users.$address.(rewards).tsx +++ b/src/routes/_merkl.users.$address.(rewards).tsx @@ -7,7 +7,7 @@ import ClaimRewardsLibrary from "src/components/element/rewards/ClaimRewardsLibr export async function loader({ params: { address } }: LoaderFunctionArgs) { if (!address) throw ""; - const { data: rewards, ...res } = await api.v4.users({ address }).rewards.full.get({ query: {} }); + const { data: rewards } = await api.v4.users({ address }).rewards.full.get({ query: {} }); if (!rewards) throw ""; diff --git a/src/routes/_merkl.users.$address.tsx b/src/routes/_merkl.users.$address.tsx index 3bbeb147..7f06a44d 100644 --- a/src/routes/_merkl.users.$address.tsx +++ b/src/routes/_merkl.users.$address.tsx @@ -5,13 +5,13 @@ import Hero from "src/components/composite/Hero"; export default function Index() { const { address } = useParams(); - const [_isEditingAddress, setIsEditingAddress] = useState(false); + const [_isEditingAddress] = useState(false); return ( ), - link: `/user/${address}`, + link: `/users/${address}`, }, { label: ( @@ -70,7 +70,7 @@ export default function Index() { Liquidity ), - link: `/user/${address}/liquidity`, + link: `/users/${address}/liquidity`, }, { label: ( @@ -79,7 +79,7 @@ export default function Index() { Claims ), - link: `/user/${address}/claims`, + link: `/users/${address}/claims`, }, ]}> diff --git a/src/routes/_merkl.users.(none).tsx b/src/routes/_merkl.users.(none).tsx index 81ba7783..b3884a92 100644 --- a/src/routes/_merkl.users.(none).tsx +++ b/src/routes/_merkl.users.(none).tsx @@ -1,20 +1,16 @@ -import { Outlet, useNavigate } from "@remix-run/react"; +import { Outlet } from "@remix-run/react"; import { Hash, Icon } from "dappkit"; import { useWalletContext } from "packages/dappkit/src/context/Wallet.context"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import Hero from "src/components/composite/Hero"; export default function Index() { - const [_isEditingAddress, setIsEditingAddress] = useState(false); + const [_isEditingAddress] = useState(false); const { address } = useWalletContext(); - const navigate = useNavigate(); - - useEffect(() => { - if (address) navigate(`/user/${address}`); - }, [address]); return ( ), - link: `/user/${address}`, + link: `/users/${address}`, }, { label: ( @@ -39,7 +35,7 @@ export default function Index() { Liquidity ), - link: `/user/${address}/liquidity`, + link: `/users/${address}/liquidity`, }, { label: ( @@ -48,7 +44,7 @@ export default function Index() { Claims ), - link: `/user/${address}/claims`, + link: `/users/${address}/claims`, }, ]}> From 6c36964790db87ea75d2b9da655c2b7851677b5f Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 12:07:40 +0100 Subject: [PATCH 05/11] update: api package --- package.json | 2 +- src/api/index.client.ts | 2 +- src/api/index.server.ts | 2 +- src/api/services/chain.service.ts | 2 +- src/api/services/opportunity.service.ts | 2 +- src/api/services/protocol.service.ts | 2 +- src/api/services/reward.service.ts | 2 +- src/api/services/token.service.ts | 2 +- src/api/types.ts | 2 +- src/components/composite/Hero.tsx | 2 +- src/components/element/Tag.tsx | 11 ++++++----- src/components/element/campaign/CampaignLibrary.tsx | 2 +- src/components/element/campaign/CampaignTableRow.tsx | 6 +++--- src/components/element/chain/Chain.tsx | 2 +- src/components/element/functions/SearchBar.tsx | 2 +- .../element/opportunity/OpportunityButton.tsx | 2 +- .../element/opportunity/OpportunityFilters.tsx | 2 +- .../element/opportunity/OpportunityLibrary.tsx | 2 +- .../element/opportunity/OpportunityTableRow.tsx | 2 +- src/components/element/participate/Participate.tsx | 2 +- .../element/rewards/ClaimRewardsChainTableRow.tsx | 2 +- .../element/rewards/ClaimRewardsLibrary.tsx | 2 +- .../element/rewards/ClaimRewardsTokenTableRow.tsx | 2 +- src/components/element/token/Token.tsx | 2 +- src/components/element/token/TokenTooltip.tsx | 2 +- src/config/actions.ts | 2 +- src/config/status.ts | 2 +- src/entry.server.tsx | 3 +++ src/hooks/resources/useCampaign.tsx | 2 +- src/hooks/resources/useOpportunity.tsx | 2 +- src/hooks/useMerklSearch.tsx | 2 +- ...erkl.opportunities.$chain.$type.$id.(overview).tsx | 1 + vite.config.ts | 1 + 33 files changed, 42 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 97e1a2f7..2900a239 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ ], "dependencies": { "@acab/ecsstatic": "^0.8.0", - "@angleprotocol/merkl-api": "0.10.69", + "@merkl/api": "0.10.78", "@ariakit/react": "^0.4.12", "@elysiajs/eden": "^1.1.3", "@emotion/css": "^11.13.4", diff --git a/src/api/index.client.ts b/src/api/index.client.ts index 5a83e1da..8e38c1f2 100644 --- a/src/api/index.client.ts +++ b/src/api/index.client.ts @@ -1,4 +1,4 @@ -import { MerklApi } from "@angleprotocol/merkl-api"; +import { MerklApi } from "@merkl/api"; const api = MerklApi((window as { ENV?: { API_URL?: string } })?.ENV?.API_URL ?? "https://api.merkl.xyz"); diff --git a/src/api/index.server.ts b/src/api/index.server.ts index ec21ff7b..b7445045 100644 --- a/src/api/index.server.ts +++ b/src/api/index.server.ts @@ -1,4 +1,4 @@ -import { MerklApi } from "@angleprotocol/merkl-api"; +import { MerklApi } from "@merkl/api"; const api = MerklApi(process.env.API_URL ?? "https://api.merkl.xyz"); diff --git a/src/api/services/chain.service.ts b/src/api/services/chain.service.ts index 0980468b..b5b6f5f8 100644 --- a/src/api/services/chain.service.ts +++ b/src/api/services/chain.service.ts @@ -1,4 +1,4 @@ -import type { Chain } from "@angleprotocol/merkl-api"; +import type { Chain } from "@merkl/api"; import { api } from "../index.server"; export abstract class ChainService { diff --git a/src/api/services/opportunity.service.ts b/src/api/services/opportunity.service.ts index 839e2eea..abb28a43 100644 --- a/src/api/services/opportunity.service.ts +++ b/src/api/services/opportunity.service.ts @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Campaign, Opportunity } from "@merkl/api"; import config from "merkl.config"; import { api } from "../index.server"; diff --git a/src/api/services/protocol.service.ts b/src/api/services/protocol.service.ts index a0664eef..4e0dd07c 100644 --- a/src/api/services/protocol.service.ts +++ b/src/api/services/protocol.service.ts @@ -1,4 +1,4 @@ -import type { Protocol } from "@angleprotocol/merkl-api"; +import type { Protocol } from "@merkl/api"; import { api } from "../index.server"; export abstract class ProtocolService { diff --git a/src/api/services/reward.service.ts b/src/api/services/reward.service.ts index b081cef0..a3bdb278 100644 --- a/src/api/services/reward.service.ts +++ b/src/api/services/reward.service.ts @@ -1,4 +1,4 @@ -import type { Reward } from "@angleprotocol/merkl-api"; +import type { Reward } from "@merkl/api"; import { api } from "../index.server"; export abstract class RewardService { diff --git a/src/api/services/token.service.ts b/src/api/services/token.service.ts index bbefb1fa..22215cab 100644 --- a/src/api/services/token.service.ts +++ b/src/api/services/token.service.ts @@ -1,4 +1,4 @@ -import type { Token } from "@angleprotocol/merkl-api"; +import type { Token } from "@merkl/api"; import { api } from "../index.server"; export abstract class TokenService { diff --git a/src/api/types.ts b/src/api/types.ts index d8a389a0..6b369f0a 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -1,3 +1,3 @@ -import type { MerklApi } from "@angleprotocol/merkl-api"; +import type { MerklApi } from "@merkl/api"; export type Api = ReturnType; diff --git a/src/components/composite/Hero.tsx b/src/components/composite/Hero.tsx index 80ce6e89..aeeb677b 100644 --- a/src/components/composite/Hero.tsx +++ b/src/components/composite/Hero.tsx @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import { useLocation } from "@remix-run/react"; import { Box, Container, Divider, Group, Icon, type IconProps, Icons, Text, Title } from "dappkit"; import { Button } from "dappkit"; diff --git a/src/components/element/Tag.tsx b/src/components/element/Tag.tsx index 42876e03..275bd353 100644 --- a/src/components/element/Tag.tsx +++ b/src/components/element/Tag.tsx @@ -1,4 +1,5 @@ import type { Opportunity, Token } from "@angleprotocol/merkl-api"; +import type { Chain } from "@merkl/api"; import { Button, Divider, Dropdown, Group, Hash, Icon, PrimitiveTag, Text } from "dappkit"; import type { ButtonProps } from "dappkit"; import { type Action, actions } from "src/config/actions"; @@ -78,7 +79,7 @@ export default function Tag({ type, value, ...props }: - @@ -110,7 +111,7 @@ export default function Tag({ type, value, ...props }: {action?.description} - @@ -148,7 +149,7 @@ export default function Tag({ type, value, ...props }: {/* {token?.description} */} - @@ -192,11 +193,11 @@ export default function Tag({ type, value, ...props }: {/* {token?.description} */} - - diff --git a/src/components/element/campaign/CampaignLibrary.tsx b/src/components/element/campaign/CampaignLibrary.tsx index dd6b8d70..66dffcd8 100644 --- a/src/components/element/campaign/CampaignLibrary.tsx +++ b/src/components/element/campaign/CampaignLibrary.tsx @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import { Button, Group, Icon, Text } from "dappkit"; import moment from "moment"; import { useMemo, useState } from "react"; diff --git a/src/components/element/campaign/CampaignTableRow.tsx b/src/components/element/campaign/CampaignTableRow.tsx index 4c55cf01..aa7f2033 100644 --- a/src/components/element/campaign/CampaignTableRow.tsx +++ b/src/components/element/campaign/CampaignTableRow.tsx @@ -1,7 +1,5 @@ -import type { Campaign } from "@angleprotocol/merkl-api"; +import type { Campaign } from "@merkl/api"; import { type Component, Group, Hash, Icon, OverrideTheme, Text, Value, mergeClass } from "dappkit"; -import moment from "moment"; -import Tooltip from "packages/dappkit/src/components/primitives/Tooltip"; import { useCallback, useMemo, useState } from "react"; import useCampaign from "src/hooks/resources/useCampaign"; import { formatUnits, parseUnits } from "viem"; @@ -9,6 +7,8 @@ import Chain from "../chain/Chain"; import Token from "../token/Token"; import { CampaignRow } from "./CampaignTable"; import RestrictionsCollumn from "./tableCollumns/RestrictionsCollumn"; +import Tooltip from "packages/dappkit/src/components/primitives/Tooltip"; +import moment from "moment"; export type CampaignTableRowProps = Component<{ campaign: Campaign; diff --git a/src/components/element/chain/Chain.tsx b/src/components/element/chain/Chain.tsx index 988e6056..35201c99 100644 --- a/src/components/element/chain/Chain.tsx +++ b/src/components/element/chain/Chain.tsx @@ -1,4 +1,4 @@ -import type { Chain as ChainType } from "@angleprotocol/merkl-api"; +import type { Chain as ChainType } from "@merkl/api"; import { Button, Dropdown, Icon, type Size } from "packages/dappkit/src"; export type ChainProps = { diff --git a/src/components/element/functions/SearchBar.tsx b/src/components/element/functions/SearchBar.tsx index dfc57c95..3ca8aee1 100644 --- a/src/components/element/functions/SearchBar.tsx +++ b/src/components/element/functions/SearchBar.tsx @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import { Form, useLocation } from "@remix-run/react"; import { Group, Icon, Icons, Input, Modal, Title, useShortcut } from "dappkit"; import { Button } from "dappkit"; diff --git a/src/components/element/opportunity/OpportunityButton.tsx b/src/components/element/opportunity/OpportunityButton.tsx index aa31be12..3789558f 100644 --- a/src/components/element/opportunity/OpportunityButton.tsx +++ b/src/components/element/opportunity/OpportunityButton.tsx @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import { Button, Icons } from "dappkit"; import { blockEvent } from "packages/dappkit/src/utils/event"; import useOpportunity from "src/hooks/resources/useOpportunity"; diff --git a/src/components/element/opportunity/OpportunityFilters.tsx b/src/components/element/opportunity/OpportunityFilters.tsx index eaf92a4a..a7f826c8 100644 --- a/src/components/element/opportunity/OpportunityFilters.tsx +++ b/src/components/element/opportunity/OpportunityFilters.tsx @@ -1,4 +1,4 @@ -import type { Chain } from "@angleprotocol/merkl-api"; +import type { Chain } from "@merkl/api"; import { Form } from "@remix-run/react"; import { Group, Icon, Input, Select } from "dappkit/src"; import { useMemo, useState } from "react"; diff --git a/src/components/element/opportunity/OpportunityLibrary.tsx b/src/components/element/opportunity/OpportunityLibrary.tsx index 92977713..72eef6e6 100644 --- a/src/components/element/opportunity/OpportunityLibrary.tsx +++ b/src/components/element/opportunity/OpportunityLibrary.tsx @@ -1,4 +1,4 @@ -import type { Chain, Opportunity } from "@angleprotocol/merkl-api"; +import type { Chain, Opportunity } from "@merkl/api"; import { Group, type Order } from "dappkit"; import { useMemo } from "react"; import useSearchParamState from "src/hooks/filtering/useSearchParamState"; diff --git a/src/components/element/opportunity/OpportunityTableRow.tsx b/src/components/element/opportunity/OpportunityTableRow.tsx index c113262b..ffe420d4 100644 --- a/src/components/element/opportunity/OpportunityTableRow.tsx +++ b/src/components/element/opportunity/OpportunityTableRow.tsx @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import { Link } from "@remix-run/react"; import { Group } from "dappkit"; import { Icons } from "dappkit"; diff --git a/src/components/element/participate/Participate.tsx b/src/components/element/participate/Participate.tsx index 4f813249..68740daf 100644 --- a/src/components/element/participate/Participate.tsx +++ b/src/components/element/participate/Participate.tsx @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import { Box, Button, Input, Space, Text } from "dappkit"; export type ParticipateProps = { diff --git a/src/components/element/rewards/ClaimRewardsChainTableRow.tsx b/src/components/element/rewards/ClaimRewardsChainTableRow.tsx index f9249b04..a338f532 100644 --- a/src/components/element/rewards/ClaimRewardsChainTableRow.tsx +++ b/src/components/element/rewards/ClaimRewardsChainTableRow.tsx @@ -1,4 +1,4 @@ -import type { Reward } from "@angleprotocol/merkl-api"; +import type { Reward } from "@merkl/api"; import { Icon, Space, Text, Value } from "dappkit"; import TransactionButton from "packages/dappkit/src/components/dapp/TransactionButton"; import Collapsible from "packages/dappkit/src/components/primitives/Collapsible"; diff --git a/src/components/element/rewards/ClaimRewardsLibrary.tsx b/src/components/element/rewards/ClaimRewardsLibrary.tsx index 05e85636..17af919a 100644 --- a/src/components/element/rewards/ClaimRewardsLibrary.tsx +++ b/src/components/element/rewards/ClaimRewardsLibrary.tsx @@ -1,4 +1,4 @@ -import type { Reward } from "@angleprotocol/merkl-api"; +import type { Reward } from "@merkl/api"; import { Group } from "dappkit"; import { ClaimRewardsChainTable } from "./ClaimRewardsChainTable"; import ClaimRewardsChainTableRow from "./ClaimRewardsChainTableRow"; diff --git a/src/components/element/rewards/ClaimRewardsTokenTableRow.tsx b/src/components/element/rewards/ClaimRewardsTokenTableRow.tsx index 76bf9551..0cc8d358 100644 --- a/src/components/element/rewards/ClaimRewardsTokenTableRow.tsx +++ b/src/components/element/rewards/ClaimRewardsTokenTableRow.tsx @@ -1,4 +1,4 @@ -import type { Reward } from "@angleprotocol/merkl-api"; +import type { Reward } from "@merkl/api"; import { Checkbox, Divider, type GetSet, Group, Icon, Space } from "dappkit"; import Collapsible from "packages/dappkit/src/components/primitives/Collapsible"; import { type PropsWithChildren, useMemo, useState } from "react"; diff --git a/src/components/element/token/Token.tsx b/src/components/element/token/Token.tsx index d45e6d89..7bcfc26e 100644 --- a/src/components/element/token/Token.tsx +++ b/src/components/element/token/Token.tsx @@ -1,4 +1,4 @@ -import type { Token as TokenType } from "@angleprotocol/merkl-api"; +import type { Token as TokenType } from "@merkl/api"; import { Button, Dropdown, Icon, Value } from "packages/dappkit/src"; import { useMemo } from "react"; import TokenTooltip from "./TokenTooltip"; diff --git a/src/components/element/token/TokenTooltip.tsx b/src/components/element/token/TokenTooltip.tsx index 397c35ed..b688b087 100644 --- a/src/components/element/token/TokenTooltip.tsx +++ b/src/components/element/token/TokenTooltip.tsx @@ -1,4 +1,4 @@ -import type { Token } from "@angleprotocol/merkl-api"; +import type { Token } from "@merkl/api"; import { Button, Divider, Group, Hash, Icon, Text, Title } from "packages/dappkit/src"; export type TokenTooltipProps = { diff --git a/src/config/actions.ts b/src/config/actions.ts index 1735ae40..772acc21 100644 --- a/src/config/actions.ts +++ b/src/config/actions.ts @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import type { IconProps } from "dappkit"; export const actions = { diff --git a/src/config/status.ts b/src/config/status.ts index 8e771859..1fbb15ca 100644 --- a/src/config/status.ts +++ b/src/config/status.ts @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import type { IconProps } from "dappkit"; export const statuses = { diff --git a/src/entry.server.tsx b/src/entry.server.tsx index 1f5a6f8b..fd0d39ec 100644 --- a/src/entry.server.tsx +++ b/src/entry.server.tsx @@ -24,6 +24,7 @@ export default function handleRequest( // eslint-disable-next-line @typescript-eslint/no-unused-vars _loadContext: AppLoadContext, ) { + return isbot(request.headers.get("user-agent") || "") ? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext) : handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext); @@ -35,6 +36,7 @@ function handleBotRequest( responseHeaders: Headers, remixContext: EntryContext, ) { + return new Promise((resolve, reject) => { let shellRendered = false; const { pipe, abort } = renderToPipeableStream( @@ -83,6 +85,7 @@ function handleBrowserRequest( ) { return new Promise((resolve, reject) => { let shellRendered = false; + const { pipe, abort } = renderToPipeableStream( , { diff --git a/src/hooks/resources/useCampaign.tsx b/src/hooks/resources/useCampaign.tsx index fef6c7b3..dcae2f51 100644 --- a/src/hooks/resources/useCampaign.tsx +++ b/src/hooks/resources/useCampaign.tsx @@ -1,4 +1,4 @@ -import type { Campaign, Opportunity } from "@angleprotocol/merkl-api"; +import type { Campaign, Opportunity } from "@merkl/api"; import { Bar } from "dappkit"; import moment from "moment"; import { Group, Text, Value } from "packages/dappkit/src"; diff --git a/src/hooks/resources/useOpportunity.tsx b/src/hooks/resources/useOpportunity.tsx index 023c28da..ef6f311e 100644 --- a/src/hooks/resources/useOpportunity.tsx +++ b/src/hooks/resources/useOpportunity.tsx @@ -1,4 +1,4 @@ -import type { Opportunity } from "@angleprotocol/merkl-api"; +import type { Opportunity } from "@merkl/api"; import { Icon } from "dappkit"; import { useMemo } from "react"; import type { TagType } from "src/components/element/Tag"; diff --git a/src/hooks/useMerklSearch.tsx b/src/hooks/useMerklSearch.tsx index 75effac1..19e83168 100644 --- a/src/hooks/useMerklSearch.tsx +++ b/src/hooks/useMerklSearch.tsx @@ -1,4 +1,4 @@ -import type { Chain, Opportunity, Protocol, Token } from "@angleprotocol/merkl-api"; +import type { Chain, Opportunity, Protocol, Token } from "@merkl/api"; import { useCallback, useEffect, useMemo, useState } from "react"; import { api } from "src/api/index.client"; diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx index 5992cb86..c6b5b0e7 100644 --- a/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx @@ -1,3 +1,4 @@ +import type { Campaign, Opportunity } from "@merkl/api"; import { Group } from "@ariakit/react"; import { useOutletContext } from "@remix-run/react"; import { Space } from "packages/dappkit/src"; diff --git a/vite.config.ts b/vite.config.ts index 4379b744..d9e4450e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -15,6 +15,7 @@ export default defineConfig({ v3_relativeSplatPath: true, v3_throwAbortReason: true, }, + }), tsconfigPaths(), ecsstatic() From d6b5ee5edda3ce85818809d1d334721faf2c7e9f Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 12:32:38 +0100 Subject: [PATCH 06/11] add: protocols page --- src/api/services/protocol.service.ts | 38 ++++++++++++++++ .../element/protocol/ProtocolFilters.tsx | 44 +++++++++++++++++++ .../element/protocol/ProtocolLibrary.tsx | 34 ++++++++++++++ .../element/protocol/ProtocolTable.tsx | 11 +++++ .../element/protocol/ProtocolTableRow.tsx | 40 +++++++++++++++++ .../_merkl.protocols.(all).(protocols).tsx | 22 ++++++++++ src/routes/_merkl.protocols.(all).tsx | 4 +- 7 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 src/components/element/protocol/ProtocolFilters.tsx create mode 100644 src/components/element/protocol/ProtocolLibrary.tsx create mode 100644 src/components/element/protocol/ProtocolTable.tsx create mode 100644 src/components/element/protocol/ProtocolTableRow.tsx create mode 100644 src/routes/_merkl.protocols.(all).(protocols).tsx diff --git a/src/api/services/protocol.service.ts b/src/api/services/protocol.service.ts index 4e0dd07c..d953f0c0 100644 --- a/src/api/services/protocol.service.ts +++ b/src/api/services/protocol.service.ts @@ -14,9 +14,47 @@ export abstract class ProtocolService { return data; } + /** + * Retrieves protocols query params from page request + * @param request request containing query params such as paginatio + * @param override params for which to override value + * @returns query + */ + static #getQueryFromRequest( + request: Request, + override?: Parameters[0]["query"], + ) { + const page = new URL(request.url).searchParams.get("page"); + const items = new URL(request.url).searchParams.get("items"); + const search = new URL(request.url).searchParams.get("search"); + + const [sort, order] = new URL(request.url).searchParams.get("sort")?.split("-") ?? []; + + const filters = Object.assign( + { items, sort, order, name: search, page }, + override ?? {}, + page !== null && { page: Number(page) - 1 }, + ); + + const query = Object.entries(filters).reduce( + (_query, [key, filter]) => Object.assign(_query, filter == null ? {} : { [key]: filter }), + {}, + ); + + return query; + } + static async get(query: { id: string }): Promise { const protocol = await ProtocolService.#fetch(async () => api.v4.protocols(query).get({ query })); return protocol; } + + static async getManyFromRequest(request: Request): Promise<{protocols: Protocol[], count: number}> { + const query = ProtocolService.#getQueryFromRequest(request); + const protocols = await ProtocolService.#fetch(async () => api.v4.protocols.index.get({ query })); + const count = await ProtocolService.#fetch(async () => api.v4.protocols.count.get({ query })); + + return { protocols, count}; + } } diff --git a/src/components/element/protocol/ProtocolFilters.tsx b/src/components/element/protocol/ProtocolFilters.tsx new file mode 100644 index 00000000..a9913533 --- /dev/null +++ b/src/components/element/protocol/ProtocolFilters.tsx @@ -0,0 +1,44 @@ +import type { Chain } from "@merkl/api"; +import { Form } from "@remix-run/react"; +import { Group, Icon, Input } from "dappkit/src"; +import { useState } from "react"; +import useSearchParamState from "src/hooks/filtering/useSearchParamState"; + +const filters = ["search"] as const; +type ProtocolFilter = (typeof filters)[number]; + +export type OpportunityFilterProps = { + only?: ProtocolFilter[]; + chains?: Chain[]; + exclude?: ProtocolFilter[]; +}; + +export default function ProtocolFilters(_props: OpportunityFilterProps) { + const [search, setSearch] = useSearchParamState( + "search", + v => v, + v => v, + ); + const [innerSearch, setInnerSearch] = useState(search ?? ""); + + function onSearchSubmit() { + if (!innerSearch || innerSearch === search) return; + + setSearch(innerSearch); + } + + return ( + +
+ } + onClick={onSearchSubmit} + placeholder="Search" + /> +
+
+ ); +} diff --git a/src/components/element/protocol/ProtocolLibrary.tsx b/src/components/element/protocol/ProtocolLibrary.tsx new file mode 100644 index 00000000..ec024e6a --- /dev/null +++ b/src/components/element/protocol/ProtocolLibrary.tsx @@ -0,0 +1,34 @@ +import type { Protocol } from "@merkl/api"; +import { Group, type Order } from "dappkit"; +import { useMemo } from "react"; +import useSearchParamState from "src/hooks/filtering/useSearchParamState"; +import ProtocolTableRow from "./ProtocolTableRow"; +import { ProtocolTable } from "./ProtocolTable"; +import OpportunityPagination from "../opportunity/OpportunityPagination"; +import OpportunityFilters from "../opportunity/OpportunityFilters"; +import ProtocolFilters from "./ProtocolFilters"; + +export type ProtocolLibraryProps = { + protocols: Protocol[]; + count?: number; +}; + +export default function ProtocolLibrary({ protocols, count }: ProtocolLibraryProps) { + const rows = useMemo( + () => + protocols?.map(p => ), + [protocols], + ); + + return ( + } + header={ + + + + }> + {rows} + + ); +} diff --git a/src/components/element/protocol/ProtocolTable.tsx b/src/components/element/protocol/ProtocolTable.tsx new file mode 100644 index 00000000..400c39b5 --- /dev/null +++ b/src/components/element/protocol/ProtocolTable.tsx @@ -0,0 +1,11 @@ +import { createTable } from "dappkit"; + +export const [ProtocolTable, ProtocolRow, protocolColumns] = createTable({ + protocol: { + name: "PROTOCOL", + size: "minmax(350px,1fr)", + compact: "1fr", + className: "justify-start", + main: true, + }, +}); diff --git a/src/components/element/protocol/ProtocolTableRow.tsx b/src/components/element/protocol/ProtocolTableRow.tsx new file mode 100644 index 00000000..c3081377 --- /dev/null +++ b/src/components/element/protocol/ProtocolTableRow.tsx @@ -0,0 +1,40 @@ +import type { Protocol } from "@merkl/api"; +import { Link } from "@remix-run/react"; +import { Group, Icon } from "dappkit"; +import type { BoxProps } from "dappkit"; +import { Title } from "dappkit"; +import { mergeClass } from "dappkit"; +import type { TagTypes } from "../Tag"; +import { ProtocolRow } from "./ProtocolTable"; + +export type ProtocolTableRowProps = { + hideTags?: (keyof TagTypes)[]; + protocol: Protocol; +} & BoxProps; + +export default function ProtocolTableRow({ hideTags, protocol, className, ...props }: OpportunityTableRowProps) { + + return ( + + + + + <Icon src={protocol.icon}/> + {protocol.name} + + +
+ } + /> + + ); +} diff --git a/src/routes/_merkl.protocols.(all).(protocols).tsx b/src/routes/_merkl.protocols.(all).(protocols).tsx new file mode 100644 index 00000000..d64cbe0a --- /dev/null +++ b/src/routes/_merkl.protocols.(all).(protocols).tsx @@ -0,0 +1,22 @@ +import type { LoaderFunctionArgs } from "@remix-run/node"; +import { json, useLoaderData } from "@remix-run/react"; +import { Container, Space } from "packages/dappkit/src"; +import { ProtocolService } from "src/api/services/protocol.service"; +import ProtocolLibrary from "src/components/element/protocol/ProtocolLibrary"; + +export async function loader({ params: { id }, request }: LoaderFunctionArgs) { + const { protocols, count } = await ProtocolService.getManyFromRequest(request); + + return json({ protocols, count }); +} + +export default function Index() { + const { protocols, count } = useLoaderData(); + + return ( + + + + + ); +} diff --git a/src/routes/_merkl.protocols.(all).tsx b/src/routes/_merkl.protocols.(all).tsx index 64de4b0e..c4c38afb 100644 --- a/src/routes/_merkl.protocols.(all).tsx +++ b/src/routes/_merkl.protocols.(all).tsx @@ -4,10 +4,10 @@ import Hero from "src/components/composite/Hero"; export default function Index() { return ( + description={"Protocols integrated by Merkl"}> ); From 0a647132835f2e21318755c0ef402c8905386b41 Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 12:46:56 +0100 Subject: [PATCH 07/11] fix: tokens --- src/api/services/token.service.ts | 40 ++++++++++++++- src/components/element/token/TokenFilters.tsx | 44 +++++++++++++++++ src/components/element/token/TokenLibrary.tsx | 32 ++++++++++++ src/components/element/token/TokenTable.tsx | 17 +++++++ .../element/token/TokenTableRow.tsx | 49 +++++++++++++++++++ src/routes/_merkl.tokens.(all).(tokens).tsx | 22 +++++++++ src/routes/_merkl.tokens.(all).tsx | 14 ++++++ 7 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 src/components/element/token/TokenFilters.tsx create mode 100644 src/components/element/token/TokenLibrary.tsx create mode 100644 src/components/element/token/TokenTable.tsx create mode 100644 src/components/element/token/TokenTableRow.tsx create mode 100644 src/routes/_merkl.tokens.(all).(tokens).tsx create mode 100644 src/routes/_merkl.tokens.(all).tsx diff --git a/src/api/services/token.service.ts b/src/api/services/token.service.ts index 22215cab..e489f77a 100644 --- a/src/api/services/token.service.ts +++ b/src/api/services/token.service.ts @@ -4,7 +4,7 @@ import { api } from "../index.server"; export abstract class TokenService { static async #fetch( call: () => Promise, - resource = "Chain", + resource = "Token", ): Promise> { const { data, status } = await call(); @@ -14,6 +14,44 @@ export abstract class TokenService { return data; } + /** + * Retrieves tokens query params from page request + * @param request request containing query params such as pagination + * @param override params for which to override value + * @returns query + */ + static #getQueryFromRequest( + request: Request, + override?: Parameters[0]["query"], + ) { + const page = new URL(request.url).searchParams.get("page"); + const items = new URL(request.url).searchParams.get("items"); + const search = new URL(request.url).searchParams.get("search"); + + const [sort, order] = new URL(request.url).searchParams.get("sort")?.split("-") ?? []; + + const filters = Object.assign( + { items, sort, order, name: search, page }, + override ?? {}, + page !== null && { page: Number(page) - 1 }, + ); + + const query = Object.entries(filters).reduce( + (_query, [key, filter]) => Object.assign(_query, filter == null ? {} : { [key]: filter }), + {}, + ); + + return query; + } + + static async getManyFromRequest(request: Request): Promise<{ tokens: Token[], count: number }> { + const query = TokenService.#getQueryFromRequest(request); + const tokens = await TokenService.#fetch(async () => api.v4.tokens.index.get({ query })); + const count = await TokenService.#fetch(async () => api.v4.tokens.count.get({ query })); + + return { tokens, count}; + } + static async getMany(query: Parameters[0]["query"]): Promise { const tokens = await TokenService.#fetch(async () => api.v4.tokens.index.get({ query })); diff --git a/src/components/element/token/TokenFilters.tsx b/src/components/element/token/TokenFilters.tsx new file mode 100644 index 00000000..a9913533 --- /dev/null +++ b/src/components/element/token/TokenFilters.tsx @@ -0,0 +1,44 @@ +import type { Chain } from "@merkl/api"; +import { Form } from "@remix-run/react"; +import { Group, Icon, Input } from "dappkit/src"; +import { useState } from "react"; +import useSearchParamState from "src/hooks/filtering/useSearchParamState"; + +const filters = ["search"] as const; +type ProtocolFilter = (typeof filters)[number]; + +export type OpportunityFilterProps = { + only?: ProtocolFilter[]; + chains?: Chain[]; + exclude?: ProtocolFilter[]; +}; + +export default function ProtocolFilters(_props: OpportunityFilterProps) { + const [search, setSearch] = useSearchParamState( + "search", + v => v, + v => v, + ); + const [innerSearch, setInnerSearch] = useState(search ?? ""); + + function onSearchSubmit() { + if (!innerSearch || innerSearch === search) return; + + setSearch(innerSearch); + } + + return ( + +
+ } + onClick={onSearchSubmit} + placeholder="Search" + /> +
+
+ ); +} diff --git a/src/components/element/token/TokenLibrary.tsx b/src/components/element/token/TokenLibrary.tsx new file mode 100644 index 00000000..e04f1248 --- /dev/null +++ b/src/components/element/token/TokenLibrary.tsx @@ -0,0 +1,32 @@ +import type { Token } from "@merkl/api"; +import { Group } from "dappkit"; +import { useMemo } from "react"; +import { TokenTable } from "./TokenTable"; +import OpportunityPagination from "../opportunity/OpportunityPagination"; +import ProtocolFilters from "./TokenFilters"; +import TokenTableRow from "./TokenTableRow"; + +export type TokenLibraryProps = { + tokens: Token[]; + count?: number; +}; + +export default function TokenLibrary({ tokens, count }: TokenLibraryProps) { + const rows = useMemo( + () => + tokens?.map(t => ), + [tokens], + ); + + return ( + } + header={ + + + + }> + {rows} + + ); +} diff --git a/src/components/element/token/TokenTable.tsx b/src/components/element/token/TokenTable.tsx new file mode 100644 index 00000000..c79a5dc2 --- /dev/null +++ b/src/components/element/token/TokenTable.tsx @@ -0,0 +1,17 @@ +import { createTable } from "dappkit"; + +export const [TokenTable, TokenRow, tokenColumns] = createTable({ + token: { + name: "TOKEN", + size: "minmax(350px,1fr)", + compact: "1fr", + className: "justify-start", + main: true, + }, + price: { + name: "PRICE", + size: "minmax(min-content,150px)", + compactSize: "minmax(min-content,1fr)", + className: "justify-end", + }, +}); diff --git a/src/components/element/token/TokenTableRow.tsx b/src/components/element/token/TokenTableRow.tsx new file mode 100644 index 00000000..07f7fa26 --- /dev/null +++ b/src/components/element/token/TokenTableRow.tsx @@ -0,0 +1,49 @@ +import type { Protocol, Token } from "@merkl/api"; +import { Link } from "@remix-run/react"; +import { Button, Group, Icon, Value } from "dappkit"; +import type { BoxProps } from "dappkit"; +import { Title } from "dappkit"; +import { mergeClass } from "dappkit"; +import type { TagTypes } from "../Tag"; +import { ProtocolRow, TokenRow } from "./TokenTable"; + +export type TokenTableRowProps = { + hideTags?: (keyof TagTypes)[]; + token: Token; +} & BoxProps; + +export default function TokenTableRow({ hideTags, token, className, ...props }: TokenTableRowProps) { + + return ( + + + + + <Icon src={token.icon}/> + {token.name} + + +
+ } + priceColumn={ + + + + } + /> + + ); +} diff --git a/src/routes/_merkl.tokens.(all).(tokens).tsx b/src/routes/_merkl.tokens.(all).(tokens).tsx new file mode 100644 index 00000000..1ca0d62f --- /dev/null +++ b/src/routes/_merkl.tokens.(all).(tokens).tsx @@ -0,0 +1,22 @@ +import type { LoaderFunctionArgs } from "@remix-run/node"; +import { json, useLoaderData } from "@remix-run/react"; +import { Container, Space } from "packages/dappkit/src"; +import { TokenService } from "src/api/services/token.service"; +import TokenLibrary from "src/components/element/token/TokenLibrary"; + +export async function loader({ params: { id }, request }: LoaderFunctionArgs) { + const { tokens, count } = await TokenService.getManyFromRequest(request); + + return json({ tokens, count }); +} + +export default function Index() { + const { tokens, count } = useLoaderData(); + + return ( + + + + + ); +} diff --git a/src/routes/_merkl.tokens.(all).tsx b/src/routes/_merkl.tokens.(all).tsx new file mode 100644 index 00000000..e12d9d27 --- /dev/null +++ b/src/routes/_merkl.tokens.(all).tsx @@ -0,0 +1,14 @@ +import { Outlet } from "@remix-run/react"; +import Hero from "src/components/composite/Hero"; + +export default function Index() { + return ( + + + + ); +} From f535e153565255673d8967b1d674ac60b43a787a Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 12:51:30 +0100 Subject: [PATCH 08/11] fix: files --- src/api/services/protocol.service.ts | 52 +++++++++---------- src/api/services/token.service.ts | 8 +-- .../element/protocol/ProtocolLibrary.tsx | 14 ++--- .../element/protocol/ProtocolTableRow.tsx | 3 +- src/components/element/token/TokenLibrary.tsx | 5 +- .../element/token/TokenTableRow.tsx | 7 ++- src/entry.server.tsx | 2 - ...ortunities.$chain.$type.$id.(overview).tsx | 2 - .../_merkl.protocols.(all).(protocols).tsx | 2 +- src/routes/_merkl.tokens.(all).(tokens).tsx | 2 +- 10 files changed, 42 insertions(+), 55 deletions(-) diff --git a/src/api/services/protocol.service.ts b/src/api/services/protocol.service.ts index d953f0c0..e3446108 100644 --- a/src/api/services/protocol.service.ts +++ b/src/api/services/protocol.service.ts @@ -14,35 +14,35 @@ export abstract class ProtocolService { return data; } - /** + /** * Retrieves protocols query params from page request * @param request request containing query params such as paginatio * @param override params for which to override value * @returns query */ - static #getQueryFromRequest( - request: Request, - override?: Parameters[0]["query"], - ) { - const page = new URL(request.url).searchParams.get("page"); - const items = new URL(request.url).searchParams.get("items"); - const search = new URL(request.url).searchParams.get("search"); - - const [sort, order] = new URL(request.url).searchParams.get("sort")?.split("-") ?? []; - - const filters = Object.assign( - { items, sort, order, name: search, page }, - override ?? {}, - page !== null && { page: Number(page) - 1 }, - ); - - const query = Object.entries(filters).reduce( - (_query, [key, filter]) => Object.assign(_query, filter == null ? {} : { [key]: filter }), - {}, - ); - - return query; - } + static #getQueryFromRequest( + request: Request, + override?: Parameters[0]["query"], + ) { + const page = new URL(request.url).searchParams.get("page"); + const items = new URL(request.url).searchParams.get("items"); + const search = new URL(request.url).searchParams.get("search"); + + const [sort, order] = new URL(request.url).searchParams.get("sort")?.split("-") ?? []; + + const filters = Object.assign( + { items, sort, order, name: search, page }, + override ?? {}, + page !== null && { page: Number(page) - 1 }, + ); + + const query = Object.entries(filters).reduce( + (_query, [key, filter]) => Object.assign(_query, filter == null ? {} : { [key]: filter }), + {}, + ); + + return query; + } static async get(query: { id: string }): Promise { const protocol = await ProtocolService.#fetch(async () => api.v4.protocols(query).get({ query })); @@ -50,11 +50,11 @@ export abstract class ProtocolService { return protocol; } - static async getManyFromRequest(request: Request): Promise<{protocols: Protocol[], count: number}> { + static async getManyFromRequest(request: Request): Promise<{ protocols: Protocol[]; count: number }> { const query = ProtocolService.#getQueryFromRequest(request); const protocols = await ProtocolService.#fetch(async () => api.v4.protocols.index.get({ query })); const count = await ProtocolService.#fetch(async () => api.v4.protocols.count.get({ query })); - return { protocols, count}; + return { protocols, count }; } } diff --git a/src/api/services/token.service.ts b/src/api/services/token.service.ts index e489f77a..2f6767d7 100644 --- a/src/api/services/token.service.ts +++ b/src/api/services/token.service.ts @@ -14,13 +14,13 @@ export abstract class TokenService { return data; } - /** + /** * Retrieves tokens query params from page request * @param request request containing query params such as pagination * @param override params for which to override value * @returns query */ - static #getQueryFromRequest( + static #getQueryFromRequest( request: Request, override?: Parameters[0]["query"], ) { @@ -44,12 +44,12 @@ export abstract class TokenService { return query; } - static async getManyFromRequest(request: Request): Promise<{ tokens: Token[], count: number }> { + static async getManyFromRequest(request: Request): Promise<{ tokens: Token[]; count: number }> { const query = TokenService.#getQueryFromRequest(request); const tokens = await TokenService.#fetch(async () => api.v4.tokens.index.get({ query })); const count = await TokenService.#fetch(async () => api.v4.tokens.count.get({ query })); - return { tokens, count}; + return { tokens, count }; } static async getMany(query: Parameters[0]["query"]): Promise { diff --git a/src/components/element/protocol/ProtocolLibrary.tsx b/src/components/element/protocol/ProtocolLibrary.tsx index ec024e6a..1ce9b1eb 100644 --- a/src/components/element/protocol/ProtocolLibrary.tsx +++ b/src/components/element/protocol/ProtocolLibrary.tsx @@ -1,12 +1,10 @@ import type { Protocol } from "@merkl/api"; -import { Group, type Order } from "dappkit"; +import { Group } from "dappkit"; import { useMemo } from "react"; -import useSearchParamState from "src/hooks/filtering/useSearchParamState"; -import ProtocolTableRow from "./ProtocolTableRow"; -import { ProtocolTable } from "./ProtocolTable"; import OpportunityPagination from "../opportunity/OpportunityPagination"; -import OpportunityFilters from "../opportunity/OpportunityFilters"; import ProtocolFilters from "./ProtocolFilters"; +import { ProtocolTable } from "./ProtocolTable"; +import ProtocolTableRow from "./ProtocolTableRow"; export type ProtocolLibraryProps = { protocols: Protocol[]; @@ -14,11 +12,7 @@ export type ProtocolLibraryProps = { }; export default function ProtocolLibrary({ protocols, count }: ProtocolLibraryProps) { - const rows = useMemo( - () => - protocols?.map(p => ), - [protocols], - ); + const rows = useMemo(() => protocols?.map(p => ), [protocols]); return ( - + {protocol.name}
diff --git a/src/components/element/token/TokenLibrary.tsx b/src/components/element/token/TokenLibrary.tsx index e04f1248..33b760fb 100644 --- a/src/components/element/token/TokenLibrary.tsx +++ b/src/components/element/token/TokenLibrary.tsx @@ -1,9 +1,9 @@ import type { Token } from "@merkl/api"; import { Group } from "dappkit"; import { useMemo } from "react"; -import { TokenTable } from "./TokenTable"; import OpportunityPagination from "../opportunity/OpportunityPagination"; import ProtocolFilters from "./TokenFilters"; +import { TokenTable } from "./TokenTable"; import TokenTableRow from "./TokenTableRow"; export type TokenLibraryProps = { @@ -13,8 +13,7 @@ export type TokenLibraryProps = { export default function TokenLibrary({ tokens, count }: TokenLibraryProps) { const rows = useMemo( - () => - tokens?.map(t => ), + () => tokens?.map(t => ), [tokens], ); diff --git a/src/components/element/token/TokenTableRow.tsx b/src/components/element/token/TokenTableRow.tsx index 07f7fa26..45f2ed5e 100644 --- a/src/components/element/token/TokenTableRow.tsx +++ b/src/components/element/token/TokenTableRow.tsx @@ -1,11 +1,11 @@ -import type { Protocol, Token } from "@merkl/api"; +import type { Token } from "@merkl/api"; import { Link } from "@remix-run/react"; import { Button, Group, Icon, Value } from "dappkit"; import type { BoxProps } from "dappkit"; import { Title } from "dappkit"; import { mergeClass } from "dappkit"; import type { TagTypes } from "../Tag"; -import { ProtocolRow, TokenRow } from "./TokenTable"; +import { TokenRow } from "./TokenTable"; export type TokenTableRowProps = { hideTags?: (keyof TagTypes)[]; @@ -13,7 +13,6 @@ export type TokenTableRowProps = { } & BoxProps; export default function TokenTableRow({ hideTags, token, className, ...props }: TokenTableRowProps) { - return ( - + {token.name} diff --git a/src/entry.server.tsx b/src/entry.server.tsx index fd0d39ec..e343283c 100644 --- a/src/entry.server.tsx +++ b/src/entry.server.tsx @@ -24,7 +24,6 @@ export default function handleRequest( // eslint-disable-next-line @typescript-eslint/no-unused-vars _loadContext: AppLoadContext, ) { - return isbot(request.headers.get("user-agent") || "") ? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext) : handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext); @@ -36,7 +35,6 @@ function handleBotRequest( responseHeaders: Headers, remixContext: EntryContext, ) { - return new Promise((resolve, reject) => { let shellRendered = false; const { pipe, abort } = renderToPipeableStream( diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx index c6b5b0e7..c9b07bce 100644 --- a/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx @@ -1,6 +1,4 @@ -import type { Campaign, Opportunity } from "@merkl/api"; import { Group } from "@ariakit/react"; -import { useOutletContext } from "@remix-run/react"; import { Space } from "packages/dappkit/src"; import CampaignLibrary from "src/components/element/campaign/CampaignLibrary"; import { ErrorContent } from "src/components/layout/ErrorContent"; diff --git a/src/routes/_merkl.protocols.(all).(protocols).tsx b/src/routes/_merkl.protocols.(all).(protocols).tsx index d64cbe0a..694977ea 100644 --- a/src/routes/_merkl.protocols.(all).(protocols).tsx +++ b/src/routes/_merkl.protocols.(all).(protocols).tsx @@ -15,7 +15,7 @@ export default function Index() { return ( - + ); diff --git a/src/routes/_merkl.tokens.(all).(tokens).tsx b/src/routes/_merkl.tokens.(all).(tokens).tsx index 1ca0d62f..a18e00ce 100644 --- a/src/routes/_merkl.tokens.(all).(tokens).tsx +++ b/src/routes/_merkl.tokens.(all).(tokens).tsx @@ -15,7 +15,7 @@ export default function Index() { return ( - + ); From f56246d8c2c29fab6fa454a3db6d7207f3e19715 Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 13:00:57 +0100 Subject: [PATCH 09/11] fix: layout --- merkl.config.ts | 7 ------- src/components/layout/Header.tsx | 3 +-- .../_merkl.opportunities.$chain.$type.$id.(overview).tsx | 7 ++++--- ..._merkl.opportunities.$chain.$type.$id.leaderboard.tsx | 9 +++++---- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/merkl.config.ts b/merkl.config.ts index 1032b023..2b4cb969 100644 --- a/merkl.config.ts +++ b/merkl.config.ts @@ -150,12 +150,5 @@ export default createConfig({ }, }), ], -<<<<<<< HEAD - transports: { - [zksync.id]: http(), - [optimism.id]: http(), - }, -======= ->>>>>>> 6e48802 (restore: tabs) }, }); diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index d9748950..4898ce24 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -2,7 +2,6 @@ import { Button, Container, Dropdown, Group, Icon, WalletButton, useTheme } from import { Image } from "dappkit"; import customerDarkLogo from "src/customer/assets/images/customer-dark-logo.svg"; import customerLogo from "src/customer/assets/images/customer-logo.svg"; -import SearchBar from "../element/functions/SearchBar"; import { motion } from "framer-motion"; import config from "merkl.config"; @@ -10,7 +9,6 @@ import { useWalletContext } from "packages/dappkit/src/context/Wallet.context"; import { useMemo, useState } from "react"; import { useMediaQuery } from "react-responsive"; import SCREENS from "../../../packages/dappkit/src/constants/SCREENS.json"; -import SwitchMode from "../element/SwitchMode"; import { LayerMenu } from "./LayerMenu"; const container = { @@ -38,6 +36,7 @@ export default function Header() { const mdScreens = useMediaQuery({ maxWidth: SCREENS.lg }); const smScreens = useMediaQuery({ maxWidth: SCREENS.md }); + const canSwitchModes = useMemo(() => !(!config.modes || config.modes?.length === 1), []); const routes = useMemo(() => { const { homepage, ...rest } = config.routes; diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx index c9b07bce..244def7d 100644 --- a/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx @@ -1,14 +1,15 @@ import { Group } from "@ariakit/react"; -import { Space } from "packages/dappkit/src"; +import { Container, Space } from "packages/dappkit/src"; import CampaignLibrary from "src/components/element/campaign/CampaignLibrary"; import { ErrorContent } from "src/components/layout/ErrorContent"; import type { OutletContextOpportunity } from "./_merkl.opportunity.$chain.$type.$id"; +import { useOutletContext } from "@remix-run/react"; export default function Index() { const { opportunity } = useOutletContext(); return ( - + {/* */} @@ -16,7 +17,7 @@ export default function Index() { */} {/* */} - + ); } diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx index b4419141..eddbe1e9 100644 --- a/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx @@ -1,6 +1,6 @@ import type { LoaderFunctionArgs } from "@remix-run/node"; import { json, useLoaderData } from "@remix-run/react"; -import { Group, Text } from "packages/dappkit/src"; +import { Container, Group, Space, Text } from "packages/dappkit/src"; import Tooltip from "packages/dappkit/src/components/primitives/Tooltip"; import LeaderboardLibrary from "src/components/element/leaderboard/LeaderboardLibrary"; // import { ChainService } from "src/api/services/chain.service"; @@ -51,7 +51,8 @@ export default function Index() { const { leaderboard } = useLoaderData(); return ( - <> + + @@ -67,8 +68,8 @@ export default function Index() { 400k - + - + ); } From 4e32ae49dc0b4bd2eeca2c3a923413a74f3471db Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 13:02:03 +0100 Subject: [PATCH 10/11] fix: lint --- src/api/services/campaign.service.ts | 13 ------------- src/api/services/opportunity.service.ts | 2 +- .../element/campaign/CampaignTableRow.tsx | 4 ++-- ...kl.opportunities.$chain.$type.$id.(overview).tsx | 3 +-- ...l.opportunities.$chain.$type.$id.leaderboard.tsx | 4 ++-- .../_merkl.opportunities.$chain.$type.$id.tsx | 2 +- 6 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/api/services/campaign.service.ts b/src/api/services/campaign.service.ts index 21539473..00604e36 100644 --- a/src/api/services/campaign.service.ts +++ b/src/api/services/campaign.service.ts @@ -1,4 +1,3 @@ -<<<<<<< HEAD import type { Campaign } from "@angleprotocol/merkl-api"; import { api } from "../index.server"; @@ -52,16 +51,4 @@ export abstract class CampaignService { static async getByID(Id: string): Promise { return null; } -======= -class CampaignService { - // // ------ Fetch all campaigns - // async get(): Promise { - // const { data } = await api.v4.campaigns.index.get({ query: {} }); - // return data; - // } - // // ------ Fetch a campaign by ID - // async getByID(Id: string): Promise { - // return "To implements"; - // } ->>>>>>> 19f3164 (fix: loaders) } diff --git a/src/api/services/opportunity.service.ts b/src/api/services/opportunity.service.ts index abb28a43..ae4ca252 100644 --- a/src/api/services/opportunity.service.ts +++ b/src/api/services/opportunity.service.ts @@ -1,4 +1,4 @@ -import type { Campaign, Opportunity } from "@merkl/api"; +import type { Opportunity } from "@merkl/api"; import config from "merkl.config"; import { api } from "../index.server"; diff --git a/src/components/element/campaign/CampaignTableRow.tsx b/src/components/element/campaign/CampaignTableRow.tsx index aa7f2033..e9c19049 100644 --- a/src/components/element/campaign/CampaignTableRow.tsx +++ b/src/components/element/campaign/CampaignTableRow.tsx @@ -1,5 +1,7 @@ import type { Campaign } from "@merkl/api"; import { type Component, Group, Hash, Icon, OverrideTheme, Text, Value, mergeClass } from "dappkit"; +import moment from "moment"; +import Tooltip from "packages/dappkit/src/components/primitives/Tooltip"; import { useCallback, useMemo, useState } from "react"; import useCampaign from "src/hooks/resources/useCampaign"; import { formatUnits, parseUnits } from "viem"; @@ -7,8 +9,6 @@ import Chain from "../chain/Chain"; import Token from "../token/Token"; import { CampaignRow } from "./CampaignTable"; import RestrictionsCollumn from "./tableCollumns/RestrictionsCollumn"; -import Tooltip from "packages/dappkit/src/components/primitives/Tooltip"; -import moment from "moment"; export type CampaignTableRowProps = Component<{ campaign: Campaign; diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx index 244def7d..0b04c6b9 100644 --- a/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.(overview).tsx @@ -1,9 +1,8 @@ -import { Group } from "@ariakit/react"; +import { useOutletContext } from "@remix-run/react"; import { Container, Space } from "packages/dappkit/src"; import CampaignLibrary from "src/components/element/campaign/CampaignLibrary"; import { ErrorContent } from "src/components/layout/ErrorContent"; import type { OutletContextOpportunity } from "./_merkl.opportunity.$chain.$type.$id"; -import { useOutletContext } from "@remix-run/react"; export default function Index() { const { opportunity } = useOutletContext(); diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx index eddbe1e9..01d28af1 100644 --- a/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard.tsx @@ -52,7 +52,7 @@ export default function Index() { return ( - + @@ -68,7 +68,7 @@ export default function Index() { 400k - + ); diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.tsx index fad4c1aa..06021a03 100644 --- a/src/routes/_merkl.opportunities.$chain.$type.$id.tsx +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.tsx @@ -42,7 +42,7 @@ export default function Index() { const spaced = opportunity?.name.split(" "); return spaced - .map((str) => { + .map(str => { const key = str + crypto.randomUUID(); if (!str.match(/[\p{Letter}\p{Mark}]+/gu)) return [ From 3a66bd335b9d11d95ac525d4f770109a279630ca Mon Sep 17 00:00:00 2001 From: sheykei Date: Tue, 3 Dec 2024 13:07:43 +0100 Subject: [PATCH 11/11] fix: lint --- src/components/composite/Hero.tsx | 5 +- .../leaderboard/LeaderboardLibrary.tsx | 2 +- .../_merkl.opportunities.$chain.$type.$id.tsx | 2 - .../_merkl.opportunity.$chain.$type.$id.tsx | 89 +++++++++++++++++++ 4 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/routes/_merkl.opportunity.$chain.$type.$id.tsx diff --git a/src/components/composite/Hero.tsx b/src/components/composite/Hero.tsx index aeeb677b..d3d89753 100644 --- a/src/components/composite/Hero.tsx +++ b/src/components/composite/Hero.tsx @@ -123,7 +123,10 @@ export default function Hero({ navigation, breadcrumbs, icons, title, descriptio {!!tabs && ( {tabs?.map(tab => ( - ))} diff --git a/src/components/element/leaderboard/LeaderboardLibrary.tsx b/src/components/element/leaderboard/LeaderboardLibrary.tsx index 6c6ddd23..5a26b522 100644 --- a/src/components/element/leaderboard/LeaderboardLibrary.tsx +++ b/src/components/element/leaderboard/LeaderboardLibrary.tsx @@ -1,6 +1,6 @@ import { Text } from "dappkit"; import { useMemo } from "react"; -import type { DummyLeaderboard } from "src/routes/_merkl.opportunity.$chain.$type.$id.leaderboard"; +import type { DummyLeaderboard } from "src/routes/_merkl.opportunities.$chain.$type.$id.leaderboard"; import { LeaderboardTable } from "./LeaderboardTable"; import LeaderboardTableRow from "./LeaderboardTableRow"; diff --git a/src/routes/_merkl.opportunities.$chain.$type.$id.tsx b/src/routes/_merkl.opportunities.$chain.$type.$id.tsx index 06021a03..67578d3b 100644 --- a/src/routes/_merkl.opportunities.$chain.$type.$id.tsx +++ b/src/routes/_merkl.opportunities.$chain.$type.$id.tsx @@ -20,8 +20,6 @@ export async function loader({ params: { id, type, chain: chainId } }: LoaderFun identifier: id, }); - if (!opportunity) throw "DAZZ"; - return json({ opportunity }); } diff --git a/src/routes/_merkl.opportunity.$chain.$type.$id.tsx b/src/routes/_merkl.opportunity.$chain.$type.$id.tsx new file mode 100644 index 00000000..67578d3b --- /dev/null +++ b/src/routes/_merkl.opportunity.$chain.$type.$id.tsx @@ -0,0 +1,89 @@ +import type { Opportunity } from "@angleprotocol/merkl-api"; +import { type LoaderFunctionArgs, type MetaFunction, json } from "@remix-run/node"; +import { Meta, Outlet, useLoaderData } from "@remix-run/react"; +import { useMemo } from "react"; +import { ChainService } from "src/api/services/chain.service"; +import { OpportunityService } from "src/api/services/opportunity.service"; +import Hero from "src/components/composite/Hero"; +import Tag from "src/components/element/Tag"; +import { ErrorHeading } from "src/components/layout/ErrorHeading"; +import useOpportunity from "src/hooks/resources/useOpportunity"; + +export async function loader({ params: { id, type, chain: chainId } }: LoaderFunctionArgs) { + if (!chainId || !id || !type) throw ""; + + const chain = await ChainService.get({ search: chainId }); + + const opportunity = await OpportunityService.getCampaignsByParams({ + chainId: chain.id, + type: type, + identifier: id, + }); + + return json({ opportunity }); +} + +export const meta: MetaFunction = ({ data, error }) => { + if (error) return [{ title: error }]; + return [{ title: `${data?.name} on Merkl` }]; +}; + +export type OutletContextOpportunity = { + opportunity: Opportunity; +}; + +export default function Index() { + const { opportunity } = useLoaderData(); + const { tags, description, link } = useOpportunity(opportunity); + + const styleName = useMemo(() => { + const spaced = opportunity?.name.split(" "); + + return spaced + .map(str => { + const key = str + crypto.randomUUID(); + if (!str.match(/[\p{Letter}\p{Mark}]+/gu)) + return [ + + {str} + , + ]; + if (str.includes("-")) + return str + .split("-") + .flatMap((s, i, arr) => [s, i !== arr.length - 1 && -]); + if (str.includes("/")) + return str + .split("/") + .flatMap((s, i, arr) => [s, i !== arr.length - 1 && /]); + return [{str}]; + }) + .flatMap((str, index, arr) => [str, index !== arr.length - 1 && " "]); + }, [opportunity]); + + return ( + <> + + ({ src: t.icon }))} + breadcrumbs={[ + { link: "/", name: "Opportunities" }, + { link: "/", name: opportunity.name }, + ]} + title={styleName} + description={description} + tabs={[ + { label: "Overview", link }, + { label: "Leaderboard", link: `${link}/leaderboard` }, + ]} + tags={tags.map(tag => )} + opportunity={opportunity}> + + + + ); +} + +export function ErrorBoundary() { + return ; +}