AddToPlaylistDropdown.vue 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <template>
  2. <tippy
  3. class="addToPlaylistDropdown"
  4. interactive="true"
  5. :placement="placement"
  6. theme="addToPlaylist"
  7. trigger="click"
  8. append-to="parent"
  9. @show="
  10. () => {
  11. $parent.showPlaylistDropdown = true;
  12. }
  13. "
  14. @hide="
  15. () => {
  16. $parent.showPlaylistDropdown = false;
  17. }
  18. "
  19. >
  20. <template #trigger>
  21. <slot name="button" />
  22. </template>
  23. <div class="nav-dropdown-items" v-if="playlists.length > 0">
  24. <button
  25. class="nav-item"
  26. href="#"
  27. v-for="(playlist, index) in playlists"
  28. :key="index"
  29. @click.prevent="toggleSongInPlaylist(index)"
  30. :title="playlist.displayName"
  31. >
  32. <p class="control is-expanded checkbox-control">
  33. <input
  34. type="checkbox"
  35. :id="index"
  36. :checked="hasSong(playlist)"
  37. @click="toggleSongInPlaylist(index)"
  38. />
  39. <label :for="index">
  40. <span></span>
  41. <p>{{ playlist.displayName }}</p>
  42. </label>
  43. </p>
  44. </button>
  45. </div>
  46. <p v-else>You haven't created any playlists.</p>
  47. </tippy>
  48. </template>
  49. <script>
  50. import { mapGetters } from "vuex";
  51. import Toast from "toasters";
  52. export default {
  53. props: {
  54. song: {
  55. type: Object,
  56. default: () => {}
  57. },
  58. placement: {
  59. type: String,
  60. default: "left"
  61. }
  62. },
  63. data() {
  64. return {
  65. playlists: []
  66. };
  67. },
  68. computed: mapGetters({
  69. socket: "websockets/getSocket"
  70. }),
  71. mounted() {
  72. this.socket.dispatch("playlists.indexMyPlaylists", false, res => {
  73. if (res.status === "success") {
  74. this.playlists = res.data.playlists;
  75. }
  76. });
  77. this.socket.on("event:playlist.create", playlist => {
  78. this.playlists.push(playlist);
  79. });
  80. this.socket.on("event:playlist.delete", playlistId => {
  81. this.playlists.forEach((playlist, index) => {
  82. if (playlist._id === playlistId) {
  83. this.playlists.splice(index, 1);
  84. }
  85. });
  86. });
  87. this.socket.on("event:playlist.updateDisplayName", data => {
  88. this.playlists.forEach((playlist, index) => {
  89. if (playlist._id === data.playlistId) {
  90. this.playlists[index].displayName = data.displayName;
  91. }
  92. });
  93. });
  94. },
  95. methods: {
  96. toggleSongInPlaylist(playlistIndex) {
  97. const playlist = this.playlists[playlistIndex];
  98. if (!this.hasSong(playlist)) {
  99. this.socket.dispatch(
  100. "playlists.addSongToPlaylist",
  101. false,
  102. this.song.youtubeId,
  103. playlist._id,
  104. res => {
  105. new Toast(res.message);
  106. if (res.status === "success") {
  107. this.playlists[playlistIndex].songs.push(this.song);
  108. }
  109. }
  110. );
  111. } else {
  112. this.socket.dispatch(
  113. "playlists.removeSongFromPlaylist",
  114. this.song.youtubeId,
  115. playlist._id,
  116. res => {
  117. new Toast(res.message);
  118. if (res.status === "success") {
  119. this.playlists[playlistIndex].songs.forEach(
  120. (song, songIndex) => {
  121. if (song.youtubeId === this.song.youtubeId)
  122. this.playlists[
  123. playlistIndex
  124. ].songs.splice(songIndex, 1);
  125. }
  126. );
  127. }
  128. }
  129. );
  130. }
  131. },
  132. hasSong(playlist) {
  133. return (
  134. playlist.songs.map(song => song._id).indexOf(this.song._id) !==
  135. -1
  136. );
  137. }
  138. }
  139. };
  140. </script>