ViewReport.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. <template>
  2. <modal class="view-report-modal" title="View Report">
  3. <template #body v-if="report && report._id">
  4. <div class="report-item">
  5. <div id="song-and-report-items">
  6. <report-info-item
  7. :created-at="report.createdAt"
  8. :created-by="report.createdBy"
  9. />
  10. <song-item
  11. :song="song"
  12. :duration="false"
  13. :disabled-actions="['report']"
  14. />
  15. </div>
  16. <div class="report-sub-items">
  17. <div
  18. class="report-sub-item report-sub-item-unresolved"
  19. :class="[
  20. 'report',
  21. issue.resolved
  22. ? 'report-sub-item-resolved'
  23. : 'report-sub-item-unresolved'
  24. ]"
  25. v-for="(issue, issueIndex) in report.issues"
  26. :key="issueIndex"
  27. >
  28. <i
  29. class="
  30. material-icons
  31. duration-icon
  32. report-sub-item-left-icon
  33. "
  34. :content="issue.category"
  35. v-tippy
  36. >
  37. {{ icons[issue.category] }}
  38. </i>
  39. <p class="report-sub-item-info">
  40. <span class="report-sub-item-title">
  41. {{ issue.title }}
  42. </span>
  43. <span
  44. class="report-sub-item-description"
  45. v-if="issue.description"
  46. >
  47. {{ issue.description }}
  48. </span>
  49. </p>
  50. <div
  51. class="
  52. report-sub-item-actions
  53. universal-item-actions
  54. "
  55. >
  56. <i
  57. class="material-icons resolve-icon"
  58. content="Resolve"
  59. v-tippy
  60. v-if="!issue.resolved"
  61. @click="toggleIssue(issue._id)"
  62. >
  63. done
  64. </i>
  65. <i
  66. class="material-icons unresolve-icon"
  67. content="Unresolve"
  68. v-tippy
  69. v-else
  70. @click="toggleIssue(issue._id)"
  71. >
  72. remove
  73. </i>
  74. </div>
  75. </div>
  76. </div>
  77. </div>
  78. </template>
  79. <template #footer v-if="report && report._id">
  80. <a class="button is-primary" @click="openSong()">
  81. <i
  82. class="material-icons icon-with-button"
  83. content="Edit Song"
  84. v-tippy
  85. >
  86. edit
  87. </i>
  88. Edit Song
  89. </a>
  90. <a class="button is-success" href="#" @click="resolve()">
  91. <i
  92. class="material-icons icon-with-button"
  93. content="Resolve"
  94. v-tippy
  95. >
  96. done_all
  97. </i>
  98. Resolve
  99. </a>
  100. </template>
  101. </modal>
  102. </template>
  103. <script>
  104. import { mapActions, mapGetters, mapState } from "vuex";
  105. import Toast from "toasters";
  106. import ws from "@/ws";
  107. import Modal from "@/components/Modal.vue";
  108. import SongItem from "@/components/SongItem.vue";
  109. import ReportInfoItem from "@/components/ReportInfoItem.vue";
  110. export default {
  111. components: { Modal, SongItem, ReportInfoItem },
  112. props: {
  113. sector: { type: String, default: "admin" }
  114. },
  115. data() {
  116. return {
  117. icons: {
  118. duration: "timer",
  119. video: "tv",
  120. thumbnail: "image",
  121. artists: "record_voice_over",
  122. title: "title",
  123. custom: "lightbulb"
  124. },
  125. report: {},
  126. song: null
  127. };
  128. },
  129. computed: {
  130. ...mapState("modals/viewReport", {
  131. reportId: state => state.viewingReportId
  132. }),
  133. ...mapGetters({
  134. socket: "websockets/getSocket"
  135. })
  136. },
  137. mounted() {
  138. ws.onConnect(this.init);
  139. this.socket.on(
  140. "event:admin.report.resolved",
  141. () => this.closeModal("viewReport"),
  142. { modal: "viewReport" }
  143. );
  144. this.socket.on(
  145. "event:admin.report.issue.toggled",
  146. res => {
  147. if (this.report._id === res.data.reportId) {
  148. const issue = this.report.issues.find(
  149. issue => issue._id.toString() === res.data.issueId
  150. );
  151. issue.resolved = res.data.resolved;
  152. }
  153. },
  154. { modal: "viewReport" }
  155. );
  156. },
  157. beforeUnmount() {
  158. this.socket.dispatch("apis.leaveRoom", `view-report.${this.reportId}`);
  159. },
  160. methods: {
  161. init() {
  162. this.socket.dispatch("reports.findOne", this.reportId, res => {
  163. if (res.status === "success") {
  164. const { report } = res.data;
  165. this.socket.dispatch(
  166. "apis.joinRoom",
  167. `view-report.${report._id}`
  168. );
  169. this.report = report;
  170. this.socket.dispatch(
  171. "songs.getSongFromSongId",
  172. this.report.song._id,
  173. res => {
  174. if (res.status === "success")
  175. this.song = res.data.song;
  176. else {
  177. new Toast(
  178. "Cannot find the report's associated song"
  179. );
  180. this.closeModal("viewReport");
  181. }
  182. }
  183. );
  184. } else {
  185. new Toast("Report with that ID not found");
  186. this.closeModal("viewReport");
  187. }
  188. });
  189. },
  190. resolve() {
  191. return this.resolveReport(this.reportId)
  192. .then(res => {
  193. if (res.status === "success") this.closeModal("viewReport");
  194. })
  195. .catch(err => new Toast(err.message));
  196. },
  197. toggleIssue(issueId) {
  198. this.socket.dispatch(
  199. "reports.toggleIssue",
  200. this.reportId,
  201. issueId,
  202. res => {
  203. if (res.status !== "success") new Toast(res.message);
  204. }
  205. );
  206. },
  207. openSong() {
  208. this.editSong({ _id: this.report.song._id });
  209. this.openModal("editSong");
  210. },
  211. ...mapActions("admin/reports", ["indexReports", "resolveReport"]),
  212. ...mapActions("modals/editSong", ["editSong"]),
  213. ...mapActions("modalVisibility", ["closeModal", "openModal"])
  214. }
  215. };
  216. </script>
  217. <style lang="scss" scoped>
  218. .night-mode {
  219. .report-sub-items {
  220. background-color: var(--dark-grey-2) !important;
  221. .report-sub-item {
  222. border: 0.5px solid #fff !important;
  223. }
  224. }
  225. }
  226. @media screen and (min-width: 650px) {
  227. .report-info-item {
  228. margin-right: 10px !important;
  229. }
  230. }
  231. .report-item {
  232. #song-and-report-items {
  233. display: flex;
  234. flex-wrap: wrap;
  235. margin-bottom: 20px;
  236. .universal-item {
  237. width: fit-content;
  238. margin: 5px 0;
  239. }
  240. }
  241. /deep/ .report-info-item {
  242. justify-content: flex-start;
  243. .item-title-description {
  244. .item-title {
  245. font-size: 20px;
  246. font-family: Karla, Arial, sans-serif;
  247. }
  248. .item-description {
  249. font-size: 14px;
  250. font-family: Karla, Arial, sans-serif;
  251. }
  252. }
  253. }
  254. .report-sub-items {
  255. .report-sub-item {
  256. border: 1px solid var(--light-grey-3);
  257. margin-top: -1px;
  258. line-height: 24px;
  259. display: flex;
  260. padding: 8px;
  261. display: flex;
  262. &:first-child {
  263. border-radius: 3px 3px 0 0;
  264. }
  265. &:last-child {
  266. border-radius: 0 0 3px 3px;
  267. }
  268. &.report-sub-item-resolved {
  269. .report-sub-item-description,
  270. .report-sub-item-title {
  271. text-decoration: line-through;
  272. }
  273. }
  274. .report-sub-item-left-icon {
  275. margin-right: 8px;
  276. margin-top: auto;
  277. margin-bottom: auto;
  278. }
  279. .report-sub-item-info {
  280. flex: 1;
  281. display: flex;
  282. flex-direction: column;
  283. .report-sub-item-title {
  284. font-size: 16px;
  285. }
  286. .report-sub-item-description {
  287. font-size: 14px;
  288. line-height: 16px;
  289. }
  290. }
  291. .report-sub-item-actions {
  292. height: 24px;
  293. margin-left: 8px;
  294. margin-top: auto;
  295. margin-bottom: auto;
  296. }
  297. }
  298. }
  299. .resolve-icon {
  300. color: var(--green);
  301. cursor: pointer;
  302. }
  303. .unresolve-icon {
  304. color: var(--red);
  305. cursor: pointer;
  306. }
  307. }
  308. </style>