ViewReport.vue 6.7 KB

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