aboutsummaryrefslogtreecommitdiffstats
path: root/apps/user_status/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'apps/user_status/src/components')
-rw-r--r--apps/user_status/src/components/ClearAtSelect.vue85
-rw-r--r--apps/user_status/src/components/CustomMessageInput.vue106
-rw-r--r--apps/user_status/src/components/OnlineStatusSelect.vue110
-rw-r--r--apps/user_status/src/components/PredefinedStatus.vue128
-rw-r--r--apps/user_status/src/components/PredefinedStatusesList.vue84
-rw-r--r--apps/user_status/src/components/PreviousStatus.vue106
-rw-r--r--apps/user_status/src/components/SetStatusModal.vue391
7 files changed, 1010 insertions, 0 deletions
diff --git a/apps/user_status/src/components/ClearAtSelect.vue b/apps/user_status/src/components/ClearAtSelect.vue
new file mode 100644
index 00000000000..91b816dc04a
--- /dev/null
+++ b/apps/user_status/src/components/ClearAtSelect.vue
@@ -0,0 +1,85 @@
+<!--
+ - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+
+<template>
+ <div class="clear-at-select">
+ <label class="clear-at-select__label" for="clearStatus">
+ {{ $t('user_status', 'Clear status after') }}
+ </label>
+ <NcSelect input-id="clearStatus"
+ class="clear-at-select__select"
+ :options="options"
+ :value="option"
+ :clearable="false"
+ placement="top"
+ label-outside
+ @option:selected="select" />
+ </div>
+</template>
+
+<script>
+import NcSelect from '@nextcloud/vue/components/NcSelect'
+import { getAllClearAtOptions } from '../services/clearAtOptionsService.js'
+import { clearAtFilter } from '../filters/clearAtFilter.js'
+
+export default {
+ name: 'ClearAtSelect',
+ components: {
+ NcSelect,
+ },
+ props: {
+ clearAt: {
+ type: Object,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ options: getAllClearAtOptions(),
+ }
+ },
+ computed: {
+ /**
+ * Returns an object of the currently selected option
+ *
+ * @return {object}
+ */
+ option() {
+ return {
+ clearAt: this.clearAt,
+ label: clearAtFilter(this.clearAt),
+ }
+ },
+ },
+ methods: {
+ /**
+ * Triggered when the user selects a new option.
+ *
+ * @param {object=} option The new selected option
+ */
+ select(option) {
+ if (!option) {
+ return
+ }
+
+ this.$emit('select-clear-at', option.clearAt)
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.clear-at-select {
+ display: flex;
+ gap: calc(2 * var(--default-grid-baseline));
+ align-items: center;
+ margin-block: 0 calc(2 * var(--default-grid-baseline));
+
+ &__select {
+ flex-grow: 1;
+ min-width: 215px;
+ }
+}
+</style>
diff --git a/apps/user_status/src/components/CustomMessageInput.vue b/apps/user_status/src/components/CustomMessageInput.vue
new file mode 100644
index 00000000000..fb129281430
--- /dev/null
+++ b/apps/user_status/src/components/CustomMessageInput.vue
@@ -0,0 +1,106 @@
+<!--
+ - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+<template>
+ <div class="custom-input" role="group">
+ <NcEmojiPicker container=".custom-input" @select="setIcon">
+ <NcButton type="tertiary"
+ :aria-label="t('user_status', 'Emoji for your status message')">
+ <template #icon>
+ {{ visibleIcon }}
+ </template>
+ </NcButton>
+ </NcEmojiPicker>
+ <div class="custom-input__container">
+ <NcTextField ref="input"
+ maxlength="80"
+ :disabled="disabled"
+ :placeholder="t('user_status', 'What is your status?')"
+ :value="message"
+ type="text"
+ :label="t('user_status', 'What is your status?')"
+ @input="onChange" />
+ </div>
+ </div>
+</template>
+
+<script>
+import NcButton from '@nextcloud/vue/components/NcButton'
+import NcEmojiPicker from '@nextcloud/vue/components/NcEmojiPicker'
+import NcTextField from '@nextcloud/vue/components/NcTextField'
+
+export default {
+ name: 'CustomMessageInput',
+
+ components: {
+ NcTextField,
+ NcButton,
+ NcEmojiPicker,
+ },
+
+ props: {
+ icon: {
+ type: String,
+ default: '😀',
+ },
+ message: {
+ type: String,
+ required: true,
+ default: () => '',
+ },
+ disabled: {
+ type: Boolean,
+ default: false,
+ },
+ },
+
+ emits: [
+ 'change',
+ 'select-icon',
+ ],
+
+ computed: {
+ /**
+ * Returns the user-set icon or a smiley in case no icon is set
+ *
+ * @return {string}
+ */
+ visibleIcon() {
+ return this.icon || '😀'
+ },
+ },
+
+ methods: {
+ focus() {
+ this.$refs.input.focus()
+ },
+
+ /**
+ * Notifies the parent component about a changed input
+ *
+ * @param {Event} event The Change Event
+ */
+ onChange(event) {
+ this.$emit('change', event.target.value)
+ },
+
+ setIcon(icon) {
+ this.$emit('select-icon', icon)
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.custom-input {
+ display: flex;
+ align-items: flex-end;
+ gap: var(--default-grid-baseline);
+ width: 100%;
+
+ &__container {
+ width: 100%;
+ }
+}
+</style>
diff --git a/apps/user_status/src/components/OnlineStatusSelect.vue b/apps/user_status/src/components/OnlineStatusSelect.vue
new file mode 100644
index 00000000000..0abcc8d68e6
--- /dev/null
+++ b/apps/user_status/src/components/OnlineStatusSelect.vue
@@ -0,0 +1,110 @@
+<!--
+ - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+<template>
+ <div class="user-status-online-select">
+ <input :id="id"
+ :checked="checked"
+ class="hidden-visually user-status-online-select__input"
+ type="radio"
+ name="user-status-online"
+ @change="onChange">
+ <label :for="id" class="user-status-online-select__label">
+ <NcUserStatusIcon :status="type"
+ class="user-status-online-select__icon"
+ aria-hidden="true" />
+ {{ label }}
+ <em class="user-status-online-select__subline">{{ subline }}</em>
+ </label>
+ </div>
+</template>
+
+<script>
+import NcUserStatusIcon from '@nextcloud/vue/components/NcUserStatusIcon'
+
+export default {
+ name: 'OnlineStatusSelect',
+
+ components: {
+ NcUserStatusIcon,
+ },
+
+ props: {
+ checked: {
+ type: Boolean,
+ default: false,
+ },
+ type: {
+ type: String,
+ required: true,
+ },
+ label: {
+ type: String,
+ required: true,
+ },
+ subline: {
+ type: String,
+ default: null,
+ },
+ },
+
+ computed: {
+ id() {
+ return `user-status-online-status-${this.type}`
+ },
+ },
+
+ methods: {
+ onChange() {
+ this.$emit('select', this.type)
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.user-status-online-select {
+ &__label {
+ box-sizing: inherit;
+ display: grid;
+ grid-template-columns: var(--default-clickable-area) 1fr 2fr;
+ align-items: center;
+ gap: var(--default-grid-baseline);
+ min-height: var(--default-clickable-area);
+ padding: var(--default-grid-baseline);
+ border-radius: var(--border-radius-large);
+ background-color: var(--color-background-hover);
+
+ &, & * {
+ cursor: pointer;
+ }
+
+ &:hover {
+ background-color: var(--color-background-dark);
+ }
+ }
+
+ &__icon {
+ flex-shrink: 0;
+ max-width: 34px;
+ max-height: 100%;
+ }
+
+ &__input:checked + &__label {
+ outline: 2px solid var(--color-main-text);
+ background-color: var(--color-background-dark);
+ box-shadow: 0 0 0 4px var(--color-main-background);
+ }
+
+ &__input:focus-visible + &__label {
+ outline: 2px solid var(--color-primary-element) !important;
+ background-color: var(--color-background-dark);
+ }
+
+ &__subline {
+ display: block;
+ color: var(--color-text-lighter);
+ }
+}
+</style>
diff --git a/apps/user_status/src/components/PredefinedStatus.vue b/apps/user_status/src/components/PredefinedStatus.vue
new file mode 100644
index 00000000000..b12892d4add
--- /dev/null
+++ b/apps/user_status/src/components/PredefinedStatus.vue
@@ -0,0 +1,128 @@
+<!--
+ - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+<template>
+ <li class="predefined-status">
+ <input :id="id"
+ class="hidden-visually predefined-status__input"
+ type="radio"
+ name="predefined-status"
+ :checked="selected"
+ @change="select">
+ <label class="predefined-status__label" :for="id">
+ <span aria-hidden="true" class="predefined-status__label--icon">
+ {{ icon }}
+ </span>
+ <span class="predefined-status__label--message">
+ {{ message }}
+ </span>
+ <span class="predefined-status__label--clear-at">
+ {{ clearAt | clearAtFilter }}
+ </span>
+ </label>
+ </li>
+</template>
+
+<script>
+import { clearAtFilter } from '../filters/clearAtFilter.js'
+
+export default {
+ name: 'PredefinedStatus',
+ filters: {
+ clearAtFilter,
+ },
+ props: {
+ messageId: {
+ type: String,
+ required: true,
+ },
+ icon: {
+ type: String,
+ required: true,
+ },
+ message: {
+ type: String,
+ required: true,
+ },
+ clearAt: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ selected: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ id() {
+ return `user-status-predefined-status-${this.messageId}`
+ },
+ },
+ methods: {
+ /**
+ * Emits an event when the user clicks the row
+ */
+ select() {
+ this.$emit('select')
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.predefined-status {
+ &__label {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ flex-basis: 100%;
+ border-radius: var(--border-radius);
+ align-items: center;
+ min-height: var(--default-clickable-area);
+ padding-inline: var(--default-grid-baseline);
+
+ &, & * {
+ cursor: pointer;
+ }
+
+ &:hover {
+ background-color: var(--color-background-dark);
+ }
+
+ &--icon {
+ flex-basis: var(--default-clickable-area);
+ text-align: center;
+ }
+
+ &--message {
+ font-weight: bold;
+ padding: 0 6px;
+ }
+
+ &--clear-at {
+ color: var(--color-text-maxcontrast);
+
+ &::before {
+ content: ' – ';
+ }
+ }
+ }
+
+ &__input:checked + &__label,
+ &__label:active {
+ outline: 2px solid var(--color-main-text);
+ box-shadow: 0 0 0 4px var(--color-main-background);
+ background-color: var(--color-background-dark);
+ border-radius: var(--border-radius-large);
+ }
+
+ &__input:focus-visible + &__label {
+ outline: 2px solid var(--color-primary-element) !important;
+ background-color: var(--color-background-dark);
+ border-radius: var(--border-radius-large);
+ }
+}
+</style>
diff --git a/apps/user_status/src/components/PredefinedStatusesList.vue b/apps/user_status/src/components/PredefinedStatusesList.vue
new file mode 100644
index 00000000000..cdf359dce76
--- /dev/null
+++ b/apps/user_status/src/components/PredefinedStatusesList.vue
@@ -0,0 +1,84 @@
+<!--
+ - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+
+<template>
+ <ul v-if="statusesHaveLoaded"
+ class="predefined-statuses-list"
+ :aria-label="t('user_status', 'Predefined statuses')">
+ <PredefinedStatus v-for="status in predefinedStatuses"
+ :key="status.id"
+ :message-id="status.id"
+ :icon="status.icon"
+ :message="status.message"
+ :clear-at="status.clearAt"
+ :selected="lastSelected === status.id"
+ @select="selectStatus(status)" />
+ </ul>
+ <div v-else
+ class="predefined-statuses-list">
+ <div class="icon icon-loading-small" />
+ </div>
+</template>
+
+<script>
+import PredefinedStatus from './PredefinedStatus.vue'
+import { mapGetters, mapState } from 'vuex'
+
+export default {
+ name: 'PredefinedStatusesList',
+ components: {
+ PredefinedStatus,
+ },
+ data() {
+ return {
+ lastSelected: null,
+ }
+ },
+ computed: {
+ ...mapState({
+ predefinedStatuses: state => state.predefinedStatuses.predefinedStatuses,
+ messageId: state => state.userStatus.messageId,
+ }),
+ ...mapGetters(['statusesHaveLoaded']),
+ },
+
+ watch: {
+ messageId: {
+ immediate: true,
+ handler() {
+ this.lastSelected = this.messageId
+ },
+ },
+ },
+
+ /**
+ * Loads all predefined statuses from the server
+ * when this component is mounted
+ */
+ created() {
+ this.$store.dispatch('loadAllPredefinedStatuses')
+ },
+ methods: {
+ /**
+ * Emits an event when the user selects a status
+ *
+ * @param {object} status The selected status
+ */
+ selectStatus(status) {
+ this.lastSelected = status.id
+ this.$emit('select-status', status)
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.predefined-statuses-list {
+ display: flex;
+ flex-direction: column;
+ gap: var(--default-grid-baseline);
+ margin-block: 0 calc(2 * var(--default-grid-baseline));
+}
+</style>
diff --git a/apps/user_status/src/components/PreviousStatus.vue b/apps/user_status/src/components/PreviousStatus.vue
new file mode 100644
index 00000000000..58d6ebd294b
--- /dev/null
+++ b/apps/user_status/src/components/PreviousStatus.vue
@@ -0,0 +1,106 @@
+<!--
+ - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+<template>
+ <div class="predefined-status backup-status"
+ tabindex="0"
+ @keyup.enter="select"
+ @keyup.space="select"
+ @click="select">
+ <span class="predefined-status__icon">
+ {{ icon }}
+ </span>
+ <span class="predefined-status__message">
+ {{ message }}
+ </span>
+ <span class="predefined-status__clear-at">
+ {{ $t('user_status', 'Previously set') }}
+ </span>
+
+ <div class="backup-status__reset-button">
+ <NcButton @click="select">
+ {{ $t('user_status', 'Reset status') }}
+ </NcButton>
+ </div>
+ </div>
+</template>
+
+<script>
+import NcButton from '@nextcloud/vue/components/NcButton'
+
+export default {
+ name: 'PreviousStatus',
+
+ components: {
+ NcButton,
+ },
+
+ props: {
+ icon: {
+ type: [String, null],
+ required: true,
+ },
+ message: {
+ type: String,
+ required: true,
+ },
+ },
+ methods: {
+ /**
+ * Emits an event when the user clicks the row
+ */
+ select() {
+ this.$emit('select')
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.predefined-status {
+ display: flex;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ flex-basis: 100%;
+ border-radius: var(--border-radius);
+ align-items: center;
+ min-height: var(--default-clickable-area);
+ padding-inline: var(--default-grid-baseline);
+
+ &:hover,
+ &:focus {
+ background-color: var(--color-background-hover);
+ }
+
+ &:active{
+ background-color: var(--color-background-dark);
+ }
+
+ &__icon {
+ flex-basis: var(--default-clickable-area);
+ text-align: center;
+ }
+
+ &__message {
+ font-weight: bold;
+ padding: 0 6px;
+ }
+
+ &__clear-at {
+ color: var(--color-text-maxcontrast);
+
+ &::before {
+ content: ' – ';
+ }
+ }
+}
+
+.backup-status {
+ &__reset-button {
+ justify-content: flex-end;
+ display: flex;
+ flex-grow: 1;
+ }
+}
+</style>
diff --git a/apps/user_status/src/components/SetStatusModal.vue b/apps/user_status/src/components/SetStatusModal.vue
new file mode 100644
index 00000000000..8624ed19e94
--- /dev/null
+++ b/apps/user_status/src/components/SetStatusModal.vue
@@ -0,0 +1,391 @@
+<!--
+ - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+
+<template>
+ <NcModal size="normal"
+ label-id="user_status-set-dialog"
+ dark
+ :set-return-focus="setReturnFocus"
+ @close="closeModal">
+ <div class="set-status-modal">
+ <!-- Status selector -->
+ <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"
+ :checked="status.type === statusType"
+ @select="changeStatus" />
+ </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 { 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'
+
+export default {
+ name: 'SetStatusModal',
+
+ components: {
+ ClearAtSelect,
+ CustomMessageInput,
+ 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,
+ 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.$store.dispatch('fetchBackupFromServer')
+
+ this.predefinedMessageId = this.$store.state.userStatus.messageId
+ if (this.$store.state.userStatus.clearAt !== null) {
+ this.clearAt = {
+ type: '_time',
+ time: this.$store.state.userStatus.clearAt,
+ }
+ }
+ },
+ methods: {
+ /**
+ * Closes the Set Status modal
+ */
+ closeModal() {
+ this.$emit('close')
+ },
+ /**
+ * Sets a new icon
+ *
+ * @param {string} icon The new icon
+ */
+ setIcon(icon) {
+ this.predefinedMessageId = null
+ this.$store.dispatch('setCustomMessage', {
+ message: this.message,
+ icon,
+ clearAt: this.clearAt,
+ })
+ this.$nextTick(() => {
+ this.$refs.customMessageInput.focus()
+ })
+ },
+ /**
+ * Sets a new message
+ *
+ * @param {string} message The new message
+ */
+ setMessage(message) {
+ this.predefinedMessageId = null
+ this.editedMessage = message
+ },
+ /**
+ * Sets a new clearAt value
+ *
+ * @param {object} clearAt The new clearAt object
+ */
+ setClearAt(clearAt) {
+ this.clearAt = clearAt
+ },
+ /**
+ * Sets new icon/message/clearAt based on a predefined message
+ *
+ * @param {object} status The predefined status object
+ */
+ selectPredefinedMessage(status) {
+ this.predefinedMessageId = status.id
+ this.clearAt = status.clearAt
+ this.$store.dispatch('setPredefinedMessage', {
+ messageId: status.id,
+ clearAt: status.clearAt,
+ })
+ },
+ /**
+ * Saves the status and closes the
+ *
+ * @return {Promise<void>}
+ */
+ async saveStatus() {
+ if (this.isSavingStatus) {
+ return
+ }
+
+ try {
+ this.isSavingStatus = true
+
+ if (this.predefinedMessageId === null) {
+ await this.$store.dispatch('setCustomMessage', {
+ message: this.editedMessage,
+ icon: this.icon,
+ clearAt: this.clearAt,
+ })
+ } else {
+ this.$store.dispatch('setPredefinedMessage', {
+ messageId: this.predefinedMessageId,
+ clearAt: this.clearAt,
+ })
+ }
+ } catch (err) {
+ showError(this.$t('user_status', 'There was an error saving the status'))
+ console.debug(err)
+ this.isSavingStatus = false
+ return
+ }
+
+ this.isSavingStatus = false
+ this.closeModal()
+ },
+ /**
+ *
+ * @return {Promise<void>}
+ */
+ async clearStatus() {
+ try {
+ this.isSavingStatus = true
+
+ await this.$store.dispatch('clearMessage')
+ } catch (err) {
+ showError(this.$t('user_status', 'There was an error clearing the status'))
+ console.debug(err)
+ this.isSavingStatus = false
+ return
+ }
+
+ 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>
+
+<style lang="scss" scoped>
+
+.set-status-modal {
+ padding: 8px 20px 20px 20px;
+
+ &, & * {
+ box-sizing: border-box;
+ }
+
+ &__header {
+ font-size: 21px;
+ text-align: center;
+ 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: 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-block: 0 calc(2 * var(--default-grid-baseline));
+ color: var(--color-text-maxcontrast);
+ }
+
+ .status-buttons {
+ display: flex;
+ padding: 3px;
+ padding-inline-start:0;
+ gap: 3px;
+ }
+}
+
+@media only screen and (max-width: 500px) {
+ .set-status-modal__online-status {
+ grid-template-columns: none !important;
+ }
+}
+
+</style>