Skip to main content

KAGE Stake Frontend Development Guide

info

This guide covers the frontend implementation details, component architecture, and development practices for the KAGE Stake platform.

Application Overview

Component Architecture

Core Components

// StakingDashboard.tsx
export const StakingDashboard = ({
userAddress,
networkConfig,
}: StakingDashboardProps) => {
const { totalStaked, rewards, lockPeriod } = useStakingStats(userAddress);

return (
<div className="staking-dashboard">
<StakingMetrics
totalStaked={totalStaked}
rewards={rewards}
lockPeriod={lockPeriod}
/>
<StakingActions />
</div>
);
};

// StakingPoolSelector.tsx
export const StakingPoolSelector = ({
availablePools,
onPoolSelect,
}: StakingPoolProps) => {
return (
<div className="pool-grid">
{availablePools.map(pool => (
<PoolCard
key={pool.id}
poolData={pool}
onSelect={() => onPoolSelect(pool)}
APY={pool.apy}
lockupPeriod={pool.lockupDays}
/>
))}
</div>
);
};

Transaction Flow Components

// StakingFlow.tsx
export const StakingFlow = ({
selectedPool,
userBalance,
}: StakingFlowProps) => {
const [step, setStep] = useState<StakingStep>("APPROVE");

const steps = {
APPROVE: <TokenApproval />,
STAKE: <StakeConfirmation />,
CONFIRM: <StakingSuccess />,
};

return (
<StakingFlowContainer>
{steps[step]}
<StakingProgress currentStep={step} />
</StakingFlowContainer>
);
};

User Interaction Flows

1. Initial Platform Entry

2. Pool Discovery & Analysis

Component States

Pool Display States

type PoolState = {
isLoading: boolean;
isStaked: boolean;
isLocked: boolean;
canWithdraw: boolean;
hasRewards: boolean;
};

const PoolDisplay: React.FC<PoolDisplayProps> = ({ poolId }) => {
const [state, setState] = useState<PoolState>({
isLoading: true,
isStaked: false,
isLocked: false,
canWithdraw: false,
hasRewards: false,
});

useEffect(() => {
// Update state based on contract data
}, [poolId]);

return (
<div
className={cn(
"pool-card",
state.isStaked && "staked",
state.isLocked && "locked",
state.canWithdraw && "withdrawable",
)}
>
{/* Pool content */}
</div>
);
};

User Experience Enhancements

1. Loading States

const LoadingState = () => (
<div className="animate-pulse">
<div className="h-4 bg-gray-200 rounded w-3/4"></div>
<div className="space-y-3 mt-4">
<div className="h-4 bg-gray-200 rounded"></div>
<div className="h-4 bg-gray-200 rounded w-5/6"></div>
</div>
</div>
);

2. Error Handling

const ErrorBoundary = ({ children }: { children: React.ReactNode }) => {
const [error, setError] = useState<Error | null>(null);

if (error) {
return (
<div className="error-container">
<h3>Something went wrong</h3>
<p>{error.message}</p>
<Button onClick={() => setError(null)}>Try Again</Button>
</div>
);
}

return children;
};

3. Transaction Feedback

const TransactionStatus = ({ hash, status }: TransactionStatusProps) => {
return (
<div className="transaction-status">
<div className="status-icon">
{status === "pending" && <Spinner />}
{status === "success" && <CheckIcon />}
{status === "error" && <ErrorIcon />}
</div>
<div className="status-details">
<p>{getStatusMessage(status)}</p>
<a href={`${scanURL}/tx/${hash}`} target="_blank">
View on Explorer
</a>
</div>
</div>
);
};

Performance Optimization

1. Data Caching

const usePoolData = (poolId: number) => {
const queryClient = useQueryClient();

return useQuery({
queryKey: ["pool", poolId],
queryFn: () => fetchPoolData(poolId),
staleTime: 30000, // 30 seconds
cacheTime: 3600000, // 1 hour
});
};

2. Component Memoization

const PoolMetrics = React.memo(({ poolData }: PoolMetricsProps) => {
const metrics = useMemo(() => calculatePoolMetrics(poolData), [poolData]);

return <div className="pool-metrics">{/* Render metrics */}</div>;
});

Accessibility Features

1. Keyboard Navigation

const KeyboardNavigationHandler = () => {
useEffect(() => {
const handleKeyPress = (e: KeyboardEvent) => {
switch (e.key) {
case "ArrowRight":
navigateToNextPool();
break;
case "ArrowLeft":
navigateToPreviousPool();
break;
case "Enter":
selectCurrentPool();
break;
case "Escape":
closeCurrentModal();
break;
}
};

window.addEventListener("keydown", handleKeyPress);
return () => window.removeEventListener("keydown", handleKeyPress);
}, []);
};

2. Screen Reader Support

const PoolMetrics = ({ poolData }: PoolMetricsProps) => {
return (
<div role="region" aria-label="Pool Statistics" tabIndex={0}>
<div aria-live="polite">
<span className="sr-only">Current APY:</span>
<span aria-label={`${poolData.apy}% Annual Percentage Yield`}>
{poolData.apy}% APY
</span>
</div>

<div
role="meter"
aria-label="Pool Utilization"
aria-valuenow={poolData.utilization}
aria-valuemin={0}
aria-valuemax={100}
>
<ProgressBar
value={poolData.utilization}
className="visually-accessible"
/>
</div>
</div>
);
};

Testing

describe("Pool Integration", () => {
test("Full Staking Flow", async () => {
const { container } = render(<PoolTabs {...mockProps} />);

// Connect wallet
await userEvent.click(screen.getByText("Connect Wallet"));

// Select pool
await userEvent.click(screen.getByText("Pool #1"));

// Enter stake amount
await userEvent.type(screen.getByPlaceholderText("Amount"), "1000");

// Confirm stake
await userEvent.click(screen.getByText("Stake KAGE"));

// Verify success state
expect(screen.getByText("Staking Successful")).toBeInTheDocument();
});
});