Skip to content
Snippets Groups Projects

User settings form

Merged Valentin Rigal requested to merge user-settings-form into master
All threads resolved!
1 file
+ 7
6
Compare changes
  • Side-by-side
  • Inline
<template>
<table class="table">
<thead>
<tr>
<th><span class="has-text-weight-bold">Email</span></th>
<td>{{ user.email }}</td>
</tr>
</thead>
<tbody>
<tr>
<td><span class="has-text-weight-bold">Display name</span></td>
<td>{{ user.display_name }}</td>
</tr>
<tr>
<td><span class="has-text-weight-bold">API Token</span></td>
<td><samp class="tag is-light">{{ user.auth_token }}</samp></td>
</tr>
</tbody>
</table>
<form v-if="user" v-on:submit.prevent="submit">
<div class="field">
<label class="label">Display name</label>
<div class="control is-expanded">
<input
type="text"
class="input"
v-model="displayName"
:class="{ 'is-danger': !displayName || fieldErrors.display_name.length }"
:disabled="loading"
required
/>
</div>
<p class="help is-danger" v-for="err in fieldErrors.display_name" :key="err">{{ err }}</p>
</div>
<div class="field">
<label class="label">E-mail address</label>
<div class="control">
<input
class="input"
name="username"
:value="user.email"
disabled
title="Your email address cannot be modified directly, please contact an administrator"
/>
</div>
</div>
<label class="label">API token</label>
<div class="field has-addons">
<div
class="control"
v-if="!showToken"
>
<button
type="button"
class="button"
v-on:click="showToken = true"
title="Reveal your personal API access token"
>
Reveal
</button>
</div>
<div
v-else
class="control is-clickable"
v-on:click="copyToken"
>
<div class="input" title="Copy your personal API access token">
{{ user.auth_token }}
</div>
</div>
<div class="control" v-on:click="copyToken">
<div class="button" title="Copy your personal API access token">
Copy <i class="icon-clipboard"></i>
</div>
</div>
</div>
<div class="field">
<div class="field">
<label class="label">New password</label>
<div class="control">
<input
type="password"
v-model="password"
class="input"
:disabled="loading"
/>
<p class="help is-danger" v-for="err in fieldErrors.password" :key="err">{{ err }}</p>
</div>
</div>
<div class="field">
<label class="label">Confirm new password</label>
<div class="control">
<input
type="password"
v-model="confirmPassword"
class="input"
:disabled="loading"
/>
<p class="help is-danger" v-for="err in fieldErrors.confirm_password" :key="err">{{ err }}</p>
</div>
</div>
</div>
<div class="field">
<p class="control">
<button
type="submit"
class="button is-primary is-pulled-right"
:class="{ 'is-loading': loading }"
:disabled="!canSubmit"
:title="canSubmit ? 'Update personal information' : 'Fields are left unchanged'"
>
Edit
</button>
</p>
</div>
</form>
</template>
<script>
import { mapState } from 'vuex'
export default {
<script lang="ts">
import { defineComponent } from 'vue'
import {
mapState as mapVuexState,
mapActions as mapVuexActions
} from 'vuex'
import { mapActions } from 'pinia'
import { useNotificationStore } from '@/stores'
import { UserUpdatePayload } from '@/api/user'
import { errorParser } from '@/helpers'
export default defineComponent({
data: () => ({
displayName: '',
password: '',
confirmPassword: '',
showToken: false,
loading: false,
fieldErrors: {
display_name: [],
password: [],
confirm_password: []
} as Record<string, Array<string>>
}),
computed: {
...mapState('auth', ['user'])
...mapVuexState('auth', ['user']),
canSubmit (): boolean {
if (this.loading) return false
return (
(this.displayName !== this.user?.display_name) ||
(this.password !== '' && this.confirmPassword !== '')
)
}
},
methods: {
...mapVuexActions('auth', ['updateUser', 'login', 'logout']),
...mapActions(useNotificationStore, ['notify']),
async copyToken () {
if (!this.user) return
try {
await navigator.clipboard.writeText(this.user.auth_token)
this.notify({ type: 'success', text: 'API token copied to clipboard' })
} catch (err) {
this.notify({ type: 'error', text: 'Failed to copy API token' })
}
},
checkPassword () {
this.fieldErrors.confirm_password = []
if (this.password !== '' && this.password !== this.confirmPassword) {
this.fieldErrors.confirm_password = ["Passwords don't match"]
return false
}
return true
},
async submit () {
if (!this.canSubmit || !this.checkPassword()) return
const payload: UserUpdatePayload = { display_name: this.displayName }
if (this.password) payload.password = this.password
this.loading = true
try {
await this.updateUser(payload)
this.notify({ type: 'success', text: 'Your account has been updated' })
} catch (err) {
this.notify({ type: 'error', text: `An error occurred updating your account: ${errorParser(err)}` })
} finally {
this.loading = false
}
}
},
watch: {
user: {
handler (newValue) {
if (!newValue) return
this.displayName = newValue.display_name
},
immediate: true
}
}
}
})
</script>
Loading