-
Notifications
You must be signed in to change notification settings - Fork 619
[Dashboard] move onramp countries page #7262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| "use client"; | ||
|
|
||
| import { Button } from "@/components/ui/button"; | ||
| import { useDashboardRouter } from "@/lib/DashboardRouter"; | ||
| import { usePathname, useSearchParams } from "next/navigation"; | ||
| import { useCallback } from "react"; | ||
|
|
||
| export type OnrampProvider = "stripe" | "coinbase" | "transak"; | ||
|
|
||
| export const ProviderSelector: React.FC<{ activeProvider: OnrampProvider }> = ({ | ||
| activeProvider, | ||
| }) => { | ||
| const pathname = usePathname(); | ||
| const searchParams = useSearchParams(); | ||
| const router = useDashboardRouter(); | ||
|
|
||
| const createPageURL = useCallback( | ||
| (provider: OnrampProvider) => { | ||
| const params = new URLSearchParams(searchParams || undefined); | ||
| params.set("provider", provider); | ||
| return `${pathname}?${params.toString()}`; | ||
| }, | ||
| [pathname, searchParams], | ||
| ); | ||
|
|
||
| const providers: OnrampProvider[] = ["coinbase", "stripe", "transak"]; | ||
|
|
||
| return ( | ||
| <div className="flex flex-row gap-2"> | ||
| {providers.map((p) => ( | ||
| <Button | ||
| key={p} | ||
| size="sm" | ||
| variant={activeProvider === p ? "default" : "outline"} | ||
| onClick={() => router.replace(createPageURL(p))} | ||
| className="capitalize" | ||
| > | ||
| {p} | ||
| </Button> | ||
| ))} | ||
| </div> | ||
| ); | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,43 @@ | ||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||
| Table, | ||||||||||||||||||||||||||
| TableBody, | ||||||||||||||||||||||||||
| TableCell, | ||||||||||||||||||||||||||
| TableContainer, | ||||||||||||||||||||||||||
| TableHead, | ||||||||||||||||||||||||||
| TableHeader, | ||||||||||||||||||||||||||
| TableRow, | ||||||||||||||||||||||||||
| } from "@/components/ui/table"; | ||||||||||||||||||||||||||
| import { getOnrampCountrySupport } from "../../../../utils"; | ||||||||||||||||||||||||||
| import type { OnrampProvider } from "../client/provider"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| export async function CountriesTable(props: { provider: OnrampProvider }) { | ||||||||||||||||||||||||||
| const data = await getOnrampCountrySupport(props.provider); | ||||||||||||||||||||||||||
| const countries = data.supportedCountries; | ||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Validate data structure before accessing properties. The code assumes Add validation for the data structure: const data = await getOnrampCountrySupport(props.provider);
- const countries = data.supportedCountries;
+ const countries = data.supportedCountries || [];
+
+ if (!Array.isArray(countries)) {
+ console.warn('Invalid country data structure received:', data);
+ return (
+ <div className="flex items-center justify-center p-8">
+ <p className="text-muted-foreground">Invalid country data format</p>
+ </div>
+ );
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||
| <TableContainer className="overflow-hidden rounded-xl border border-border/50 bg-card/50 shadow-sm transition-all"> | ||||||||||||||||||||||||||
| <Table> | ||||||||||||||||||||||||||
| <TableHeader className="z-0"> | ||||||||||||||||||||||||||
| <TableRow className="border-border/50 border-b bg-muted/50"> | ||||||||||||||||||||||||||
| <TableHead className="py-4 font-medium text-muted-foreground/80 text-xs uppercase tracking-wider"> | ||||||||||||||||||||||||||
| Country | ||||||||||||||||||||||||||
| </TableHead> | ||||||||||||||||||||||||||
| <TableHead className="py-4 font-medium text-muted-foreground/80 text-xs uppercase tracking-wider"> | ||||||||||||||||||||||||||
| Currencies | ||||||||||||||||||||||||||
| </TableHead> | ||||||||||||||||||||||||||
| </TableRow> | ||||||||||||||||||||||||||
| </TableHeader> | ||||||||||||||||||||||||||
| <TableBody> | ||||||||||||||||||||||||||
| {countries.map((country) => ( | ||||||||||||||||||||||||||
| <TableRow key={country.code} className="hover:bg-accent/50"> | ||||||||||||||||||||||||||
| <TableCell className="font-medium">{country.name}</TableCell> | ||||||||||||||||||||||||||
| <TableCell className="text-muted-foreground"> | ||||||||||||||||||||||||||
| {country.currencies.join(", ")} | ||||||||||||||||||||||||||
| </TableCell> | ||||||||||||||||||||||||||
| </TableRow> | ||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||
| </TableBody> | ||||||||||||||||||||||||||
| </Table> | ||||||||||||||||||||||||||
| </TableContainer> | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,47 @@ | ||||||||||||||||||||
| import type { Metadata } from "next"; | ||||||||||||||||||||
| import { | ||||||||||||||||||||
| type OnrampProvider, | ||||||||||||||||||||
| ProviderSelector, | ||||||||||||||||||||
| } from "./components/client/provider"; | ||||||||||||||||||||
| import { CountriesTable } from "./components/server/countries-table"; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const title = "Onramp Country Support"; | ||||||||||||||||||||
| const description = "Countries and currencies supported by onramp providers."; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| export const metadata: Metadata = { | ||||||||||||||||||||
| title, | ||||||||||||||||||||
| description, | ||||||||||||||||||||
| openGraph: { | ||||||||||||||||||||
| title, | ||||||||||||||||||||
| description, | ||||||||||||||||||||
| }, | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| export default async function OnrampCountriesPage(props: { | ||||||||||||||||||||
| searchParams: Promise<{ provider?: OnrampProvider }>; | ||||||||||||||||||||
| }) { | ||||||||||||||||||||
| const searchParams = await props.searchParams; | ||||||||||||||||||||
| const activeProvider: OnrampProvider = | ||||||||||||||||||||
| (searchParams.provider as OnrampProvider) || "coinbase"; | ||||||||||||||||||||
|
Comment on lines
+23
to
+25
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add type safety for search params provider validation. The type assertion Add validation for the provider parameter: const searchParams = await props.searchParams;
- const activeProvider: OnrampProvider =
- (searchParams.provider as OnrampProvider) || "coinbase";
+ const validProviders: OnrampProvider[] = ["stripe", "coinbase", "transak"];
+ const activeProvider: OnrampProvider =
+ validProviders.includes(searchParams.provider as OnrampProvider)
+ ? (searchParams.provider as OnrampProvider)
+ : "coinbase";📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| return ( | ||||||||||||||||||||
| <section className="container mx-auto flex h-full flex-col px-4 py-10"> | ||||||||||||||||||||
| <header className="flex flex-col gap-6"> | ||||||||||||||||||||
| <div className="flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between"> | ||||||||||||||||||||
| <div className="flex flex-col gap-2"> | ||||||||||||||||||||
| <h1 className="font-semibold text-4xl tracking-tighter lg:text-5xl"> | ||||||||||||||||||||
| Onramp Countries | ||||||||||||||||||||
| </h1> | ||||||||||||||||||||
| </div> | ||||||||||||||||||||
| <div className="flex flex-row items-end gap-4 lg:flex-col"> | ||||||||||||||||||||
| <div className="flex w-full flex-row items-center gap-4"> | ||||||||||||||||||||
| <ProviderSelector activeProvider={activeProvider} /> | ||||||||||||||||||||
| </div> | ||||||||||||||||||||
| </div> | ||||||||||||||||||||
| </div> | ||||||||||||||||||||
| </header> | ||||||||||||||||||||
| <div className="h-10" /> | ||||||||||||||||||||
| <CountriesTable provider={activeProvider} /> | ||||||||||||||||||||
| </section> | ||||||||||||||||||||
| ); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| export type OnrampCountryToken = { | ||
| chainId: number; | ||
| address: string; | ||
| symbol: string; | ||
| }; | ||
|
|
||
| export type OnrampCountryDetails = { | ||
| code: string; | ||
| name: string; | ||
| currencies: string[]; | ||
| tokens: OnrampCountryToken[]; | ||
| }; | ||
|
|
||
| export type OnrampCountrySupport = { | ||
| provider: "stripe" | "coinbase" | "transak"; | ||
| supportedCountries: OnrampCountryDetails[]; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for the async data fetching.
The component directly awaits
getOnrampCountrySupportwithout error handling. If the API call fails, this will cause the entire page to error.Consider wrapping the data fetching in a try-catch block or creating an error boundary:
export async function CountriesTable(props: { provider: OnrampProvider }) { + try { const data = await getOnrampCountrySupport(props.provider); const countries = data.supportedCountries; + } catch (error) { + return ( + <div className="flex items-center justify-center p-8"> + <p className="text-muted-foreground"> + Failed to load country data for {props.provider} + </p> + </div> + ); + }📝 Committable suggestion
🤖 Prompt for AI Agents