diff options
Diffstat (limited to 'apps/settings/src/components/PersonalInfo/shared/AccountPropertySection.vue')
-rw-r--r-- | apps/settings/src/components/PersonalInfo/shared/AccountPropertySection.vue | 171 |
1 files changed, 69 insertions, 102 deletions
diff --git a/apps/settings/src/components/PersonalInfo/shared/AccountPropertySection.vue b/apps/settings/src/components/PersonalInfo/shared/AccountPropertySection.vue index c9b74eeb3f4..d039641ec72 100644 --- a/apps/settings/src/components/PersonalInfo/shared/AccountPropertySection.vue +++ b/apps/settings/src/components/PersonalInfo/shared/AccountPropertySection.vue @@ -1,94 +1,66 @@ <!-- - - @copyright 2022 Christopher Ng <chrng8@gmail.com> - - - - @author Christopher Ng <chrng8@gmail.com> - - - - @license AGPL-3.0-or-later - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - This program is distributed in the hope that it will be useful, - - but WITHOUT ANY WARRANTY; without even the implied warranty of - - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - - GNU Affero General Public License for more details. - - - - You should have received a copy of the GNU Affero General Public License - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - + - SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later --> <template> <section> - <HeaderBar :scope.sync="scope" - :readable.sync="readable" + <HeaderBar :scope="scope" + :readable="readable" :input-id="inputId" - :is-editable="isEditable" /> + :is-editable="isEditable" + @update:scope="(scope) => $emit('update:scope', scope)" /> <div v-if="isEditable" class="property"> - <textarea v-if="multiLine" + <NcTextArea v-if="multiLine" :id="inputId" - :placeholder="placeholder" - :value="value" - rows="8" autocapitalize="none" autocomplete="off" + :error="hasError || !!helperText" + :helper-text="helperText" + label-outside + :placeholder="placeholder" + rows="8" spellcheck="false" - @input="onPropertyChange" /> - <input v-else + :success="isSuccess" + :value.sync="inputValue" /> + <NcInputField v-else :id="inputId" ref="input" - :placeholder="placeholder" - :type="type" - :value="value" - :aria-describedby="helperText ? `${name}-helper-text` : undefined" autocapitalize="none" - spellcheck="false" :autocomplete="autocomplete" - @input="onPropertyChange"> - - <div class="property__actions-container"> - <Transition name="fade"> - <Check v-if="showCheckmarkIcon" :size="20" /> - <AlertOctagon v-else-if="showErrorIcon" :size="20" /> - </Transition> - </div> + :error="hasError || !!helperText" + :helper-text="helperText" + label-outside + :placeholder="placeholder" + spellcheck="false" + :success="isSuccess" + :type="type" + :value.sync="inputValue" /> </div> <span v-else> {{ value || t('settings', 'No {property} set', { property: readable.toLocaleLowerCase() }) }} </span> - - <p v-if="helperText" - :id="`${name}-helper-text`" - class="property__helper-text-message property__helper-text-message--error"> - <AlertCircle class="property__helper-text-message__icon" :size="18" /> - {{ helperText }} - </p> </section> </template> <script> import debounce from 'debounce' +import NcInputField from '@nextcloud/vue/components/NcInputField' +import NcTextArea from '@nextcloud/vue/components/NcTextArea' -import AlertCircle from 'vue-material-design-icons/AlertCircleOutline.vue' -import AlertOctagon from 'vue-material-design-icons/AlertOctagon.vue' -import Check from 'vue-material-design-icons/Check.vue' - -import HeaderBar from '../shared/HeaderBar.vue' +import HeaderBar from './HeaderBar.vue' import { savePrimaryAccountProperty } from '../../../service/PersonalInfo/PersonalInfoService.js' -import { handleError } from '../../../utils/handlers.js' +import { handleError } from '../../../utils/handlers.ts' export default { name: 'AccountPropertySection', components: { - AlertCircle, - AlertOctagon, - Check, HeaderBar, + NcInputField, + NcTextArea, }, props: { @@ -138,12 +110,14 @@ export default { }, }, + emits: ['update:scope', 'update:value'], + data() { return { initialValue: this.value, - helperText: null, - showCheckmarkIcon: false, - showErrorIcon: false, + helperText: '', + isSuccess: false, + hasError: false, } }, @@ -151,28 +125,37 @@ export default { inputId() { return `account-property-${this.name}` }, - }, - methods: { - onPropertyChange(e) { - this.$emit('update:value', e.target.value) - this.debouncePropertyChange(e.target.value.trim()) + inputValue: { + get() { + return this.value + }, + set(value) { + this.$emit('update:value', value) + this.debouncePropertyChange(value.trim()) + }, }, - debouncePropertyChange: debounce(async function(value) { - this.helperText = null - if (this.$refs.input && this.$refs.input.validationMessage) { - this.helperText = this.$refs.input.validationMessage - return - } - if (this.onValidate && !this.onValidate(value)) { - return - } - await this.updateProperty(value) - }, 500), + debouncePropertyChange() { + return debounce(async function(value) { + this.helperText = this.$refs.input?.$refs.input?.validationMessage || '' + if (this.helperText !== '') { + return + } + this.hasError = this.onValidate && !this.onValidate(value) + if (this.hasError) { + this.helperText = t('settings', 'Invalid value') + return + } + await this.updateProperty(value) + }, 1000) + }, + }, + methods: { async updateProperty(value) { try { + this.hasError = false const responseData = await savePrimaryAccountProperty( this.name, value, @@ -195,13 +178,11 @@ export default { if (this.onSave) { this.onSave(value) } - this.showCheckmarkIcon = true - setTimeout(() => { this.showCheckmarkIcon = false }, 2000) + this.isSuccess = true + setTimeout(() => { this.isSuccess = false }, 2000) } else { - this.$emit('update:value', this.initialValue) handleError(error, errorMessage) - this.showErrorIcon = true - setTimeout(() => { this.showErrorIcon = false }, 2000) + this.hasError = true } }, }, @@ -212,34 +193,20 @@ export default { section { padding: 10px 10px; - &::v-deep button:disabled { - cursor: default; - } - .property { - display: grid; - align-items: center; - - textarea { - resize: vertical; - grid-area: 1 / 1; - width: 100%; - } - - input { - grid-area: 1 / 1; - width: 100%; - } + display: flex; + flex-direction: row; + align-items: start; + gap: 4px; .property__actions-container { - grid-area: 1 / 1; + margin-top: 6px; justify-self: flex-end; align-self: flex-end; - height: 30px; display: flex; gap: 0 2px; - margin-right: 5px; + margin-inline-end: 5px; margin-bottom: 5px; } } @@ -250,7 +217,7 @@ section { align-items: center; &__icon { - margin-right: 8px; + margin-inline-end: 8px; align-self: start; margin-top: 4px; } |