|
|
@ -51,7 +51,7 @@ |
|
|
|
v-icon(left) mdi-comment |
|
|
|
span.text-none Post Comment |
|
|
|
v-divider.mt-3(v-if='permissions.write') |
|
|
|
.pa-5.d-flex.align-center.justify-center(v-if='isLoading') |
|
|
|
.pa-5.d-flex.align-center.justify-center(v-if='isLoading && !hasLoadedOnce') |
|
|
|
v-progress-circular( |
|
|
|
indeterminate |
|
|
|
size='20' |
|
|
@ -63,22 +63,38 @@ |
|
|
|
dense |
|
|
|
v-else-if='comments && comments.length > 0' |
|
|
|
) |
|
|
|
v-timeline-item( |
|
|
|
v-timeline-item.comments-post( |
|
|
|
color='pink darken-4' |
|
|
|
large |
|
|
|
v-for='cm of comments' |
|
|
|
:key='`comment-` + cm.id' |
|
|
|
:id='`comment-post-id-` + cm.id' |
|
|
|
) |
|
|
|
template(v-slot:icon) |
|
|
|
v-avatar |
|
|
|
v-img(src='http://i.pravatar.cc/64') |
|
|
|
v-avatar(color='blue-grey') |
|
|
|
//- v-img(src='http://i.pravatar.cc/64') |
|
|
|
span.white--text.title {{cm.initials}} |
|
|
|
v-card.elevation-1 |
|
|
|
v-card-text |
|
|
|
.caption: strong {{cm.authorName}} |
|
|
|
.overline.grey--text 3 minutes ago |
|
|
|
.mt-3 {{cm.render}} |
|
|
|
.comments-post-actions(v-if='permissions.manage && !isBusy') |
|
|
|
v-icon.mr-3(small, @click='editComment(cm)') mdi-pencil |
|
|
|
v-icon(small, @click='deleteCommentConfirm(cm)') mdi-delete |
|
|
|
.comments-post-name.caption: strong {{cm.authorName}} |
|
|
|
.comments-post-date.overline.grey--text {{cm.createdAt | moment('from') }} #[em(v-if='cm.createdAt !== cm.updatedAt') - modified {{cm.updatedAt | moment('from') }}] |
|
|
|
.comments-post-content.mt-3(v-html='cm.render') |
|
|
|
.pt-5.text-center.body-2.blue-grey--text(v-else-if='permissions.write') Be the first to comment. |
|
|
|
.text-center.body-2.blue-grey--text(v-else) No comments yet. |
|
|
|
|
|
|
|
v-dialog(v-model='deleteCommentDialogShown', max-width='500') |
|
|
|
v-card |
|
|
|
.dialog-header.is-red Confirm Delete |
|
|
|
v-card-text.pt-5 |
|
|
|
span Are you sure you want to permanently delete this comment? |
|
|
|
.caption: strong This action cannot be undone! |
|
|
|
v-card-chin |
|
|
|
v-spacer |
|
|
|
v-btn(text, @click='deleteCommentDialogShown = false') {{$t('common:actions.cancel')}} |
|
|
|
v-btn(color='red', dark, @click='deleteComment') {{$t('common:actions.delete')}} |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
@ -92,10 +108,18 @@ export default { |
|
|
|
return { |
|
|
|
newcomment: '', |
|
|
|
isLoading: true, |
|
|
|
canFetch: false, |
|
|
|
hasLoadedOnce: false, |
|
|
|
comments: [], |
|
|
|
guestName: '', |
|
|
|
guestEmail: '' |
|
|
|
guestEmail: '', |
|
|
|
commentToDelete: {}, |
|
|
|
deleteCommentDialogShown: false, |
|
|
|
isBusy: false, |
|
|
|
scrollOpts: { |
|
|
|
duration: 1500, |
|
|
|
offset: 0, |
|
|
|
easing: 'easeInOutCubic' |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
@ -107,10 +131,46 @@ export default { |
|
|
|
methods: { |
|
|
|
onIntersect (entries, observer, isIntersecting) { |
|
|
|
if (isIntersecting) { |
|
|
|
this.isLoading = true |
|
|
|
this.canFetch = true |
|
|
|
this.fetch() |
|
|
|
} |
|
|
|
}, |
|
|
|
async fetch () { |
|
|
|
this.isLoading = true |
|
|
|
const results = await this.$apollo.query({ |
|
|
|
query: gql` |
|
|
|
query ($locale: String!, $path: String!) { |
|
|
|
comments { |
|
|
|
list(locale: $locale, path: $path) { |
|
|
|
id |
|
|
|
render |
|
|
|
authorName |
|
|
|
createdAt |
|
|
|
updatedAt |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
`, |
|
|
|
variables: { |
|
|
|
locale: this.$store.get('page/locale'), |
|
|
|
path: this.$store.get('page/path') |
|
|
|
}, |
|
|
|
fetchPolicy: 'network-only' |
|
|
|
}) |
|
|
|
this.comments = _.get(results, 'data.comments.list', []).map(c => { |
|
|
|
const nameParts = c.authorName.toUpperCase().split(' ') |
|
|
|
let initials = _.head(nameParts).charAt(0) |
|
|
|
if (nameParts.length > 1) { |
|
|
|
initials += _.last(nameParts).charAt(0) |
|
|
|
} |
|
|
|
c.initials = initials |
|
|
|
return c |
|
|
|
}) |
|
|
|
this.isLoading = false |
|
|
|
this.hasLoadedOnce = true |
|
|
|
}, |
|
|
|
/** |
|
|
|
* Post New Comment |
|
|
|
*/ |
|
|
|
async postComment () { |
|
|
|
let rules = { |
|
|
|
comment: { |
|
|
@ -177,6 +237,7 @@ export default { |
|
|
|
slug |
|
|
|
message |
|
|
|
} |
|
|
|
id |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -198,6 +259,10 @@ export default { |
|
|
|
}) |
|
|
|
|
|
|
|
this.newcomment = '' |
|
|
|
await this.fetch() |
|
|
|
this.$nextTick(() => { |
|
|
|
this.$vuetify.goTo(`#comment-post-id-${_.get(resp, 'data.comments.create.id', 0)}`, this.scrollOpts) |
|
|
|
}) |
|
|
|
} else { |
|
|
|
this.$store.commit('showNotification', { |
|
|
|
style: 'red', |
|
|
@ -205,41 +270,117 @@ export default { |
|
|
|
icon: 'alert' |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
apollo: { |
|
|
|
comments: { |
|
|
|
query: gql` |
|
|
|
query ($pageId: Int!) { |
|
|
|
comments { |
|
|
|
list(pageId: $pageId) { |
|
|
|
id |
|
|
|
render |
|
|
|
authorName |
|
|
|
createdAt |
|
|
|
updatedAt |
|
|
|
}, |
|
|
|
async editComment (cm) { |
|
|
|
|
|
|
|
}, |
|
|
|
deleteCommentConfirm (cm) { |
|
|
|
this.commentToDelete = cm |
|
|
|
this.deleteCommentDialogShown = true |
|
|
|
}, |
|
|
|
/** |
|
|
|
* Delete Comment |
|
|
|
*/ |
|
|
|
async deleteComment () { |
|
|
|
this.$store.commit(`loadingStart`, 'comments-delete') |
|
|
|
this.isBusy = true |
|
|
|
this.deleteCommentDialogShown = false |
|
|
|
|
|
|
|
const resp = await this.$apollo.mutate({ |
|
|
|
mutation: gql` |
|
|
|
mutation ( |
|
|
|
$id: Int! |
|
|
|
) { |
|
|
|
comments { |
|
|
|
delete ( |
|
|
|
id: $id |
|
|
|
) { |
|
|
|
responseResult { |
|
|
|
succeeded |
|
|
|
errorCode |
|
|
|
slug |
|
|
|
message |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
`, |
|
|
|
variables: { |
|
|
|
id: this.commentToDelete.id |
|
|
|
} |
|
|
|
`, |
|
|
|
variables() { |
|
|
|
return { |
|
|
|
pageId: this.pageId |
|
|
|
} |
|
|
|
}, |
|
|
|
skip () { |
|
|
|
return !this.canFetch |
|
|
|
}, |
|
|
|
fetchPolicy: 'cache-and-network', |
|
|
|
update: (data) => data.comments.list, |
|
|
|
watchLoading (isLoading) { |
|
|
|
this.isLoading = isLoading |
|
|
|
}) |
|
|
|
|
|
|
|
if (_.get(resp, 'data.comments.delete.responseResult.succeeded', false)) { |
|
|
|
this.$store.commit('showNotification', { |
|
|
|
style: 'success', |
|
|
|
message: 'Comment was deleted successfully.', |
|
|
|
icon: 'check' |
|
|
|
}) |
|
|
|
|
|
|
|
this.comments = _.reject(this.comments, ['id', this.commentToDelete.id]) |
|
|
|
} else { |
|
|
|
this.$store.commit('showNotification', { |
|
|
|
style: 'red', |
|
|
|
message: _.get(resp, 'data.comments.delete.responseResult.message', 'An unexpected error occured.'), |
|
|
|
icon: 'alert' |
|
|
|
}) |
|
|
|
} |
|
|
|
this.isBusy = false |
|
|
|
this.$store.commit(`loadingStop`, 'comments-delete') |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style lang="scss"> |
|
|
|
.comments-post { |
|
|
|
position: relative; |
|
|
|
|
|
|
|
&:hover { |
|
|
|
.comments-post-actions { |
|
|
|
opacity: 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&-actions { |
|
|
|
position: absolute; |
|
|
|
top: 16px; |
|
|
|
right: 16px; |
|
|
|
opacity: 0; |
|
|
|
transition: opacity .4s ease; |
|
|
|
} |
|
|
|
|
|
|
|
&-content { |
|
|
|
> p:first-child { |
|
|
|
padding-top: 0; |
|
|
|
} |
|
|
|
|
|
|
|
p { |
|
|
|
padding-top: 1rem; |
|
|
|
margin-bottom: 0; |
|
|
|
} |
|
|
|
|
|
|
|
img { |
|
|
|
max-width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
code { |
|
|
|
background-color: rgba(mc('pink', '500'), .1); |
|
|
|
box-shadow: none; |
|
|
|
} |
|
|
|
|
|
|
|
pre > code { |
|
|
|
margin-top: 1rem; |
|
|
|
padding: 12px; |
|
|
|
background-color: #111; |
|
|
|
box-shadow: none; |
|
|
|
border-radius: 5px; |
|
|
|
width: 100%; |
|
|
|
color: #FFF; |
|
|
|
font-weight: 400; |
|
|
|
font-size: .85rem; |
|
|
|
font-family: Roboto Mono, monospace; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
</style> |