Standardize toast notifications for blockchain transactions

Implemented standardized error and success handling for blockchain transactions using the error-handler.ts utilities. This provides consistent, user-friendly, bilingual (EN/KMR) messaging across the app.

Changes:
- web/src/components/staking/StakingDashboard.tsx:
  * Import handleBlockchainError and handleBlockchainSuccess
  * Replace manual dispatchError parsing in bond() transaction
  * Replace manual dispatchError parsing in nominate() transaction
  * Replace manual dispatchError parsing in unbond() transaction
  * All transactions now show context-aware error messages
  * Success messages use template interpolation (e.g., "{{amount}} HEZ")

Benefits:
- Consistent error messaging across all blockchain operations
- Automatic bilingual support (English + Kurmanji)
- Proper error categorization (Staking, Identity, Tiki, etc.)
- User-friendly error descriptions instead of raw pallet errors
- Reduced code duplication (removed ~40 lines of manual error parsing)

This is Phase 1 of toast standardization. Other components with blockchain transactions (DEX, Governance, Treasury) should follow this pattern in future updates.

Pattern to follow:
```typescript
if (dispatchError) {
  handleBlockchainError(dispatchError, api, toast);
} else {
  handleBlockchainSuccess('operation.key', toast, { param: value });
}
```
This commit is contained in:
Claude
2025-11-16 22:06:10 +00:00
parent 4f2c96bb56
commit a78214ec6a
@@ -22,6 +22,7 @@ import {
type StakingInfo
} from '@pezkuwi/lib/staking';
import { LoadingState } from '@pezkuwi/components/AsyncComponent';
import { handleBlockchainError, handleBlockchainSuccess } from '@pezkuwi/lib/error-handler';
export const StakingDashboard: React.FC = () => {
const { t } = useTranslation();
@@ -120,22 +121,10 @@ export const StakingDashboard: React.FC = () => {
console.log('Transaction in block:', status.asInBlock.toHex());
if (dispatchError) {
let errorMessage = 'Transaction failed';
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
errorMessage = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`;
}
toast({
title: 'Error',
description: errorMessage,
variant: 'destructive',
});
handleBlockchainError(dispatchError, api, toast);
setIsLoading(false);
} else {
toast({
title: 'Success',
description: `Bonded ${bondAmount} HEZ successfully`,
});
handleBlockchainSuccess('staking.bonded', toast, { amount: bondAmount });
setBondAmount('');
refreshBalances();
// Refresh staking data after a delay
@@ -184,22 +173,10 @@ export const StakingDashboard: React.FC = () => {
({ status, dispatchError }) => {
if (status.isInBlock) {
if (dispatchError) {
let errorMessage = 'Nomination failed';
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
errorMessage = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`;
}
toast({
title: 'Error',
description: errorMessage,
variant: 'destructive',
});
handleBlockchainError(dispatchError, api, toast);
setIsLoading(false);
} else {
toast({
title: 'Success',
description: `Nominated ${selectedValidators.length} validator(s)`,
});
handleBlockchainSuccess('staking.nominated', toast, { count: selectedValidators.length.toString() });
// Refresh staking data
setTimeout(() => {
if (api && selectedAccount) {
@@ -242,21 +219,12 @@ export const StakingDashboard: React.FC = () => {
({ status, dispatchError }) => {
if (status.isInBlock) {
if (dispatchError) {
let errorMessage = 'Unbond failed';
if (dispatchError.isModule) {
const decoded = api.registry.findMetaError(dispatchError.asModule);
errorMessage = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`;
}
toast({
title: 'Error',
description: errorMessage,
variant: 'destructive',
});
handleBlockchainError(dispatchError, api, toast);
setIsLoading(false);
} else {
toast({
title: 'Success',
description: `Unbonded ${unbondAmount} HEZ. Withdrawal available in ${bondingDuration} eras`,
handleBlockchainSuccess('staking.unbonded', toast, {
amount: unbondAmount,
duration: bondingDuration.toString()
});
setUnbondAmount('');
setTimeout(() => {