@b3dotfun/sdk 0.0.9-alpha.1 → 0.0.9-alpha.3

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.
@@ -0,0 +1,707 @@
1
+ # Examples & Use Cases
2
+
3
+ Real-world implementation examples for common AnySpend integration patterns.
4
+
5
+ ## 🔄 Cross-Chain Token Swaps
6
+
7
+ ### Basic Swap Interface
8
+
9
+ Perfect for DeFi applications, portfolio managers, or any app that needs token exchange functionality.
10
+
11
+ ```tsx
12
+ import { AnySpend } from "@b3dotfun/sdk/anyspend/react";
13
+
14
+ function TokenSwapPage() {
15
+ const [userAddress] = useWallet(); // Your wallet hook
16
+
17
+ return (
18
+ <div className="swap-container">
19
+ <h1>Swap Tokens</h1>
20
+ <AnySpend
21
+ mode="page"
22
+ recipientAddress={userAddress}
23
+ onSuccess={(txHash) => {
24
+ // Update user's portfolio
25
+ toast.success("Swap completed successfully!");
26
+
27
+ // Optional: Track analytics
28
+ analytics.track("swap_completed", {
29
+ txHash,
30
+ userAddress,
31
+ });
32
+
33
+ // Refresh user balances
34
+ queryClient.invalidateQueries(['user-balances', userAddress]);
35
+ }}
36
+ />
37
+ </div>
38
+ );
39
+ }
40
+ ```
41
+
42
+ ### Advanced Swap with Quote Preview
43
+
44
+ ```tsx
45
+ import { useAnyspendQuote, AnySpend } from "@b3dotfun/sdk/anyspend/react";
46
+
47
+ function AdvancedSwapInterface() {
48
+ const [fromToken, setFromToken] = useState(USDC_ETHEREUM);
49
+ const [toToken, setToToken] = useState(ETH_B3);
50
+ const [amount, setAmount] = useState("100");
51
+ const [isSwapOpen, setIsSwapOpen] = useState(false);
52
+
53
+ const quoteRequest = useMemo(() => ({
54
+ srcChain: fromToken.chainId,
55
+ dstChain: toToken.chainId,
56
+ srcTokenAddress: fromToken.address,
57
+ dstTokenAddress: toToken.address,
58
+ type: "swap" as const,
59
+ tradeType: "EXACT_INPUT" as const,
60
+ amount: parseUnits(amount || "0", fromToken.decimals).toString(),
61
+ }), [fromToken, toToken, amount]);
62
+
63
+ const { anyspendQuote, isLoadingAnyspendQuote } = useAnyspendQuote(true, quoteRequest);
64
+
65
+ return (
66
+ <div className="advanced-swap">
67
+ <div className="swap-form">
68
+ <TokenInput
69
+ label="From"
70
+ token={fromToken}
71
+ amount={amount}
72
+ onTokenChange={setFromToken}
73
+ onAmountChange={setAmount}
74
+ />
75
+
76
+ <SwapArrowButton onClick={() => {
77
+ setFromToken(toToken);
78
+ setToToken(fromToken);
79
+ }} />
80
+
81
+ <TokenInput
82
+ label="To"
83
+ token={toToken}
84
+ amount={anyspendQuote?.expectedOutput || "0"}
85
+ onTokenChange={setToToken}
86
+ readOnly
87
+ />
88
+
89
+ {anyspendQuote && (
90
+ <div className="quote-details">
91
+ <div>Rate: 1 {fromToken.symbol} = {anyspendQuote.rate} {toToken.symbol}</div>
92
+ <div>Network Fee: ${anyspendQuote.networkFeeUsd}</div>
93
+ <div>Service Fee: ${anyspendQuote.serviceFeeUsd}</div>
94
+ <div>Total: ${anyspendQuote.totalUsdCost}</div>
95
+ </div>
96
+ )}
97
+
98
+ <button
99
+ onClick={() => setIsSwapOpen(true)}
100
+ disabled={isLoadingAnyspendQuote || !anyspendQuote}
101
+ className="swap-button"
102
+ >
103
+ {isLoadingAnyspendQuote ? "Getting Quote..." : "Swap Tokens"}
104
+ </button>
105
+ </div>
106
+
107
+ {isSwapOpen && (
108
+ <AnySpend
109
+ mode="modal"
110
+ recipientAddress={userAddress}
111
+ destinationTokenAddress={toToken.address}
112
+ destinationTokenChainId={toToken.chainId}
113
+ onSuccess={() => {
114
+ setIsSwapOpen(false);
115
+ toast.success("Swap completed!");
116
+ }}
117
+ />
118
+ )}
119
+ </div>
120
+ );
121
+ }
122
+ ```
123
+
124
+ ## 🖼️ NFT Marketplace Integration
125
+
126
+ ### Simple NFT Purchase
127
+
128
+ ```tsx
129
+ import { AnySpendNFTButton } from "@b3dotfun/sdk/anyspend/react";
130
+
131
+ function NFTCard({ nft }: { nft: NFTListing }) {
132
+ const [userAddress] = useWallet();
133
+ const [isOwned, setIsOwned] = useState(false);
134
+
135
+ const nftContract = {
136
+ chainId: nft.chainId,
137
+ contractAddress: nft.contractAddress,
138
+ price: nft.priceWei,
139
+ priceFormatted: nft.priceFormatted,
140
+ currency: nft.currency,
141
+ name: nft.name,
142
+ description: nft.description,
143
+ imageUrl: nft.imageUrl,
144
+ };
145
+
146
+ return (
147
+ <div className="nft-card">
148
+ <img src={nft.imageUrl} alt={nft.name} />
149
+ <div className="nft-details">
150
+ <h3>{nft.name}</h3>
151
+ <p>{nft.description}</p>
152
+ <div className="price">
153
+ {nft.priceFormatted} {nft.currency.symbol}
154
+ </div>
155
+
156
+ {isOwned ? (
157
+ <div className="owned-badge">✅ Owned</div>
158
+ ) : (
159
+ <AnySpendNFTButton
160
+ nftContract={nftContract}
161
+ recipientAddress={userAddress}
162
+ onSuccess={(txHash) => {
163
+ setIsOwned(true);
164
+
165
+ // Update user's NFT collection
166
+ queryClient.invalidateQueries(['user-nfts', userAddress]);
167
+
168
+ // Show success message with explorer link
169
+ toast.success(
170
+ <div>
171
+ NFT purchased successfully!
172
+ <a href={`https://explorer.b3.fun/tx/${txHash}`} target="_blank">
173
+ View Transaction
174
+ </a>
175
+ </div>
176
+ );
177
+ }}
178
+ />
179
+ )}
180
+ </div>
181
+ </div>
182
+ );
183
+ }
184
+ ```
185
+
186
+ ### NFT Marketplace with Bulk Purchase
187
+
188
+ ```tsx
189
+ function NFTMarketplace() {
190
+ const [selectedNFTs, setSelectedNFTs] = useState<NFTListing[]>([]);
191
+ const [userAddress] = useWallet();
192
+
193
+ const handleBulkPurchase = () => {
194
+ // For bulk purchases, create multiple orders or use batch contract
195
+ selectedNFTs.forEach((nft, index) => {
196
+ setTimeout(() => {
197
+ // Stagger purchases to avoid rate limiting
198
+ createSingleNFTPurchase(nft);
199
+ }, index * 1000);
200
+ });
201
+ };
202
+
203
+ return (
204
+ <div className="marketplace">
205
+ <div className="nft-grid">
206
+ {nfts.map((nft) => (
207
+ <NFTCard
208
+ key={nft.id}
209
+ nft={nft}
210
+ onSelect={(selected) => {
211
+ if (selected) {
212
+ setSelectedNFTs([...selectedNFTs, nft]);
213
+ } else {
214
+ setSelectedNFTs(selectedNFTs.filter(n => n.id !== nft.id));
215
+ }
216
+ }}
217
+ />
218
+ ))}
219
+ </div>
220
+
221
+ {selectedNFTs.length > 0 && (
222
+ <div className="bulk-purchase">
223
+ <p>Selected: {selectedNFTs.length} NFTs</p>
224
+ <p>Total: {calculateTotal(selectedNFTs)} ETH</p>
225
+ <button onClick={handleBulkPurchase}>
226
+ Purchase Selected NFTs
227
+ </button>
228
+ </div>
229
+ )}
230
+ </div>
231
+ );
232
+ }
233
+ ```
234
+
235
+ ## 🎮 Gaming & DeFi Applications
236
+
237
+ ### Staking Interface
238
+
239
+ ```tsx
240
+ import { AnySpendCustom } from "@b3dotfun/sdk/anyspend/react";
241
+ import { encodeFunctionData } from "viem";
242
+
243
+ function StakingPool({ pool }: { pool: StakingPool }) {
244
+ const [stakeAmount, setStakeAmount] = useState("");
245
+ const [stakingDuration, setStakingDuration] = useState(30);
246
+ const [userAddress] = useWallet();
247
+
248
+ const stakingCalldata = useMemo(() => {
249
+ if (!stakeAmount) return "0x";
250
+
251
+ const amountWei = parseUnits(stakeAmount, pool.token.decimals);
252
+
253
+ return encodeFunctionData({
254
+ abi: stakingPoolABI,
255
+ functionName: "stake",
256
+ args: [amountWei, stakingDuration * 24 * 60 * 60], // duration in seconds
257
+ });
258
+ }, [stakeAmount, stakingDuration]);
259
+
260
+ const expectedRewards = useMemo(() => {
261
+ if (!stakeAmount) return "0";
262
+ const amount = parseFloat(stakeAmount);
263
+ const apy = pool.apy / 100;
264
+ const durationInYears = stakingDuration / 365;
265
+ return (amount * apy * durationInYears).toFixed(4);
266
+ }, [stakeAmount, stakingDuration, pool.apy]);
267
+
268
+ return (
269
+ <div className="staking-pool">
270
+ <div className="pool-info">
271
+ <h2>{pool.name}</h2>
272
+ <p>APY: {pool.apy}%</p>
273
+ <p>TVL: ${pool.totalValueLocked.toLocaleString()}</p>
274
+ </div>
275
+
276
+ <div className="stake-form">
277
+ <div className="input-group">
278
+ <label>Amount to stake</label>
279
+ <input
280
+ type="number"
281
+ value={stakeAmount}
282
+ onChange={(e) => setStakeAmount(e.target.value)}
283
+ placeholder="0.0"
284
+ />
285
+ <span>{pool.token.symbol}</span>
286
+ </div>
287
+
288
+ <div className="input-group">
289
+ <label>Staking Duration</label>
290
+ <select
291
+ value={stakingDuration}
292
+ onChange={(e) => setStakingDuration(Number(e.target.value))}
293
+ >
294
+ <option value={7}>7 days (2% APY)</option>
295
+ <option value={30}>30 days (5% APY)</option>
296
+ <option value={90}>90 days (8% APY)</option>
297
+ <option value={365}>1 year (12% APY)</option>
298
+ </select>
299
+ </div>
300
+
301
+ <div className="rewards-preview">
302
+ <p>Expected rewards: {expectedRewards} {pool.token.symbol}</p>
303
+ </div>
304
+
305
+ <AnySpendCustom
306
+ orderType="custom"
307
+ dstChainId={pool.chainId}
308
+ dstToken={pool.token}
309
+ dstAmount={parseUnits(stakeAmount || "0", pool.token.decimals).toString()}
310
+ contractAddress={pool.contractAddress}
311
+ encodedData={stakingCalldata}
312
+ metadata={{
313
+ action: "stake",
314
+ poolId: pool.id,
315
+ duration: stakingDuration,
316
+ expectedRewards,
317
+ }}
318
+ header={({ anyspendPrice, isLoadingAnyspendPrice }) => (
319
+ <div className="staking-header">
320
+ <h3>Stake {pool.token.symbol}</h3>
321
+ <div className="stake-summary">
322
+ <div>Amount: {stakeAmount} {pool.token.symbol}</div>
323
+ <div>Duration: {stakingDuration} days</div>
324
+ <div>Expected rewards: {expectedRewards} {pool.token.symbol}</div>
325
+ {anyspendPrice && (
326
+ <div>Total cost: ${anyspendPrice.totalUsdCost}</div>
327
+ )}
328
+ </div>
329
+ </div>
330
+ )}
331
+ onSuccess={(txHash) => {
332
+ toast.success("Staking successful!");
333
+
334
+ // Update user's staking positions
335
+ queryClient.invalidateQueries(['staking-positions', userAddress]);
336
+
337
+ // Reset form
338
+ setStakeAmount("");
339
+ }}
340
+ />
341
+ </div>
342
+ </div>
343
+ );
344
+ }
345
+ ```
346
+
347
+ ### Gaming Spin Wheel
348
+
349
+ ```tsx
350
+ import { AnySpendBuySpin } from "@b3dotfun/sdk/anyspend/react";
351
+
352
+ function SpinWheel({ game }: { game: GameConfig }) {
353
+ const [userAddress] = useWallet();
354
+ const [spinHistory, setSpinHistory] = useState<SpinResult[]>([]);
355
+
356
+ return (
357
+ <div className="spin-game">
358
+ <div className="wheel-container">
359
+ <SpinWheelVisual prizes={game.prizes} />
360
+ </div>
361
+
362
+ <div className="game-info">
363
+ <h2>{game.name}</h2>
364
+ <p>Cost per spin: {game.spinCost} {game.currency.symbol}</p>
365
+ <div className="prizes">
366
+ <h3>Possible Prizes:</h3>
367
+ {game.prizes.map((prize, index) => (
368
+ <div key={index} className="prize">
369
+ <span>{prize.name}</span>
370
+ <span>{prize.probability}% chance</span>
371
+ </div>
372
+ ))}
373
+ </div>
374
+ </div>
375
+
376
+ <AnySpendBuySpin
377
+ gameContract={game.contractAddress}
378
+ spinPrice={game.spinCostWei}
379
+ recipientAddress={userAddress}
380
+ onSuccess={(txHash) => {
381
+ // Listen for spin result event
382
+ listenForSpinResult(txHash).then((result) => {
383
+ setSpinHistory([result, ...spinHistory]);
384
+
385
+ if (result.isWinner) {
386
+ toast.success(`You won ${result.prize.name}!`);
387
+ } else {
388
+ toast.info("Better luck next time!");
389
+ }
390
+ });
391
+ }}
392
+ />
393
+
394
+ {spinHistory.length > 0 && (
395
+ <div className="spin-history">
396
+ <h3>Recent Spins</h3>
397
+ {spinHistory.map((spin, index) => (
398
+ <div key={index} className={`spin-result ${spin.isWinner ? 'winner' : 'loser'}`}>
399
+ <span>{spin.prize.name}</span>
400
+ <span>{new Date(spin.timestamp).toLocaleTimeString()}</span>
401
+ </div>
402
+ ))}
403
+ </div>
404
+ )}
405
+ </div>
406
+ );
407
+ }
408
+ ```
409
+
410
+ ### Tournament Entry
411
+
412
+ ```tsx
413
+ import { AnySpendTournament } from "@b3dotfun/sdk/anyspend/react";
414
+
415
+ function TournamentCard({ tournament }: { tournament: Tournament }) {
416
+ const [userAddress] = useWallet();
417
+ const [isRegistered, setIsRegistered] = useState(false);
418
+
419
+ const timeUntilStart = tournament.startTime - Date.now();
420
+ const isStartingSoon = timeUntilStart < 60 * 60 * 1000; // 1 hour
421
+
422
+ return (
423
+ <div className="tournament-card">
424
+ <div className="tournament-header">
425
+ <h3>{tournament.name}</h3>
426
+ <div className="tournament-status">
427
+ {tournament.status === "upcoming" && (
428
+ <span className="status upcoming">
429
+ Starts in {formatTimeUntil(tournament.startTime)}
430
+ </span>
431
+ )}
432
+ {tournament.status === "live" && (
433
+ <span className="status live">🔴 Live</span>
434
+ )}
435
+ </div>
436
+ </div>
437
+
438
+ <div className="tournament-details">
439
+ <div className="prize-pool">
440
+ <h4>Prize Pool</h4>
441
+ <p>{tournament.prizePool} {tournament.currency.symbol}</p>
442
+ </div>
443
+
444
+ <div className="participants">
445
+ <h4>Participants</h4>
446
+ <p>{tournament.currentParticipants} / {tournament.maxParticipants}</p>
447
+ </div>
448
+
449
+ <div className="entry-fee">
450
+ <h4>Entry Fee</h4>
451
+ <p>{tournament.entryFee} {tournament.currency.symbol}</p>
452
+ </div>
453
+ </div>
454
+
455
+ {isRegistered ? (
456
+ <div className="registered">
457
+ ✅ Registered for tournament
458
+ </div>
459
+ ) : tournament.status === "upcoming" && !isStartingSoon ? (
460
+ <AnySpendTournament
461
+ tournamentId={tournament.id}
462
+ entryFee={tournament.entryFeeWei}
463
+ recipientAddress={userAddress}
464
+ onSuccess={() => {
465
+ setIsRegistered(true);
466
+ toast.success("Successfully registered for tournament!");
467
+
468
+ // Update tournament data
469
+ queryClient.invalidateQueries(['tournament', tournament.id]);
470
+ }}
471
+ />
472
+ ) : (
473
+ <div className="cannot-register">
474
+ {isStartingSoon ? "Registration closed" : "Tournament started"}
475
+ </div>
476
+ )}
477
+ </div>
478
+ );
479
+ }
480
+ ```
481
+
482
+ ## 💰 Fiat-to-Crypto Onramp
483
+
484
+ ### Simple Onboarding Flow
485
+
486
+ ```tsx
487
+ function FiatOnramp({ targetToken }: { targetToken: Token }) {
488
+ const [userAddress] = useWallet();
489
+
490
+ return (
491
+ <div className="onramp-flow">
492
+ <div className="onramp-header">
493
+ <h2>Buy {targetToken.symbol}</h2>
494
+ <p>Purchase crypto with your credit card or bank account</p>
495
+ </div>
496
+
497
+ <AnySpend
498
+ defaultActiveTab="fiat"
499
+ destinationTokenAddress={targetToken.address}
500
+ destinationTokenChainId={targetToken.chainId}
501
+ recipientAddress={userAddress}
502
+ mode="page"
503
+ onSuccess={(txHash) => {
504
+ // Welcome new user
505
+ toast.success("Welcome to crypto! Your purchase was successful.");
506
+
507
+ // Track onboarding completion
508
+ analytics.track("onramp_completed", {
509
+ userAddress,
510
+ token: targetToken.symbol,
511
+ txHash,
512
+ });
513
+
514
+ // Redirect to main app
515
+ router.push("/dashboard");
516
+ }}
517
+ />
518
+ </div>
519
+ );
520
+ }
521
+ ```
522
+
523
+ ### Multi-Step Onboarding
524
+
525
+ ```tsx
526
+ function OnboardingWizard() {
527
+ const [step, setStep] = useState(1);
528
+ const [userAddress, setUserAddress] = useState("");
529
+ const [selectedToken, setSelectedToken] = useState<Token>(USDC_BASE);
530
+
531
+ return (
532
+ <div className="onboarding-wizard">
533
+ <div className="progress-bar">
534
+ <div className={`step ${step >= 1 ? 'completed' : ''}`}>1. Connect Wallet</div>
535
+ <div className={`step ${step >= 2 ? 'completed' : ''}`}>2. Choose Token</div>
536
+ <div className={`step ${step >= 3 ? 'completed' : ''}`}>3. Purchase</div>
537
+ </div>
538
+
539
+ {step === 1 && (
540
+ <WalletConnectionStep
541
+ onConnect={(address) => {
542
+ setUserAddress(address);
543
+ setStep(2);
544
+ }}
545
+ />
546
+ )}
547
+
548
+ {step === 2 && (
549
+ <TokenSelectionStep
550
+ selectedToken={selectedToken}
551
+ onTokenSelect={(token) => {
552
+ setSelectedToken(token);
553
+ setStep(3);
554
+ }}
555
+ />
556
+ )}
557
+
558
+ {step === 3 && (
559
+ <div className="purchase-step">
560
+ <h2>Purchase {selectedToken.symbol}</h2>
561
+ <AnySpend
562
+ defaultActiveTab="fiat"
563
+ destinationTokenAddress={selectedToken.address}
564
+ destinationTokenChainId={selectedToken.chainId}
565
+ recipientAddress={userAddress}
566
+ mode="page"
567
+ onSuccess={() => {
568
+ // Complete onboarding
569
+ completeOnboarding(userAddress, selectedToken);
570
+ }}
571
+ />
572
+ </div>
573
+ )}
574
+ </div>
575
+ );
576
+ }
577
+ ```
578
+
579
+ ## 🛒 E-commerce Integration
580
+
581
+ ### Crypto Checkout
582
+
583
+ ```tsx
584
+ function CryptoCheckout({ order }: { order: Order }) {
585
+ const [userAddress] = useWallet();
586
+ const [paymentMethod, setPaymentMethod] = useState<"crypto" | "fiat">("crypto");
587
+
588
+ const orderTotal = order.items.reduce((sum, item) => sum + item.price, 0);
589
+
590
+ return (
591
+ <div className="checkout">
592
+ <div className="order-summary">
593
+ <h2>Order Summary</h2>
594
+ {order.items.map((item) => (
595
+ <div key={item.id} className="order-item">
596
+ <span>{item.name}</span>
597
+ <span>${item.price}</span>
598
+ </div>
599
+ ))}
600
+ <div className="total">
601
+ <strong>Total: ${orderTotal}</strong>
602
+ </div>
603
+ </div>
604
+
605
+ <div className="payment-section">
606
+ <div className="payment-method-selector">
607
+ <button
608
+ className={paymentMethod === "crypto" ? "active" : ""}
609
+ onClick={() => setPaymentMethod("crypto")}
610
+ >
611
+ Pay with Crypto
612
+ </button>
613
+ <button
614
+ className={paymentMethod === "fiat" ? "active" : ""}
615
+ onClick={() => setPaymentMethod("fiat")}
616
+ >
617
+ Pay with Card
618
+ </button>
619
+ </div>
620
+
621
+ <AnySpend
622
+ defaultActiveTab={paymentMethod}
623
+ destinationTokenAddress={USDC_BASE.address}
624
+ destinationTokenChainId={USDC_BASE.chainId}
625
+ recipientAddress={MERCHANT_WALLET_ADDRESS}
626
+ mode="page"
627
+ onSuccess={(txHash) => {
628
+ // Process order fulfillment
629
+ processOrder(order.id, txHash);
630
+
631
+ // Send confirmation email
632
+ sendOrderConfirmation(order, txHash);
633
+
634
+ // Redirect to success page
635
+ router.push(`/order-confirmation/${order.id}`);
636
+ }}
637
+ />
638
+ </div>
639
+ </div>
640
+ );
641
+ }
642
+ ```
643
+
644
+ ## 🎯 Advanced Patterns
645
+
646
+ ### Multi-Chain Portfolio Rebalancing
647
+
648
+ ```tsx
649
+ function PortfolioRebalancer() {
650
+ const [userAddress] = useWallet();
651
+ const [targetAllocation, setTargetAllocation] = useState({
652
+ ETH: 50,
653
+ BTC: 30,
654
+ USDC: 20,
655
+ });
656
+
657
+ const { data: currentBalances } = useUserBalances(userAddress);
658
+ const rebalanceOrders = calculateRebalanceOrders(currentBalances, targetAllocation);
659
+
660
+ return (
661
+ <div className="portfolio-rebalancer">
662
+ <h2>Portfolio Rebalancing</h2>
663
+
664
+ <div className="current-allocation">
665
+ <h3>Current Allocation</h3>
666
+ <AllocationChart balances={currentBalances} />
667
+ </div>
668
+
669
+ <div className="target-allocation">
670
+ <h3>Target Allocation</h3>
671
+ <AllocationInputs
672
+ allocation={targetAllocation}
673
+ onChange={setTargetAllocation}
674
+ />
675
+ </div>
676
+
677
+ <div className="rebalance-orders">
678
+ <h3>Required Transactions</h3>
679
+ {rebalanceOrders.map((order, index) => (
680
+ <div key={index} className="rebalance-order">
681
+ <p>
682
+ Swap {order.sellAmount} {order.sellToken.symbol} → {order.buyToken.symbol}
683
+ </p>
684
+ <AnySpendCustom
685
+ orderType="swap"
686
+ dstChainId={order.buyToken.chainId}
687
+ dstToken={order.buyToken}
688
+ dstAmount={order.buyAmountWei}
689
+ contractAddress="0x" // Use standard swap
690
+ encodedData="0x"
691
+ onSuccess={() => {
692
+ toast.success(`Rebalanced ${order.sellToken.symbol} → ${order.buyToken.symbol}`);
693
+ }}
694
+ />
695
+ </div>
696
+ ))}
697
+ </div>
698
+ </div>
699
+ );
700
+ }
701
+ ```
702
+
703
+ ## Next Steps
704
+
705
+ - [Error Handling Guide →](./error-handling.md)
706
+ - [Components Reference →](./components.md)
707
+ - [Hooks Reference →](./hooks.md)