From 722938d1ce774befb0f187f2d6d112ea368de8ec Mon Sep 17 00:00:00 2001 From: Jemimah Suleiman Date: Tue, 30 Jun 2026 09:07:48 +0000 Subject: [PATCH 1/4] refactor: extract helpers and types from large components --- package-lock.json | 1 + .../TransactionHistory.constants.ts | 29 ++++++++++++++++++ .../TransactionHistory.types.ts | 30 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 src/components/TransactionHistory/TransactionHistory.constants.ts create mode 100644 src/components/TransactionHistory/TransactionHistory.types.ts diff --git a/package-lock.json b/package-lock.json index b146856c..6208e36e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18534,6 +18534,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, diff --git a/src/components/TransactionHistory/TransactionHistory.constants.ts b/src/components/TransactionHistory/TransactionHistory.constants.ts new file mode 100644 index 00000000..64f79c8f --- /dev/null +++ b/src/components/TransactionHistory/TransactionHistory.constants.ts @@ -0,0 +1,29 @@ +import type { + TransactionStatus, + TransactionType, +} from "@/store/transactionStore"; + +export const TRANSACTION_TYPES: TransactionType[] = [ + "purchase", + "transfer", + "management", + "other", +]; + +export const TRANSACTION_STATUSES: TransactionStatus[] = [ + "pending", + "processing", + "confirmed", + "failed", + "cancelled", +]; + +export const isTransactionType = ( + value: string +): value is TransactionType => + TRANSACTION_TYPES.includes(value as TransactionType); + +export const isTransactionStatus = ( + value: string +): value is TransactionStatus => + TRANSACTION_STATUSES.includes(value as TransactionStatus); \ No newline at end of file diff --git a/src/components/TransactionHistory/TransactionHistory.types.ts b/src/components/TransactionHistory/TransactionHistory.types.ts new file mode 100644 index 00000000..7278e800 --- /dev/null +++ b/src/components/TransactionHistory/TransactionHistory.types.ts @@ -0,0 +1,30 @@ +import type { + Transaction, + TransactionStatus, + TransactionType, +} from "@/store/transactionStore"; + +export type SortBy = "timestamp" | "value" | "gasUsed"; + +export type SortOrder = "asc" | "desc"; + +export interface DateRange { + from?: Date; + to?: Date; +} + +export interface FilterTransactionsParams { + transactions: Transaction[]; + typeFilter: TransactionType | "all"; + statusFilter: TransactionStatus | "all"; + propertyFilter: string; + searchTerm: string; + amountRange: [number, number]; + gasPriceRange: [number, number]; + dateRange: DateRange; + sortBy: SortBy; + sortOrder: SortOrder; + getTransactionsByType: ( + type: TransactionType + ) => Transaction[]; +} \ No newline at end of file From 6e7bf09a79a42fe9632478bdff3359ac19f8d49b Mon Sep 17 00:00:00 2001 From: Jemimah Suleiman Date: Tue, 30 Jun 2026 09:24:07 +0000 Subject: [PATCH 2/4] refactor(config): centralize chain IDs and replace magic numbers --- src/config/chains.ts | 51 +++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/src/config/chains.ts b/src/config/chains.ts index 052cc486..46d7a9f1 100644 --- a/src/config/chains.ts +++ b/src/config/chains.ts @@ -1,57 +1,74 @@ -import {mainnet, polygon, bsc} from "wagmi/chains"; -import {getRpcUrl} from "./env"; +import { mainnet, polygon, bsc } from "wagmi/chains"; +import { getRpcUrl } from "./env"; + +/** + * Supported EVM chain IDs. + */ +export const CHAIN_IDS = { + ETHEREUM: 1, + POLYGON: 137, + BSC: 56, +} as const; + +export type ChainId = (typeof CHAIN_IDS)[keyof typeof CHAIN_IDS]; export const SUPPORTED_CHAINS = [mainnet, polygon, bsc]; /** - * Get RPC URL for a chain, falling back to defaults if env var is not set + * Get RPC URL for a chain, falling back to defaults if env var is not set. */ -const getChainRpcUrl = (chainId: number): string => { +const getChainRpcUrl = (chainId: ChainId): string => { switch (chainId) { - case 1: + case CHAIN_IDS.ETHEREUM: return getRpcUrl("ethereum") ?? "https://mainnet.infura.io/v3/"; - case 137: + + case CHAIN_IDS.POLYGON: return getRpcUrl("polygon") ?? "https://polygon-rpc.com"; - case 56: + + case CHAIN_IDS.BSC: return getRpcUrl("bsc") ?? "https://bsc-dataseed1.binance.org"; + default: return ""; } }; export const CHAIN_CONFIG = { - 1: { + [CHAIN_IDS.ETHEREUM]: { + id: CHAIN_IDS.ETHEREUM, name: "Ethereum", symbol: "ETH", decimals: 18, - rpcUrl: getChainRpcUrl(1), + rpcUrl: getChainRpcUrl(CHAIN_IDS.ETHEREUM), blockExplorer: "https://etherscan.io", color: "#627EEA", }, - 137: { + + [CHAIN_IDS.POLYGON]: { + id: CHAIN_IDS.POLYGON, name: "Polygon", symbol: "MATIC", decimals: 18, - rpcUrl: getChainRpcUrl(137), + rpcUrl: getChainRpcUrl(CHAIN_IDS.POLYGON), blockExplorer: "https://polygonscan.com", color: "#8247E5", }, - 56: { + + [CHAIN_IDS.BSC]: { + id: CHAIN_IDS.BSC, name: "Binance Smart Chain", symbol: "BNB", decimals: 18, - rpcUrl: getChainRpcUrl(56), + rpcUrl: getChainRpcUrl(CHAIN_IDS.BSC), blockExplorer: "https://bscscan.com", color: "#F3BA2F", }, } as const; -export type ChainId = keyof typeof CHAIN_CONFIG; - -export const DEFAULT_CHAIN_ID: ChainId = 1; +export const DEFAULT_CHAIN_ID: ChainId = CHAIN_IDS.ETHEREUM; export const isChainId = (value: number): value is ChainId => value in CHAIN_CONFIG; export const toChainId = (value: number): ChainId | null => - isChainId(value) ? value : null; + isChainId(value) ? value : null; \ No newline at end of file From 7bb960c539caa10a170de27796a700354e61242a Mon Sep 17 00:00:00 2001 From: Jemimah Suleiman Date: Tue, 30 Jun 2026 09:32:56 +0000 Subject: [PATCH 3/4] feat(gas-estimator): display estimated USD gas cost with confidence indicator --- src/components/GasEstimator.tsx | 82 +++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 8 deletions(-) diff --git a/src/components/GasEstimator.tsx b/src/components/GasEstimator.tsx index e6d8d44b..4e5d6c2f 100644 --- a/src/components/GasEstimator.tsx +++ b/src/components/GasEstimator.tsx @@ -18,7 +18,46 @@ interface GasEstimatorProps { type GasSpeed = 'slow' | 'standard' | 'fast'; -const ETH_PRICE_USD = 2500; // Mock ETH price +type GasConfidence = { + label: "High" | "Medium" | "Low"; + variance: string; +}; + +const getGasConfidence = ( + gasPrice?: bigint +): GasConfidence => { + if (!gasPrice) { + return { + label: "Low", + variance: "±20%", + }; + } + + const gwei = Number(formatUnits(gasPrice, 9)); + + if (gwei < 30) { + return { + label: "High", + variance: "±5%", + }; + } + + if (gwei < 80) { + return { + label: "Medium", + variance: "±10%", + }; + } + + return { + label: "Low", + variance: "±20%", + }; +}; + +const confidence = getGasConfidence(adjustedGasPrice); + +const ESTIMATED_ETH_PRICE_USD = 2500; // Mock ETH price export const GasEstimator: React.FC = ({ to, @@ -28,7 +67,7 @@ export const GasEstimator: React.FC = ({ }) => { const [selectedSpeed, setSelectedSpeed] = useState('standard'); const [estimatedGas, setEstimatedGas] = useState(null); - + const { data: baseGasPrice, isLoading: isGasPriceLoading } = useGasPrice(); const { data: gasEstimate, isLoading: isGasEstimateLoading } = useEstimateGas({ to: to as `0x${string}`, @@ -62,7 +101,7 @@ export const GasEstimator: React.FC = ({ const totalCostWei = estimatedGas && adjustedGasPrice ? estimatedGas * adjustedGasPrice : null; const totalCostEth = totalCostWei ? formatUnits(totalCostWei, 18) : null; const totalCostUsd = totalCostEth ? (parseFloat(totalCostEth) * ETH_PRICE_USD).toFixed(2) : null; - + const isHighGas = adjustedGasPrice ? adjustedGasPrice > parseUnits('100', 9) : false; return ( @@ -73,9 +112,9 @@ export const GasEstimator: React.FC = ({ Gas Fee Estimator - @@ -117,8 +156,18 @@ export const GasEstimator: React.FC = ({
Estimated Cost
-
- ${totalCostUsd || '0.00'} +
+ ≈ ${totalCostUsd || "0.00"} +
+ +
+ Approximate USD value +
+ +
+ {totalCostEth + ? parseFloat(totalCostEth).toFixed(6) + : "0"} ETH
{totalCostEth ? parseFloat(totalCostEth).toFixed(6) : '0'} ETH @@ -136,6 +185,23 @@ export const GasEstimator: React.FC = ({
Gas Limit +
+ + Confidence + + + + {confidence.label} ({confidence.variance}) + +
{estimatedGas?.toString() || '0'}
From 2c9b00133af20ce5042fd924dcf44dc3afd0e98a Mon Sep 17 00:00:00 2001 From: Jemimah Suleiman Date: Tue, 30 Jun 2026 09:35:46 +0000 Subject: [PATCH 4/4] refactor(dialog): replace ad-hoc confirmation flows with shared dialog --- src/components/dialogs/ConfirmDialog.tsx | 13 +++++++++++++ src/components/dialogs/ConfirmDialog.types.ts | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 src/components/dialogs/ConfirmDialog.tsx create mode 100644 src/components/dialogs/ConfirmDialog.types.ts diff --git a/src/components/dialogs/ConfirmDialog.tsx b/src/components/dialogs/ConfirmDialog.tsx new file mode 100644 index 00000000..ec5a0baf --- /dev/null +++ b/src/components/dialogs/ConfirmDialog.tsx @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/dialogs/ConfirmDialog.types.ts b/src/components/dialogs/ConfirmDialog.types.ts new file mode 100644 index 00000000..7d465652 --- /dev/null +++ b/src/components/dialogs/ConfirmDialog.types.ts @@ -0,0 +1,13 @@ +export interface ConfirmDialogOptions { + + title: string; + + description?: string; + + confirmText?: string; + + cancelText?: string; + + variant?: "default" | "destructive"; + +} \ No newline at end of file