@oxyhq/services
Version:
89 lines (87 loc) • 2.35 kB
JavaScript
;
import { useState, useCallback } from 'react';
import { toast } from '../../lib/sonner';
/**
* Hook for handling async actions with loading state, error handling, and toast notifications.
* Reduces boilerplate for common patterns like try-catch with toast feedback.
*
* @example
* const { execute, isLoading } = useAsyncAction({
* action: () => api.saveSettings(settings),
* successMessage: 'Settings saved!',
* errorMessage: 'Failed to save settings',
* });
*
* <Button onPress={execute} disabled={isLoading}>Save</Button>
*/
export function useAsyncAction(options) {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const execute = useCallback(async () => {
const {
action,
successMessage,
errorMessage,
onSuccess,
onError,
showLoadingToast,
loadingMessage
} = options;
setIsLoading(true);
setError(null);
if (showLoadingToast && loadingMessage) {
toast.loading(loadingMessage);
}
try {
const result = await action();
if (successMessage) {
toast.success(successMessage);
}
onSuccess?.(result);
return result;
} catch (err) {
const message = typeof errorMessage === 'function' ? errorMessage(err) : errorMessage || err?.message || 'An error occurred';
toast.error(message);
setError(err instanceof Error ? err : new Error(message));
onError?.(err);
return undefined;
} finally {
setIsLoading(false);
}
}, [options]);
const resetError = useCallback(() => {
setError(null);
}, []);
return {
execute,
isLoading,
error,
resetError
};
}
/**
* Simplified version that just executes an async action with toast feedback.
* Useful for one-off actions.
*/
export async function executeWithToast(action, options) {
const {
successMessage,
errorMessage,
loadingMessage
} = options || {};
if (loadingMessage) {
toast.loading(loadingMessage);
}
try {
const result = await action();
if (successMessage) {
toast.success(successMessage);
}
return result;
} catch (err) {
toast.error(errorMessage || err?.message || 'An error occurred');
return undefined;
}
}
export default useAsyncAction;
//# sourceMappingURL=useAsyncAction.js.map