Browse Source

refactor: various changes to station sidebar like adding an add to queue button, hiding autorequest sometimes, and more

Kristian Vos 1 year ago
parent
commit
95237ed29d

+ 25 - 21
frontend/src/components/PlaylistTabBase.vue

@@ -266,7 +266,7 @@ const searchForPlaylists = page => {
 };
 
 onMounted(() => {
-	showTab("search");
+	showTab("my-playlists");
 
 	socket.onConnect(() => {
 		socket.dispatch("playlists.indexMyPlaylists", res => {
@@ -304,7 +304,10 @@ onMounted(() => {
 			`autorequest-${station.value._id}`
 		);
 
-		if (autorequestLocalStorageItem) {
+		if (
+			autorequestLocalStorageItem &&
+			station.value.requests.allowAutorequest
+		) {
 			const autorequestParsedItem = JSON.parse(
 				autorequestLocalStorageItem
 			);
@@ -349,6 +352,17 @@ onMounted(() => {
 		</div>
 		<div class="tabs-container">
 			<div class="tab-selection">
+				<button
+					v-if="
+						type === 'autorequest' || station.type === 'community'
+					"
+					class="button is-default"
+					:ref="el => (tabs['my-playlists-tab'] = el)"
+					:class="{ selected: tab === 'my-playlists' }"
+					@click="showTab('my-playlists')"
+				>
+					My Playlists
+				</button>
 				<button
 					class="button is-default"
 					:ref="el => (tabs['search-tab'] = el)"
@@ -365,17 +379,6 @@ onMounted(() => {
 				>
 					Current
 				</button>
-				<button
-					v-if="
-						type === 'autorequest' || station.type === 'community'
-					"
-					class="button is-default"
-					:ref="el => (tabs['my-playlists-tab'] = el)"
-					:class="{ selected: tab === 'my-playlists' }"
-					@click="showTab('my-playlists')"
-				>
-					My Playlists
-				</button>
 			</div>
 			<div class="tab" v-show="tab === 'search'">
 				<div v-if="featuredPlaylists.length > 0">
@@ -840,13 +843,6 @@ onMounted(() => {
 				class="tab"
 				v-show="tab === 'my-playlists'"
 			>
-				<button
-					class="button is-primary"
-					id="create-new-playlist-button"
-					@click="openModal('createPlaylist')"
-				>
-					Create new playlist
-				</button>
 				<div
 					class="menu-list scrollable-list"
 					v-if="playlists.length > 0"
@@ -1011,8 +1007,16 @@ onMounted(() => {
 				</div>
 
 				<p v-else class="has-text-centered scrollable-list">
-					You don't have any playlists!
+					You don't have any playlists
 				</p>
+
+				<button
+					class="button is-primary"
+					id="create-new-playlist-button"
+					@click="openModal('createPlaylist')"
+				>
+					Create new playlist
+				</button>
 			</div>
 		</div>
 	</div>

+ 120 - 65
frontend/src/components/Queue.vue

@@ -2,9 +2,11 @@
 import { defineAsyncComponent, ref, computed, onUpdated } from "vue";
 import Toast from "toasters";
 import { DraggableList } from "vue-draggable-list";
+import { storeToRefs } from "pinia";
 import { useWebsocketsStore } from "@/stores/websockets";
 import { useStationStore } from "@/stores/station";
 import { useManageStationStore } from "@/stores/manageStation";
+import { useUserAuthStore } from "@/stores/userAuth";
 
 const SongItem = defineAsyncComponent(
 	() => import("@/components/SongItem.vue")
@@ -18,6 +20,9 @@ const props = defineProps({
 	sector: { type: String, default: "station" }
 });
 
+const userAuthStore = useUserAuthStore();
+const { loggedIn } = storeToRefs(userAuthStore);
+
 const { socket } = useWebsocketsStore();
 const stationStore = useStationStore();
 const manageStationStore = useManageStationStore({
@@ -58,6 +63,15 @@ const hasPermission = permission =>
 		? manageStationStore.hasPermission(permission)
 		: stationStore.hasPermission(permission);
 
+const canRequest = () =>
+	station.value &&
+	loggedIn.value &&
+	station.value.requests &&
+	station.value.requests.enabled &&
+	(station.value.requests.access === "user" ||
+		(station.value.requests.access === "owner" &&
+			hasPermission("stations.request")));
+
 const removeFromQueue = youtubeId => {
 	socket.dispatch(
 		"stations.removeFromQueue",
@@ -128,73 +142,91 @@ onUpdated(() => {
 			.getElementById("queue")
 			.querySelectorAll(".tab-actionable-button").length > 0;
 });
+
+defineEmits(["onChangeTab"]);
 </script>
 
 <template>
 	<div id="queue">
-		<div
-			v-if="queue.length > 0"
-			:class="{
-				'actionable-button-hidden': !actionableButtonVisible,
-				'scrollable-list': true
-			}"
-		>
-			<draggable-list
-				v-model:list="queue"
-				item-key="youtubeId"
-				@start="drag = true"
-				@end="drag = false"
-				@update="repositionSongInQueue"
-				:disabled="!hasPermission('stations.queue.reposition')"
+		<div class="inner-queue">
+			<div
+				v-if="queue.length > 0"
+				:class="{
+					'actionable-button-hidden': !actionableButtonVisible,
+					'scrollable-list': true
+				}"
 			>
-				<template #item="{ element, index }">
-					<song-item
-						:song="element"
-						:requested-by="true"
-						:disabled-actions="[]"
-						:ref="el => (songItems[`song-item-${index}`] = el)"
-						:key="`queue-song-item-${element.youtubeId}`"
-					>
-						<template
-							v-if="hasPermission('stations.queue.reposition')"
-							#tippyActions
+				<draggable-list
+					v-model:list="queue"
+					item-key="youtubeId"
+					@start="drag = true"
+					@end="drag = false"
+					@update="repositionSongInQueue"
+					:disabled="!hasPermission('stations.queue.reposition')"
+				>
+					<template #item="{ element, index }">
+						<song-item
+							:song="element"
+							:requested-by="true"
+							:disabled-actions="[]"
+							:ref="el => (songItems[`song-item-${index}`] = el)"
+							:key="`queue-song-item-${element.youtubeId}`"
 						>
-							<quick-confirm
-								v-if="hasPermission('stations.queue.remove')"
-								placement="left"
-								@confirm="removeFromQueue(element.youtubeId)"
+							<template
+								v-if="
+									hasPermission('stations.queue.reposition')
+								"
+								#tippyActions
 							>
+								<quick-confirm
+									v-if="
+										hasPermission('stations.queue.remove')
+									"
+									placement="left"
+									@confirm="
+										removeFromQueue(element.youtubeId)
+									"
+								>
+									<i
+										class="material-icons delete-icon"
+										content="Remove Song from Queue"
+										v-tippy
+										>delete_forever</i
+									>
+								</quick-confirm>
 								<i
-									class="material-icons delete-icon"
-									content="Remove Song from Queue"
+									class="material-icons"
+									v-if="index > 0"
+									@click="moveSongToTop(index)"
+									content="Move to top of Queue"
 									v-tippy
-									>delete_forever</i
+									>vertical_align_top</i
 								>
-							</quick-confirm>
-							<i
-								class="material-icons"
-								v-if="index > 0"
-								@click="moveSongToTop(index)"
-								content="Move to top of Queue"
-								v-tippy
-								>vertical_align_top</i
-							>
-							<i
-								v-if="queue.length - 1 !== index"
-								@click="moveSongToBottom(index)"
-								class="material-icons"
-								content="Move to bottom of Queue"
-								v-tippy
-								>vertical_align_bottom</i
-							>
-						</template>
-					</song-item>
-				</template>
-			</draggable-list>
+								<i
+									v-if="queue.length - 1 !== index"
+									@click="moveSongToBottom(index)"
+									class="material-icons"
+									content="Move to bottom of Queue"
+									v-tippy
+									>vertical_align_bottom</i
+								>
+							</template>
+						</song-item>
+					</template>
+				</draggable-list>
+			</div>
+			<p class="nothing-here-text has-text-centered" v-else>
+				There are no songs currently queued
+			</p>
+			<button
+				v-if="canRequest && sector === 'station'"
+				class="floating button is-primary"
+				@click="$emit('onChangeTab', 'request')"
+			>
+				<i class="material-icons icon-with-button">playlist_play</i>
+				<span>Add song to queue</span>
+			</button>
 		</div>
-		<p class="nothing-here-text has-text-centered" v-else>
-			There are no songs currently queued
-		</p>
 	</div>
 </template>
 
@@ -211,17 +243,40 @@ onUpdated(() => {
 	border-radius: 0 0 @border-radius @border-radius;
 	user-select: none;
 
-	.actionable-button-hidden {
-		max-height: 100%;
-	}
+	.inner-queue {
+		position: relative;
+		height: 100%;
+		width: 100%;
 
-	#queue-locked {
-		display: flex;
-		justify-content: center;
-	}
+		.actionable-button-hidden {
+			max-height: 100%;
+		}
+
+		#queue-locked {
+			display: flex;
+			justify-content: center;
+		}
 
-	button.disabled {
-		filter: grayscale(0.4);
+		button.disabled {
+			filter: grayscale(0.4);
+		}
+
+		> .scrollable-list:last-of-type:not(:last-child) {
+			padding-bottom: 50px;
+		}
+
+		.button.floating {
+			position: sticky;
+			z-index: 10;
+
+			bottom: 8px;
+			right: 8px;
+			left: 8px;
+
+			width: calc(100% - 16px);
+
+			margin-top: 50px;
+		}
 	}
 }
 </style>

+ 16 - 3
frontend/src/components/Request.vue

@@ -135,11 +135,23 @@ onMounted(async () => {
 
 <template>
 	<div class="station-playlists">
-		<p class="top-info has-text-centered">
+		<p
+			class="top-info has-text-centered"
+			v-if="
+				tab !== 'songs' ||
+				(station.requests.allowAutorequest && !disableAutoRequest)
+			"
+		>
 			Add songs to the queue or automatically request songs from playlists
 		</p>
 		<div class="tabs-container">
-			<div class="tab-selection">
+			<div
+				class="tab-selection"
+				v-if="
+					tab !== 'songs' ||
+					(station.requests.allowAutorequest && !disableAutoRequest)
+				"
+			>
 				<button
 					class="button is-default"
 					:ref="el => (tabs['songs-tab'] = el)"
@@ -367,6 +379,7 @@ onMounted(async () => {
 
 	.tabs-container {
 		.tab-selection {
+			margin-bottom: 10px;
 			display: flex;
 			overflow-x: auto;
 
@@ -392,7 +405,7 @@ onMounted(async () => {
 			}
 		}
 		.tab {
-			padding: 10px 0;
+			padding-bottom: 10px;
 			border-radius: 0;
 			.item.item-draggable:not(:last-of-type) {
 				margin-bottom: 10px;

+ 1 - 1
frontend/src/pages/Station/Sidebar/index.vue

@@ -82,7 +82,7 @@ onMounted(() => {
 				Request
 			</button>
 		</div>
-		<Queue class="tab" v-show="tab === 'queue'" />
+		<Queue class="tab" v-show="tab === 'queue'" @on-change-tab="showTab" />
 		<Users class="tab" v-show="tab === 'users'" />
 		<Request
 			v-if="canRequest()"

+ 3 - 1
frontend/src/stores/station.ts

@@ -161,7 +161,9 @@ export const useStationStore = defineStore("station", {
 		},
 		updateAutorequestLocalStorage() {
 			const key = `autorequest-${this.station._id}`;
-			const playlistIds = this.autoRequest.map(playlist => playlist._id);
+			const playlistIds = Array.from(
+				new Set(this.autoRequest.map(playlist => playlist._id))
+			);
 			const value = {
 				updatedAt: new Date(),
 				playlistIds