Added infrastructure for editable properties in settings page.
This commit is contained in:
parent
40891656d0
commit
88089f2e11
|
@ -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;
|
||||
|
|
|
@ -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>
|
|
@ -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',
|
||||
|
|
|
@ -3,33 +3,105 @@
|
|||
<StandardCenteredPage>
|
||||
<h3>{{ $t('userSettingsPage.title') }}</h3>
|
||||
<hr>
|
||||
<q-form>
|
||||
|
||||
</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>
|
||||
|
||||
</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 {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>
|
||||
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue