Initial work on the profile view

This commit is contained in:
Johannes Zellner
2025-01-14 10:27:27 +01:00
parent bffd7c8d24
commit 380791211f
5 changed files with 199 additions and 2 deletions
+138
View File
@@ -0,0 +1,138 @@
<template>
<div class="content">
<InputDialog ref="inputDialog" />
<h1>{{ $t('profile.title') }}</h1>
<Card>
<div style="display: flex;">
<div style="width: 150px;">
<div class="settings-avatar" :style="`background-image: url('${user.avatarUrl}');`" ng-click="avatarChange.showChangeAvatar()">
<i class="picture-edit-indicator fa fa-pencil-alt"></i>
</div>
</div>
<div style="flex-grow: 1;">
<table style="width: 100%; max-width: 1024px;">
<tbody>
<tr>
<td class="text-muted" style="vertical-align: top;">{{ $t('main.username') }}</td>
<td class="text-right" style="vertical-align: top;">
{{ user.username }} &nbsp;&nbsp;&nbsp;
</td>
</tr>
<tr>
<td class="text-muted" style="vertical-align: top;">{{ $t('main.displayName') }}</td>
<td class="text-right" style="vertical-align: top; white-space: nowrap;">
{{ user.displayName }} <Button small tool outline @click="onChangeDisplayName(user.displayName)" v-show="!user.source && !config.profileLocked" icon="fa fa-edit text-small"></Button>
</td>
</tr>
<tr>
<td class="text-muted" style="vertical-align: top;">{{ $t('profile.primaryEmail') }}</td>
<td class="text-right" style="vertical-align: top; white-space: nowrap;">
{{ user.email }} <a href="" ng-click="emailChange.show()" ng-hide="user.source || config.profileLocked"><i class="fa fa-edit text-small"></i></a>
</td>
</tr>
<tr>
<td class="text-muted" style="vertical-align: top;">{{ $t('profile.passwordRecoveryEmail') }}</td>
<td class="text-right" style="vertical-align: top; white-space: nowrap;">
{{ user.fallbackEmail }} <a href="" ng-click="fallbackEmailChange.show()" ng-hide="user.source || config.profileLocked"><i class="fa fa-edit text-small"></i></a>
</td>
</tr>
<tr ng-hide="user.source">
<td colspan="2" class="text-right">
<a href="" ng-click="sendPasswordReset()">{{ $t('profile.passwordResetAction') }}</a>
</td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
<tr>
<td class="text-muted" style="vertical-align: middle;">{{ $t('profile.language') }}</td>
<td class="text-right" style="vertical-align: middle;">
<Dropdown small v-model="language" :options="languages" option-label="display" option-key="id" @select="onSelectLanguage"/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</Card>
</div>
</template>
<script setup>
import { useI18n } from 'vue-i18n';
import { ref, onMounted, useTemplateRef } from 'vue';
import { Button, Dropdown, InputDialog } from 'pankow';
import Card from './Card.vue';
import ProfileModel from '../models/ProfileModel.js';
import CloudronModel from '../models/CloudronModel.js';
const i18n = useI18n();
const t = i18n.t;
const API_ORIGIN = import.meta.env.VITE_API_ORIGIN ? import.meta.env.VITE_API_ORIGIN : window.location.origin;
const profileModel = ProfileModel.create(API_ORIGIN, localStorage.token);
const cloudronModel = CloudronModel.create(API_ORIGIN, localStorage.token);
// TODO what is this?
const config = ref({});
const user = ref({});
const languages = ref([]);
const language = ref('');
const inputDialog = useTemplateRef('inputDialog');
onMounted(async () => {
user.value = await profileModel.get();
const langs = await cloudronModel.languages();
languages.value = langs.map(l => {
return {
id: l,
display: t(`lang.${l}`)
};
}).sort((a, b) => {
return a.display.localeCompare(b.display);
});
const usedLang = window.localStorage.NG_TRANSLATE_LANG_KEY || 'en';
language.value = languages.value.find(l => l.id === usedLang).id;
});
async function onSelectLanguage(lang) {
window.localStorage.NG_TRANSLATE_LANG_KEY = lang.id;
const error = await profileModel.setLanguage(lang.id);
if (error) console.error('Failed to set language', error);
else window.location.reload();
// TODO dynamically change lange instead of reloading
}
async function onChangeDisplayName(currentDisplayName) {
const displayName = await inputDialog.value.prompt({
message: 'Display Name',
modal: false,
value: currentDisplayName,
confirmStyle: 'success',
confirmLabel: 'Save',
rejectLabel: 'Close'
});
if (!displayName) return;
const error = await profileModel.setDisplayName(displayName);
if (error) return console.error('Failed to set displayName', error);
user.value = await profileModel.get();
}
</script>
<style scoped>
.content {
margin-right: 10px;
}
</style>