Report.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. <template>
  2. <modal title="Report">
  3. <div slot="body">
  4. <div class="columns song-types">
  5. <div
  6. v-if="previousSong !== null && localSong === null"
  7. class="column song-type"
  8. >
  9. <div
  10. class="card is-fullwidth"
  11. :class="{ 'is-highlight-active': isPreviousSongActive }"
  12. @click="highlight('previousSong')"
  13. >
  14. <header class="card-header">
  15. <p class="card-header-title">Previous Song</p>
  16. </header>
  17. <div class="card-content">
  18. <article class="media">
  19. <figure class="media-left">
  20. <p class="image is-64x64">
  21. <img
  22. :src="previousSong.thumbnail"
  23. onerror='this.src="/assets/notes-transparent.png"'
  24. />
  25. </p>
  26. </figure>
  27. <div class="media-content">
  28. <div class="content">
  29. <p>
  30. <strong>{{
  31. previousSong.title
  32. }}</strong>
  33. <br />
  34. <small>{{
  35. previousSong.artists.join(", ")
  36. }}</small>
  37. </p>
  38. </div>
  39. </div>
  40. </article>
  41. </div>
  42. <a
  43. href="#"
  44. class="absolute-a"
  45. @click="highlight('previousSong')"
  46. />
  47. </div>
  48. </div>
  49. <div
  50. v-if="currentSong !== {} && localSong === null"
  51. class="column song-type"
  52. >
  53. <div
  54. class="card is-fullwidth"
  55. :class="{ 'is-highlight-active': isCurrentSongActive }"
  56. @click="highlight('currentSong')"
  57. >
  58. <header class="card-header">
  59. <p class="card-header-title">Current Song</p>
  60. </header>
  61. <div class="card-content">
  62. <article class="media">
  63. <figure class="media-left">
  64. <p class="image is-64x64">
  65. <img
  66. :src="currentSong.thumbnail"
  67. onerror='this.src="/assets/notes-transparent.png"'
  68. />
  69. </p>
  70. </figure>
  71. <div class="media-content">
  72. <div class="content">
  73. <p>
  74. <strong>{{
  75. currentSong.title
  76. }}</strong>
  77. <br />
  78. <small>{{
  79. currentSong.artists.join(", ")
  80. }}</small>
  81. </p>
  82. </div>
  83. </div>
  84. </article>
  85. </div>
  86. <a
  87. href="#"
  88. class="absolute-a"
  89. @click="highlight('currentSong')"
  90. />
  91. </div>
  92. </div>
  93. <div v-if="localSong !== null" class="column song-type">
  94. <div class="card is-fullwidth">
  95. <header class="card-header">
  96. <p class="card-header-title">Song</p>
  97. </header>
  98. <div class="card-content">
  99. <article class="media">
  100. <figure class="media-left">
  101. <p class="image is-64x64">
  102. <img
  103. :src="localSong.thumbnail"
  104. onerror='this.src="/assets/notes-transparent.png"'
  105. />
  106. </p>
  107. </figure>
  108. <div class="media-content">
  109. <div class="content">
  110. <p>
  111. <strong>{{
  112. localSong.title
  113. }}</strong>
  114. <br />
  115. <small>{{
  116. localSong.artists.join(", ")
  117. }}</small>
  118. </p>
  119. </div>
  120. </div>
  121. </article>
  122. </div>
  123. </div>
  124. </div>
  125. </div>
  126. <div class="edit-report-wrapper">
  127. <div class="columns is-multiline">
  128. <div
  129. v-for="(issue, issueIndex) in issues"
  130. class="column is-half"
  131. :key="issueIndex"
  132. >
  133. <label class="label">{{ issue.name }}</label>
  134. <p
  135. v-for="(reason, reasonIndex) in issue.reasons"
  136. class="control"
  137. :key="reasonIndex"
  138. >
  139. <label class="checkbox">
  140. <input
  141. type="checkbox"
  142. @click="toggleIssue(issue.name, reason)"
  143. />
  144. {{ reason }}
  145. </label>
  146. </p>
  147. </div>
  148. <div class="column">
  149. <label class="label">Other</label>
  150. <textarea
  151. v-model="report.description"
  152. class="textarea"
  153. maxlength="400"
  154. placeholder="Any other details..."
  155. />
  156. <div class="textarea-counter">
  157. {{ charactersRemaining }}
  158. </div>
  159. </div>
  160. </div>
  161. </div>
  162. </div>
  163. <div slot="footer">
  164. <a class="button is-success" @click="create()" href="#">
  165. <i class="material-icons save-changes">done</i>
  166. <span>&nbsp;Create</span>
  167. </a>
  168. <a
  169. class="button is-danger"
  170. href="#"
  171. @click="
  172. closeModal({
  173. sector: 'station',
  174. modal: 'report'
  175. })
  176. "
  177. >
  178. <span>&nbsp;Cancel</span>
  179. </a>
  180. </div>
  181. </modal>
  182. </template>
  183. <script>
  184. import { mapState, mapActions } from "vuex";
  185. import Toast from "toasters";
  186. import Modal from "../Modal.vue";
  187. import io from "../../io";
  188. export default {
  189. components: { Modal },
  190. data() {
  191. return {
  192. isPreviousSongActive: false,
  193. isCurrentSongActive: true,
  194. localSong: null,
  195. report: {
  196. resolved: false,
  197. songId: "",
  198. description: "",
  199. issues: [
  200. { name: "Video", reasons: [] },
  201. { name: "Title", reasons: [] },
  202. { name: "Duration", reasons: [] },
  203. { name: "Artists", reasons: [] },
  204. { name: "Thumbnail", reasons: [] }
  205. ]
  206. },
  207. issues: [
  208. {
  209. name: "Video",
  210. reasons: [
  211. "Doesn't exist",
  212. "It's private",
  213. "It's not available in my country",
  214. "Unofficial"
  215. ]
  216. },
  217. {
  218. name: "Title",
  219. reasons: ["Incorrect", "Inappropriate"]
  220. },
  221. {
  222. name: "Duration",
  223. reasons: [
  224. "Skips too soon",
  225. "Skips too late",
  226. "Starts too soon",
  227. "Starts too late"
  228. ]
  229. },
  230. {
  231. name: "Artists",
  232. reasons: ["Incorrect", "Inappropriate"]
  233. },
  234. {
  235. name: "Thumbnail",
  236. reasons: ["Incorrect", "Inappropriate", "Doesn't exist"]
  237. }
  238. ]
  239. };
  240. },
  241. computed: {
  242. charactersRemaining() {
  243. return 400 - this.report.description.length;
  244. },
  245. ...mapState({
  246. currentSong: state => state.station.currentSong,
  247. previousSong: state => state.station.previousSong,
  248. song: state => state.modals.report.song
  249. })
  250. },
  251. mounted() {
  252. io.getSocket(socket => {
  253. this.socket = socket;
  254. });
  255. this.report.songId = this.currentSong.songId;
  256. if (this.song !== null) {
  257. this.localSong = this.song;
  258. this.report.songId = this.song.songId;
  259. this.reportSong(null);
  260. }
  261. },
  262. methods: {
  263. create() {
  264. console.log(this.report);
  265. this.socket.dispatch("reports.create", this.report, res => {
  266. new Toast({ content: res.message, timeout: 4000 });
  267. if (res.status === "success")
  268. this.closeModal({
  269. sector: "station",
  270. modal: "report"
  271. });
  272. });
  273. },
  274. highlight(type) {
  275. if (type === "currentSong") {
  276. this.report.songId = this.currentSong.songId;
  277. this.isPreviousSongActive = false;
  278. this.isCurrentSongActive = true;
  279. } else if (type === "previousSong") {
  280. this.report.songId = this.previousSong.songId;
  281. this.isCurrentSongActive = false;
  282. this.isPreviousSongActive = true;
  283. }
  284. },
  285. toggleIssue(name, reason) {
  286. for (let z = 0; z < this.report.issues.length; z += 1) {
  287. if (this.report.issues[z].name === name) {
  288. if (this.report.issues[z].reasons.indexOf(reason) > -1) {
  289. this.report.issues[z].reasons.splice(
  290. this.report.issues[z].reasons.indexOf(reason),
  291. 1
  292. );
  293. } else this.report.issues[z].reasons.push(reason);
  294. }
  295. }
  296. },
  297. ...mapActions("modals/report", ["reportSong"]),
  298. ...mapActions("modalVisibility", ["closeModal"])
  299. }
  300. };
  301. </script>
  302. <style lang="scss" scoped>
  303. h6 {
  304. margin-bottom: 15px;
  305. }
  306. .song-type:first-of-type {
  307. padding-left: 0;
  308. }
  309. .song-type:last-of-type {
  310. padding-right: 0;
  311. }
  312. .media-content {
  313. display: flex;
  314. align-items: center;
  315. height: 64px;
  316. }
  317. .radio-controls .control {
  318. display: flex;
  319. align-items: center;
  320. }
  321. .textarea-counter {
  322. text-align: right;
  323. }
  324. @media screen and (min-width: 769px) {
  325. .radio-controls .control-label {
  326. padding-top: 0 !important;
  327. }
  328. }
  329. .edit-report-wrapper {
  330. padding: 20px;
  331. }
  332. .is-highlight-active {
  333. border: 3px var(--primary-color) solid;
  334. }
  335. </style>