| 
					
				 | 
			
			
				@@ -1,3 +1,109 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<script setup lang="ts"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { ref, computed, onMounted } from "vue"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { useStore } from "vuex"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import Toast from "toasters"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import ws from "@/ws"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const store = useStore(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const props = defineProps({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	song: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		type: Object, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		default: () => {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	placement: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		type: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		default: "left" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const dropdown = ref(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const playlists = computed(() => store.state.user.playlists.playlists); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const fetchedPlaylists = computed( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	() => store.state.user.playlists.fetchedPlaylists 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const { socket } = store.state.websockets; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const setPlaylists = payload => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	store.dispatch("user/playlists/setPlaylists", payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const addPlaylist = payload => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	store.dispatch("user/playlists/addPlaylist", payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const removePlaylist = payload => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	store.dispatch("user/playlists/removePlaylist", payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const openModal = payload => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	store.dispatch("modalVisibility/openModal", payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const init = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!fetchedPlaylists.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		socket.dispatch("playlists.indexMyPlaylists", res => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (res.status === "success") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (!fetchedPlaylists.value) setPlaylists(res.data.playlists); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const hasSong = playlist => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	playlist.songs.map(song => song.youtubeId).indexOf(props.song.youtubeId) !== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	-1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const toggleSongInPlaylist = playlistIndex => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const playlist = playlists.value[playlistIndex]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!hasSong(playlist)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		socket.dispatch( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			"playlists.addSongToPlaylist", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			props.song.youtubeId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			playlist._id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			res => new Toast(res.message) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		socket.dispatch( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			"playlists.removeSongFromPlaylist", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			props.song.youtubeId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			playlist._id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			res => new Toast(res.message) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const createPlaylist = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	dropdown.value.tippy.setProps({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		zIndex: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		hideOnClick: false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	window.addToPlaylistDropdown = dropdown.value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	openModal("createPlaylist"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	ws.onConnect(init); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	socket.on("event:playlist.created", res => addPlaylist(res.data.playlist), { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		replaceable: true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	socket.on( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		"event:playlist.deleted", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		res => removePlaylist(res.data.playlistId), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ replaceable: true } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	socket.on( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		"event:playlist.displayName.updated", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		res => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			playlists.value.forEach((playlist, index) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (playlist._id === res.data.playlistId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					playlists.value[index].displayName = res.data.displayName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ replaceable: true } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 <template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	<tippy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		class="addToPlaylistDropdown" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -63,114 +169,6 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	</tippy> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-<script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { mapGetters, mapState, mapActions } from "vuex"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import Toast from "toasters"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import ws from "@/ws"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	props: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		song: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			type: Object, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			default: () => {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		placement: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			type: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			default: "left" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	computed: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		...mapGetters({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			socket: "websockets/getSocket" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		...mapState({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			playlists: state => state.user.playlists.playlists, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			fetchedPlaylists: state => state.user.playlists.fetchedPlaylists 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	mounted() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		ws.onConnect(this.init); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.socket.on( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			"event:playlist.created", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			res => this.addPlaylist(res.data.playlist), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			{ replaceable: true } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.socket.on( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			"event:playlist.deleted", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			res => this.removePlaylist(res.data.playlistId), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			{ replaceable: true } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.socket.on( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			"event:playlist.displayName.updated", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			res => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				this.playlists.forEach((playlist, index) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if (playlist._id === res.data.playlistId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						this.playlists[index].displayName = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							res.data.displayName; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			{ replaceable: true } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	methods: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		init() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if (!this.fetchedPlaylists) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				this.socket.dispatch("playlists.indexMyPlaylists", res => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if (res.status === "success") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						if (!this.fetchedPlaylists) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							this.setPlaylists(res.data.playlists); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		toggleSongInPlaylist(playlistIndex) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			const playlist = this.playlists[playlistIndex]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if (!this.hasSong(playlist)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				this.socket.dispatch( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					"playlists.addSongToPlaylist", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					this.song.youtubeId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					playlist._id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					res => new Toast(res.message) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				this.socket.dispatch( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					"playlists.removeSongFromPlaylist", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					this.song.youtubeId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					playlist._id, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					res => new Toast(res.message) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		hasSong(playlist) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			return ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				playlist.songs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					.map(song => song.youtubeId) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					.indexOf(this.song.youtubeId) !== -1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		createPlaylist() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			this.$refs.dropdown.tippy.setProps({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				zIndex: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				hideOnClick: false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			window.addToPlaylistDropdown = this.$refs.dropdown; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			this.openModal("createPlaylist"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		...mapActions("user/playlists", [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			"setPlaylists", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			"addPlaylist", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			"removePlaylist" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		]), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		...mapActions("modalVisibility", ["openModal"]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-</script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 <style lang="less" scoped> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 .no-playlists { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	text-align: center; 
			 |