Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ playground:
packages:
- changed-files:
- any-glob-to-any-file: "packages/**/*"
sdk:
- changed-files:
- any-glob-to-any-file: "packages/thirdweb/**/*"
portal:
- changed-files:
- any-glob-to-any-file: "apps/portal/**/*"
"Ecosystem Portal":
- changed-files:
- any-glob-to-any-file: "apps/wallet-ui/**/*"
4 changes: 3 additions & 1 deletion apps/wallet-ui/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Root domain for the app
NEXT_PUBLIC_ROOT_DOMAIN=ecosystem.localhost:3000
NEXT_PUBLIC_ROOT_DOMAIN=localhost:3000
# If set to production, multi-tenant subdomains will be used
NEXT_PUBLIC_ENVIRONMENT=development
# Thirdweb client ID
NEXT_PUBLIC_THIRDWEB_CLIENT_ID=
# Thirdweb API key
Expand Down
71 changes: 71 additions & 0 deletions apps/wallet-ui/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
module.exports = {
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@next/next/recommended",
],
rules: {
"react-compiler/react-compiler": "error",
"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".',
},
{
selector: "CallExpression[callee.name='createContext']",
message:
'Are you *sure* you need to use a "Context"? In almost all cases you should prefer passing props directly.',
},
],
"no-restricted-imports": [
"error",
{
paths: [
{
name: "next/navigation",
importNames: ["useRouter"],
message:
'Use `import { useRouter } from "@/lib/useRouter";` instead',
},
],
},
],
},
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint", "react-compiler"],
parserOptions: {
ecmaVersion: 2019,
ecmaFeatures: {
impliedStrict: true,
jsx: true,
},
warnOnUnsupportedTypeScriptVersion: true,
},
settings: {
react: {
createClass: "createReactClass",
pragma: "React",
version: "detect",
},
},
overrides: [
// enable rule specifically for TypeScript files
{
files: ["*.ts", "*.tsx"],
rules: {
"@typescript-eslint/explicit-module-boundary-types": ["off"],
},
},
// THIS NEEDS TO GO LAST!
{
files: ["*.ts", "*.js", "*.tsx", "*.jsx"],
extends: ["biome"],
},
],
env: {
browser: true,
node: true,
},
};
2 changes: 1 addition & 1 deletion apps/wallet-ui/README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# thirdweb Wallet UI
# thirdweb Ecosystem Portal
16 changes: 16 additions & 0 deletions apps/wallet-ui/biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.2/schema.json",
"extends": ["../../biome.json"],
"overrides": [
{
"include": ["src/css/swagger-ui.css"],
"linter": {
"rules": {
"suspicious": {
"noImportantInKeyframe": "off"
}
}
}
}
]
}
8 changes: 8 additions & 0 deletions apps/wallet-ui/knip.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://unpkg.com/knip@latest/schema.json",
"next": true,
"ignore": ["src/components/ui/**"],
"ignoreBinaries": ["biome"],
"ignoreDependencies": ["thirdweb"],
"project": ["src/**"]
}
14 changes: 10 additions & 4 deletions apps/wallet-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "biome check ./src",
"fix": "biome check ./src --fix"
"lint": "biome check ./src && knip && eslint ./src",
"fix": "biome check ./src --fix && knip --fix --allow-remove-files && eslint ./src --fix"
},
"dependencies": {
"@hookform/resolvers": "^3.9.1",
Expand All @@ -16,7 +16,6 @@
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.2",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-toast": "^1.2.2",
"@tanstack/react-query": "5.60.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
Expand All @@ -27,6 +26,7 @@
"react": "19.0.0-rc-69d4b800-20241021",
"react-dom": "19.0.0-rc-69d4b800-20241021",
"react-hook-form": "7.52.0",
"server-only": "^0.0.1",
"sonner": "^1.7.0",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7",
Expand All @@ -35,12 +35,18 @@
"zod": "3.23.8"
},
"devDependencies": {
"@next/eslint-plugin-next": "15.0.3",
"@types/node": "20.14.9",
"@types/react": "npm:[email protected]",
"@types/react-dom": "npm:[email protected]",
"@typescript-eslint/eslint-plugin": "7.14.1",
"@typescript-eslint/parser": "7.14.1",
"eslint": "8.57.0",
"eslint-config-next": "15.0.3",
"eslint-config-biome": "1.9.3",
"eslint-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110",
"knip": "5.37.0",
"postcss": "8.4.49",
"postcss-load-config": "^6.0.1",
"tailwindcss": "3.4.15",
"typescript": "5.6.3"
}
Expand Down
2 changes: 1 addition & 1 deletion apps/wallet-ui/postcss.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ const config = {
},
};

