@wopr-network/platform-ui-core 1.25.0 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/__tests__/amount-selector.test.tsx +36 -0
- package/src/__tests__/billing.test.tsx +2 -2
- package/src/__tests__/confirmation-tracker.test.tsx +57 -0
- package/src/__tests__/crypto-checkout.test.tsx +79 -0
- package/src/__tests__/deposit-view.test.tsx +43 -0
- package/src/__tests__/payment-method-picker.test.tsx +88 -0
- package/src/app/(dashboard)/billing/credits/page.tsx +2 -2
- package/src/app/(dashboard)/onboarding/page.tsx +0 -1
- package/src/app/(dashboard)/settings/profile/page.tsx +1 -0
- package/src/app/admin/pool-config/page.tsx +5 -0
- package/src/components/admin/admin-nav.tsx +1 -0
- package/src/components/admin/pool-config-dashboard.tsx +139 -0
- package/src/components/billing/amount-selector.tsx +66 -0
- package/src/components/billing/buy-crypto-credits-panel.tsx +1 -302
- package/src/components/billing/confirmation-tracker.tsx +92 -0
- package/src/components/billing/crypto-checkout.tsx +185 -0
- package/src/components/billing/deposit-view.tsx +90 -0
- package/src/components/billing/payment-method-picker.tsx +129 -0
- package/src/lib/admin-pool-api.ts +15 -0
- package/src/lib/trpc-types.ts +2 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import { Input } from "@/components/ui/input";
|
|
5
|
+
import type { SupportedPaymentMethod } from "@/lib/api";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
type Filter = "popular" | "stablecoins" | "l2" | "native";
|
|
9
|
+
|
|
10
|
+
const FILTERS: { key: Filter; label: string }[] = [
|
|
11
|
+
{ key: "popular", label: "Popular" },
|
|
12
|
+
{ key: "stablecoins", label: "Stablecoins" },
|
|
13
|
+
{ key: "l2", label: "L2s" },
|
|
14
|
+
{ key: "native", label: "Native" },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const STABLECOIN_TOKENS = new Set(["USDC", "USDT", "DAI"]);
|
|
18
|
+
const L2_CHAINS = new Set(["base", "arbitrum", "optimism", "polygon"]);
|
|
19
|
+
const POPULAR_COUNT = 6;
|
|
20
|
+
|
|
21
|
+
interface PaymentMethodPickerProps {
|
|
22
|
+
methods: SupportedPaymentMethod[];
|
|
23
|
+
onSelect: (method: SupportedPaymentMethod) => void;
|
|
24
|
+
onBack?: () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function PaymentMethodPicker({ methods, onSelect, onBack }: PaymentMethodPickerProps) {
|
|
28
|
+
const [search, setSearch] = useState("");
|
|
29
|
+
const [filter, setFilter] = useState<Filter>("popular");
|
|
30
|
+
|
|
31
|
+
const filtered = useMemo(() => {
|
|
32
|
+
if (search) {
|
|
33
|
+
const q = search.toLowerCase();
|
|
34
|
+
return methods.filter(
|
|
35
|
+
(m) =>
|
|
36
|
+
m.token.toLowerCase().includes(q) ||
|
|
37
|
+
m.chain.toLowerCase().includes(q) ||
|
|
38
|
+
m.displayName.toLowerCase().includes(q),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
switch (filter) {
|
|
43
|
+
case "popular":
|
|
44
|
+
return methods.slice(0, POPULAR_COUNT);
|
|
45
|
+
case "stablecoins":
|
|
46
|
+
return methods.filter((m) => STABLECOIN_TOKENS.has(m.token));
|
|
47
|
+
case "l2":
|
|
48
|
+
return methods.filter((m) => L2_CHAINS.has(m.chain));
|
|
49
|
+
case "native":
|
|
50
|
+
return methods.filter((m) => m.type === "native" && !L2_CHAINS.has(m.chain));
|
|
51
|
+
default:
|
|
52
|
+
return methods;
|
|
53
|
+
}
|
|
54
|
+
}, [methods, search, filter]);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className="space-y-3">
|
|
58
|
+
{onBack && (
|
|
59
|
+
<button
|
|
60
|
+
type="button"
|
|
61
|
+
onClick={onBack}
|
|
62
|
+
className="text-sm text-muted-foreground hover:text-foreground"
|
|
63
|
+
>
|
|
64
|
+
← Back
|
|
65
|
+
</button>
|
|
66
|
+
)}
|
|
67
|
+
<Input
|
|
68
|
+
placeholder="Search token or network..."
|
|
69
|
+
value={search}
|
|
70
|
+
onChange={(e) => setSearch(e.target.value)}
|
|
71
|
+
/>
|
|
72
|
+
<div className="flex flex-wrap gap-2">
|
|
73
|
+
{FILTERS.map((f) => (
|
|
74
|
+
<button
|
|
75
|
+
key={f.key}
|
|
76
|
+
type="button"
|
|
77
|
+
onClick={() => {
|
|
78
|
+
setFilter(f.key);
|
|
79
|
+
setSearch("");
|
|
80
|
+
}}
|
|
81
|
+
className={cn(
|
|
82
|
+
"rounded-full px-3 py-1 text-xs font-medium transition-colors",
|
|
83
|
+
filter === f.key && !search
|
|
84
|
+
? "bg-primary text-primary-foreground"
|
|
85
|
+
: "bg-muted text-muted-foreground hover:text-foreground",
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
88
|
+
{f.label}
|
|
89
|
+
</button>
|
|
90
|
+
))}
|
|
91
|
+
</div>
|
|
92
|
+
<div className="max-h-[320px] space-y-2 overflow-y-auto">
|
|
93
|
+
{filtered.map((m) => (
|
|
94
|
+
<button
|
|
95
|
+
key={m.id}
|
|
96
|
+
type="button"
|
|
97
|
+
onClick={() => onSelect(m)}
|
|
98
|
+
className="flex w-full items-center justify-between rounded-lg border border-border p-3 text-left transition-colors hover:bg-accent"
|
|
99
|
+
>
|
|
100
|
+
<div className="flex items-center gap-3">
|
|
101
|
+
{m.iconUrl && (
|
|
102
|
+
// biome-ignore lint/performance/noImgElement: external dynamic URLs
|
|
103
|
+
<img
|
|
104
|
+
src={m.iconUrl}
|
|
105
|
+
alt={m.token}
|
|
106
|
+
className="h-7 w-7 rounded-full"
|
|
107
|
+
loading="lazy"
|
|
108
|
+
onError={(e) => {
|
|
109
|
+
e.currentTarget.style.display = "none";
|
|
110
|
+
}}
|
|
111
|
+
/>
|
|
112
|
+
)}
|
|
113
|
+
<div>
|
|
114
|
+
<div className="text-sm font-medium">{m.displayName}</div>
|
|
115
|
+
<div className="text-xs text-muted-foreground">
|
|
116
|
+
{m.token} · {m.chain}
|
|
117
|
+
{m.type === "erc20" ? " · ERC-20" : " · Native"}
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</button>
|
|
122
|
+
))}
|
|
123
|
+
{filtered.length === 0 && (
|
|
124
|
+
<p className="py-4 text-center text-sm text-muted-foreground">No payment methods found</p>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { trpcVanilla } from "./trpc";
|
|
2
|
+
|
|
3
|
+
export interface PoolConfig {
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
poolSize: number;
|
|
6
|
+
warmCount: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function getPoolConfig(): Promise<PoolConfig> {
|
|
10
|
+
return trpcVanilla.admin.getPoolConfig.query({});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function setPoolSize(size: number): Promise<{ poolSize: number }> {
|
|
14
|
+
return trpcVanilla.admin.setPoolSize.mutate({ size });
|
|
15
|
+
}
|
package/src/lib/trpc-types.ts
CHANGED
|
@@ -80,6 +80,8 @@ type AppRouterRecord = {
|
|
|
80
80
|
listAllOrgs: AnyTRPCQueryProcedure;
|
|
81
81
|
billingOverview: AnyTRPCQueryProcedure;
|
|
82
82
|
listAvailableModels: AnyTRPCQueryProcedure;
|
|
83
|
+
getPoolConfig: AnyTRPCQueryProcedure;
|
|
84
|
+
setPoolSize: AnyTRPCMutationProcedure;
|
|
83
85
|
};
|
|
84
86
|
promotions: {
|
|
85
87
|
list: AnyTRPCQueryProcedure;
|