Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

readme.md

I have a table generated to document the issues in the original code and compare them with the refactored code. Here is the updated component that fixed all the issues: WalletPage.tsx

Code Analysis: Before & After

Issue Original Code (Before) Refactored Code (After) Improvement
Undefined Variables Used lhsPriority and leftPriority which were never declared, causing runtime crashes. Properly scoped variables priorityA and priorityB extracted directly from the items being compared. Bug Fix: Code now executes without throwing ReferenceError.
Inverted Filter Logic if (balance.amount <= 0) return true; kept empty/negative balances and discarded positive ones. return priority > -99 && balance.amount > 0; correctly filters out empty balances and unsupported chains. Bug Fix: Displays correct data to the user.
Missing Sort Return The sort function did not return 0 for items with equal priority, leading to unstable sorting. Added a fallback return 0; to ensure strict sorting contract compliance. Bug Fix: Stable and predictable array sorting across all browsers.
Redundant Dependency prices was included in the useMemo dependency array but never actually used inside the block. Removed unused dependencies and integrated pricing calculation cleanly in one pass. Performance: Prevents unnecessary re-computations when prices update but balances do not.
Inefficient Lookups getPriority used an O(N) switch statement that was re-evaluated constantly. Replaced with a static O(1) HashMap (Record<string, number>) defined outside the component. Performance: Faster lookups and prevents recreating the function on every render.
Multiple Array Passes Mapped over the sorted array to create formattedBalances, then mapped again to create React rows, dropping the formatted data. Consolidated .filter, .sort, and .map into a single useMemo pipeline that handles formatting and USD calculation. Performance: Reduced memory allocation and fewer iterations over the array.
Index as React Key Used key={index} when rendering <WalletRow />, which causes UI bugs during reordering/filtering. Used key={balance.currency} to ensure stable DOM elements during state changes. Performance & UX: Optimized React reconciliation and prevents component state leakage.

Comparison

Before

interface WalletBalance {
  currency: string;
  amount: number;
}
interface FormattedWalletBalance {
  currency: string;
  amount: number;
  formatted: string;
}

interface Props extends BoxProps {

}
const WalletPage: React.FC<Props> = (props: Props) => {
  const { children, ...rest } = props;
  const balances = useWalletBalances();
  const prices = usePrices();

	const getPriority = (blockchain: any): number => {
	  switch (blockchain) {
	    case 'Osmosis':
	      return 100
	    case 'Ethereum':
	      return 50
	    case 'Arbitrum':
	      return 30
	    case 'Zilliqa':
	      return 20
	    case 'Neo':
	      return 20
	    default:
	      return -99
	  }
	}

  const sortedBalances = useMemo(() => {
    return balances.filter((balance: WalletBalance) => {
		  const balancePriority = getPriority(balance.blockchain);
		  if (lhsPriority > -99) {
		     if (balance.amount <= 0) {
		       return true;
		     }
		  }
		  return false
		}).sort((lhs: WalletBalance, rhs: WalletBalance) => {
			const leftPriority = getPriority(lhs.blockchain);
		  const rightPriority = getPriority(rhs.blockchain);
		  if (leftPriority > rightPriority) {
		    return -1;
		  } else if (rightPriority > leftPriority) {
		    return 1;
		  }
    });
  }, [balances, prices]);

  const formattedBalances = sortedBalances.map((balance: WalletBalance) => {
    return {
      ...balance,
      formatted: balance.amount.toFixed()
    }
  })

  const rows = sortedBalances.map((balance: FormattedWalletBalance, index: number) => {
    const usdValue = prices[balance.currency] * balance.amount;
    return (
      <WalletRow
        className={classes.row}
        key={index}
        amount={balance.amount}
        usdValue={usdValue}
        formattedAmount={balance.formatted}
      />
    )
  })

  return (
    <div {...rest}>
      {rows}
    </div>
  )
}

After

// Problem 3 Fix: Define BLOCKCHAIN_PRIORITY as a HashMap for O(1) lookup instead of O(n) switch
const BLOCKCHAIN_PRIORITY: Record<string, number> = {
  'Osmosis': 100,
  'Ethereum': 50,
  'Arbitrum': 30,
  'Zilliqa': 20,
  'Neo': 20
};

