@wopr-network/platform-ui-core 1.3.0 → 1.4.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
CHANGED
|
@@ -8,7 +8,9 @@ import { Button } from "@/components/ui/button";
|
|
|
8
8
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
9
9
|
import {
|
|
10
10
|
createCryptoCheckout,
|
|
11
|
+
createEthCheckout,
|
|
11
12
|
createStablecoinCheckout,
|
|
13
|
+
type EthCheckoutResult,
|
|
12
14
|
type StablecoinCheckoutResult,
|
|
13
15
|
} from "@/lib/api";
|
|
14
16
|
import { cn } from "@/lib/utils";
|
|
@@ -27,7 +29,17 @@ const STABLECOIN_TOKENS = [
|
|
|
27
29
|
{ token: "DAI", label: "DAI", chain: "base", chainLabel: "Base" },
|
|
28
30
|
];
|
|
29
31
|
|
|
30
|
-
type PaymentMethod = "btc" | "stablecoin";
|
|
32
|
+
type PaymentMethod = "btc" | "stablecoin" | "eth";
|
|
33
|
+
|
|
34
|
+
/** Format wei (BigInt string) to ETH string without Number precision loss. */
|
|
35
|
+
function formatWeiToEth(weiStr: string): string {
|
|
36
|
+
const wei = BigInt(weiStr);
|
|
37
|
+
const divisor = BigInt("1000000000000000000");
|
|
38
|
+
const whole = wei / divisor;
|
|
39
|
+
const frac = wei % divisor;
|
|
40
|
+
const fracStr = frac.toString().padStart(18, "0").slice(0, 6);
|
|
41
|
+
return `${whole}.${fracStr}`;
|
|
42
|
+
}
|
|
31
43
|
|
|
32
44
|
function CopyButton({ text }: { text: string }) {
|
|
33
45
|
const [copied, setCopied] = useState(false);
|
|
@@ -52,7 +64,7 @@ function StablecoinDeposit({
|
|
|
52
64
|
checkout: StablecoinCheckoutResult;
|
|
53
65
|
onReset: () => void;
|
|
54
66
|
}) {
|
|
55
|
-
const [confirmed,
|
|
67
|
+
const [confirmed, _setConfirmed] = useState(false);
|
|
56
68
|
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
57
69
|
|
|
58
70
|
useEffect(() => {
|
|
@@ -122,6 +134,21 @@ export function BuyCryptoCreditPanel() {
|
|
|
122
134
|
const [stablecoinCheckout, setStablecoinCheckout] = useState<StablecoinCheckoutResult | null>(
|
|
123
135
|
null,
|
|
124
136
|
);
|
|
137
|
+
const [ethCheckout, setEthCheckout] = useState<EthCheckoutResult | null>(null);
|
|
138
|
+
|
|
139
|
+
async function handleEthCheckout() {
|
|
140
|
+
if (selected === null) return;
|
|
141
|
+
setLoading(true);
|
|
142
|
+
setError(null);
|
|
143
|
+
try {
|
|
144
|
+
const result = await createEthCheckout(selected, "base");
|
|
145
|
+
setEthCheckout(result);
|
|
146
|
+
} catch {
|
|
147
|
+
setError("Checkout failed. Please try again.");
|
|
148
|
+
} finally {
|
|
149
|
+
setLoading(false);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
125
152
|
|
|
126
153
|
async function handleBtcCheckout() {
|
|
127
154
|
if (selected === null) return;
|
|
@@ -161,6 +188,7 @@ export function BuyCryptoCreditPanel() {
|
|
|
161
188
|
|
|
162
189
|
function handleReset() {
|
|
163
190
|
setStablecoinCheckout(null);
|
|
191
|
+
setEthCheckout(null);
|
|
164
192
|
setSelected(null);
|
|
165
193
|
setError(null);
|
|
166
194
|
}
|
|
@@ -176,6 +204,8 @@ export function BuyCryptoCreditPanel() {
|
|
|
176
204
|
<CardTitle className="flex items-center gap-2">
|
|
177
205
|
{method === "btc" ? (
|
|
178
206
|
<Bitcoin className="h-4 w-4 text-amber-500" />
|
|
207
|
+
) : method === "eth" ? (
|
|
208
|
+
<CircleDollarSign className="h-4 w-4 text-indigo-500" />
|
|
179
209
|
) : (
|
|
180
210
|
<CircleDollarSign className="h-4 w-4 text-blue-500" />
|
|
181
211
|
)}
|
|
@@ -197,6 +227,21 @@ export function BuyCryptoCreditPanel() {
|
|
|
197
227
|
>
|
|
198
228
|
Stablecoin
|
|
199
229
|
</button>
|
|
230
|
+
<button
|
|
231
|
+
type="button"
|
|
232
|
+
onClick={() => {
|
|
233
|
+
setMethod("eth");
|
|
234
|
+
handleReset();
|
|
235
|
+
}}
|
|
236
|
+
className={cn(
|
|
237
|
+
"rounded-full px-3 py-1 text-xs font-medium transition-colors",
|
|
238
|
+
method === "eth"
|
|
239
|
+
? "bg-indigo-500/10 text-indigo-500"
|
|
240
|
+
: "text-muted-foreground hover:text-foreground",
|
|
241
|
+
)}
|
|
242
|
+
>
|
|
243
|
+
ETH
|
|
244
|
+
</button>
|
|
200
245
|
<button
|
|
201
246
|
type="button"
|
|
202
247
|
onClick={() => {
|
|
@@ -215,7 +260,41 @@ export function BuyCryptoCreditPanel() {
|
|
|
215
260
|
</div>
|
|
216
261
|
</CardHeader>
|
|
217
262
|
<CardContent className="space-y-4">
|
|
218
|
-
{
|
|
263
|
+
{ethCheckout ? (
|
|
264
|
+
<motion.div
|
|
265
|
+
initial={{ opacity: 0, y: 8 }}
|
|
266
|
+
animate={{ opacity: 1, y: 0 }}
|
|
267
|
+
className="space-y-4"
|
|
268
|
+
>
|
|
269
|
+
<div className="rounded-md border p-4 space-y-3">
|
|
270
|
+
<div className="flex items-center justify-between">
|
|
271
|
+
<p className="text-sm text-muted-foreground">
|
|
272
|
+
Send approximately{" "}
|
|
273
|
+
<span className="font-mono font-bold text-foreground">
|
|
274
|
+
{formatWeiToEth(ethCheckout.expectedWei)} ETH
|
|
275
|
+
</span>{" "}
|
|
276
|
+
(${ethCheckout.amountUsd}) to:
|
|
277
|
+
</p>
|
|
278
|
+
<Badge variant="outline" className="text-xs">
|
|
279
|
+
ETH on {ethCheckout.chain}
|
|
280
|
+
</Badge>
|
|
281
|
+
</div>
|
|
282
|
+
<div className="flex items-center gap-2 rounded-md bg-muted/50 px-3 py-2">
|
|
283
|
+
<code className="flex-1 text-xs font-mono break-all text-foreground">
|
|
284
|
+
{ethCheckout.depositAddress}
|
|
285
|
+
</code>
|
|
286
|
+
<CopyButton text={ethCheckout.depositAddress} />
|
|
287
|
+
</div>
|
|
288
|
+
<p className="text-xs text-muted-foreground">
|
|
289
|
+
ETH price at checkout: ${(ethCheckout.priceCents / 100).toFixed(2)}. Only send ETH
|
|
290
|
+
on the {ethCheckout.chain} network.
|
|
291
|
+
</p>
|
|
292
|
+
</div>
|
|
293
|
+
<Button variant="ghost" size="sm" onClick={handleReset}>
|
|
294
|
+
Cancel
|
|
295
|
+
</Button>
|
|
296
|
+
</motion.div>
|
|
297
|
+
) : stablecoinCheckout ? (
|
|
219
298
|
<StablecoinDeposit checkout={stablecoinCheckout} onReset={handleReset} />
|
|
220
299
|
) : (
|
|
221
300
|
<>
|
|
@@ -263,7 +342,13 @@ export function BuyCryptoCreditPanel() {
|
|
|
263
342
|
{error && <p className="text-sm text-destructive">{error}</p>}
|
|
264
343
|
|
|
265
344
|
<Button
|
|
266
|
-
onClick={
|
|
345
|
+
onClick={
|
|
346
|
+
method === "btc"
|
|
347
|
+
? handleBtcCheckout
|
|
348
|
+
: method === "eth"
|
|
349
|
+
? handleEthCheckout
|
|
350
|
+
: handleStablecoinCheckout
|
|
351
|
+
}
|
|
267
352
|
disabled={selected === null || loading}
|
|
268
353
|
variant="outline"
|
|
269
354
|
className="w-full sm:w-auto"
|
|
@@ -272,7 +357,9 @@ export function BuyCryptoCreditPanel() {
|
|
|
272
357
|
? "Creating checkout..."
|
|
273
358
|
: method === "btc"
|
|
274
359
|
? "Pay with BTC"
|
|
275
|
-
:
|
|
360
|
+
: method === "eth"
|
|
361
|
+
? "Pay with ETH"
|
|
362
|
+
: `Pay with ${selectedToken.label}`}
|
|
276
363
|
</Button>
|
|
277
364
|
</>
|
|
278
365
|
)}
|
package/src/lib/api.ts
CHANGED
|
@@ -1353,6 +1353,22 @@ export async function createStablecoinCheckout(
|
|
|
1353
1353
|
return trpcVanilla.billing.stablecoinCheckout.mutate({ amountUsd, token, chain });
|
|
1354
1354
|
}
|
|
1355
1355
|
|
|
1356
|
+
export interface EthCheckoutResult {
|
|
1357
|
+
depositAddress: string;
|
|
1358
|
+
expectedWei: string;
|
|
1359
|
+
amountUsd: number;
|
|
1360
|
+
priceCents: number;
|
|
1361
|
+
chain: string;
|
|
1362
|
+
referenceId: string;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
export async function createEthCheckout(
|
|
1366
|
+
amountUsd: number,
|
|
1367
|
+
chain: string,
|
|
1368
|
+
): Promise<EthCheckoutResult> {
|
|
1369
|
+
return trpcVanilla.billing.ethCheckout.mutate({ amountUsd, chain });
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1356
1372
|
// --- Dividend types ---
|
|
1357
1373
|
|
|
1358
1374
|
export interface DividendWalletStats {
|
package/src/lib/trpc-types.ts
CHANGED
|
@@ -114,6 +114,7 @@ type AppRouterRecord = {
|
|
|
114
114
|
affiliateReferrals: AnyTRPCQueryProcedure;
|
|
115
115
|
cryptoCheckout: AnyTRPCMutationProcedure;
|
|
116
116
|
stablecoinCheckout: AnyTRPCMutationProcedure;
|
|
117
|
+
ethCheckout: AnyTRPCMutationProcedure;
|
|
117
118
|
autoTopupSettings: AnyTRPCQueryProcedure;
|
|
118
119
|
updateAutoTopupSettings: AnyTRPCMutationProcedure;
|
|
119
120
|
accountStatus: AnyTRPCQueryProcedure;
|