Recovery API Integration - Quick Start Guide
1. Set Environment Variable
# .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
import { useRecoveryStatus } from "@/hooks/useRecoveryStatus" ;
export function RecoveryPage ( ) {
const { timeline, loading, error } = useRecoveryStatus ( "wallet-123" ) ;
if ( loading === "loading" ) return < div > Loading ...< / d i v > ;
if ( error ) return < div > Error : { error} < / d i v > ;
if ( ! timeline ) return < div > No data < / d i v > ;
return < RecoveryTimelineList events = { timeline . events } / > ;
}
const { timeline } = useRecoveryStatus ( "wallet-123" ) ;
const { error, clearError } = useRecoveryStatus ( "wallet-123" ) ;
if ( error ) {
return (
< div >
< p > { error} < / p >
< button onClick = { clearError} > Dismiss < / b u t t o n >
< / div >
) ;
}
const { refetch } = useRecoveryStatus ( "wallet-123" ) ;
< button onClick = { refetch} > Refresh < / b u t t o n >
const { timeline, refetch } = useRecoveryStatus ( "wallet-123" , {
autoFetch : false ,
} ) ;
// Fetch manually
< button onClick = { refetch} > Fetch Status < / b u t t o n >
const { timeline } = useRecoveryStatus ( "wallet-123" , {
onStatusChange : ( timeline ) => {
console . log ( "Status:" , timeline . status ) ;
if ( timeline . status === "completed" ) {
showSuccess ( "Recovery complete!" ) ;
}
} ,
} ) ;
const { startPolling, stopPolling } = useRecoveryStatus ( "wallet-123" , {
pollInterval : 10000 , // 10 seconds
maxPollDuration : 600000 , // 10 minutes
} ) ;
< button onClick = { startPolling} > Start Polling < / b u t t o n >
< button onClick = { stopPolling} > Stop Polling < / b u t t o n >
const { isStale, refetch } = useRecoveryStatus ( "wallet-123" ) ;
if ( isStale ) {
return < button onClick = { refetch} > Data is stale - Refresh < / b u t t o n > ;
}
import { fetchRecoveryStatus } from "@/services/recoveryApi" ;
const result = await fetchRecoveryStatus ( "wallet-123" ) ;
if ( result . success ) {
console . log ( result . data ) ;
} else {
console . error ( result . error ) ;
}
import { pollRecoveryStatus } from "@/services/recoveryApi" ;
const stop = pollRecoveryStatus (
"wallet-123" ,
5000 , // interval
300000 , // max duration
( response ) => {
if ( response . success ) {
console . log ( response . data ?. status ) ;
}
}
) ;
// Stop later
stop ( ) ;
const result = await fetchRecoveryStatus ( "wallet-123" , {
baseUrl : "https://custom-api.com" ,
timeout : 15000 ,
retryAttempts : 5 ,
retryDelay : 2000 ,
} ) ;
const {
timeline, // RecoveryTimeline | null
loading, // "idle" | "loading" | "success" | "error"
error, // string | null
isStale, // boolean
lastFetchTime, // number | null
} = useRecoveryStatus ( "wallet-123" ) ;
const {
refetch, // () => Promise<void>
startPolling, // () => void
stopPolling, // () => void
markAsStale, // () => void
clearError, // () => void
} = useRecoveryStatus ( "wallet-123" ) ;
const {
isLoading, // boolean
isError, // boolean
isSuccess, // boolean
isIdle, // boolean
} = useRecoveryStatus ( "wallet-123" ) ;
useRecoveryStatus ( "wallet-123" , {
autoFetch : true , // Auto-fetch on mount
pollInterval : 5000 , // Polling interval (ms)
maxPollDuration : 300000 , // Max polling duration (ms)
onStatusChange : ( timeline ) => { } , // Status change callback
onError : ( error ) => { } , // Error callback
} ) ;
const { loading } = useRecoveryStatus ( "wallet-123" ) ;
switch ( loading ) {
case "idle" :
return < div > Not started < / d i v > ;
case "loading" :
return < div > Loading ...< / d i v > ;
case "success" :
return < div > Success < / d i v > ;
case "error" :
return < div > Error < / d i v > ;
}
const { error, isError, clearError } = useRecoveryStatus ( "wallet-123" ) ;
if ( isError ) {
return (
< div className = "error" >
< p > { error} < / p >
< button onClick = { clearError} > Dismiss < / b u t t o n >
< / div >
) ;
}
# API service tests
pnpm test recoveryApi
# Hook tests
pnpm test useRecoveryStatus
# All recovery tests
pnpm test recovery
# With coverage
pnpm test:coverage
API Service Tests: 40+ tests
Hook Tests: 50+ tests
Total: 90+ tests
# Required
NEXT_PUBLIC_API_URL=https://api.example.com
# Optional
NEXT_PUBLIC_API_TIMEOUT=10000
NEXT_PUBLIC_API_RETRY_ATTEMPTS=3
NEXT_PUBLIC_API_RETRY_DELAY=1000
import { useRecoveryStatus } from "@/hooks/useRecoveryStatus" ;
import { RecoveryTimelineList } from "@/components/recovery/RecoveryTimelineList" ;
export function RecoveryPage ( ) {
const {
timeline,
loading,
error,
isStale,
refetch,
clearError,
} = useRecoveryStatus ( "wallet-123" , {
onStatusChange : ( timeline ) => {
if ( timeline . status === "completed" ) {
showSuccess ( "Recovery complete!" ) ;
}
} ,
onError : ( error ) => {
showError ( error ) ;
} ,
} ) ;
if ( loading === "loading" ) {
return < div className = "spinner" > Loading recovery status ...< / d i v > ;
}
if ( error ) {
return (
< div className = "error" >
< p > { error} < / p >
< button onClick = { clearError} > Dismiss < / b u t t o n >
< button onClick = { refetch} > Retry < / b u t t o n >
< / div >
) ;
}
if ( ! timeline ) {
return < div > No recovery data available < / d i v > ;
}
return (
< div className = "space-y-4" >
{ isStale && (
< div className = "warning" >
< p > Data is stale < / p >
< button onClick = { refetch} > Refresh < / b u t t o n >
< / div >
) }
< RecoveryTimelineList events = { timeline . events } / >
< / div >
) ;
}
export function RecoveryWithPolling ( ) {
const {
timeline,
loading,
startPolling,
stopPolling,
} = useRecoveryStatus ( "wallet-123" , {
autoFetch : true ,
pollInterval : 10000 ,
} ) ;
return (
< div >
< div className = "controls" >
< button onClick = { startPolling} > Start Polling < / b u t t o n >
< button onClick = { stopPolling} > Stop Polling < / b u t t o n >
< / div >
{ loading = = = "loading" && < div > Loading ...< / d i v > }
{ timeline && < RecoveryTimelineList events = { timeline . events } / > }
< / div >
) ;
}
export function RecoveryWithRetry ( ) {
const { timeline, error, refetch, isError } = useRecoveryStatus (
"wallet-123"
) ;
const handleRetry = async ( ) => {
await refetch ( ) ;
} ;
if ( isError ) {
return (
< div className = "error-container" >
< h2 > Failed to load recovery status < / h 2 >
< p > { error} < / p >
< button onClick = { handleRetry} className = "retry-button" >
Try Again
< / b u t t o n >
< / div >
) ;
}
return timeline ? (
< RecoveryTimelineList events = { timeline . events } / >
) : null ;
}
# Check environment variable
echo $NEXT_PUBLIC_API_URL
# Verify API is running
curl https://api.example.com/health
// Check if status is in_progress
console . log ( timeline ?. status ) ;
// Manually start polling
startPolling ( ) ;
// Refresh data
refetch ( ) ;
// Check when data was fetched
console . log ( lastFetchTime ) ;
Read RECOVERY_API_DOCUMENTATION.md for detailed info
Check src/services/recoveryApi.ts for API service
Review src/hooks/useRecoveryStatus.ts for hook
Check tests in src/services/tests / and src/hooks/tests /
Integrate into your recovery page