Skip to content

Commit

Permalink
Use localStorage to cache logged-in user (#124)
Browse files Browse the repository at this point in the history
* Use localStorage to cache logged-in user

* Rename import to use existing variable name

* Update frontend/src/views/ProfileView.vue

Co-authored-by: Andreas <mail@devmount.de>

---------

Co-authored-by: Andreas <mail@devmount.de>
  • Loading branch information
radishmouse and devmount authored Sep 18, 2023
1 parent 221090d commit 52639a9
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 5 deletions.
13 changes: 9 additions & 4 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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([]);
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/SettingsAccount.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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();
Expand Down
73 changes: 73 additions & 0 deletions frontend/src/stores/user-store.js
Original file line number Diff line number Diff line change
@@ -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,
});
}
4 changes: 3 additions & 1 deletion frontend/src/views/ProfileView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@
</template>

<script setup>
import { subscriberLevels, appointmentState } from '@/definitions';
import { inject, computed, onMounted } from 'vue';
import { keyByValue } from '@/utils';
import { useI18n } from 'vue-i18n';
import { subscriberLevels, appointmentState } from '@/definitions';
import { removeUserFromStorage } from '@/stores/user-store';
import PrimaryButton from '@/elements/PrimaryButton';
// icons
Expand All @@ -58,6 +59,7 @@ const pendingAppointments = computed(() => props.appointments.filter((a) => a.st
// do log out
const logout = () => {
removeUserFromStorage();
auth.logout({
logoutParams: {
returnTo: window.location.origin,
Expand Down

0 comments on commit 52639a9

Please sign in to comment.