Skip to content
This repository has been archived by the owner on Jun 19, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into kien/INFRA-303
Browse files Browse the repository at this point in the history
  • Loading branch information
kien-ngo authored Jun 14, 2024
2 parents f5734f1 + 4112dcf commit 3f089e4
Show file tree
Hide file tree
Showing 112 changed files with 1,089 additions and 630 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ module.exports = {
"inclusive-language/use-inclusive-words": "error",
// turn off deprecated things?
"react/react-in-jsx-scope": "off",
"no-restricted-syntax": [
"error",
{
selector: "CallExpression[callee.name='useEffect']",
message:
'Are you *sure* you need to use "useEffect" here? If you loading any async function prefer using "useQuery".',
},
],
"no-restricted-imports": [
"error",
{
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@
"@tanstack/react-query-persist-client": "^4.36.1",
"@tanstack/react-table": "^8.17.3",
"@thirdweb-dev/chains": "0.1.117",
"@thirdweb-dev/react": "4.7.0",
"@thirdweb-dev/react-core": "4.7.0",
"@thirdweb-dev/sdk": "4.0.93",
"@thirdweb-dev/react": "4.8.0",
"@thirdweb-dev/react-core": "4.8.0",
"@thirdweb-dev/sdk": "4.0.94",
"@thirdweb-dev/service-utils": "0.4.31",
"@thirdweb-dev/storage": "2.0.15",
"@thirdweb-dev/wallets": "2.5.33",
Expand Down
320 changes: 297 additions & 23 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions redirects.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ function redirects() {
destination: "/dashboard/settings/api-keys",
permanent: false,
},
{
source: "/dashboard/settings",
destination: "/dashboard/settings/api-keys",
permanent: false,
},
{
source: "/dashboard/connect",
destination: "/dashboard/connect/playground",
permanent: false,
},
{
source: "/dashboard/wallet",
destination: "/dashboard/connect/playground",
Expand Down
4 changes: 2 additions & 2 deletions src/@/components/ui/ScrollShadow/ScrollShadow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"use client";

import { cn } from "@/lib/utils";
import { useEffect, useRef } from "react";
import { useLayoutEffect, useRef } from "react";
import styles from "./ScrollShadow.module.css";

export function ScrollShadow(props: {
Expand All @@ -17,7 +17,7 @@ export function ScrollShadow(props: {
const shadowRightEl = useRef<HTMLDivElement>(null);
const wrapperEl = useRef<HTMLDivElement>(null);

useEffect(() => {
useLayoutEffect(() => {
const content = scrollableEl.current;
const shadowTop = shadowTopEl.current;
const shadowBottom = shadowBottomEl.current;
Expand Down
4 changes: 2 additions & 2 deletions src/@/components/ui/tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, useState, useCallback, useEffect } from "react";
import { useRef, useState, useCallback, useLayoutEffect } from "react";
import { cn } from "../../lib/utils";
import { ScrollShadow } from "./ScrollShadow/ScrollShadow";
import { Button } from "./button";
Expand All @@ -23,7 +23,7 @@ export function TabLinks(props: {
setActiveTabEl(el);
}, []);

useEffect(() => {
useLayoutEffect(() => {
if (activeTabEl && containerRef.current && lineRef.current) {
const containerRect = containerRef.current.getBoundingClientRect();
const lineEl = lineRef.current;
Expand Down
2 changes: 2 additions & 0 deletions src/@3rdweb-sdk/react/hooks/useActiveChainId.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export function EVMContractInfoProvider(props: {
});
}, []);

// no better way right now - this whole file is going away with RSC migration
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
_setValue(props.value);
}, [_setValue, props.value]);
Expand Down
3 changes: 2 additions & 1 deletion src/@3rdweb-sdk/react/hooks/useApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1085,8 +1085,9 @@ export function useApiAuthToken() {
const [paymentsSellerId, setPaymentsSellerId] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
// not using a query because we don't want to store this in any cache

// not using a query because we don't want to store this in any cache
// eslint-disable-next-line no-restricted-syntax
useEffect(() => {
let mounted = true;
setError(null);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use client";

import { Button } from "@/components/ui/button";
import { useAddress, useChainId, useSwitchChain } from "@thirdweb-dev/react";
import { ToolTipLabel } from "@/components/ui/tooltip";
import { useMutation } from "@tanstack/react-query";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { useDebounce } from "use-debounce";

type AddChainToWalletProps = {
chainId: number;
};

export const AddChainToWallet: React.FC<AddChainToWalletProps> = (props) => {
const address = useAddress();
const switchChain = useSwitchChain();
const activeWalletChainId = useChainId();

const switchChainMutation = useMutation({
mutationFn: async () => {
await switchChain(props.chainId);
},
});

// debounce the loading state to prevent flickering
const [debouncedLoading] = useDebounce(switchChainMutation.isLoading, 50);

const buttonContent = (
<Button
disabled={
!address || debouncedLoading || activeWalletChainId === props.chainId
}
className="w-full md:min-w-40"
onClick={() => switchChainMutation.mutate()}
>
{debouncedLoading && <Spinner />}
<span>Add to wallet</span>
</Button>
);

if (address && activeWalletChainId !== props.chainId) {
return buttonContent;
}

return (
<ToolTipLabel
label={
activeWalletChainId === props.chainId
? "You are already connected to this chain"
: "Connect your wallet first"
}
>
<div className="cursor-not-allowed">{buttonContent}</div>
</ToolTipLabel>
);
};
118 changes: 71 additions & 47 deletions src/app/(dashboard)/(chain)/[chain_id]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { ChainIcon } from "../components/server/chain-icon";
import { Badge } from "@/components/ui/badge";
import { getChain, getChainMetadata } from "../utils";
import { ChainCTA } from "./components/server/cta-card";
import { Button } from "@/components/ui/button";
import { AddChainToWallet } from "./components/client/add-chain-to-wallet";

export async function generateMetadata(
{ params }: { params: { chain_id: string } },
Expand Down Expand Up @@ -66,6 +68,8 @@ export default async function ChainPageLayout({
redirect(chain.slug);
}
const chainMetadata = await getChainMetadata(chain.chainId);
// true if we *have* chainMetadata for the chain
const isVerified = !!chainMetadata;
const isDeprecated = chain.status === "deprecated";

return (
Expand All @@ -89,9 +93,7 @@ export default async function ChainPageLayout({
<header
className={cn(
"py-6 md:py-8 border-b relative overflow-hidden",
!chainMetadata?.gasSponsored &&
!chainMetadata?.verified &&
"md:pb-2",
!chainMetadata?.gasSponsored && !isVerified && "md:pb-2",
chainMetadata?.headerImgUrl && "md:py-10",
)}
>
Expand All @@ -111,56 +113,78 @@ export default async function ChainPageLayout({
</div>

{/* end header shaningans */}
<div className="container px-4 flex flex-col md:flex-row justify-between md:items-center">
<div className="flex flex-col gap-2 md:gap-6">
<Link
href="/chainlist"
className="inline-flex items-center gap-1 text-foreground hover:underline mt-4"
>
<ArrowLeftIcon className="size-5" />
Chainlist
</Link>

<div className="container px-4 flex flex-col gap-2 md:gap-6">
<Link
href="/chainlist"
className="inline-flex items-center gap-1 text-foreground hover:underline mt-4"
>
<ArrowLeftIcon className="size-5" />
Chainlist
</Link>

<div className="flex gap-3 md:gap-5 items-center">
{chain.icon?.url && (
<ChainIcon
iconUrl={chain.icon.url}
className="size-16 md:size-20 bg-secondary p-2 border-2 rounded-full"
/>
)}
<div className="flex gap-3 md:gap-5 items-center">
{chain.icon?.url && (
<ChainIcon
iconUrl={chain.icon.url}
className="size-16 md:size-20 bg-secondary p-2 border-2 rounded-full"
/>
)}

{/* Chain Name */}
{/* Chain Name */}

<h1
className={cn(
"font-semibold tracking-tighter text-4xl md:text-6xl",
)}
>
{chain.name}
</h1>
<StarButton chainId={chain.chainId} variant="secondary" />
</div>

<h1
className={cn(
"font-semibold tracking-tighter text-4xl md:text-6xl",
<div className="flex flex-row gap-2 md:gap-4 items-center h-8 mb-4 md:mb-6">
{isVerified && (
<Badge
variant="secondary"
className="text-accent-foreground pointer-events-none flex flex-row items-center h-full gap-1.5 border border-border"
>
<VerifiedIcon className="size-5" />
<span className="font-bold text-xs uppercase">
verified
</span>
</Badge>
)}
>
{chain.name}
</h1>
<StarButton chainId={chain.chainId} variant="secondary" />
{chainMetadata?.gasSponsored && (
<Badge
variant="secondary"
className="text-accent-foreground pointer-events-none flex flex-row items-center h-full gap-1.5 border border-border"
>
<TicketCheckIcon className="size-5" />
<span className="font-bold text-xs uppercase">
gas sponsored
</span>
</Badge>
)}
</div>
</div>

<div className="flex flex-row gap-2 md:gap-4 items-center h-8 mb-4 md:mb-6">
{chainMetadata?.verified && (
<Badge
variant="secondary"
className="text-accent-foreground pointer-events-none flex flex-row items-center h-full gap-1.5 border border-border"
>
<VerifiedIcon className="size-5" />
<span className="font-bold text-xs uppercase">verified</span>
</Badge>
)}
{chainMetadata?.gasSponsored && (
<Badge
variant="secondary"
className="text-accent-foreground pointer-events-none flex flex-row items-center h-full gap-1.5 border border-border"
<div className="flex flex-row md:flex-col gap-4">
<AddChainToWallet chainId={chain.chainId} />
{isVerified ? null : (
<Button
className="w-full md:min-w-40"
variant="outline"
asChild
>
<TicketCheckIcon className="size-5" />
<span className="font-bold text-xs uppercase">
gas sponsored
</span>
</Badge>
<Link
className="gap-2"
href="https://share.hsforms.com/1o01TyfsZRAao2eCrzuXSVgea58c"
target="_blank"
>
<span>Claim this chain</span>
<ExternalLinkIcon className="size-3" />
</Link>
</Button>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,20 +319,10 @@ function isServiceActive(searchParams: URLSearchParams, service: string) {
}

function toggleService(searchParams: URLSearchParams, service: string) {
if (!searchParams.has("service")) {
// default case is that all services are selected so we have to now add all *other* services except for ours
const allServices = products.map((product) => product.id);
const otherServices = allServices.filter((s) => s !== service);
for (const otherService of otherServices) {
searchParams.append("service", otherService);
}
if (searchParams.getAll("service").includes(service)) {
searchParams.delete("service", service);
} else {
// we have services selected, so we need to toggle our service
if (searchParams.getAll("service").includes(service)) {
searchParams.delete("service", service);
} else {
searchParams.append("service", service);
}
searchParams.append("service", service);
}
}

Expand Down
20 changes: 9 additions & 11 deletions src/app/(dashboard)/(chain)/chainlist/components/client/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { SearchIcon, XCircleIcon } from "lucide-react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useRef } from "react";
import { useRef } from "react";
import { useDebouncedCallback } from "use-debounce";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
Expand All @@ -21,16 +21,14 @@ export const SearchInput: React.FC = () => {

const inputRef = useRef<HTMLInputElement>(null);

// sync the input state back with the searchParams on updates
useEffect(() => {
if (
inputRef.current &&
inputRef.current.value &&
!searchParams?.get("query")
) {
inputRef.current.value = "";
}
}, [searchParams]);
// hah, no need for useEffect here this just works!
if (
inputRef.current &&
inputRef.current.value &&
!searchParams?.get("query")
) {
inputRef.current.value = "";
}

const handleSearch = useDebouncedCallback((term: string) => {
const params = new URLSearchParams(searchParams ?? undefined);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export async function ChainListCard({
iconUrl,
}: ChainListCardProps) {
const chainMetadata = await getChainMetadata(chainId);
const isVerified = !!chainMetadata;
return (
<div className="relative h-full">
<Card className="h-full w-full hover:bg-muted">
Expand Down Expand Up @@ -70,13 +71,11 @@ export async function ChainListCard({
</tbody>
</table>

{(isDeprecated ||
chainMetadata?.gasSponsored ||
chainMetadata?.verified) && (
{(isDeprecated || chainMetadata?.gasSponsored || isVerified) && (
<div className="mt-5 flex gap-5 border-t pt-4">
{!isDeprecated && (
<>
{chainMetadata?.verified && (
{isVerified && (
<div className="gap-1.5 flex items-center">
<VerifiedIcon className="text-primary-foreground size-5" />
<p className="text-sm">Verified</p>
Expand Down
Loading

0 comments on commit 3f089e4

Please sign in to comment.