154 lines
3.9 KiB
Vue
154 lines
3.9 KiB
Vue
<script>
|
|
import appIcon from '@components/AppIcon';
|
|
|
|
/**
|
|
* Account settings, saved one field at a time.
|
|
*
|
|
* There is no Save button on purpose: each field commits on change, the same
|
|
* way the book itself autosaves. A language change is the one setting that
|
|
* needs the page back to pick up the new dictionary.
|
|
*/
|
|
export default {
|
|
components: {
|
|
appIcon
|
|
},
|
|
emits: ['close', 'signed-out'],
|
|
inject: ['api', 'consts', 'lang', 'user'],
|
|
data() {
|
|
return {
|
|
sName: this.user.name,
|
|
sError: '',
|
|
sSaved: '',
|
|
bBusy: false
|
|
};
|
|
},
|
|
computed: {
|
|
languages() {
|
|
return this.consts.languages || ['en'];
|
|
},
|
|
//Intl knows the zone list; older engines only know the one in use.
|
|
timezones() {
|
|
try {
|
|
return Intl.supportedValuesOf('timeZone');
|
|
}
|
|
catch{
|
|
return [this.user.timezone].filter((sZone) => sZone !== '');
|
|
}
|
|
},
|
|
languageNames() {
|
|
const oNames = new Intl.DisplayNames([this.lang.locale], {type: 'language'});
|
|
return this.languages.map((sCode) => ({
|
|
code: sCode,
|
|
label: oNames.of(sCode) || sCode
|
|
}));
|
|
}
|
|
},
|
|
methods: {
|
|
async set(sField, sValue) {
|
|
this.bBusy = true;
|
|
this.sError = '';
|
|
this.sSaved = '';
|
|
|
|
try {
|
|
const asData = await this.api.post('account', {field: sField, value: sValue});
|
|
Object.assign(this.user, asData.user);
|
|
this.sSaved = sField;
|
|
|
|
//The dictionary is baked into the page, so a new language means
|
|
//a new page - and nothing is lost, the book is already saved.
|
|
if(sField === 'language') window.location.reload();
|
|
}
|
|
catch(oError) {
|
|
this.sError = oError.desc_lang_text || oError.message || this.lang.get('error.unexpected');
|
|
this.sName = this.user.name;
|
|
}
|
|
finally {
|
|
this.bBusy = false;
|
|
}
|
|
},
|
|
saveName() {
|
|
const sName = this.sName.trim();
|
|
if((sName !== '') && (sName !== this.user.name)) this.set('name', sName);
|
|
},
|
|
async signOut() {
|
|
this.bBusy = true;
|
|
try {
|
|
await this.api.post('logout');
|
|
this.$emit('signed-out');
|
|
}
|
|
catch(oError) {
|
|
this.sError = oError.desc_lang_text || oError.message;
|
|
}
|
|
finally {
|
|
this.bBusy = false;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="veil" @click.self="$emit('close')">
|
|
<div class="leaf leaf--wide" role="dialog" aria-modal="true">
|
|
<div class="leaf__head">
|
|
<h2 class="leaf__title">{{ lang.get('account.settings') }}</h2>
|
|
<p class="leaf__sub">{{ user.email }}</p>
|
|
</div>
|
|
|
|
<p v-if="sError" class="leaf__error" role="alert">{{ sError }}</p>
|
|
|
|
<div class="leaf__row">
|
|
<label class="paper-label" for="set-name">{{ lang.get('account.name') }}</label>
|
|
<input
|
|
id="set-name"
|
|
v-model="sName"
|
|
class="paper-field"
|
|
type="text"
|
|
maxlength="100"
|
|
:disabled="bBusy"
|
|
@change="saveName"
|
|
@keyup.enter="saveName"
|
|
/>
|
|
</div>
|
|
|
|
<div class="leaf__row">
|
|
<label class="paper-label" for="set-lang">{{ lang.get('account.language') }}</label>
|
|
<select
|
|
id="set-lang"
|
|
class="paper-field"
|
|
:value="user.language"
|
|
:disabled="bBusy"
|
|
@change="set('language', $event.target.value)"
|
|
>
|
|
<option v-for="oLanguage in languageNames" :key="oLanguage.code" :value="oLanguage.code">
|
|
{{ oLanguage.label }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="leaf__row">
|
|
<label class="paper-label" for="set-tz">{{ lang.get('account.timezone') }}</label>
|
|
<select
|
|
id="set-tz"
|
|
class="paper-field"
|
|
:value="user.timezone"
|
|
:disabled="bBusy"
|
|
@change="set('timezone', $event.target.value)"
|
|
>
|
|
<option v-for="sZone in timezones" :key="sZone" :value="sZone">{{ sZone }}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="leaf__actions">
|
|
<button type="button" class="ink-button" @click="$emit('close')">
|
|
<appIcon icon="check" />
|
|
<span>{{ lang.get('action.close') }}</span>
|
|
</button>
|
|
<button type="button" class="text-button text-button--bad" :disabled="bBusy" @click="signOut">
|
|
<span>{{ lang.get('account.sign_out') }}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|