diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 376ea177..6274014a 100755 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -34,6 +34,11 @@ import NavBar from '@/components/NavBar'; import TitleBar from '@/components/TitleBar'; import SiteNotification from '@/elements/SiteNotification'; import { siteNotificationStore } from '@/stores/alert-store'; + +// current user object +// structure: { username, email, name, level, timezone, id } +import { userStore as currentUser } from '@/stores/user-store'; + // component constants const apiUrl = inject('apiUrl'); const dj = inject('dayjs'); @@ -91,10 +96,6 @@ provide('call', call); // menu items for main navigation const navItems = ['calendar', 'appointments', 'settings']; -// current user object -// structure: { username, email, name, level, timezone, id } -const currentUser = ref(null); - // db tables const calendars = ref([]); const appointments = ref([]); @@ -107,6 +108,10 @@ const routeIsPublic = computed( // check login state of current user first const checkLogin = async () => { if (auth.isAuthenticated.value) { + if (currentUser.value) { + // avoid calling the backend unnecessarily + return; + } // call backend to create user if they do not exist in database const { data, error } = await call('login').get().json(); // assign authed user data diff --git a/frontend/src/components/SettingsAccount.vue b/frontend/src/components/SettingsAccount.vue index 61baf463..e8967626 100644 --- a/frontend/src/components/SettingsAccount.vue +++ b/frontend/src/components/SettingsAccount.vue @@ -132,6 +132,7 @@ import PrimaryButton from '@/elements/PrimaryButton.vue'; import SecondaryButton from '@/elements/SecondaryButton.vue'; import TextButton from '@/elements/TextButton.vue'; import CautionButton from '@/elements/CautionButton.vue'; +import { updateUserInStorage } from '@/stores/user-store'; // view properties const props = defineProps({ @@ -197,6 +198,8 @@ const updateUser = async () => { }; const { error } = await call('me').put(inputData).json(); if (!error.value) { + // Trigger update to user in localStorage + updateUserInStorage(inputData); errorUsername.value = false; // TODO show some confirmation await refreshData(); diff --git a/frontend/src/stores/user-store.js b/frontend/src/stores/user-store.js new file mode 100644 index 00000000..d5c7f04b --- /dev/null +++ b/frontend/src/stores/user-store.js @@ -0,0 +1,73 @@ +import { ref, watch } from 'vue'; + +const STORAGE_KEY = 'tba/user'; + +const keys = [ + 'email', + 'level', + 'name', + 'timezone', + 'username', +]; + +let userObj = null; + +function load() { + // Retrieve values from localStorage + const jsonData = localStorage.getItem(STORAGE_KEY); + if (jsonData) { + try { + const data = JSON.parse(jsonData); + userObj = { + ...data, + }; + } catch (e) { + // console.log('Could not parse user from localStorage'); + } + } +} + +function store(data) { + try { + const jsonData = JSON.stringify(data); + localStorage.setItem(STORAGE_KEY, jsonData); + } catch (e) { + // console.log('Could not stringify and store to localStorage'); + } +} + +function copyRefValuesToObj(aRef, obj) { + keys.forEach((k) => { + try { + obj[k] = aRef[k] ?? aRef.value[k]; + } catch (e) { + // console.log(e); + } + }); +} + +// Attempt initial load of data +load(); +export const userStore = ref(userObj); + +// Store in localStorage on update +watch(userStore, (newUser) => { + const data = {}; + copyRefValuesToObj(newUser, data); + store(data); +}); + +export function removeUserFromStorage() { + localStorage.removeItem(STORAGE_KEY); +} + +export function updateUserInStorage(obj) { + // Provides a way to update the userStore + // from a component that received it as a prop + const data = {}; + copyRefValuesToObj(userStore, data); + store({ + ...data, + ...obj, + }); +} diff --git a/frontend/src/views/ProfileView.vue b/frontend/src/views/ProfileView.vue index ab72d422..5284947a 100755 --- a/frontend/src/views/ProfileView.vue +++ b/frontend/src/views/ProfileView.vue @@ -30,10 +30,11 @@