QueueSongs.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. <template>
  2. <div>
  3. <div class="container">
  4. <input
  5. v-model="searchQuery"
  6. type="text"
  7. class="input"
  8. placeholder="Search for Songs"
  9. />
  10. <br />
  11. <br />
  12. <table class="table is-striped">
  13. <thead>
  14. <tr>
  15. <td>Thumbnail</td>
  16. <td>Title</td>
  17. <td>ID</td>
  18. <td>YouTube ID</td>
  19. <td>Artists</td>
  20. <td>Genres</td>
  21. <td>Requested By</td>
  22. <td>Options</td>
  23. </tr>
  24. </thead>
  25. <tbody>
  26. <tr v-for="(song, index) in filteredSongs" :key="index">
  27. <td>
  28. <img
  29. class="song-thumbnail"
  30. :src="song.thumbnail"
  31. onerror="this.src='/assets/notes-transparent.png'"
  32. />
  33. </td>
  34. <td>
  35. <strong>{{ song.title }}</strong>
  36. </td>
  37. <td>{{ song._id }}</td>
  38. <td>
  39. <a
  40. :href="
  41. 'https://www.youtube.com/watch?v=' +
  42. `${song.songId}`
  43. "
  44. target="_blank"
  45. >
  46. {{ song.songId }}</a
  47. >
  48. </td>
  49. <td>{{ song.artists.join(", ") }}</td>
  50. <td>{{ song.genres.join(", ") }}</td>
  51. <td>
  52. <user-id-to-username
  53. :userId="song.requestedBy"
  54. :link="true"
  55. />
  56. </td>
  57. <td class="optionsColumn">
  58. <button
  59. class="button is-primary"
  60. @click="edit(song, index)"
  61. >
  62. <i class="material-icons">edit</i>
  63. </button>
  64. <button
  65. class="button is-success"
  66. @click="add(song)"
  67. >
  68. <i class="material-icons">add</i>
  69. </button>
  70. <button
  71. class="button is-danger"
  72. @click="remove(song._id, index)"
  73. >
  74. <i class="material-icons">cancel</i>
  75. </button>
  76. </td>
  77. </tr>
  78. </tbody>
  79. </table>
  80. </div>
  81. <nav class="pagination">
  82. <a
  83. v-if="position > 1"
  84. class="button"
  85. href="#"
  86. @click="getSet(position - 1)"
  87. >
  88. <i class="material-icons">navigate_before</i>
  89. </a>
  90. <a
  91. v-if="maxPosition > position"
  92. class="button"
  93. href="#"
  94. @click="getSet(position + 1)"
  95. >
  96. <i class="material-icons">navigate_next</i>
  97. </a>
  98. </nav>
  99. <edit-song v-if="modals.editSong" />
  100. </div>
  101. </template>
  102. <script>
  103. import { mapState, mapActions } from "vuex";
  104. import { Toast } from "vue-roaster";
  105. import EditSong from "../Modals/EditSong.vue";
  106. import UserIdToUsername from "../UserIdToUsername.vue";
  107. import io from "../../io";
  108. export default {
  109. components: { EditSong, UserIdToUsername },
  110. data() {
  111. return {
  112. position: 1,
  113. maxPosition: 1,
  114. searchQuery: "",
  115. songs: []
  116. };
  117. },
  118. computed: {
  119. filteredSongs() {
  120. return this.songs;
  121. // return this.songs.filter(song => song.indexOf(song.searchQuery) !== -1);
  122. },
  123. ...mapState("modals", {
  124. modals: state => state.modals.admin
  125. })
  126. },
  127. // watch: {
  128. // "modals.editSong": function(value) {
  129. // console.log(value);
  130. // if (value === false) this.stopVideo();
  131. // }
  132. // },
  133. methods: {
  134. getSet(position) {
  135. const _this = this;
  136. this.socket.emit("queueSongs.getSet", position, data => {
  137. _this.songs = data;
  138. this.position = position;
  139. });
  140. },
  141. edit(song, index) {
  142. const newSong = {};
  143. Object.keys(song).forEach(n => {
  144. newSong[n] = song[n];
  145. });
  146. this.editSong({ index, song: newSong, type: "queueSongs" });
  147. this.openModal({ sector: "admin", modal: "editSong" });
  148. },
  149. add(song) {
  150. this.socket.emit("songs.add", song, res => {
  151. if (res.status === "success")
  152. Toast.methods.addToast(res.message, 2000);
  153. else Toast.methods.addToast(res.message, 4000);
  154. });
  155. },
  156. remove(id) {
  157. this.socket.emit("queueSongs.remove", id, res => {
  158. if (res.status === "success")
  159. Toast.methods.addToast(res.message, 2000);
  160. else Toast.methods.addToast(res.message, 4000);
  161. });
  162. },
  163. init() {
  164. const _this = this;
  165. _this.socket.emit("queueSongs.index", data => {
  166. _this.songs = data.songs;
  167. _this.maxPosition = Math.round(data.maxLength / 50);
  168. });
  169. _this.socket.emit("apis.joinAdminRoom", "queue", () => {});
  170. },
  171. ...mapActions("admin/songs", ["stopVideo", "editSong"]),
  172. ...mapActions("modals", ["openModal"])
  173. },
  174. mounted() {
  175. const _this = this;
  176. io.getSocket(socket => {
  177. _this.socket = socket;
  178. if (_this.socket.connected) {
  179. _this.init();
  180. _this.socket.on("event:admin.queueSong.added", queueSong => {
  181. _this.songs.push(queueSong);
  182. });
  183. _this.socket.on("event:admin.queueSong.removed", songId => {
  184. _this.songs = _this.songs.filter(song => {
  185. return song._id !== songId;
  186. });
  187. });
  188. _this.socket.on(
  189. "event:admin.queueSong.updated",
  190. updatedSong => {
  191. for (let i = 0; i < _this.songs.length; i += 1) {
  192. const song = _this.songs[i];
  193. if (song._id === updatedSong._id) {
  194. _this.songs.$set(i, updatedSong);
  195. }
  196. }
  197. }
  198. );
  199. }
  200. io.onConnect(() => {
  201. _this.init();
  202. });
  203. });
  204. }
  205. };
  206. </script>
  207. <style lang="scss" scoped>
  208. .optionsColumn {
  209. width: 140px;
  210. button {
  211. width: 35px;
  212. }
  213. }
  214. .song-thumbnail {
  215. display: block;
  216. max-width: 50px;
  217. margin: 0 auto;
  218. }
  219. td {
  220. vertical-align: middle;
  221. }
  222. .is-primary:focus {
  223. background-color: #029ce3 !important;
  224. }
  225. </style>