Skip to content

Commit 5daa10a

Browse files
fix: sync local value to meta in api
1 parent f18e12b commit 5daa10a

File tree

4 files changed

+40
-46
lines changed

4 files changed

+40
-46
lines changed

src/store/reducers/settings/api.ts

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
import type {Action, ThunkAction} from '@reduxjs/toolkit';
1+
import {isNil} from 'lodash';
22

33
import 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';
910
import {api} from '../api';
1011

1112
import {SETTINGS_OPTIONS} from './constants';
1213

1314
export 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+
}

src/store/reducers/settings/useSetting.ts

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import type {SettingKey} from './constants';
1414
import {DEFAULT_USER_SETTINGS, SETTINGS_OPTIONS} from './constants';
1515
import {getSettingValue, setSettingValue} from './settings';
1616
import {
17-
deleteValueFromLS,
1817
parseSettingValue,
1918
readSettingValueFromLS,
2019
setSettingValueToLS,
@@ -81,34 +80,6 @@ export function useSetting<T>(
8180
}
8281
}, [shouldUseMetaSettings, shouldUseOnlyExternalSettings, metaSetting, name, dispatch]);
8382

84-
// Load local value to backend
85-
React.useEffect(() => {
86-
const savedValue = readSettingValueFromLS<T>(name);
87-
88-
const isMetaSettingEmpty = !isSettingLoading && !metaSetting?.value;
89-
90-
if (shouldUseMetaSettings && isMetaSettingEmpty && savedValue) {
91-
setMetaSetting({name, user, value: stringifySettingValue(savedValue)})
92-
.unwrap()
93-
.then(() => {
94-
if (shouldUseOnlyExternalSettings) {
95-
deleteValueFromLS(name);
96-
}
97-
})
98-
.catch((error) => {
99-
console.error('Failed to set setting via meta API:', error);
100-
});
101-
}
102-
}, [
103-
shouldUseMetaSettings,
104-
shouldUseOnlyExternalSettings,
105-
metaSetting,
106-
isSettingLoading,
107-
name,
108-
user,
109-
setMetaSetting,
110-
]);
111-
11283
const debouncedSetMetaSetting = React.useMemo(
11384
() =>
11485
debounce((params: SetSingleSettingParams) => {

src/store/reducers/settings/utils.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import {parseJson} from '../../../utils/utils';
44
export function stringifySettingValue<T>(value?: T): string {
55
return typeof value === 'string' ? value : JSON.stringify(value);
66
}
7-
export function parseSettingValue<T>(value: SettingValue) {
7+
export function parseSettingValue<T>(value?: SettingValue) {
88
try {
99
return (typeof value === 'string' ? parseJson(value) : value) as T;
1010
} catch {
1111
return undefined;
1212
}
1313
}
14-
export function readSettingValueFromLS<T>(name: string | undefined): T | undefined {
14+
export function readSettingValueFromLS<T = unknown>(name: string | undefined): T | undefined {
1515
if (!name) {
1616
return undefined;
1717
}
@@ -34,10 +34,3 @@ export function setSettingValueToLS(name: string | undefined, value: unknown): v
3434
localStorage.setItem(name, preparedValue);
3535
} catch {}
3636
}
37-
export function deleteValueFromLS(name: string | undefined) {
38-
if (!name) {
39-
return;
40-
}
41-
42-
localStorage.removeItem(name);
43-
}

src/types/api/settings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export type GetSettingResponse = Record<string, Setting>;
66
export interface Setting {
77
user: string;
88
name: string;
9-
value?: string | Record<string, string>;
9+
value?: SettingValue;
1010
}
1111
export type SettingValue = string | Record<string, string>;
1212
export interface GetSingleSettingParams {

0 commit comments

Comments
 (0)