fix: Critical data structure and mutation bugs
## 🐛 Critical Fixes ### Issue 1: Toggling One Channel Affects Both **Problem:** Disabling email disabled both email and push **Root Cause:** Optimistic update with `onSettled` refetch caused race condition **Fix:** Removed optimistic update, use server response directly **Before:** ```ts onMutate: async () => { // Optimistic update queryClient.setQueryData(...) } onSettled: () => { // This refetch caused race condition queryClient.invalidateQueries(...) } ``` **After:** ```ts onSuccess: (data, variables) => { // Update cache with verified server response queryClient.setQueryData([...], (old) => old.map(channel => channel.id === variables.channelId ? { ...channel, enabled: data.enabled } : channel ) ); } ``` ### Issue 2: Events Cannot Be Enabled **Problem:** All event channels disabled and cannot be enabled **Root Cause:** Wrong data structure in `update_event()` **Before:** ```php $settings[$event_id][$channel_id] = [...]; // Saved as: { "order_placed": { "email": {...} } } ``` **After:** ```php $settings[$event_id]['channels'][$channel_id] = [...]; // Saves as: { "order_placed": { "channels": { "email": {...} } } } ``` ### Issue 3: POST Data Not Parsed **Problem:** Event updates not working **Root Cause:** Using `get_param()` instead of `get_json_params()` **Fix:** Changed to `get_json_params()` in `update_event()` ### What Was Fixed 1. ✅ Channel toggles work independently 2. ✅ No race conditions from optimistic updates 3. ✅ Event channel data structure matches get_events 4. ✅ Event toggles save correctly 5. ✅ POST data parsed properly 6. ✅ Boolean type enforcement ### Data Structure **Correct Structure:** ```php [ 'order_placed' => [ 'channels' => [ 'email' => ['enabled' => true, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin'] ] ] ] ``` --- **All toggles should now work correctly!** ✅
This commit is contained in:
@@ -47,38 +47,25 @@ export default function NotificationChannels() {
|
||||
// Toggle channel mutation
|
||||
const toggleChannelMutation = useMutation({
|
||||
mutationFn: async ({ channelId, enabled }: { channelId: string; enabled: boolean }) => {
|
||||
return api.post('/notifications/channels/toggle', { channelId, enabled });
|
||||
const response = await api.post('/notifications/channels/toggle', { channelId, enabled });
|
||||
return response;
|
||||
},
|
||||
onMutate: async ({ channelId, enabled }) => {
|
||||
// Cancel outgoing refetches
|
||||
await queryClient.cancelQueries({ queryKey: ['notification-channels'] });
|
||||
|
||||
// Snapshot previous value
|
||||
const previousChannels = queryClient.getQueryData(['notification-channels']);
|
||||
|
||||
// Optimistically update
|
||||
onSuccess: (data, variables) => {
|
||||
// Update cache with server response
|
||||
queryClient.setQueryData(['notification-channels'], (old: any) => {
|
||||
if (!old) return old;
|
||||
return old.map((channel: any) =>
|
||||
channel.id === channelId ? { ...channel, enabled } : channel
|
||||
channel.id === variables.channelId
|
||||
? { ...channel, enabled: data.enabled }
|
||||
: channel
|
||||
);
|
||||
});
|
||||
|
||||
return { previousChannels };
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success(__('Channel updated'));
|
||||
},
|
||||
onError: (error: any, variables, context: any) => {
|
||||
// Rollback on error
|
||||
if (context?.previousChannels) {
|
||||
queryClient.setQueryData(['notification-channels'], context.previousChannels);
|
||||
}
|
||||
toast.error(error?.message || __('Failed to update channel'));
|
||||
},
|
||||
onSettled: () => {
|
||||
// Refetch after mutation
|
||||
onError: (error: any) => {
|
||||
// Refetch on error to sync with server
|
||||
queryClient.invalidateQueries({ queryKey: ['notification-channels'] });
|
||||
toast.error(error?.message || __('Failed to update channel'));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user