Added infrastructure for editable properties in settings page.

This commit is contained in:
Andrew Lalis 2023-02-16 10:20:05 +01:00
parent 40891656d0
commit 88089f2e11
4 changed files with 144 additions and 12 deletions

View File

@ -127,10 +127,20 @@ class AuthModule {
return response.data;
}
public async updateMyPersonalDetails(authStore: AuthStoreType, newPersonalDetails: UserPersonalDetails): Promise<UserPersonalDetails> {
const response = await api.post('/auth/me/personal-details', newPersonalDetails, authStore.axiosConfig);
return response.data;
}
public async getMyPreferences(authStore: AuthStoreType): Promise<UserPreferences> {
const response = await api.get('/auth/me/preferences', authStore.axiosConfig);
return response.data;
}
public async updateMyPreferences(authStore: AuthStoreType, newPreferences: UserPreferences): Promise<UserPreferences> {
const response = await api.post('/auth/me/preferences', newPreferences, authStore.axiosConfig);
return response.data;
}
}
export default AuthModule;

View File

@ -0,0 +1,42 @@
<template>
<div class="row justify-between">
<span class="property-label">{{ label }}</span>
<div v-if="typeof modelValue === 'string'">
<q-input
:model-value="modelValue"
@update:modelValue="onValueUpdated"
:type="inputType"
dense
/>
</div>
<div v-if="typeof modelValue === 'boolean'">
<q-toggle :model-value="modelValue" @update:modelValue="onValueUpdated"/>
</div>
</div>
</template>
<script setup lang="ts">
import {DateTime} from 'luxon';
interface Props {
label: string;
inputType?: any;
modelValue: string | number | boolean | DateTime;
}
defineProps<Props>();
const emits = defineEmits(['update:modelValue']);
function onValueUpdated(newValue: string) {
emits('update:modelValue', newValue);
}
</script>
<style scoped>
.property-label {
font-weight: bold;
margin-top: auto;
margin-bottom: auto;
}
</style>

View File

@ -47,7 +47,15 @@ export default {
}
},
userSettingsPage: {
title: 'Account Settings'
title: 'Account Settings',
personalDetails: {
birthDate: 'Date of Birth'
},
preferences: {
accountPrivate: 'Private Account'
},
save: 'Save',
undo: 'Undo'
},
accountMenuItem: {
logIn: 'Login',

View File

@ -3,33 +3,105 @@
<StandardCenteredPage>
<h3>{{ $t('userSettingsPage.title') }}</h3>
<hr>
<q-form>
<div v-if="personalDetails">
<h4>Personal Information</h4>
<EditablePropertyRow
v-model="personalDetails.birthDate"
:label="$t('userSettingsPage.personalDetails.birthDate')"
input-type="date"
/>
<div v-if="personalDetailsChanged">
<q-btn :label="$t('userSettingsPage.save')" color="positive" @click="savePersonalDetails"/>
<q-btn :label="$t('userSettingsPage.undo')" color="secondary" @click="undoPersonalDetailsChanges"/>
</div>
</div>
<div v-if="preferences">
<h4>Preferences</h4>
<EditablePropertyRow
v-model="preferences.accountPrivate"
:label="$t('userSettingsPage.preferences.accountPrivate')"
/>
<div v-if="preferencesChanged">
<q-btn :label="$t('userSettingsPage.save')" color="positive" @click="savePreferences"/>
<q-btn :label="$t('userSettingsPage.undo')" color="secondary" @click="undoPreferencesChanges"/>
</div>
</div>
</q-form>
</StandardCenteredPage>
</q-page>
</template>
<script setup lang="ts">
import StandardCenteredPage from 'components/StandardCenteredPage.vue';
import { User } from 'src/api/main/auth';
import { getUserRoute } from 'src/router/user-routing';
import { useAuthStore } from 'src/stores/auth-store';
import { onMounted } from 'vue';
import {useRoute, useRouter} from 'vue-router';
import {useAuthStore} from 'stores/auth-store';
import {computed, onMounted, ref, Ref, toRaw} from 'vue';
import {UserPersonalDetails, UserPreferences} from 'src/api/main/auth';
import api from 'src/api/main';
import EditablePropertyRow from 'components/EditablePropertyRow.vue';
const route = useRoute();
const router = useRouter();
const authStore = useAuthStore();
const personalDetails: Ref<UserPersonalDetails | undefined> = ref();
const preferences: Ref<UserPreferences | undefined> = ref();
let initialPersonalDetails: UserPersonalDetails | null = null;
let initialPreferences: UserPreferences | null = null;
onMounted(async () => {
// If the user isn't on their own settings page, redirect them back to the user's profile page.
// Redirect away from the page if the user isn't viewing their own settings.
const userId = route.params.userId as string;
if (authStore.user?.id !== userId) {
if (!authStore.user || authStore.user.id !== userId) {
await router.push(`/users/${userId}`);
}
personalDetails.value = await api.auth.getMyPersonalDetails(authStore);
initialPersonalDetails = structuredClone(toRaw(personalDetails.value));
preferences.value = await api.auth.getMyPreferences(authStore);
initialPreferences = structuredClone(toRaw(preferences.value));
});
const personalDetailsChanged = computed(() => {
return initialPersonalDetails !== null &&
JSON.stringify(initialPersonalDetails) !== JSON.stringify(personalDetails.value);
});
const preferencesChanged = computed(() => {
return initialPreferences !== null &&
JSON.stringify(initialPreferences) !== JSON.stringify(preferences.value);
});
async function savePersonalDetails() {
if (personalDetails.value) {
personalDetails.value = await api.auth.updateMyPersonalDetails(authStore, personalDetails.value);
initialPersonalDetails = structuredClone(toRaw(personalDetails.value));
}
}
function undoPersonalDetailsChanges() {
personalDetails.value = structuredClone(initialPersonalDetails);
}
async function savePreferences() {
if (preferences.value) {
preferences.value = await api.auth.updateMyPreferences(authStore, preferences.value);
initialPreferences = structuredClone(toRaw(preferences.value));
}
}
function undoPreferencesChanges() {
preferences.value = structuredClone(initialPreferences);
}
</script>
<style scoped>
</style>