2019-09-09 09:31:08 +02:00
< template >
< section class = "container" >
< b -message title = "Error" type = "is-danger" v-for ="error in errors" :key ="error" > {{ error }} < / b -message >
< div class = "container" v-if ="report" >
< nav class = "breadcrumb" aria -label = " breadcrumbs " >
< ul >
2019-11-15 18:36:47 +01:00
< li > < router -link : to = "{ name: RouteName.DASHBOARD }" > { { $t ( 'Dashboard' ) } } < / r o u t e r - l i n k > < / l i >
< li > < router -link : to = "{ name: RouteName.REPORTS }" > { { $t ( 'Reports' ) } } < / r o u t e r - l i n k > < / l i >
< li class = "is-active" > < router -link : to = "{ name: RouteName.REPORT, params: { reportId: this.report.id} }" aria -current = " page " > { { $t ( 'Report' ) } } < / r o u t e r - l i n k > < / l i >
2019-09-09 09:31:08 +02:00
< / ul >
< / nav >
< div class = "buttons" >
2019-11-15 18:36:47 +01:00
< b -button v-if ="report.status !== ReportStatusEnum.RESOLVED" @click="updateReport(ReportStatusEnum.RESOLVED)" type="is-primary" > {{ $ t ( ' Mark as resolved ' ) }} < / b -button >
< b -button v-if ="report.status !== ReportStatusEnum.OPEN" @click="updateReport(ReportStatusEnum.OPEN)" type="is-success" > {{ $ t ( ' Reopen ' ) }} < / b -button >
< b -button v-if ="report.status !== ReportStatusEnum.CLOSED" @click="updateReport(ReportStatusEnum.CLOSED)" type="is-danger" > {{ $ t ( ' Close ' ) }} < / b -button >
< / div >
< div class = "table-container" >
< table class = "table is-striped is-fullwidth" >
< tbody >
< tr >
< td > { { $t ( 'Reported identity' ) } } < / td >
< td >
< router -link : to = "{ name: RouteName.PROFILE, params: { name: report.reported.preferredUsername } }" >
< img v -if = " report.reported.avatar " class = "image" :src ="report.reported.avatar.url" / > @ { { report . reported . preferredUsername } }
< / r o u t e r - l i n k >
< / td >
< / tr >
< tr >
< td > { { $t ( 'Reported by' ) } } < / td >
< td >
< router -link : to = "{ name: RouteName.PROFILE, params: { name: report.reporter.preferredUsername } }" >
< img v -if = " report.reporter.avatar " class = "image" :src ="report.reporter.avatar.url" / > @ { { report . reporter . preferredUsername } }
< / r o u t e r - l i n k >
< / td >
< / tr >
< tr >
< td > { { $t ( 'Reported' ) } } < / td >
< td > { { report . insertedAt | formatDateTimeString } } < / td >
< / tr >
< tr v-if ="report.updatedAt !== report.insertedAt" >
< td > { { $t ( 'Updated' ) } } < / td >
< td > { { report . updatedAt | formatDateTimeString } } < / td >
< / tr >
< tr >
< td > { { $t ( 'Status' ) } } < / td >
< td >
< span v-if ="report.status === ReportStatusEnum.OPEN" > {{ $ t ( ' Open ' ) }} < / span >
< span v -else -if = " report.status = = = ReportStatusEnum.CLOSED " > { { $t ( 'Closed' ) } } < / span >
< span v -else -if = " report.status = = = ReportStatusEnum.RESOLVED " > { { $t ( 'Resolved' ) } } < / span >
< span v-else > {{ $ t ( ' Unknown ' ) }} < / span >
< / td >
< / tr >
< tr v-if ="report.event && report.comments.length > 0" >
< td > { { $t ( 'Event' ) } } < / td >
< td >
< router -link : to = "{ name: RouteName.EVENT, params: { uuid: report.event.uuid }}" > { { report . event . title } } < / r o u t e r - l i n k >
< span class = "is-pulled-right" >
< b -button
tag = "router-link"
type = "is-primary"
: to = "{ name: RouteName.EDIT_EVENT, params: {eventId: report.event.uuid } }"
icon - left = "pencil"
size = "is-small" > { { $t ( 'Edit' ) } } < / b - b u t t o n >
< b -button
type = "is-danger"
@ click = "confirmDelete()"
icon - left = "delete"
size = "is-small" > { { $t ( 'Delete' ) } } < / b - b u t t o n >
< / span >
< / td >
< / tr >
< / tbody >
< / table >
2019-09-09 09:31:08 +02:00
< / div >
2019-11-15 18:36:47 +01:00
< div class = "box report-content" >
< p v-if ="report.content" v-html="nl2br(report.content)" > < / p >
< p v-else > {{ $ t ( ' No comment ' ) }} < / p >
2019-09-09 09:31:08 +02:00
< / div >
2019-11-15 18:36:47 +01:00
< div class = "box" v-if ="report.event && report.comments.length === 0" >
2019-10-03 12:32:20 +02:00
< router -link : to = "{ name: RouteName.EVENT, params: { uuid: report.event.uuid }}" >
2019-09-09 09:31:08 +02:00
< h3 class = "title" > { { report . event . title } } < / h3 >
< p v-html ="report.event.description" > < / p >
< / r o u t e r - l i n k >
< b -button
tag = "router-link"
type = "is-primary"
2019-10-03 12:32:20 +02:00
: to = "{ name: RouteName.EDIT_EVENT, params: {eventId: report.event.uuid } }"
2019-09-09 09:31:08 +02:00
icon - left = "pencil"
2019-11-15 18:36:47 +01:00
size = "is-small" > { { $t ( 'Edit' ) } } < / b - b u t t o n >
2019-09-09 09:31:08 +02:00
< b -button
type = "is-danger"
@ click = "confirmDelete()"
icon - left = "delete"
2019-11-15 18:36:47 +01:00
size = "is-small" > { { $t ( 'Delete' ) } } < / b - b u t t o n >
2019-09-09 09:31:08 +02:00
< / div >
2019-11-15 18:36:47 +01:00
< ul v-for ="comment in report.comments" v-if="report.comments.length > 0" >
< li >
< div class = "box" v-if ="comment" >
< article class = "media" >
< div class = "media-left" >
< figure class = "image is-48x48" v-if ="comment.actor.avatar" >
< img :src ="comment.actor.avatar.url" alt = "Image" >
< / figure >
< b -icon class = "media-left" v -else size = "is-large" icon = "account-circle" / >
< / div >
< div class = "media-content" >
< div class = "content" >
< strong > { { comment . actor . name } } < / strong > < small > @ { { comment . actor . preferredUsername } } < / small >
< br >
< p v-html ="comment.text" > < / p >
< / div >
< / div >
< / article >
< / div >
< / li >
< / ul >
< h2 class = "title" v-if ="report.notes.length > 0" > {{ $ t ( ' Notes ' ) }} < / h2 >
2019-09-09 09:31:08 +02:00
< div class = "box note" v-for ="note in report.notes" :id="`note-${note.id}`" >
< p > { { note . content } } < / p >
2019-10-03 12:32:20 +02:00
< router -link : to = "{ name: RouteName.PROFILE, params: { name: note.moderator.preferredUsername } }" >
2019-11-15 18:36:47 +01:00
< img alt = "" class = "image" :src ="note.moderator.avatar.url" / > @ { { note . moderator . preferredUsername } }
2019-09-09 09:31:08 +02:00
< /router-link><br / >
< small > < a :href ="`#note-${note.id}`" v-if ="note.insertedAt" > {{ note.insertedAt | formatDateTimeString }} < / a > < / small >
< / div >
< form @submit ="addNote()" >
2019-11-15 18:36:47 +01:00
< b -field : label = "$t('New note')" >
2019-09-09 09:31:08 +02:00
< b -input type = "textarea" v-model ="noteContent" > < / b -input >
< / b - f i e l d >
2019-11-15 18:36:47 +01:00
< b -button type = "submit" @click ="addNote" > {{ $ t ( ' Ajouter une note ' ) }} < / b -button >
2019-09-09 09:31:08 +02:00
< / form >
< / div >
< / section >
< / template >
< script lang = "ts" >
import { Component , Prop , Vue } from 'vue-property-decorator' ;
import { CREATE _REPORT _NOTE , REPORT , REPORTS , UPDATE _REPORT } from '@/graphql/report' ;
import { IReport , IReportNote , ReportStatusEnum } from '@/types/report.model' ;
2019-10-03 12:32:20 +02:00
import { RouteName } from '@/router' ;
2019-09-11 09:59:01 +02:00
import { CURRENT _ACTOR _CLIENT } from '@/graphql/actor' ;
2019-09-09 09:31:08 +02:00
import { IPerson } from '@/types/actor' ;
import { DELETE _EVENT } from '@/graphql/event' ;
import { uniq } from 'lodash' ;
2019-11-15 18:36:47 +01:00
import { nl2br } from '@/utils/html' ;
2019-09-09 09:31:08 +02:00
@ Component ( {
apollo : {
report : {
query : REPORT ,
variables ( ) {
return {
id : this . reportId ,
} ;
} ,
error ( { graphQLErrors } ) {
this . errors = uniq ( graphQLErrors . map ( ( { message } ) => message ) ) ;
} ,
} ,
2019-09-11 09:59:01 +02:00
currentActor : {
query : CURRENT _ACTOR _CLIENT ,
2019-09-09 09:31:08 +02:00
} ,
} ,
} )
export default class Report extends Vue {
@ Prop ( { required : true } ) reportId ! : number ;
report ! : IReport ;
2019-09-11 09:59:01 +02:00
currentActor ! : IPerson ;
2019-09-09 09:31:08 +02:00
errors : string [ ] = [ ] ;
ReportStatusEnum = ReportStatusEnum ;
2019-10-03 12:32:20 +02:00
RouteName = RouteName ;
2019-11-15 18:36:47 +01:00
nl2br = nl2br ;
2019-09-09 09:31:08 +02:00
noteContent : string = '' ;
addNote ( ) {
try {
this . $apollo . mutate < { createReportNote : IReportNote } > ( {
mutation : CREATE _REPORT _NOTE ,
variables : {
reportId : this . report . id ,
2019-09-11 09:59:01 +02:00
moderatorId : this . currentActor . id ,
2019-09-09 09:31:08 +02:00
content : this . noteContent ,
} ,
update : ( store , { data } ) => {
if ( data == null ) return ;
const cachedData = store . readQuery < { report : IReport } > ( { query : REPORT , variables : { id : this . report . id } } ) ;
if ( cachedData == null ) return ;
const { report } = cachedData ;
if ( report === null ) {
console . error ( 'Cannot update event notes cache, because of null value.' ) ;
return ;
}
const note = data . createReportNote ;
2019-09-11 09:59:01 +02:00
note . moderator = this . currentActor ;
2019-09-09 09:31:08 +02:00
report . notes = report . notes . concat ( [ note ] ) ;
2019-09-26 16:38:58 +02:00
store . writeQuery ( { query : REPORT , variables : { id : this . report . id } , data : { report } } ) ;
2019-09-09 09:31:08 +02:00
} ,
} ) ;
this . noteContent = '' ;
} catch ( error ) {
console . error ( error ) ;
}
}
confirmDelete ( ) {
this . $buefy . dialog . confirm ( {
2019-11-15 18:36:47 +01:00
title : this . $t ( 'Deleting event' ) as string ,
message : this . $t ( 'Are you sure you want to <b>delete</b> this event? This action cannot be undone. You may want to engage the conversation with the event creator or edit its event instead.' ) as string ,
confirmText : this . $t ( 'Delete Event' ) as string ,
2019-09-09 09:31:08 +02:00
type : 'is-danger' ,
hasIcon : true ,
onConfirm : ( ) => this . deleteEvent ( ) ,
} ) ;
}
async deleteEvent ( ) {
if ( ! this . report . event || ! this . report . event . id ) return ;
const eventTitle = this . report . event . title ;
try {
await this . $apollo . mutate ( {
mutation : DELETE _EVENT ,
variables : {
eventId : this . report . event . id . toString ( ) ,
2019-09-11 09:59:01 +02:00
actorId : this . currentActor . id ,
2019-09-09 09:31:08 +02:00
} ,
} ) ;
this . $buefy . notification . open ( {
2019-09-12 11:34:01 +02:00
message : this . $t ( 'Event {eventTitle} deleted' , { eventTitle } ) as string ,
2019-09-09 09:31:08 +02:00
type : 'is-success' ,
position : 'is-bottom-right' ,
duration : 5000 ,
} ) ;
} catch ( error ) {
console . error ( error ) ;
}
}
async updateReport ( status : ReportStatusEnum ) {
try {
await this . $apollo . mutate ( {
mutation : UPDATE _REPORT ,
variables : {
reportId : this . report . id ,
2019-09-11 09:59:01 +02:00
moderatorId : this . currentActor . id ,
2019-09-09 09:31:08 +02:00
status ,
} ,
update : ( store , { data } ) => {
if ( data == null ) return ;
const reportCachedData = store . readQuery < { report : IReport } > ( { query : REPORT , variables : { id : this . report . id } } ) ;
if ( reportCachedData == null ) return ;
const { report } = reportCachedData ;
if ( report === null ) {
console . error ( 'Cannot update event notes cache, because of null value.' ) ;
return ;
}
const updatedReport = data . updateReportStatus ;
report . status = updatedReport . status ;
2019-09-26 16:38:58 +02:00
store . writeQuery ( { query : REPORT , variables : { id : this . report . id } , data : { report } } ) ;
2019-09-09 09:31:08 +02:00
} ,
} ) ;
2019-11-15 18:36:47 +01:00
await this . $router . push ( { name : RouteName . REPORTS } ) ;
2019-09-09 09:31:08 +02:00
} catch ( error ) {
console . error ( error ) ;
}
}
// TODO make me a global function
formatDate ( value ) {
return value ? new Date ( value ) . toLocaleString ( undefined , { weekday : 'long' , year : 'numeric' , month : 'long' , day : 'numeric' } ) : null ;
}
formatTime ( value ) {
return value ? new Date ( value ) . toLocaleTimeString ( undefined , { hour : 'numeric' , minute : 'numeric' } ) : null ;
}
}
< / script >
2019-11-15 18:36:47 +01:00
< style lang = "scss" scoped >
@ import "@/variables.scss" ;
2019-09-09 09:31:08 +02:00
. container li {
margin : 10 px auto ;
}
tbody td img . image , . note img . image {
display : inline ;
height : 1.5 em ;
vertical - align : text - bottom ;
}
. dialog . modal - card - foot {
justify - content : flex - end ;
}
2019-11-15 18:36:47 +01:00
. report - content {
border - left : 4 px solid $primary ;
}
2019-09-09 09:31:08 +02:00
< / style >