Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: only save updated settings to server, store theme and landingpage in localStorage as well #573

Merged
merged 1 commit into from
May 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 2 additions & 18 deletions src/components/UserSatisfactionPoll.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ import moment from 'moment';
import { useSettingsStore } from '~/stores/settings';

const NUM_OPTIONS = 10;
// INITIAL_WAIT_PERIOD is how long to wait from initialTimestamp to the first time that the poll shows up
const INITIAL_WAIT_PERIOD = 7 * 24 * 60 * 60;
// BACKOFF_PERIOD is how many seconds to wait to show the poll again if the user closed it
const BACKOFF_PERIOD = 7 * 24 * 60 * 60;
// The following may be used for testing
Expand Down Expand Up @@ -106,16 +104,6 @@ export default {
},
},
async mounted() {
// Get the rest of the data
const settingsStore = useSettingsStore();
if (!this.data) {
this.data = {
isEnabled: true,
nextPollTime: settingsStore.initialTimestamp.add(INITIAL_WAIT_PERIOD, 'seconds'),
timesPollIsShown: 0,
};
}

if (!this.data.isEnabled) {
return;
}
Expand All @@ -135,9 +123,7 @@ export default {
methods: {
submit() {
this.isPollVisible = false;
const data = this.data;
data.isEnabled = false;
this.data = data;
this.data = { ...this.data, isEnabled: false };

if (parseInt(this.rating) >= 6) {
this.isPosFollowUpVisible = true;
Expand All @@ -147,9 +133,7 @@ export default {
},
dontShowAgain() {
this.isPollVisible = false;
const data = this.data;
data.isEnabled = false;
this.data = data;
this.data = { ...this.data, isEnabled: false };
},
},
};
Expand Down
65 changes: 54 additions & 11 deletions src/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@ import moment, { Moment } from 'moment';
import { getClient } from '~/util/awclient';
import { Category, defaultCategories } from '~/util/classes';
import { View, defaultViews } from '~/stores/views';
import { isEqual } from 'lodash';

function jsonEq(a: any, b: any) {
const jsonA = JSON.parse(JSON.stringify(a));
const jsonB = JSON.parse(JSON.stringify(b));
return isEqual(jsonA, jsonB);
}

// Backoffs for NewReleaseNotification
export const SHORT_BACKOFF_PERIOD = 24 * 60 * 60;
export const LONG_BACKOFF_PERIOD = 5 * 24 * 60 * 60;

// Initial wait period for UserSatisfactionPoll
export const INITIAL_WAIT_PERIOD = 7 * 24 * 60 * 60;

interface State {
// Timestamp when user was first seen (first time webapp is run)
initialTimestamp: Moment;
Expand All @@ -20,7 +30,11 @@ interface State {
theme: 'light' | 'dark';

newReleaseCheckData: Record<string, any>;
userSatisfactionPollData: Record<string, any>;
userSatisfactionPollData: {
isEnabled: boolean;
nextPollTime: Moment;
timesPollIsShown: number;
};
always_active_pattern: string;
classes: Category[];
views: View[];
Expand Down Expand Up @@ -53,7 +67,11 @@ export const useSettingsStore = defineStore('settings', {
howOftenToCheck: SHORT_BACKOFF_PERIOD,
timesChecked: 0,
},
userSatisfactionPollData: {},
userSatisfactionPollData: {
isEnabled: true,
nextPollTime: moment().add(INITIAL_WAIT_PERIOD, 'seconds'),
timesPollIsShown: 0,
},

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

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

// Save to localStorage and backend
// NOTE: localStorage deprecated, will be removed in future
const client = getClient();

// Fetch current settings from server
const server_settings = await client.get_settings();

// Save settings
for (const key of Object.keys(this.$state)) {
// Skip keys starting with underscore, as they are local to the vuex store.
if (key.startsWith('_')) {
continue;
}

const value = this.$state[key];

// Save to localStorage
if (saveToLocalStorage) {
// NOTE: we always save the theme and landingpage to localStorage, since they are used before the settings are loaded
if (saveToLocalStorage || key == 'theme' || key == 'landingpage') {
if (typeof value === 'object') {
localStorage.setItem(key, JSON.stringify(value));
} else {
localStorage.setItem(key, value);
}
}

// Save to backend
await client.req.post('/0/settings/' + key, value, {
headers: {
'Content-Type': 'application/json',
},
});
// Save changed settings to backend
if (server_settings[key] === undefined || !jsonEq(server_settings[key], value)) {
if (server_settings[key] === undefined && value === false) {
// Skip saving settings that are set to false and not already saved on the server
continue;
}
console.log('Saving', { [key]: value });
//console.log('Was:', server_settings[key]);
//console.log('Now:', value);
await client.req.post('/0/settings/' + key, value, {
headers: {
'Content-Type': 'application/json',
},
});
}
}

// After save, reload
Expand Down
Loading