aboutsummaryrefslogtreecommitdiffstats
path: root/apps/user_status/src/components/SetStatusModal.vue
diff options
context:
space:
mode:
Diffstat (limited to 'apps/user_status/src/components/SetStatusModal.vue')
-rw-r--r--apps/user_status/src/components/SetStatusModal.vue290
1 files changed, 208 insertions, 82 deletions
diff --git a/apps/user_status/src/components/SetStatusModal.vue b/apps/user_status/src/components/SetStatusModal.vue
index d7adc99da14..8624ed19e94 100644
--- a/apps/user_status/src/components/SetStatusModal.vue
+++ b/apps/user_status/src/components/SetStatusModal.vue
@@ -1,34 +1,22 @@
<!--
- - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com>
- - @author Georg Ehrke <oc.list@georgehrke.com>
- -
- - @license GNU AGPL version 3 or any later version
- -
- - 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: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
<template>
<NcModal size="normal"
- :title="$t('user_status', 'Set status')"
+ label-id="user_status-set-dialog"
+ dark
+ :set-return-focus="setReturnFocus"
@close="closeModal">
<div class="set-status-modal">
<!-- Status selector -->
- <div class="set-status-modal__header">
- <h2>{{ $t('user_status', 'Online status') }}</h2>
- </div>
- <div class="set-status-modal__online-status">
+ <h2 id="user_status-set-dialog" class="set-status-modal__header">
+ {{ $t('user_status', 'Online status') }}
+ </h2>
+ <div class="set-status-modal__online-status"
+ role="radiogroup"
+ :aria-label="$t('user_status', 'Online status')">
<OnlineStatusSelect v-for="status in statuses"
:key="status.type"
v-bind="status"
@@ -36,48 +24,66 @@
@select="changeStatus" />
</div>
- <!-- Status message -->
- <div class="set-status-modal__header">
- <h2>{{ $t('user_status', 'Status message') }}</h2>
- </div>
- <div class="set-status-modal__custom-input">
- <CustomMessageInput ref="customMessageInput"
- :icon="icon"
- :message="message"
- @change="setMessage"
- @submit="saveStatus"
- @select-icon="setIcon" />
- </div>
- <PredefinedStatusesList @select-status="selectPredefinedMessage" />
- <ClearAtSelect :clear-at="clearAt"
- @select-clear-at="setClearAt" />
- <div class="status-buttons">
- <NcButton :wide="true"
- type="tertiary"
- :text="$t('user_status', 'Clear status message')"
- :disabled="isSavingStatus"
- @click="clearStatus">
- {{ $t('user_status', 'Clear status message') }}
- </NcButton>
- <NcButton :wide="true"
- type="primary"
- :text="$t('user_status', 'Set status message')"
- :disabled="isSavingStatus"
- @click="saveStatus">
- {{ $t('user_status', 'Set status message') }}
- </NcButton>
- </div>
+ <!-- Status message form -->
+ <form @submit.prevent="saveStatus" @reset="clearStatus">
+ <h3 class="set-status-modal__header">
+ {{ $t('user_status', 'Status message') }}
+ </h3>
+ <div class="set-status-modal__custom-input">
+ <CustomMessageInput ref="customMessageInput"
+ :icon="icon"
+ :message="editedMessage"
+ @change="setMessage"
+ @select-icon="setIcon" />
+ <NcButton v-if="messageId === 'vacationing'"
+ :href="absencePageUrl"
+ target="_blank"
+ type="secondary"
+ :aria-label="$t('user_status', 'Set absence period')">
+ {{ $t('user_status', 'Set absence period and replacement') + ' ↗' }}
+ </NcButton>
+ </div>
+ <div v-if="hasBackupStatus"
+ class="set-status-modal__automation-hint">
+ {{ $t('user_status', 'Your status was set automatically') }}
+ </div>
+ <PreviousStatus v-if="hasBackupStatus"
+ :icon="backupIcon"
+ :message="backupMessage"
+ @select="revertBackupFromServer" />
+ <PredefinedStatusesList @select-status="selectPredefinedMessage" />
+ <ClearAtSelect :clear-at="clearAt"
+ @select-clear-at="setClearAt" />
+ <div class="status-buttons">
+ <NcButton :wide="true"
+ type="tertiary"
+ native-type="reset"
+ :aria-label="$t('user_status', 'Clear status message')"
+ :disabled="isSavingStatus">
+ {{ $t('user_status', 'Clear status message') }}
+ </NcButton>
+ <NcButton :wide="true"
+ type="primary"
+ native-type="submit"
+ :aria-label="$t('user_status', 'Set status message')"
+ :disabled="isSavingStatus">
+ {{ $t('user_status', 'Set status message') }}
+ </NcButton>
+ </div>
+ </form>
</div>
</NcModal>
</template>
<script>
import { showError } from '@nextcloud/dialogs'
-import NcModal from '@nextcloud/vue/dist/Components/NcModal'
-import NcButton from '@nextcloud/vue/dist/Components/NcButton'
+import { generateUrl } from '@nextcloud/router'
+import NcModal from '@nextcloud/vue/components/NcModal'
+import NcButton from '@nextcloud/vue/components/NcButton'
import { getAllStatusOptions } from '../services/statusOptionsService.js'
import OnlineStatusMixin from '../mixins/OnlineStatusMixin.js'
import PredefinedStatusesList from './PredefinedStatusesList.vue'
+import PreviousStatus from './PreviousStatus.vue'
import CustomMessageInput from './CustomMessageInput.vue'
import ClearAtSelect from './ClearAtSelect.vue'
import OnlineStatusSelect from './OnlineStatusSelect.vue'
@@ -91,29 +97,100 @@ export default {
NcModal,
OnlineStatusSelect,
PredefinedStatusesList,
+ PreviousStatus,
NcButton,
},
mixins: [OnlineStatusMixin],
+ props: {
+ /**
+ * Whether the component should be rendered as a Dashboard Status or a User Menu Entries
+ * true = Dashboard Status
+ * false = User Menu Entries
+ */
+ inline: {
+ type: Boolean,
+ default: false,
+ },
+ },
+
data() {
return {
clearAt: null,
- icon: null,
- message: '',
- messageId: '',
+ editedMessage: '',
+ predefinedMessageId: null,
isSavingStatus: false,
statuses: getAllStatusOptions(),
}
},
+ computed: {
+ messageId() {
+ return this.$store.state.userStatus.messageId
+ },
+ icon() {
+ return this.$store.state.userStatus.icon
+ },
+ message() {
+ return this.$store.state.userStatus.message || ''
+ },
+ hasBackupStatus() {
+ return this.messageId && (this.backupIcon || this.backupMessage)
+ },
+ backupIcon() {
+ return this.$store.state.userBackupStatus.icon || ''
+ },
+ backupMessage() {
+ return this.$store.state.userBackupStatus.message || ''
+ },
+
+ absencePageUrl() {
+ return generateUrl('settings/user/availability#absence')
+ },
+
+ resetButtonText() {
+ if (this.backupIcon && this.backupMessage) {
+ return this.$t('user_status', 'Reset status to "{icon} {message}"', {
+ icon: this.backupIcon,
+ message: this.backupMessage,
+ })
+ } else if (this.backupMessage) {
+ return this.$t('user_status', 'Reset status to "{message}"', {
+ message: this.backupMessage,
+ })
+ } else if (this.backupIcon) {
+ return this.$t('user_status', 'Reset status to "{icon}"', {
+ icon: this.backupIcon,
+ })
+ }
+
+ return this.$t('user_status', 'Reset status')
+ },
+
+ setReturnFocus() {
+ if (this.inline) {
+ return undefined
+ }
+ return document.querySelector('[aria-controls="header-menu-user-menu"]') ?? undefined
+ },
+ },
+
+ watch: {
+ message: {
+ immediate: true,
+ handler(newValue) {
+ this.editedMessage = newValue
+ },
+ },
+ },
+
/**
* Loads the current status when a user opens dialog
*/
mounted() {
- this.messageId = this.$store.state.userStatus.messageId
- this.icon = this.$store.state.userStatus.icon
- this.message = this.$store.state.userStatus.message || ''
+ this.$store.dispatch('fetchBackupFromServer')
+ this.predefinedMessageId = this.$store.state.userStatus.messageId
if (this.$store.state.userStatus.clearAt !== null) {
this.clearAt = {
type: '_time',
@@ -134,8 +211,12 @@ export default {
* @param {string} icon The new icon
*/
setIcon(icon) {
- this.messageId = null
- this.icon = icon
+ this.predefinedMessageId = null
+ this.$store.dispatch('setCustomMessage', {
+ message: this.message,
+ icon,
+ clearAt: this.clearAt,
+ })
this.$nextTick(() => {
this.$refs.customMessageInput.focus()
})
@@ -146,8 +227,8 @@ export default {
* @param {string} message The new message
*/
setMessage(message) {
- this.messageId = null
- this.message = message
+ this.predefinedMessageId = null
+ this.editedMessage = message
},
/**
* Sets a new clearAt value
@@ -163,10 +244,12 @@ export default {
* @param {object} status The predefined status object
*/
selectPredefinedMessage(status) {
- this.messageId = status.id
+ this.predefinedMessageId = status.id
this.clearAt = status.clearAt
- this.icon = status.icon
- this.message = status.message
+ this.$store.dispatch('setPredefinedMessage', {
+ messageId: status.id,
+ clearAt: status.clearAt,
+ })
},
/**
* Saves the status and closes the
@@ -181,15 +264,15 @@ export default {
try {
this.isSavingStatus = true
- if (this.messageId !== undefined && this.messageId !== null) {
- await this.$store.dispatch('setPredefinedMessage', {
- messageId: this.messageId,
+ if (this.predefinedMessageId === null) {
+ await this.$store.dispatch('setCustomMessage', {
+ message: this.editedMessage,
+ icon: this.icon,
clearAt: this.clearAt,
})
} else {
- await this.$store.dispatch('setCustomMessage', {
- message: this.message,
- icon: this.icon,
+ this.$store.dispatch('setPredefinedMessage', {
+ messageId: this.predefinedMessageId,
clearAt: this.clearAt,
})
}
@@ -220,8 +303,30 @@ export default {
}
this.isSavingStatus = false
+ this.predefinedMessageId = null
this.closeModal()
},
+ /**
+ *
+ * @return {Promise<void>}
+ */
+ async revertBackupFromServer() {
+ try {
+ this.isSavingStatus = true
+
+ await this.$store.dispatch('revertBackupFromServer', {
+ messageId: this.messageId,
+ })
+ } catch (err) {
+ showError(this.$t('user_status', 'There was an error reverting the status'))
+ console.debug(err)
+ this.isSavingStatus = false
+ return
+ }
+
+ this.isSavingStatus = false
+ this.predefinedMessageId = this.$store.state.userStatus?.messageId
+ },
},
}
</script>
@@ -231,27 +336,48 @@ export default {
.set-status-modal {
padding: 8px 20px 20px 20px;
+ &, & * {
+ box-sizing: border-box;
+ }
+
&__header {
+ font-size: 21px;
text-align: center;
- font-weight: bold;
- margin: 15px 0;
+ height: fit-content;
+ min-height: var(--default-clickable-area);
+ line-height: var(--default-clickable-area);
+ overflow-wrap: break-word;
+ margin-block: 0 calc(2 * var(--default-grid-baseline));
}
&__online-status {
- display: grid;
- grid-template-columns: 1fr 1fr;
+ display: flex;
+ flex-direction: column;
+ gap: calc(2 * var(--default-grid-baseline));
+ margin-block: 0 calc(2 * var(--default-grid-baseline));
}
&__custom-input {
display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--default-grid-baseline);
+ width: 100%;
+ padding-inline-start: var(--default-grid-baseline);
+ margin-block: 0 calc(2 * var(--default-grid-baseline));
+ }
+
+ &__automation-hint {
+ display: flex;
width: 100%;
- margin-bottom: 10px;
+ margin-block: 0 calc(2 * var(--default-grid-baseline));
+ color: var(--color-text-maxcontrast);
}
.status-buttons {
display: flex;
padding: 3px;
- padding-left:0;
+ padding-inline-start:0;
gap: 3px;
}
}