diff options
Diffstat (limited to 'src/components/announcement')
| -rw-r--r-- | src/components/announcement/announcement.js | 105 | ||||
| -rw-r--r-- | src/components/announcement/announcement.vue | 136 |
2 files changed, 241 insertions, 0 deletions
diff --git a/src/components/announcement/announcement.js b/src/components/announcement/announcement.js new file mode 100644 index 00000000..c10c7d90 --- /dev/null +++ b/src/components/announcement/announcement.js @@ -0,0 +1,105 @@ +import { mapState } from 'vuex' +import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' +import RichContent from '../rich_content/rich_content.jsx' +import localeService from '../../services/locale/locale.service.js' + +const Announcement = { + components: { + AnnouncementEditor, + RichContent + }, + data () { + return { + editing: false, + editedAnnouncement: { + content: '', + startsAt: undefined, + endsAt: undefined, + allDay: undefined + }, + editError: '' + } + }, + props: { + announcement: Object + }, + computed: { + ...mapState({ + currentUser: state => state.users.currentUser + }), + content () { + return this.announcement.content + }, + isRead () { + return this.announcement.read + }, + publishedAt () { + const time = this.announcement.published_at + if (!time) { + return + } + + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) + }, + startsAt () { + const time = this.announcement.starts_at + if (!time) { + return + } + + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) + }, + endsAt () { + const time = this.announcement.ends_at + if (!time) { + return + } + + return this.formatTimeOrDate(time, localeService.internalToBrowserLocale(this.$i18n.locale)) + }, + inactive () { + return this.announcement.inactive + } + }, + methods: { + markAsRead () { + if (!this.isRead) { + return this.$store.dispatch('markAnnouncementAsRead', this.announcement.id) + } + }, + deleteAnnouncement () { + return this.$store.dispatch('deleteAnnouncement', this.announcement.id) + }, + formatTimeOrDate (time, locale) { + const d = new Date(time) + return this.announcement.all_day ? d.toLocaleDateString(locale) : d.toLocaleString(locale) + }, + enterEditMode () { + this.editedAnnouncement.content = this.announcement.pleroma.raw_content + this.editedAnnouncement.startsAt = this.announcement.starts_at + this.editedAnnouncement.endsAt = this.announcement.ends_at + this.editedAnnouncement.allDay = this.announcement.all_day + this.editing = true + }, + submitEdit () { + this.$store.dispatch('editAnnouncement', { + id: this.announcement.id, + ...this.editedAnnouncement + }) + .then(() => { + this.editing = false + }) + .catch(error => { + this.editError = error.error + }) + }, + cancelEdit () { + this.editing = false + }, + clearError () { + this.editError = undefined + } + } +} + +export default Announcement diff --git a/src/components/announcement/announcement.vue b/src/components/announcement/announcement.vue new file mode 100644 index 00000000..5f64232a --- /dev/null +++ b/src/components/announcement/announcement.vue @@ -0,0 +1,136 @@ +<template> + <div class="announcement"> + <div class="heading"> + <h4>{{ $t('announcements.title') }}</h4> + </div> + <div class="body"> + <rich-content + v-if="!editing" + :html="content" + :emoji="announcement.emojis" + :handle-links="true" + /> + <announcement-editor + v-else + :announcement="editedAnnouncement" + /> + </div> + <div class="footer"> + <div + v-if="!editing" + class="times" + > + <span v-if="publishedAt"> + {{ $t('announcements.published_time_display', { time: publishedAt }) }} + </span> + <span v-if="startsAt"> + {{ $t('announcements.start_time_display', { time: startsAt }) }} + </span> + <span v-if="endsAt"> + {{ $t('announcements.end_time_display', { time: endsAt }) }} + </span> + </div> + <div + v-if="!editing" + class="actions" + > + <button + v-if="currentUser" + class="btn button-default" + :class="{ toggled: isRead }" + :disabled="inactive" + :title="inactive ? $t('announcements.inactive_message') : ''" + @click="markAsRead" + > + {{ $t('announcements.mark_as_read_action') }} + </button> + <button + v-if="currentUser && currentUser.role === 'admin'" + class="btn button-default" + @click="enterEditMode" + > + {{ $t('announcements.edit_action') }} + </button> + <button + v-if="currentUser && currentUser.role === 'admin'" + class="btn button-default" + @click="deleteAnnouncement" + > + {{ $t('announcements.delete_action') }} + </button> + </div> + <div + v-else + class="actions" + > + <button + class="btn button-default" + @click="submitEdit" + > + {{ $t('announcements.submit_edit_action') }} + </button> + <button + class="btn button-default" + @click="cancelEdit" + > + {{ $t('announcements.cancel_edit_action') }} + </button> + <div + v-if="editing && editError" + class="alert error" + > + {{ $t('announcements.edit_error', { error }) }} + <button + class="button-unstyled" + @click="clearError" + > + <FAIcon + class="fa-scale-110 fa-old-padding" + icon="times" + :title="$t('announcements.close_error')" + /> + </button> + </div> + </div> + </div> + </div> +</template> + +<script src="./announcement.js"></script> + +<style lang="scss"> +@import "../../variables"; + +.announcement { + border-bottom-width: 1px; + border-bottom-style: solid; + border-bottom-color: var(--border, $fallback--border); + border-radius: 0; + padding: var(--status-margin, $status-margin); + + .heading, .body { + margin-bottom: var(--status-margin, $status-margin); + } + + .footer { + display: flex; + flex-direction: column; + .times { + display: flex; + flex-direction: column; + } + } + + .footer .actions { + display: flex; + flex-direction: row; + justify-content: space-evenly; + + .btn { + flex: 1; + margin: 1em; + max-width: 10em; + } + } +} +</style> |
