# Frontend Integration Guide

Complete guide for integrating the wallet hook system with frontend applications using TypeScript, React, and Vue.

## Table of Contents

1. [TypeScript Types](#typescript-types)
2. [API Response Handling](#api-response-handling)
3. [React Components](#react-components)
4. [Vue Components](#vue-components)
5. [Error Code Mapping](#error-code-mapping)
6. [Best Practices](#best-practices)

---

## TypeScript Types

### Core Types

```typescript
/**
 * Result of a wallet transaction with hook execution status
 */
interface TransactionResult {
  /** Whether the transaction was successful */
  success: boolean;
  
  /** Transaction ID if successful */
  transaction_id?: number;
  
  /** Error details if transaction failed (PRE hook rejection or validation error) */
  error?: {
    /** Machine-readable error code in ALL_CAPS format */
    code: string;
    
    /** Human-readable error message */
    message: string;
    
    /** Additional error context */
    details: Record<string, any>;
  };
  
  /** Warnings from POST hooks (transaction still successful) */
  warnings?: Array<{
    /** Name of the hook that failed */
    hook: string;
    
    /** Error code */
    code: string;
    
    /** Error message */
    message: string;
    
    /** Additional context */
    details: Record<string, any>;
  }>;
}

/**
 * Transaction operation types
 */
type TransactionOperation = 'add' | 'deduct' | 'transfer';

/**
 * Request payload for wallet operations
 */
interface WalletOperationRequest {
  user_id: number;
  point_type: string;
  amount: number | string;  // Can send as string to preserve precision
  remarks: string;
  trans_type?: number;
  iid?: number;
}

/**
 * Transfer-specific request
 */
interface TransferRequest extends WalletOperationRequest {
  to_user_id: number;
  to_point_type?: string;
}
```

### Error Code Types

```typescript
/**
 * Standard error codes from hook system
 */
type WalletErrorCode =
  // Limit errors
  | 'DAILY_LIMIT_EXCEEDED'
  | 'MONTHLY_LIMIT_EXCEEDED'
  | 'TRANSACTION_LIMIT_EXCEEDED'
  | 'AMOUNT_TOO_HIGH'
  | 'AMOUNT_TOO_LOW'
  
  // Balance errors
  | 'INSUFFICIENT_BALANCE'
  | 'BALANCE_BELOW_MINIMUM'
  | 'BALANCE_FROZEN'
  
  // Fraud & Security
  | 'FRAUD_DETECTED'
  | 'HIGH_FREQUENCY_DETECTED'
  | 'SUSPICIOUS_AMOUNT'
  | 'SUSPICIOUS_PATTERN'
  | 'MANUAL_REVIEW_REQUIRED'
  | 'ACCOUNT_SUSPENDED'
  
  // Business Rules
  | 'OUTSIDE_BUSINESS_HOURS'
  | 'BLACKLISTED_USER'
  | 'RESTRICTED_POINT_TYPE'
  | 'INVALID_TRANSACTION_TYPE'
  | 'DUPLICATE_TRANSACTION'
  
  // User Status
  | 'USER_NOT_VERIFIED'
  | 'KYC_REQUIRED'
  | 'PENDING_VERIFICATION'
  
  // Hook System
  | 'HOOK_EXECUTION_ERROR'
  | 'HOOK_REJECTED'
  
  // Generic
  | 'VALIDATION_ERROR'
  | 'SYSTEM_ERROR';

/**
 * Type guard for error codes
 */
function isWalletErrorCode(code: string): code is WalletErrorCode {
  const validCodes: WalletErrorCode[] = [
    'DAILY_LIMIT_EXCEEDED',
    'MONTHLY_LIMIT_EXCEEDED',
    // ... list all codes
  ];
  return validCodes.includes(code as WalletErrorCode);
}
```

---

## API Response Handling

### Success Response

```typescript
// Transaction succeeded without warnings
{
  "success": true,
  "transaction_id": 12345
}

// Transaction succeeded with POST hook warnings
{
  "success": true,
  "transaction_id": 12345,
  "warnings": [
    {
      "hook": "email_notification",
      "code": "EMAIL_SERVICE_UNAVAILABLE",
      "message": "Failed to send email notification",
      "details": {
        "exception_type": "SMTPException"
      }
    }
  ]
}
```

### Error Response

```typescript
// PRE hook rejected transaction
{
  "success": false,
  "error": {
    "code": "DAILY_LIMIT_EXCEEDED",
    "message": "Daily transaction limit of $1,000 exceeded",
    "details": {
      "current_total": 850.00,
      "requested": 500.00,
      "limit": 1000.00,
      "remaining": 150.00
    }
  }
}
```

### API Client

```typescript
class WalletAPIClient {
  private baseURL: string;
  
  constructor(baseURL: string = '/api/wallet') {
    this.baseURL = baseURL;
  }
  
  /**
   * Add points to user wallet
   */
  async addPoints(request: WalletOperationRequest): Promise<TransactionResult> {
    const response = await fetch(`${this.baseURL}/add`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        // Add authentication headers as needed
      },
      body: JSON.stringify(request),
    });
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    return response.json();
  }
  
  /**
   * Deduct points from user wallet
   */
  async deductPoints(request: WalletOperationRequest): Promise<TransactionResult> {
    const response = await fetch(`${this.baseURL}/deduct`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(request),
    });
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    return response.json();
  }
  
  /**
   * Transfer points between users
   */
  async transferPoints(request: TransferRequest): Promise<TransactionResult> {
    const response = await fetch(`${this.baseURL}/transfer`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(request),
    });
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    return response.json();
  }
}

// Usage
const walletAPI = new WalletAPIClient();

try {
  const result = await walletAPI.deductPoints({
    user_id: 123,
    point_type: 'cash',
    amount: '500.00',  // String to preserve decimal precision
    remarks: 'Purchase',
  });
  
  if (result.success) {
    console.log('Transaction successful:', result.transaction_id);
  } else {
    console.error('Transaction failed:', result.error?.code);
  }
} catch (error) {
  console.error('API call failed:', error);
}
```

---

## React Components

### Transaction Result Display

```typescript
import React from 'react';
import { TransactionResult, WalletErrorCode } from './types';

interface TransactionResultProps {
  result: TransactionResult;
  onRetry?: () => void;
  onContactSupport?: () => void;
}

export const TransactionResultDisplay: React.FC<TransactionResultProps> = ({
  result,
  onRetry,
  onContactSupport,
}) => {
  if (result.success) {
    return (
      <div className="transaction-success">
        <div className="success-icon">✓</div>
        <h3>Transaction Successful</h3>
        <p>Transaction ID: {result.transaction_id}</p>
        
        {result.warnings && result.warnings.length > 0 && (
          <div className="warnings">
            <h4>Warnings</h4>
            <ul>
              {result.warnings.map((warning, index) => (
                <li key={index}>
                  <strong>{warning.hook}:</strong> {warning.message}
                </li>
              ))}
            </ul>
            <p className="warning-note">
              Your transaction completed successfully, but some notifications may not have been sent.
            </p>
          </div>
        )}
      </div>
    );
  }
  
  // Transaction failed
  return (
    <div className="transaction-error">
      <div className="error-icon">✗</div>
      <h3>Transaction Failed</h3>
      
      <ErrorMessage
        code={result.error?.code as WalletErrorCode}
        message={result.error?.message}
        details={result.error?.details}
        onRetry={onRetry}
        onContactSupport={onContactSupport}
      />
    </div>
  );
};
```

### Error Message Component

```typescript
interface ErrorMessageProps {
  code?: WalletErrorCode;
  message?: string;
  details?: Record<string, any>;
  onRetry?: () => void;
  onContactSupport?: () => void;
}

export const ErrorMessage: React.FC<ErrorMessageProps> = ({
  code,
  message,
  details,
  onRetry,
  onContactSupport,
}) => {
  // Map error codes to user-friendly messages with actions
  const getErrorContent = () => {
    switch (code) {
      case 'DAILY_LIMIT_EXCEEDED':
        return {
          title: 'Daily Limit Exceeded',
          description: message || 'You have reached your daily transaction limit.',
          actionText: 'View Limits',
          action: () => {/* Navigate to limits page */},
          showSupport: false,
          details: details && (
            <div className="error-details">
              <p>Used today: ${details.current_total?.toFixed(2)}</p>
              <p>Requested: ${details.requested?.toFixed(2)}</p>
              <p>Remaining: ${details.remaining?.toFixed(2)}</p>
              <p>Daily limit: ${details.limit?.toFixed(2)}</p>
            </div>
          ),
        };
      
      case 'AMOUNT_TOO_HIGH':
        return {
          title: 'Amount Exceeds Limit',
          description: `Maximum transaction amount is $${details?.limit?.toFixed(2)}`,
          actionText: 'Contact Support',
          action: onContactSupport,
          showSupport: true,
        };
      
      case 'INSUFFICIENT_BALANCE':
        return {
          title: 'Insufficient Balance',
          description: message || 'You do not have enough balance for this transaction.',
          actionText: 'Add Funds',
          action: () => {/* Navigate to deposit page */},
          showSupport: false,
          details: details && (
            <div className="error-details">
              <p>Available: ${details.available?.toFixed(2)}</p>
              <p>Required: ${details.requested?.toFixed(2)}</p>
            </div>
          ),
        };
      
      case 'FRAUD_DETECTED':
      case 'SUSPICIOUS_AMOUNT':
      case 'MANUAL_REVIEW_REQUIRED':
        return {
          title: 'Security Review Required',
          description: message || 'This transaction requires additional verification.',
          actionText: 'Contact Support',
          action: onContactSupport,
          showSupport: true,
        };
      
      case 'OUTSIDE_BUSINESS_HOURS':
        return {
          title: 'Outside Business Hours',
          description: message || 'This transaction can only be processed during business hours (9 AM - 5 PM).',
          actionText: 'Try Again Later',
          action: onRetry,
          showSupport: false,
        };
      
      case 'HIGH_FREQUENCY_DETECTED':
        return {
          title: 'Too Many Transactions',
          description: message || 'You are making transactions too quickly. Please wait a moment.',
          actionText: 'Try Again in 5 Minutes',
          action: onRetry,
          showSupport: false,
        };
      
      default:
        return {
          title: 'Transaction Error',
          description: message || 'An error occurred while processing your transaction.',
          actionText: 'Try Again',
          action: onRetry,
          showSupport: true,
        };
    }
  };
  
  const errorContent = getErrorContent();
  
  return (
    <div className="error-content">
      <h4>{errorContent.title}</h4>
      <p className="error-description">{errorContent.description}</p>
      
      {errorContent.details}
      
      <div className="error-actions">
        {errorContent.action && (
          <button onClick={errorContent.action} className="btn btn-primary">
            {errorContent.actionText}
          </button>
        )}
        
        {errorContent.showSupport && onContactSupport && (
          <button onClick={onContactSupport} className="btn btn-secondary">
            Contact Support
          </button>
        )}
      </div>
      
      {code && (
        <p className="error-code">Error Code: {code}</p>
      )}
    </div>
  );
};
```

### Complete Transaction Form

```typescript
import React, { useState } from 'react';
import { WalletAPIClient } from './api-client';

interface TransactionFormProps {
  userId: number;
  pointType: string;
  operation: 'add' | 'deduct';
}

export const TransactionForm: React.FC<TransactionFormProps> = ({
  userId,
  pointType,
  operation,
}) => {
  const [amount, setAmount] = useState('');
  const [remarks, setRemarks] = useState('');
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState<TransactionResult | null>(null);
  
  const walletAPI = new WalletAPIClient();
  
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setResult(null);
    
    try {
      const request = {
        user_id: userId,
        point_type: pointType,
        amount: amount,
        remarks: remarks,
      };
      
      const result = operation === 'add'
        ? await walletAPI.addPoints(request)
        : await walletAPI.deductPoints(request);
      
      setResult(result);
      
      if (result.success) {
        // Clear form on success
        setAmount('');
        setRemarks('');
      }
    } catch (error) {
      console.error('Transaction failed:', error);
      setResult({
        success: false,
        error: {
          code: 'SYSTEM_ERROR',
          message: error instanceof Error ? error.message : 'Unknown error',
          details: {},
        },
      });
    } finally {
      setLoading(false);
    }
  };
  
  return (
    <div className="transaction-form">
      <h2>{operation === 'add' ? 'Add' : 'Deduct'} {pointType}</h2>
      
      <form onSubmit={handleSubmit}>
        <div className="form-group">
          <label htmlFor="amount">Amount</label>
          <input
            id="amount"
            type="number"
            step="0.01"
            min="0"
            value={amount}
            onChange={(e) => setAmount(e.target.value)}
            required
            disabled={loading}
          />
        </div>
        
        <div className="form-group">
          <label htmlFor="remarks">Remarks</label>
          <textarea
            id="remarks"
            value={remarks}
            onChange={(e) => setRemarks(e.target.value)}
            required
            disabled={loading}
          />
        </div>
        
        <button type="submit" disabled={loading} className="btn btn-primary">
          {loading ? 'Processing...' : 'Submit'}
        </button>
      </form>
      
      {result && (
        <TransactionResultDisplay
          result={result}
          onRetry={() => {
            setResult(null);
            handleSubmit(new Event('submit') as any);
          }}
          onContactSupport={() => {
            // Navigate to support page or open chat
            window.location.href = '/support';
          }}
        />
      )}
    </div>
  );
};
```

### Custom Hook for Wallet Operations

```typescript
import { useState, useCallback } from 'react';
import { WalletAPIClient } from './api-client';
import type { TransactionResult, WalletOperationRequest } from './types';

export function useWalletTransaction() {
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState<TransactionResult | null>(null);
  const [error, setError] = useState<Error | null>(null);
  
  const walletAPI = new WalletAPIClient();
  
  const addPoints = useCallback(async (request: WalletOperationRequest) => {
    setLoading(true);
    setError(null);
    
    try {
      const result = await walletAPI.addPoints(request);
      setResult(result);
      return result;
    } catch (err) {
      const error = err instanceof Error ? err : new Error('Unknown error');
      setError(error);
      throw error;
    } finally {
      setLoading(false);
    }
  }, []);
  
  const deductPoints = useCallback(async (request: WalletOperationRequest) => {
    setLoading(true);
    setError(null);
    
    try {
      const result = await walletAPI.deductPoints(request);
      setResult(result);
      return result;
    } catch (err) {
      const error = err instanceof Error ? err : new Error('Unknown error');
      setError(error);
      throw error;
    } finally {
      setLoading(false);
    }
  }, []);
  
  const reset = useCallback(() => {
    setResult(null);
    setError(null);
  }, []);
  
  return {
    loading,
    result,
    error,
    addPoints,
    deductPoints,
    reset,
  };
}

// Usage
function MyComponent() {
  const { loading, result, addPoints } = useWalletTransaction();
  
  const handleAddFunds = async () => {
    try {
      await addPoints({
        user_id: 123,
        point_type: 'cash',
        amount: '100.00',
        remarks: 'Deposit',
      });
    } catch (error) {
      console.error('Failed to add points:', error);
    }
  };
  
  return (
    <div>
      <button onClick={handleAddFunds} disabled={loading}>
        {loading ? 'Processing...' : 'Add $100'}
      </button>
      
      {result && <TransactionResultDisplay result={result} />}
    </div>
  );
}
```

---

## Vue Components

### Transaction Result Component

```vue
<template>
  <div v-if="result" class="transaction-result">
    <div v-if="result.success" class="success">
      <div class="icon">✓</div>
      <h3>Transaction Successful</h3>
      <p>Transaction ID: {{ result.transaction_id }}</p>
      
      <div v-if="result.warnings && result.warnings.length > 0" class="warnings">
        <h4>Warnings</h4>
        <ul>
          <li v-for="(warning, index) in result.warnings" :key="index">
            <strong>{{ warning.hook }}:</strong> {{ warning.message }}
          </li>
        </ul>
      </div>
    </div>
    
    <div v-else class="error">
      <div class="icon">✗</div>
      <h3>Transaction Failed</h3>
      
      <ErrorMessage
        :code="result.error?.code"
        :message="result.error?.message"
        :details="result.error?.details"
        @retry="$emit('retry')"
        @contact-support="$emit('contact-support')"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import type { TransactionResult } from './types';
import ErrorMessage from './ErrorMessage.vue';

defineProps<{
  result: TransactionResult | null;
}>();

defineEmits<{
  retry: [];
  'contact-support': [];
}>();
</script>
```

### Transaction Form Component

```vue
<template>
  <div class="transaction-form">
    <h2>{{ operation === 'add' ? 'Add' : 'Deduct' }} {{ pointType }}</h2>
    
    <form @submit.prevent="handleSubmit">
      <div class="form-group">
        <label for="amount">Amount</label>
        <input
          id="amount"
          v-model="amount"
          type="number"
          step="0.01"
          min="0"
          required
          :disabled="loading"
        />
      </div>
      
      <div class="form-group">
        <label for="remarks">Remarks</label>
        <textarea
          id="remarks"
          v-model="remarks"
          required
          :disabled="loading"
        />
      </div>
      
      <button type="submit" :disabled="loading" class="btn btn-primary">
        {{ loading ? 'Processing...' : 'Submit' }}
      </button>
    </form>
    
    <TransactionResultDisplay
      v-if="result"
      :result="result"
      @retry="handleSubmit"
      @contact-support="handleContactSupport"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { WalletAPIClient } from './api-client';
import type { TransactionResult } from './types';
import TransactionResultDisplay from './TransactionResultDisplay.vue';

const props = defineProps<{
  userId: number;
  pointType: string;
  operation: 'add' | 'deduct';
}>();

const amount = ref('');
const remarks = ref('');
const loading = ref(false);
const result = ref<TransactionResult | null>(null);

const walletAPI = new WalletAPIClient();

const handleSubmit = async () => {
  loading.value = true;
  result.value = null;
  
  try {
    const request = {
      user_id: props.userId,
      point_type: props.pointType,
      amount: amount.value,
      remarks: remarks.value,
    };
    
    const transactionResult = props.operation === 'add'
      ? await walletAPI.addPoints(request)
      : await walletAPI.deductPoints(request);
    
    result.value = transactionResult;
    
    if (transactionResult.success) {
      amount.value = '';
      remarks.value = '';
    }
  } catch (error) {
    console.error('Transaction failed:', error);
    result.value = {
      success: false,
      error: {
        code: 'SYSTEM_ERROR',
        message: error instanceof Error ? error.message : 'Unknown error',
        details: {},
      },
    };
  } finally {
    loading.value = false;
  }
};

const handleContactSupport = () => {
  window.location.href = '/support';
};
</script>
```

### Composable for Wallet Operations

```typescript
// composables/useWallet.ts
import { ref } from 'vue';
import { WalletAPIClient } from '@/api/wallet-client';
import type { TransactionResult, WalletOperationRequest } from '@/types';

export function useWallet() {
  const loading = ref(false);
  const result = ref<TransactionResult | null>(null);
  const error = ref<Error | null>(null);
  
  const walletAPI = new WalletAPIClient();
  
  const addPoints = async (request: WalletOperationRequest) => {
    loading.value = true;
    error.value = null;
    
    try {
      const transactionResult = await walletAPI.addPoints(request);
      result.value = transactionResult;
      return transactionResult;
    } catch (err) {
      const apiError = err instanceof Error ? err : new Error('Unknown error');
      error.value = apiError;
      throw apiError;
    } finally {
      loading.value = false;
    }
  };
  
  const deductPoints = async (request: WalletOperationRequest) => {
    loading.value = true;
    error.value = null;
    
    try {
      const transactionResult = await walletAPI.deductPoints(request);
      result.value = transactionResult;
      return transactionResult;
    } catch (err) {
      const apiError = err instanceof Error ? err : new Error('Unknown error');
      error.value = apiError;
      throw apiError;
    } finally {
      loading.value = false;
    }
  };
  
  const reset = () => {
    result.value = null;
    error.value = null;
  };
  
  return {
    loading,
    result,
    error,
    addPoints,
    deductPoints,
    reset,
  };
}
```

---

## Error Code Mapping

### Severity Levels

```typescript
type ErrorSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';

const ERROR_SEVERITY_MAP: Record<string, ErrorSeverity> = {
  // Critical - requires immediate attention
  'FRAUD_DETECTED': 'critical',
  'ACCOUNT_SUSPENDED': 'critical',
  'SECURITY_BREACH': 'critical',
  
  // High - blocks transaction
  'DAILY_LIMIT_EXCEEDED': 'high',
  'MONTHLY_LIMIT_EXCEEDED': 'high',
  'AMOUNT_TOO_HIGH': 'high',
  'INSUFFICIENT_BALANCE': 'high',
  
  // Medium - can be resolved by user
  'OUTSIDE_BUSINESS_HOURS': 'medium',
  'USER_NOT_VERIFIED': 'medium',
  'KYC_REQUIRED': 'medium',
  
  // Low - temporary issues
  'HIGH_FREQUENCY_DETECTED': 'low',
  'SYSTEM_BUSY': 'low',
  
  // Info - warnings
  'EMAIL_SERVICE_UNAVAILABLE': 'info',
};

function getErrorSeverity(code: string): ErrorSeverity {
  return ERROR_SEVERITY_MAP[code] || 'medium';
}
```

### Icon Mapping

```typescript
const ERROR_ICON_MAP: Record<ErrorSeverity, string> = {
  critical: '🚨',
  high: '⛔',
  medium: '⚠️',
  low: 'ℹ️',
  info: '💡',
};

function getErrorIcon(code: string): string {
  const severity = getErrorSeverity(code);
  return ERROR_ICON_MAP[severity];
}
```

### Action Mapping

```typescript
interface ErrorAction {
  label: string;
  handler: () => void;
  variant: 'primary' | 'secondary' | 'danger';
}

function getErrorActions(code: string): ErrorAction[] {
  const actions: Record<string, ErrorAction[]> = {
    'DAILY_LIMIT_EXCEEDED': [
      { label: 'View Limits', handler: () => navigateTo('/limits'), variant: 'primary' },
      { label: 'Upgrade Account', handler: () => navigateTo('/upgrade'), variant: 'secondary' },
    ],
    
    'INSUFFICIENT_BALANCE': [
      { label: 'Add Funds', handler: () => navigateTo('/deposit'), variant: 'primary' },
      { label: 'View Balance', handler: () => navigateTo('/wallet'), variant: 'secondary' },
    ],
    
    'AMOUNT_TOO_HIGH': [
      { label: 'Contact Support', handler: () => openSupport(), variant: 'primary' },
    ],
    
    'FRAUD_DETECTED': [
      { label: 'Verify Identity', handler: () => navigateTo('/verify'), variant: 'danger' },
      { label: 'Contact Support', handler: () => openSupport(), variant: 'primary' },
    ],
  };
  
  return actions[code] || [
    { label: 'Try Again', handler: () => window.location.reload(), variant: 'primary' },
  ];
}
```

---

## Best Practices

### 1. Always Check Success Flag

```typescript
// ✅ Good
const result = await walletAPI.deductPoints(request);
if (result.success) {
  showSuccessMessage(result.transaction_id);
} else {
  showErrorMessage(result.error);
}

// ❌ Bad - assumes success
const result = await walletAPI.deductPoints(request);
showSuccessMessage(result.transaction_id);  // May be undefined!
```

### 2. Handle POST Hook Warnings

```typescript
// ✅ Good - show warnings to user
if (result.success) {
  showSuccessMessage(result.transaction_id);
  
  if (result.warnings && result.warnings.length > 0) {
    showWarningToast('Transaction completed with some issues');
  }
}

// ❌ Bad - ignore warnings
if (result.success) {
  showSuccessMessage(result.transaction_id);
}
```

### 3. Use Error Codes for Logic

```typescript
// ✅ Good - use error codes
if (!result.success) {
  switch (result.error?.code) {
    case 'DAILY_LIMIT_EXCEEDED':
      showUpgradePrompt();
      break;
    case 'INSUFFICIENT_BALANCE':
      showAddFundsPrompt();
      break;
    default:
      showGenericError(result.error?.message);
  }
}

// ❌ Bad - parse error messages
if (!result.success && result.error?.message.includes('limit')) {
  // Fragile - message may change
}
```

### 4. Preserve Decimal Precision

```typescript
// ✅ Good - send amount as string
const result = await walletAPI.addPoints({
  user_id: 123,
  point_type: 'cash',
  amount: '123.45',  // String preserves precision
  remarks: 'Deposit',
});

// ❌ Bad - number may lose precision
const result = await walletAPI.addPoints({
  user_id: 123,
  point_type: 'cash',
  amount: 123.45,  // May become 123.44999...
  remarks: 'Deposit',
});
```

### 5. Log Error Details

```typescript
// ✅ Good - log full error details
if (!result.success) {
  console.error('Transaction failed:', {
    code: result.error?.code,
    message: result.error?.message,
    details: result.error?.details,
  });
  
  // Send to error tracking service
  Sentry.captureMessage('Wallet transaction failed', {
    extra: {
      errorCode: result.error?.code,
      errorDetails: result.error?.details,
    },
  });
}

// ❌ Bad - lose context
if (!result.success) {
  console.error('Transaction failed');
}
```

### 6. Provide Context in UI

```typescript
// ✅ Good - show detailed error with context
<ErrorMessage
  code="DAILY_LIMIT_EXCEEDED"
  message="Daily limit of $1,000 exceeded"
  details={{
    current_total: 850.00,
    requested: 500.00,
    remaining: 150.00,
  }}
/>

// Renders:
// Daily Limit Exceeded
// You have reached your daily transaction limit.
// Used today: $850.00
// Requested: $500.00
// Remaining: $150.00

// ❌ Bad - generic error
<ErrorMessage message="Transaction failed" />
```

### 7. Handle Network Errors

```typescript
// ✅ Good - distinguish network errors from business logic errors
try {
  const result = await walletAPI.deductPoints(request);
  
  if (result.success) {
    // Handle success
  } else {
    // Handle business logic error (hook rejection)
    showBusinessError(result.error);
  }
} catch (error) {
  // Handle network/system error
  showNetworkError(error);
}

// ❌ Bad - mix error types
const result = await walletAPI.deductPoints(request);
if (!result.success) {
  showError(result.error);  // May also need to catch network errors
}
```

### 8. Implement Retry Logic

```typescript
// ✅ Good - smart retry based on error code
async function executeTransactionWithRetry(request: WalletOperationRequest, maxRetries = 3) {
  let attempt = 0;
  
  while (attempt < maxRetries) {
    try {
      const result = await walletAPI.deductPoints(request);
      
      if (result.success) {
        return result;
      }
      
      // Don't retry business logic errors
      if (result.error?.code === 'DAILY_LIMIT_EXCEEDED' ||
          result.error?.code === 'INSUFFICIENT_BALANCE') {
        return result;
      }
      
      // Retry system errors
      attempt++;
      await sleep(1000 * attempt);  // Exponential backoff
    } catch (error) {
      // Retry network errors
      attempt++;
      if (attempt >= maxRetries) throw error;
      await sleep(1000 * attempt);
    }
  }
}
```

---

## Summary

**Key Takeaways:**

1. **Use TypeScript** for type safety with `TransactionResult` interface
2. **Check `success` flag** before accessing transaction_id
3. **Map error codes** to user-friendly messages and actions
4. **Handle warnings** from POST hooks gracefully
5. **Preserve decimals** by sending amounts as strings
6. **Log errors** with full context for debugging
7. **Distinguish** between network errors and business logic errors
8. **Implement** smart retry logic based on error types

**Example Integration:**

```typescript
// API Client
const walletAPI = new WalletAPIClient();

// Execute transaction
const result = await walletAPI.deductPoints({
  user_id: 123,
  point_type: 'cash',
  amount: '500.00',
  remarks: 'Purchase',
});

// Handle result
if (result.success) {
  toast.success(`Transaction successful: ${result.transaction_id}`);
  
  if (result.warnings) {
    toast.warning('Some notifications may not have been sent');
  }
} else {
  const action = getErrorActions(result.error.code);
  showErrorDialog(result.error, action);
}
```

For more examples, see the React and Vue component sections above!