// Mock balances since we don't have a real wallet connection
const generateMockBalances = (coins: Coin[]) => {
  return coins.map((c, i) => ({
    currency: c.currency,
    blockchain: c.blockchain,
    amount: i % 3 === 0 ? 0 : Math.random() * 100 + 10 // Every 3rd coin is empty
  }));
};

export const WalletPage: FC<WalletPageProps> = ({ coins }) => {
  const [showComparison, setShowComparison] = useState(false);

  // Create mock balances only once
  const balances = useMemo(() => generateMockBalances(coins), [coins]);

  // Problem 3 Fix: Single pass filter, sort, and map using useMemo
  const processedBalances = useMemo(() => {
    return balances
      // 1. Filter: Fix inverted logic (amount > 0)
      .filter(balance => {
        const priority = BLOCKCHAIN_PRIORITY[balance.blockchain] ?? -99;
        return priority > -99 && balance.amount > 0;
      })
      // 2. Sort: Fix missing return 0
      .sort((a, b) => {
        const priorityA = BLOCKCHAIN_PRIORITY[a.blockchain] ?? -99;
        const priorityB = BLOCKCHAIN_PRIORITY[b.blockchain] ?? -99;
        if (priorityA > priorityB) return -1;
        if (priorityA < priorityB) return 1;
        return 0;
      })
      // 3. Map to include formatted data + USD value (since we have coins array with prices)
      .map(balance => {
        const coinInfo = coins.find(c => c.currency === balance.currency);
        const price = coinInfo ? coinInfo.price : 0;
        const usdValue = price * balance.amount;

        return {
          ...balance,
          formatted: balance.amount.toFixed(4),
          usdValue,
          iconFilename: coinInfo?.iconFilename
        };
      });
  }, [balances, coins]); // Removed 'prices' dependency as they are inside 'coins'

  return (
    <div className="max-w-4xl mx-auto pt-4">
      <div className="flex justify-between items-end mb-6">
        <div>
          <h1 className="text-2xl font-bold text-white">Your Wallet</h1>
          <p className="text-slate-400 text-sm">Refactored version of the Problem 3 component</p>
        </div>
        <button
          onClick={() => setShowComparison(!showComparison)}
          className="px-4 py-2 bg-slate-800 hover:bg-slate-700 text-cyan-400 rounded-lg text-sm font-medium border border-slate-700 transition-colors"
        >
          {showComparison ? 'View Wallet' : 'View Code Comparison'}
        </button>
      </div>

      {showComparison ? (
        <WalletComparison />
      ) : (
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          {processedBalances.map((balance) => (
            <div key={balance.currency} className="glass-card p-4 flex items-center justify-between hover:bg-white/10 transition-colors">
              <div className="flex items-center gap-4">
                {balance.iconFilename ? (
                  <img src={`/coins/${balance.iconFilename}`} alt={balance.currency} className="w-10 h-10 rounded-full" />
                ) : (
                  <div className="w-10 h-10 rounded-full bg-slate-800 flex items-center justify-center text-slate-400 font-bold">
                    {balance.currency[0]}
                  </div>
                )}
                <div>
                  <h3 className="text-lg font-bold text-white">{balance.currency}</h3>
                  <span className="text-[10px] px-2 py-0.5 rounded-full bg-slate-800 border border-slate-700 text-slate-400 uppercase">
                    {balance.blockchain}
                  </span>
                </div>
              </div>
              <div className="text-right">
                <div className="font-mono text-white font-medium">{balance.formatted}</div>
                <div className="text-sm text-slate-400">${balance.usdValue.toFixed(2)}</div>
              </div>
            </div>
          ))}
          {processedBalances.length === 0 && (
            <div className="col-span-full p-8 text-center text-slate-500 border border-dashed border-slate-700 rounded-2xl">
              No balances found matching priority criteria.
            </div>
          )}
        </div>
      )}
    </div>
  );
}