@oxyhq/services
Version:
126 lines (120 loc) • 3.4 kB
JavaScript
;
import { useState, useCallback, useEffect } from 'react';
import { toast } from '../../lib/sonner';
/**
* Hook for handling boolean toggle settings with optimistic updates.
* Automatically reverts to the previous value if the save fails.
*
* @example
* const { value, toggle, isSaving } = useSettingToggle({
* initialValue: user.notificationsEnabled,
* onSave: (value) => api.updateNotifications(value),
* errorMessage: 'Failed to update notifications',
* });
*
* <Switch value={value} onValueChange={toggle} disabled={isSaving} />
*/
export function useSettingToggle(options) {
const {
initialValue,
onSave,
successMessage,
errorMessage = 'Failed to save setting',
revertOnError = true,
showSuccessToast = false
} = options;
const [value, setValue] = useState(initialValue);
const [isSaving, setIsSaving] = useState(false);
// Update value when initialValue changes (e.g., from server)
useEffect(() => {
setValue(initialValue);
}, [initialValue]);
const toggle = useCallback(async () => {
const previousValue = value;
const newValue = !value;
// Optimistic update
setValue(newValue);
setIsSaving(true);
try {
await onSave(newValue);
if (showSuccessToast && successMessage) {
toast.success(successMessage);
}
} catch (err) {
// Revert on error
if (revertOnError) {
setValue(previousValue);
}
toast.error(errorMessage || err?.message || 'An error occurred');
} finally {
setIsSaving(false);
}
}, [value, onSave, successMessage, errorMessage, revertOnError, showSuccessToast]);
return {
value,
isSaving,
toggle,
setValue
};
}
/**
* Hook for managing multiple toggle settings at once.
* Useful when you have several related boolean settings.
*/
export function useSettingToggles(options) {
const {
initialValues,
onSave,
errorMessage = 'Failed to save setting',
revertOnError = true
} = options;
const [values, setValues] = useState(initialValues);
const [savingKeys, setSavingKeys] = useState(new Set());
// Update values when initialValues change
useEffect(() => {
setValues(initialValues);
}, [initialValues]);
const toggle = useCallback(async key => {
const previousValue = values[key];
const newValue = !previousValue;
// Optimistic update
setValues(prev => ({
...prev,
[key]: newValue
}));
setSavingKeys(prev => new Set(prev).add(key));
try {
await onSave(key, newValue);
} catch (err) {
// Revert on error
if (revertOnError) {
setValues(prev => ({
...prev,
[key]: previousValue
}));
}
const message = typeof errorMessage === 'function' ? errorMessage(key) : errorMessage;
toast.error(message || err?.message || 'An error occurred');
} finally {
setSavingKeys(prev => {
const next = new Set(prev);
next.delete(key);
return next;
});
}
}, [values, onSave, errorMessage, revertOnError]);
const setValuesExternal = useCallback(newValues => {
setValues(prev => ({
...prev,
...newValues
}));
}, []);
return {
values,
savingKeys,
toggle,
setValues: setValuesExternal
};
}
export default useSettingToggle;
//# sourceMappingURL=useSettingToggle.js.map