Reports.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <template>
  2. <div>
  3. <page-metadata title="Admin | Songs | Reports" />
  4. <div class="container">
  5. <advanced-table
  6. :column-default="columnDefault"
  7. :columns="columns"
  8. :filters="filters"
  9. data-action="reports.getData"
  10. name="admin-reports"
  11. max-width="1200"
  12. :events="events"
  13. >
  14. <template #column-options="slotProps">
  15. <div class="row-options">
  16. <button
  17. class="button is-primary icon-with-button material-icons"
  18. @click="
  19. openModal({
  20. modal: 'viewReport',
  21. data: { reportId: slotProps.item._id }
  22. })
  23. "
  24. :disabled="slotProps.item.removed"
  25. content="View Report"
  26. v-tippy
  27. >
  28. open_in_full
  29. </button>
  30. <button
  31. v-if="slotProps.item.resolved"
  32. class="button is-danger material-icons icon-with-button"
  33. @click="resolve(slotProps.item._id, false)"
  34. :disabled="slotProps.item.removed"
  35. content="Unresolve Report"
  36. v-tippy
  37. >
  38. remove_done
  39. </button>
  40. <button
  41. v-else
  42. class="button is-success material-icons icon-with-button"
  43. @click="resolve(slotProps.item._id, true)"
  44. :disabled="slotProps.item.removed"
  45. content="Resolve Report"
  46. v-tippy
  47. >
  48. done_all
  49. </button>
  50. </div>
  51. </template>
  52. <template #column-_id="slotProps">
  53. <span :title="slotProps.item._id">{{
  54. slotProps.item._id
  55. }}</span>
  56. </template>
  57. <template #column-songId="slotProps">
  58. <span :title="slotProps.item.song._id">{{
  59. slotProps.item.song._id
  60. }}</span>
  61. </template>
  62. <template #column-songYoutubeId="slotProps">
  63. <a
  64. :href="
  65. 'https://www.youtube.com/watch?v=' +
  66. `${slotProps.item.song.youtubeId}`
  67. "
  68. target="_blank"
  69. >
  70. {{ slotProps.item.song.youtubeId }}
  71. </a>
  72. </template>
  73. <template #column-resolved="slotProps">
  74. <span :title="slotProps.item.resolved">{{
  75. slotProps.item.resolved
  76. }}</span>
  77. </template>
  78. <template #column-categories="slotProps">
  79. <span
  80. :title="
  81. slotProps.item.issues
  82. .map(issue => issue.category)
  83. .join(', ')
  84. "
  85. >{{
  86. slotProps.item.issues
  87. .map(issue => issue.category)
  88. .join(", ")
  89. }}</span
  90. >
  91. </template>
  92. <template #column-createdBy="slotProps">
  93. <span v-if="slotProps.item.createdBy === 'Musare'"
  94. >Musare</span
  95. >
  96. <user-id-to-username
  97. v-else
  98. :user-id="slotProps.item.createdBy"
  99. :link="true"
  100. />
  101. </template>
  102. <template #column-createdAt="slotProps">
  103. <span :title="new Date(slotProps.item.createdAt)">{{
  104. getDateFormatted(slotProps.item.createdAt)
  105. }}</span>
  106. </template>
  107. </advanced-table>
  108. </div>
  109. </div>
  110. </template>
  111. <script>
  112. import { mapActions } from "vuex";
  113. import Toast from "toasters";
  114. import AdvancedTable from "@/components/AdvancedTable.vue";
  115. export default {
  116. components: {
  117. AdvancedTable
  118. },
  119. data() {
  120. return {
  121. columnDefault: {
  122. sortable: true,
  123. hidable: true,
  124. defaultVisibility: "shown",
  125. draggable: true,
  126. resizable: true,
  127. minWidth: 150,
  128. maxWidth: 600
  129. },
  130. columns: [
  131. {
  132. name: "options",
  133. displayName: "Options",
  134. properties: ["_id", "resolved"],
  135. sortable: false,
  136. hidable: false,
  137. resizable: false,
  138. minWidth: 85,
  139. defaultWidth: 85
  140. },
  141. {
  142. name: "_id",
  143. displayName: "Report ID",
  144. properties: ["_id"],
  145. sortProperty: "_id",
  146. minWidth: 215,
  147. defaultWidth: 215
  148. },
  149. {
  150. name: "songId",
  151. displayName: "Song ID",
  152. properties: ["song"],
  153. sortProperty: "song._id",
  154. minWidth: 215,
  155. defaultWidth: 215
  156. },
  157. {
  158. name: "songYoutubeId",
  159. displayName: "Song YouTube ID",
  160. properties: ["song"],
  161. sortProperty: "song.youtubeId",
  162. minWidth: 165,
  163. defaultWidth: 165
  164. },
  165. {
  166. name: "resolved",
  167. displayName: "Resolved",
  168. properties: ["resolved"],
  169. sortProperty: "resolved"
  170. },
  171. {
  172. name: "categories",
  173. displayName: "Categories",
  174. properties: ["issues"],
  175. sortable: false
  176. },
  177. {
  178. name: "createdBy",
  179. displayName: "Created By",
  180. properties: ["createdBy"],
  181. sortProperty: "createdBy",
  182. defaultWidth: 150
  183. },
  184. {
  185. name: "createdAt",
  186. displayName: "Created At",
  187. properties: ["createdAt"],
  188. sortProperty: "createdAt",
  189. defaultWidth: 150
  190. }
  191. ],
  192. filters: [
  193. {
  194. name: "_id",
  195. displayName: "Report ID",
  196. property: "_id",
  197. filterTypes: ["exact"],
  198. defaultFilterType: "exact"
  199. },
  200. {
  201. name: "songId",
  202. displayName: "Song ID",
  203. property: "song._id",
  204. filterTypes: ["exact"],
  205. defaultFilterType: "exact"
  206. },
  207. {
  208. name: "songYoutubeId",
  209. displayName: "Song YouTube ID",
  210. property: "song.youtubeId",
  211. filterTypes: ["contains", "exact", "regex"],
  212. defaultFilterType: "contains"
  213. },
  214. {
  215. name: "resolved",
  216. displayName: "Resolved",
  217. property: "resolved",
  218. filterTypes: ["boolean"],
  219. defaultFilterType: "boolean"
  220. },
  221. {
  222. name: "categories",
  223. displayName: "Categories",
  224. property: "issues.category",
  225. filterTypes: ["contains", "exact", "regex"],
  226. defaultFilterType: "contains"
  227. },
  228. {
  229. name: "createdBy",
  230. displayName: "Created By",
  231. property: "createdBy",
  232. filterTypes: ["contains", "exact", "regex"],
  233. defaultFilterType: "contains"
  234. },
  235. {
  236. name: "createdAt",
  237. displayName: "Created At",
  238. property: "createdAt",
  239. filterTypes: ["datetimeBefore", "datetimeAfter"],
  240. defaultFilterType: "datetimeBefore"
  241. }
  242. ],
  243. events: {
  244. adminRoom: "reports",
  245. updated: {
  246. event: "admin.report.updated",
  247. id: "report._id",
  248. item: "report"
  249. },
  250. removed: {
  251. event: "admin.report.removed",
  252. id: "reportId"
  253. }
  254. }
  255. };
  256. },
  257. methods: {
  258. resolve(reportId, value) {
  259. return this.resolveReport({ reportId, value })
  260. .then(res => {
  261. if (res.status !== "success") new Toast(res.message);
  262. })
  263. .catch(err => new Toast(err.message));
  264. },
  265. getDateFormatted(createdAt) {
  266. const date = new Date(createdAt);
  267. const year = date.getFullYear();
  268. const month = `${date.getMonth() + 1}`.padStart(2, 0);
  269. const day = `${date.getDate()}`.padStart(2, 0);
  270. const hour = `${date.getHours()}`.padStart(2, 0);
  271. const minute = `${date.getMinutes()}`.padStart(2, 0);
  272. return `${year}-${month}-${day} ${hour}:${minute}`;
  273. },
  274. ...mapActions("modalVisibility", ["openModal", "closeModal"]),
  275. ...mapActions("admin/reports", ["resolveReport"])
  276. }
  277. };
  278. </script>