1- import type { Action , ThunkAction } from '@reduxjs/toolkit ' ;
1+ import { isNil } from 'lodash ' ;
22
33import type {
44 GetSettingsParams ,
55 GetSingleSettingParams ,
66 SetSingleSettingParams ,
7+ Setting ,
78} from '../../../types/api/settings' ;
8- import type { RootState } from '../../defaultStore' ;
9+ import type { AppDispatch } from '../../defaultStore' ;
910import { api } from '../api' ;
1011
1112import { SETTINGS_OPTIONS } from './constants' ;
1213
1314export const settingsApi = api . injectEndpoints ( {
1415 endpoints : ( builder ) => ( {
1516 getSingleSetting : builder . query ( {
16- queryFn : async ( { name, user} : GetSingleSettingParams ) => {
17+ queryFn : async ( { name, user} : GetSingleSettingParams , baseApi ) => {
1718 try {
1819 if ( ! window . api . metaSettings ) {
1920 throw new Error ( 'MetaSettings API is not available' ) ;
@@ -24,12 +25,17 @@ export const settingsApi = api.injectEndpoints({
2425 // Directly access options here to avoid them in cache key
2526 preventBatching : SETTINGS_OPTIONS [ name ] ?. preventBatching ,
2627 } ) ;
28+
29+ const dispatch = baseApi . dispatch as AppDispatch ;
30+
31+ // Try to sync local value if there is no backend value
32+ syncLocalValueToMetaIfNoData ( data , dispatch ) ;
33+
2734 return { data} ;
2835 } catch ( error ) {
2936 return { error} ;
3037 }
3138 } ,
32- providesTags : ( _ , __ , args ) => [ { type : 'UserData' , id : `Setting_${ args . name } ` } ] ,
3339 } ) ,
3440 setSingleSetting : builder . mutation ( {
3541 queryFn : async ( params : SetSingleSettingParams ) => {
@@ -66,14 +72,15 @@ export const settingsApi = api.injectEndpoints({
6672 } ,
6773 } ) ,
6874 getSettings : builder . query ( {
69- queryFn : async ( { name, user} : GetSettingsParams , { dispatch } ) => {
75+ queryFn : async ( { name, user} : GetSettingsParams , baseApi ) => {
7076 try {
7177 if ( ! window . api . metaSettings ) {
7278 throw new Error ( 'MetaSettings API is not available' ) ;
7379 }
7480 const data = await window . api . metaSettings . getSettings ( { name, user} ) ;
7581
76- const patches : ThunkAction < unknown , RootState , unknown , Action > [ ] = [ ] ;
82+ const patches : Promise < void > [ ] = [ ] ;
83+ const dispatch = baseApi . dispatch as AppDispatch ;
7784
7885 // Upsert received data in getSingleSetting cache
7986 name . forEach ( ( settingName ) => {
@@ -91,11 +98,20 @@ export const settingsApi = api.injectEndpoints({
9198 cacheEntryParams ,
9299 newValue ,
93100 ) ,
94- ) ;
101+ ) . then ( ( ) => {
102+ // Try to sync local value if there is no backend value
103+ // Do it after upsert if finished to ensure proper values update order
104+ // 1. New entry added to cache with nil value
105+ // 2. Positive entry update - local storage value replace nil in cache
106+ // 3.1. Set is successful, local value in cache
107+ // 3.2. Set is not successful, cache value reverted to previous nil
108+ syncLocalValueToMetaIfNoData ( settingData , dispatch ) ;
109+ } ) ;
95110
96111 patches . push ( patch ) ;
97112 } ) ;
98113
114+ // Wait for all patches for proper loading state
99115 await Promise . all ( patches ) ;
100116
101117 return { data} ;
@@ -107,3 +123,17 @@ export const settingsApi = api.injectEndpoints({
107123 } ) ,
108124 overrideExisting : 'throw' ,
109125} ) ;
126+
127+ function syncLocalValueToMetaIfNoData ( params : Setting , dispatch : AppDispatch ) {
128+ const localValue = localStorage . getItem ( params . name ) ;
129+
130+ if ( isNil ( params . value ) && ! isNil ( localValue ) ) {
131+ dispatch (
132+ settingsApi . endpoints . setSingleSetting . initiate ( {
133+ name : params . name ,
134+ user : params . user ,
135+ value : localValue ,
136+ } ) ,
137+ ) ;
138+ }
139+ }
0 commit comments