export default config;
export default config;
5 changes: 3 additions & 2 deletions apps/wallet-ui/src/app/[ecosystem]/(authed)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ConnectButton from "@/components/ConnectButton";
import { Image } from "@/components/ui/image";
import { authedOnly } from "@/lib/auth";
import { getEcosystemInfo } from "@/lib/ecosystems";
import { resolveScheme } from "thirdweb/storage";
Expand All @@ -12,14 +13,14 @@ export default async function Layout(props: {

const { children } = props;

await authedOnly();
await authedOnly(params.ecosystem);
const ecosystem = await getEcosystemInfo(params.ecosystem);
return (
<div className="flex w-full flex-col items-stretch">
<header className="hidden w-full border-accent border-b bg-card py-4 sm:block">
<div className="container mx-auto flex justify-between">
<div className="flex items-center gap-2">
<img
<Image
className="h-8 w-8"
src={resolveScheme({ uri: ecosystem.imageUrl, client })}
alt={ecosystem.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ export default async function Page(props: {
params: Promise<{ address: string }>;
searchParams: Promise<{ chainId?: string; uri?: string }>;
}) {
const searchParams = await props.searchParams;
const [searchParams, params] = await Promise.all([
props.searchParams,
props.params,
]);

const { chainId, uri } = searchParams;

const params = await props.params;

const { address } = params;

return (
Expand Down
11 changes: 7 additions & 4 deletions apps/wallet-ui/src/app/[ecosystem]/login/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { redirect } from "next/navigation";
import { getCurrentUser } from "../../../lib/auth";
import { getCurrentUser } from "@/lib/auth";
import { redirect } from "@/lib/redirect";

export default async function Layout({
children,
}: { children: React.ReactNode }) {
params,
}: { children: React.ReactNode; params: Promise<{ ecosystem: string }> }) {
const { ecosystem } = await params;

const userAddress = await getCurrentUser();
if (userAddress) {
redirect(`/wallet/${userAddress}`);
redirect(`/wallet/${userAddress}`, ecosystem);
}

return (
Expand Down
11 changes: 7 additions & 4 deletions apps/wallet-ui/src/app/[ecosystem]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { getCurrentUser } from "@/lib/auth";
import { redirect } from "next/navigation";
import { redirect } from "@/lib/redirect";

export default async function Page() {
export default async function Page({
params,
}: { params: Promise<{ ecosystem: string }> }) {
const { ecosystem } = await params;
const user = await getCurrentUser();
if (user) {
redirect("/wallet/${user}");
redirect(`/wallet/${user}`, ecosystem);
}
redirect("/login");
redirect("/login", ecosystem);
}
16 changes: 11 additions & 5 deletions apps/wallet-ui/src/app/[ecosystem]/wc/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
// This page is to accept a Wallet Connect request
import { getCurrentUser } from "@/lib/auth";
import { redirect } from "next/navigation";
import { redirect } from "@/lib/redirect";

export default async function Page(props: {
params: Promise<{ ecosystem: string }>;
searchParams: Promise<{ uri: string }>;
}) {
const searchParams = await props.searchParams;

const [params, searchParams] = await Promise.all([
props.params,
props.searchParams,
]);
const { uri } = searchParams;

const currentUser = await getCurrentUser();

if (!currentUser) {
redirect(`/login?uri=${encodeURIComponent(uri)}`);
redirect(`/login?uri=${encodeURIComponent(uri)}`, params.ecosystem);
}

redirect(`/wallet/${currentUser}?uri=${encodeURIComponent(uri)}`);
redirect(
`/wallet/${currentUser}?uri=${encodeURIComponent(uri)}`,
params.ecosystem,
);
}
2 changes: 1 addition & 1 deletion apps/wallet-ui/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Providers from "@/components/Providers";
import { cn } from "@/lib/utils";
import { Inter } from "next/font/google";
import "./globals.css";
import { cn } from "../lib/utils";

const inter = Inter({ subsets: ["latin"] });

Expand Down
2 changes: 2 additions & 0 deletions apps/wallet-ui/src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable @next/next/no-img-element */

export default function NotFound() {
return (
<div className="flex h-screen w-screen items-center justify-center">
Expand Down
6 changes: 4 additions & 2 deletions apps/wallet-ui/src/components/ChainCombobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { useRouter } from "@/hooks/useRouter";
import { cn } from "@/lib/utils";
import { ChevronsUpDown } from "lucide-react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useParams, usePathname, useSearchParams } from "next/navigation";
import React from "react";
import type { ChainMetadata } from "thirdweb/chains";
import { ChainIcon } from "./ChainIcon";

export function ChainCombobox({ chains }: { chains: ChainMetadata[] }) {
const router = useRouter();
const pathname = usePathname();
const params = useParams();
const searchParams = useSearchParams();
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState(searchParams.get("chainId") ?? "0");
Expand All @@ -43,7 +45,7 @@ export function ChainCombobox({ chains }: { chains: ChainMetadata[] }) {
const search = current.toString();
const query = search ? `?${search}` : "";

router.push(`${pathname}${query}`);
router.push(`${pathname}${query}`, params.ecosystem as string);
};

return (
Expand Down
5 changes: 3 additions & 2 deletions apps/wallet-ui/src/components/ChainIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use client";
import { Image } from "@/components/ui/image";
import { client } from "@/lib/client";
import { useQuery } from "@tanstack/react-query";
import { resolveScheme } from "thirdweb/storage";
import { client } from "../lib/client";

const fallbackChainIcon =
"data:image/svg+xml;charset=UTF-8,%3csvg width='15' height='14' viewBox='0 0 15 14' fill='none' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M7 8.04238e-07C5.1435 8.04238e-07 3.36301 0.737501 2.05025 2.05025C0.7375 3.36301 0 5.1435 0 7C0 7.225 -1.52737e-07 7.445 0.0349998 7.665C0.16385 9.0151 0.68213 10.2988 1.52686 11.3598C2.37158 12.4209 3.50637 13.2137 4.79326 13.642C6.0801 14.0702 7.4637 14.1153 8.7758 13.7719C10.0879 13.4285 11.2719 12.7113 12.184 11.7075C13.0961 10.7038 13.6969 9.4567 13.9135 8.1178C14.1301 6.7789 13.9531 5.406 13.4039 4.16587C12.8548 2.92574 11.9573 1.87184 10.8204 1.13228C9.6835 0.392721 8.3563 -0.000649196 7 8.04238e-07ZM7 1C8.581 1.00137 10.0975 1.62668 11.22 2.74V3.24C9.2438 2.55991 7.0956 2.56872 5.125 3.265C4.96758 3.1116 4.76997 3.00586 4.555 2.96H4.43C4.37 2.75 4.315 2.54 4.27 2.325C4.225 2.11 4.2 1.92 4.175 1.715C5.043 1.24658 6.0137 1.00091 7 1ZM5.5 3.935C7.3158 3.32693 9.2838 3.34984 11.085 4C10.8414 5.2703 10.3094 6.4677 9.53 7.5C9.312 7.4077 9.0707 7.3855 8.8395 7.4366C8.6083 7.4877 8.3988 7.6094 8.24 7.785C8.065 7.685 7.89 7.585 7.74 7.47C6.7307 6.7966 5.8877 5.9023 5.275 4.855C5.374 4.73221 5.4461 4.58996 5.4866 4.43749C5.5271 4.28502 5.5351 4.12575 5.51 3.97L5.5 3.935ZM3.5 2.135C3.5 2.24 3.53 2.35 3.55 2.455C3.595 2.675 3.655 2.89 3.715 3.105C3.52353 3.21838 3.36943 3.38531 3.2717 3.58522C3.17397 3.78513 3.13688 4.00927 3.165 4.23C2.37575 4.7454 1.67078 5.3795 1.075 6.11C1.19455 5.3189 1.47112 4.55966 1.88843 3.87701C2.30575 3.19437 2.85539 2.60208 3.505 2.135H3.5ZM3.5 9.99C3.30481 10.0555 3.13037 10.1714 2.9943 10.3259C2.85822 10.4804 2.76533 10.6681 2.725 10.87H2.405C1.59754 9.9069 1.1146 8.7136 1.025 7.46L1.08 7.365C1.70611 6.3942 2.52463 5.562 3.485 4.92C3.62899 5.0704 3.81094 5.179 4.01162 5.2345C4.2123 5.2899 4.42423 5.2901 4.625 5.235C5.2938 6.3652 6.208 7.3306 7.3 8.06C7.505 8.195 7.715 8.32 7.925 8.44C7.9082 8.6312 7.9391 8.8237 8.015 9C7.1 9.7266 6.0445 10.256 4.915 10.555C4.78401 10.3103 4.57028 10.1201 4.31199 10.0184C4.05369 9.9167 3.76766 9.9102 3.505 10L3.5 9.99ZM7 12.99C5.9831 12.9903 4.98307 12.7304 4.095 12.235L4.235 12.205C4.43397 12.1397 4.61176 12.0222 4.74984 11.8648C4.88792 11.7074 4.98122 11.5158 5.02 11.31C6.2985 10.984 7.4921 10.3872 8.52 9.56C8.7642 9.7027 9.0525 9.75 9.3295 9.6927C9.6064 9.6355 9.8524 9.4778 10.02 9.25C10.7254 9.4334 11.4511 9.5275 12.18 9.53H12.445C11.9626 10.5673 11.1938 11.4451 10.2291 12.0599C9.2643 12.6747 8.144 13.0009 7 13V12.99ZM10.255 8.54C10.2545 8.3304 10.1975 8.1249 10.09 7.945C10.9221 6.8581 11.5012 5.5991 11.785 4.26C12.035 4.37667 12.2817 4.50667 12.525 4.65C13.0749 5.9495 13.1493 7.4012 12.735 8.75C11.9049 8.8142 11.0698 8.7484 10.26 8.555L10.255 8.54Z' fill='%23646D7A'/%3e%3c/svg%3e";
Expand Down Expand Up @@ -32,7 +33,7 @@ export function ChainIcon(props: {
});

return (
<img
<Image
alt=""
width={100}
height={100}
Expand Down
17 changes: 16 additions & 1 deletion apps/wallet-ui/src/components/ConnectEmbed.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use client";
import { useRouter } from "@/hooks/useRouter";
import { generatePayload, getCurrentUser, login, logout } from "@/lib/auth";
import { client } from "@/lib/client";
import { useQuery } from "@tanstack/react-query";
import { useTheme } from "next-themes";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { useParams, useSearchParams } from "next/navigation";
import type { VerifyLoginPayloadParams } from "thirdweb/auth";
import { ConnectEmbed as ThirdwebConnectEmbed } from "thirdweb/react";
import { ecosystemWallet } from "thirdweb/wallets";
Expand All @@ -13,6 +15,18 @@ export function ConnectEmbed() {
const params = useParams();
const searchParams = useSearchParams();

const { data: userAddress } = useQuery({
queryKey: ["userAddress"],
queryFn: getCurrentUser,
});

if (userAddress) {
router.push(
`/wallet/${userAddress}?${searchParams.toString()}`,
params.ecosystem as string,
);
}

return (
<ThirdwebConnectEmbed
theme={theme === "light" ? "light" : "dark"}
Expand All @@ -26,6 +40,7 @@ export function ConnectEmbed() {
if (success) {
router.push(
`/wallet/${loginParams.payload.address}?${searchParams.toString()}`,
params.ecosystem as string,
);
}
},
Expand Down
Loading
Loading