Skip to content

Commit 59934b3

Browse files
committed
[Dashboard] move onramp countries page
1 parent 6cce31d commit 59934b3

File tree

5 files changed

+172
-0
lines changed

5 files changed

+172
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"use client";
2+
3+
import { Button } from "@/components/ui/button";
4+
import { useDashboardRouter } from "@/lib/DashboardRouter";
5+
import { usePathname, useSearchParams } from "next/navigation";
6+
import { useCallback } from "react";
7+
8+
export type OnrampProvider = "stripe" | "coinbase" | "transak";
9+
10+
export const ProviderSelector: React.FC<{ activeProvider: OnrampProvider }> = ({
11+
activeProvider,
12+
}) => {
13+
const pathname = usePathname();
14+
const searchParams = useSearchParams();
15+
const router = useDashboardRouter();
16+
17+
const createPageURL = useCallback(
18+
(provider: OnrampProvider) => {
19+
const params = new URLSearchParams(searchParams || undefined);
20+
params.set("provider", provider);
21+
return `${pathname}?${params.toString()}`;
22+
},
23+
[pathname, searchParams],
24+
);
25+
26+
const providers: OnrampProvider[] = ["coinbase", "stripe", "transak"];
27+
28+
return (
29+
<div className="flex flex-row gap-2">
30+
{providers.map((p) => (
31+
<Button
32+
key={p}
33+
size="sm"
34+
variant={activeProvider === p ? "default" : "outline"}
35+
onClick={() => router.replace(createPageURL(p))}
36+
className="capitalize"
37+
>
38+
{p}
39+
</Button>
40+
))}
41+
</div>
42+
);
43+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
Table,
3+
TableBody,
4+
TableCell,
5+
TableContainer,
6+
TableHead,
7+
TableHeader,
8+
TableRow,
9+
} from "@/components/ui/table";
10+
import { getOnrampCountrySupport } from "../../../../utils";
11+
import type { OnrampProvider } from "../client/provider";
12+
13+
export async function CountriesTable(props: { provider: OnrampProvider }) {
14+
const data = await getOnrampCountrySupport(props.provider);
15+
const countries = data.supportedCountries;
16+
17+
return (
18+
<TableContainer className="overflow-hidden rounded-xl border border-border/50 bg-card/50 shadow-sm transition-all">
19+
<Table>
20+
<TableHeader className="z-0">
21+
<TableRow className="border-border/50 border-b bg-muted/50">
22+
<TableHead className="py-4 font-medium text-muted-foreground/80 text-xs uppercase tracking-wider">
23+
Country
24+
</TableHead>
25+
<TableHead className="py-4 font-medium text-muted-foreground/80 text-xs uppercase tracking-wider">
26+
Currencies
27+
</TableHead>
28+
</TableRow>
29+
</TableHeader>
30+
<TableBody>
31+
{countries.map((country) => (
32+
<TableRow key={country.code} className="hover:bg-accent/50">
33+
<TableCell className="font-medium">{country.name}</TableCell>
34+
<TableCell className="text-muted-foreground">
35+
{country.currencies.join(", ")}
36+
</TableCell>
37+
</TableRow>
38+
))}
39+
</TableBody>
40+
</Table>
41+
</TableContainer>
42+
);
43+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { Metadata } from "next";
2+
import {
3+
type OnrampProvider,
4+
ProviderSelector,
5+
} from "./components/client/provider";
6+
import { CountriesTable } from "./components/server/countries-table";
7+
8+
const title = "Onramp Country Support";
9+
const description = "Countries and currencies supported by onramp providers.";
10+
11+
export const metadata: Metadata = {
12+
title,
13+
description,
14+
openGraph: {
15+
title,
16+
description,
17+
},
18+
};
19+
20+
export default async function OnrampCountriesPage(props: {
21+
searchParams: Promise<{ provider?: OnrampProvider }>;
22+
}) {
23+
const searchParams = await props.searchParams;
24+
const activeProvider: OnrampProvider =
25+
(searchParams.provider as OnrampProvider) || "coinbase";
26+
27+
return (
28+
<section className="container mx-auto flex h-full flex-col px-4 py-10">
29+
<header className="flex flex-col gap-6">
30+
<div className="flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between">
31+
<div className="flex flex-col gap-2">
32+
<h1 className="font-semibold text-4xl tracking-tighter lg:text-5xl">
33+
Onramp Countries
34+
</h1>
35+
</div>
36+
<div className="flex flex-row items-end gap-4 lg:flex-col">
37+
<div className="flex w-full flex-row items-center gap-4">
38+
<ProviderSelector activeProvider={activeProvider} />
39+
</div>
40+
</div>
41+
</div>
42+
</header>
43+
<div className="h-10" />
44+
<CountriesTable provider={activeProvider} />
45+
</section>
46+
);
47+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export type OnrampCountryToken = {
2+
chainId: number;
3+
address: string;
4+
symbol: string;
5+
};
6+
7+
export type OnrampCountryDetails = {
8+
code: string;
9+
name: string;
10+
currencies: string[];
11+
tokens: OnrampCountryToken[];
12+
};
13+
14+
export type OnrampCountrySupport = {
15+
provider: "stripe" | "coinbase" | "transak";
16+
supportedCountries: OnrampCountryDetails[];
17+
};

apps/dashboard/src/app/(app)/(dashboard)/(bridge)/utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,25 @@ export async function getRoutes({
6868

6969
return routes;
7070
}
71+
72+
export async function getOnrampCountrySupport(
73+
provider: "stripe" | "coinbase" | "transak",
74+
) {
75+
const url = new URL(
76+
`${NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST}/v1/onramp/countries`,
77+
);
78+
url.searchParams.set("provider", provider);
79+
const res = await fetch(url.toString(), {
80+
headers: {
81+
"x-secret-key": DASHBOARD_THIRDWEB_SECRET_KEY,
82+
},
83+
next: { revalidate: 60 * 60 },
84+
});
85+
86+
if (!res.ok) {
87+
throw new Error("Failed to fetch onramp countries");
88+
}
89+
90+
const json = await res.json();
91+
return json.data as import("./types/onramp-country").OnrampCountrySupport;
92+
}

0 commit comments

Comments
 (0)