Skip to content

Commit 021acc4

Browse files
authored
fix: only save updated settings to server, store theme and landingpage in localStorage as well (#573)
1 parent bf16309 commit 021acc4

File tree

2 files changed

+56
-29
lines changed

2 files changed

+56
-29
lines changed

src/components/UserSatisfactionPoll.vue

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ import moment from 'moment';
7070
import { useSettingsStore } from '~/stores/settings';
7171
7272
const NUM_OPTIONS = 10;
73-
// INITIAL_WAIT_PERIOD is how long to wait from initialTimestamp to the first time that the poll shows up
74-
const INITIAL_WAIT_PERIOD = 7 * 24 * 60 * 60;
7573
// BACKOFF_PERIOD is how many seconds to wait to show the poll again if the user closed it
7674
const BACKOFF_PERIOD = 7 * 24 * 60 * 60;
7775
// The following may be used for testing
@@ -106,16 +104,6 @@ export default {
106104
},
107105
},
108106
async mounted() {
109-
// Get the rest of the data
110-
const settingsStore = useSettingsStore();
111-
if (!this.data) {
112-
this.data = {
113-
isEnabled: true,
114-
nextPollTime: settingsStore.initialTimestamp.add(INITIAL_WAIT_PERIOD, 'seconds'),
115-
timesPollIsShown: 0,
116-
};
117-
}
118-
119107
if (!this.data.isEnabled) {
120108
return;
121109
}
@@ -135,9 +123,7 @@ export default {
135123
methods: {
136124
submit() {
137125
this.isPollVisible = false;
138-
const data = this.data;
139-
data.isEnabled = false;
140-
this.data = data;
126+
this.data = { ...this.data, isEnabled: false };
141127
142128
if (parseInt(this.rating) >= 6) {
143129
this.isPosFollowUpVisible = true;
@@ -147,9 +133,7 @@ export default {
147133
},
148134
dontShowAgain() {
149135
this.isPollVisible = false;
150-
const data = this.data;
151-
data.isEnabled = false;
152-
this.data = data;
136+
this.data = { ...this.data, isEnabled: false };
153137
},
154138
},
155139
};

src/stores/settings.ts

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,21 @@ import moment, { Moment } from 'moment';
33
import { getClient } from '~/util/awclient';
44
import { Category, defaultCategories } from '~/util/classes';
55
import { View, defaultViews } from '~/stores/views';
6+
import { isEqual } from 'lodash';
7+
8+
function jsonEq(a: any, b: any) {
9+
const jsonA = JSON.parse(JSON.stringify(a));
10+
const jsonB = JSON.parse(JSON.stringify(b));
11+
return isEqual(jsonA, jsonB);
12+
}
613

714
// Backoffs for NewReleaseNotification
815
export const SHORT_BACKOFF_PERIOD = 24 * 60 * 60;
916
export const LONG_BACKOFF_PERIOD = 5 * 24 * 60 * 60;
1017

18+
// Initial wait period for UserSatisfactionPoll
19+
export const INITIAL_WAIT_PERIOD = 7 * 24 * 60 * 60;
20+
1121
interface State {
1222
// Timestamp when user was first seen (first time webapp is run)
1323
initialTimestamp: Moment;
@@ -20,7 +30,11 @@ interface State {
2030
theme: 'light' | 'dark';
2131

2232
newReleaseCheckData: Record<string, any>;
23-
userSatisfactionPollData: Record<string, any>;
33+
userSatisfactionPollData: {
34+
isEnabled: boolean;
35+
nextPollTime: Moment;
36+
timesPollIsShown: number;
37+
};
2438
always_active_pattern: string;
2539
classes: Category[];
2640
views: View[];
@@ -53,7 +67,11 @@ export const useSettingsStore = defineStore('settings', {
5367
howOftenToCheck: SHORT_BACKOFF_PERIOD,
5468
timesChecked: 0,
5569
},
56-
userSatisfactionPollData: {},
70+
userSatisfactionPollData: {
71+
isEnabled: true,
72+
nextPollTime: moment().add(INITIAL_WAIT_PERIOD, 'seconds'),
73+
timesPollIsShown: 0,
74+
},
5775

5876
always_active_pattern: '',
5977
classes: defaultCategories,
@@ -110,8 +128,8 @@ export const useSettingsStore = defineStore('settings', {
110128
//const locstr = set_in_server ? '[server]' : '[localStorage]';
111129
//console.debug(`${locstr} ${key}:`, value);
112130

113-
// Keys ending with 'Data' are JSON-serialized objects
114-
if (key.includes('Data') && !set_in_server) {
131+
// Keys ending with 'Data' are JSON-serialized objects in localStorage
132+
if (key.endsWith('Data') && !set_in_server) {
115133
try {
116134
storage[key] = JSON.parse(value);
117135
} catch (e) {
@@ -134,31 +152,56 @@ export const useSettingsStore = defineStore('settings', {
134152
}
135153
},
136154
async save() {
155+
// Important check, to avoid saving settings before they are loaded (potentially overwriting them with defaults)
156+
if (!this.loaded) {
157+
console.error('Settings not loaded, not saving');
158+
return;
159+
}
137160
// We want to avoid saving to localStorage to not accidentally mess up pre-migration data
138161
// For example, if the user is using several browsers, and opened in their non-main browser on first run after upgrade.
139162
const saveToLocalStorage = false;
140163

141164
// Save to localStorage and backend
142165
// NOTE: localStorage deprecated, will be removed in future
143166
const client = getClient();
167+
168+
// Fetch current settings from server
169+
const server_settings = await client.get_settings();
170+
171+
// Save settings
144172
for (const key of Object.keys(this.$state)) {
173+
// Skip keys starting with underscore, as they are local to the vuex store.
174+
if (key.startsWith('_')) {
175+
continue;
176+
}
177+
145178
const value = this.$state[key];
146179

147180
// Save to localStorage
148-
if (saveToLocalStorage) {
181+
// NOTE: we always save the theme and landingpage to localStorage, since they are used before the settings are loaded
182+
if (saveToLocalStorage || key == 'theme' || key == 'landingpage') {
149183
if (typeof value === 'object') {
150184
localStorage.setItem(key, JSON.stringify(value));
151185
} else {
152186
localStorage.setItem(key, value);
153187
}
154188
}
155189

156-
// Save to backend
157-
await client.req.post('/0/settings/' + key, value, {
158-
headers: {
159-
'Content-Type': 'application/json',
160-
},
161-
});
190+
// Save changed settings to backend
191+
if (server_settings[key] === undefined || !jsonEq(server_settings[key], value)) {
192+
if (server_settings[key] === undefined && value === false) {
193+
// Skip saving settings that are set to false and not already saved on the server
194+
continue;
195+
}
196+
console.log('Saving', { [key]: value });
197+
//console.log('Was:', server_settings[key]);
198+
//console.log('Now:', value);
199+
await client.req.post('/0/settings/' + key, value, {
200+
headers: {
201+
'Content-Type': 'application/json',
202+
},
203+
});
204+
}
162205
}
163206

164207
// After save, reload

0 commit comments

Comments
 (0)