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();
});
});