118 lines
4.8 KiB
Vue
118 lines
4.8 KiB
Vue
<template>
|
|
<div class="guestbook-post" :id="'guestbook-post-' + post.id">
|
|
<div class="guestbook-contents" :class="{deleted: post.deleted}">
|
|
<div style="display:flex;align-items:center">
|
|
<div class="guestbook-avatar">
|
|
<character-link :character="post.character">
|
|
<img :src="avatarUrl" class="character-avatar icon"/>
|
|
</character-link>
|
|
</div>
|
|
<div style="flex:1;margin-left:10px">
|
|
<span v-show="post.private" class="post-private">*</span>
|
|
<span v-show="!post.approved" class="post-unapproved"> (unapproved)</span>
|
|
|
|
<span class="guestbook-timestamp">
|
|
<character-link :character="post.character"></character-link>, posted <date-display
|
|
:time="post.postedAt"></date-display>
|
|
</span>
|
|
<button class="btn btn-secondary" v-show="canEdit" @click="approve" :disabled="approving" style="margin-left:10px">
|
|
{{ (post.approved) ? 'Unapprove' : 'Approve' }}
|
|
</button>
|
|
</div>
|
|
<button class="btn btn-danger" v-show="!post.deleted && (canEdit || post.canEdit)"
|
|
@click="deletePost" :disabled="deleting">Delete
|
|
</button>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="bbcode guestbook-message" v-bbcode="post.message"></div>
|
|
<div v-if="post.reply && !replyBox" class="guestbook-reply">
|
|
<date-display v-if="post.repliedAt" :time="post.repliedAt"></date-display>
|
|
<div class="reply-message" v-bbcode="post.reply"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<a v-show="canEdit && !replyBox" class="reply-link" @click="replyBox = !replyBox">
|
|
{{ post.reply ? 'Edit Reply' : 'Reply' }}
|
|
</a>
|
|
<template v-if="replyBox">
|
|
<bbcode-editor v-model="replyMessage" :maxlength="5000" classes="form-control"></bbcode-editor>
|
|
<button class="btn btn-success" @click="postReply" :disabled="replying">Reply</button>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import {Component, Prop} from '@f-list/vue-ts';
|
|
import Vue from 'vue';
|
|
import CharacterLink from '../../components/character_link.vue';
|
|
import DateDisplay from '../../components/date_display.vue';
|
|
import * as Utils from '../utils';
|
|
import {methods} from './data_store';
|
|
import {GuestbookPost} from './interfaces';
|
|
|
|
@Component({
|
|
components: {'date-display': DateDisplay, 'character-link': CharacterLink}
|
|
})
|
|
export default class GuestbookPostView extends Vue {
|
|
@Prop({required: true})
|
|
readonly post!: GuestbookPost;
|
|
@Prop({required: true})
|
|
readonly canEdit!: boolean;
|
|
|
|
replying = false;
|
|
replyBox = false;
|
|
replyMessage = this.post.reply;
|
|
|
|
approving = false;
|
|
deleting = false;
|
|
|
|
get avatarUrl(): string {
|
|
return Utils.avatarURL(this.post.character.name);
|
|
}
|
|
|
|
async deletePost(): Promise<void> {
|
|
try {
|
|
this.deleting = true;
|
|
await methods.guestbookPostDelete(this.post.id);
|
|
Vue.set(this.post, 'deleted', true);
|
|
this.$emit('reload');
|
|
} catch(e) {
|
|
Utils.ajaxError(e, 'Unable to delete guestbook post.');
|
|
} finally {
|
|
this.deleting = false;
|
|
}
|
|
}
|
|
|
|
async approve(): Promise<void> {
|
|
try {
|
|
this.approving = true;
|
|
await methods.guestbookPostApprove(this.post.id, !this.post.approved);
|
|
this.post.approved = !this.post.approved;
|
|
} catch(e) {
|
|
Utils.ajaxError(e, 'Unable to change post approval.');
|
|
} finally {
|
|
this.approving = false;
|
|
}
|
|
}
|
|
|
|
async postReply(): Promise<void> {
|
|
try {
|
|
this.replying = true;
|
|
const replyData = await methods.guestbookPostReply(this.post.id, this.replyMessage);
|
|
this.post.reply = replyData.reply;
|
|
this.post.repliedAt = replyData.repliedAt;
|
|
this.replyBox = false;
|
|
} catch(e) {
|
|
Utils.ajaxError(e, 'Unable to post guestbook reply.');
|
|
} finally {
|
|
this.replying = false;
|
|
}
|
|
}
|
|
}
|
|
</script> |