Browse Source

Reverted to older commit before vue 3 breaking changes

Owen Diffey 4 years ago
parent
commit
d7fd4452df

+ 1 - 2
frontend/dist/config/template.json

@@ -22,7 +22,6 @@
 	"messages": {
 		"accountRemoval": "Your account will be deactivated instantly and your data will shortly be deleted by an admin."
 	},
-	"manageStationVersion": "kris or owen",
 	"skipConfigVersionCheck": false,
-	"configVersion": 5
+	"configVersion": 6
 }

+ 0 - 0
frontend/src/components/modals/ManageStationOwen/Tabs/Blacklist.vue → frontend/src/components/modals/ManageStation/Tabs/Blacklist.vue


+ 0 - 0
frontend/src/components/modals/ManageStationOwen/Tabs/Playlists.vue → frontend/src/components/modals/ManageStation/Tabs/Playlists.vue


+ 0 - 0
frontend/src/components/modals/ManageStationOwen/Tabs/Search.vue → frontend/src/components/modals/ManageStation/Tabs/Search.vue


+ 0 - 0
frontend/src/components/modals/ManageStationKris/Tabs/Settings.vue → frontend/src/components/modals/ManageStation/Tabs/Settings.vue


+ 0 - 0
frontend/src/components/modals/ManageStationOwen/index.vue → frontend/src/components/modals/ManageStation/index.vue


+ 0 - 1012
frontend/src/components/modals/ManageStationKris/Tabs/Playlists.vue

@@ -1,1012 +0,0 @@
-<template>
-	<div class="station-playlists">
-		<div class="tabs-container">
-			<div class="tab-selection">
-				<button
-					class="button is-default"
-					ref="search-tab"
-					:class="{ selected: tab === 'search' }"
-					@click="showTab('search')"
-				>
-					Search
-				</button>
-				<button
-					v-if="station.type === 'community'"
-					class="button is-default"
-					ref="my-playlists-tab"
-					:class="{ selected: tab === 'my-playlists' }"
-					@click="showTab('my-playlists')"
-				>
-					My Playlists
-				</button>
-				<button
-					class="button is-default"
-					ref="party-tab"
-					:class="{ selected: tab === 'party' }"
-					v-if="isPartyMode()"
-					@click="showTab('party')"
-				>
-					Party
-				</button>
-				<button
-					class="button is-default"
-					ref="included-tab"
-					:class="{ selected: tab === 'included' }"
-					v-if="isPlaylistMode()"
-					@click="showTab('included')"
-				>
-					Included
-				</button>
-				<button
-					class="button is-default"
-					ref="excluded-tab"
-					:class="{ selected: tab === 'excluded' }"
-					@click="showTab('excluded')"
-				>
-					Excluded
-				</button>
-			</div>
-			<div class="tab" v-show="tab === 'search'">
-				<label class="label"> Search for a public playlist </label>
-				<div class="control is-grouped input-with-button">
-					<p class="control is-expanded">
-						<input
-							class="input"
-							type="text"
-							placeholder="Enter your playlist query here..."
-							v-model="search.query"
-							@keyup.enter="searchForPlaylists(1)"
-						/>
-					</p>
-					<p class="control">
-						<a class="button is-info" @click="searchForPlaylists(1)"
-							><i class="material-icons icon-with-button"
-								>search</i
-							>Search</a
-						>
-					</p>
-				</div>
-				<div v-if="search.results.length > 0">
-					<playlist-item
-						v-for="playlist in search.results"
-						:key="`searchKey-${playlist._id}`"
-						:playlist="playlist"
-						:show-owner="true"
-					>
-						<i
-							class="material-icons"
-							slot="item-icon"
-							v-if="
-								isAllowedToParty() && isSelected(playlist._id)
-							"
-							content="This playlist is currently selected"
-							v-tippy
-						>
-							radio
-						</i>
-						<i
-							class="material-icons"
-							slot="item-icon"
-							v-else-if="
-								isOwnerOrAdmin() &&
-									isPlaylistMode() &&
-									isIncluded(playlist._id)
-							"
-							content="This playlist is currently included"
-							v-tippy
-						>
-							play_arrow
-						</i>
-						<i
-							class="material-icons excluded-icon"
-							slot="item-icon"
-							v-else-if="
-								isOwnerOrAdmin() && isExcluded(playlist._id)
-							"
-							content="This playlist is currently excluded"
-							v-tippy
-						>
-							block
-						</i>
-						<i
-							class="material-icons"
-							slot="item-icon"
-							v-else
-							:content="
-								isPartyMode()
-									? 'This playlist is currently not selected or excluded'
-									: 'This playlist is currently not included or excluded'
-							"
-							v-tippy
-						>
-							play_disabled
-						</i>
-						<div class="icons-group" slot="actions">
-							<i
-								v-if="isExcluded(playlist._id)"
-								class="material-icons stop-icon"
-								content="This playlist is blacklisted in this station"
-								v-tippy="{ theme: 'info' }"
-								>play_disabled</i
-							>
-							<confirm
-								v-if="isPartyMode() && isSelected(playlist._id)"
-								@confirm="deselectPartyPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Stop playing songs from this playlist"
-									v-tippy
-								>
-									stop
-								</i>
-							</confirm>
-							<confirm
-								v-if="
-									isOwnerOrAdmin() &&
-										isPlaylistMode() &&
-										isIncluded(playlist._id)
-								"
-								@confirm="removeIncludedPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Stop playing songs from this playlist"
-									v-tippy
-								>
-									stop
-								</i>
-							</confirm>
-							<i
-								v-if="
-									isPartyMode() &&
-										!isSelected(playlist._id) &&
-										!isExcluded(playlist._id)
-								"
-								@click="selectPartyPlaylist(playlist)"
-								class="material-icons play-icon"
-								content="Request songs from this playlist"
-								v-tippy
-								>play_arrow</i
-							>
-							<i
-								v-if="
-									isOwnerOrAdmin() &&
-										isPlaylistMode() &&
-										!isIncluded(playlist._id) &&
-										!isExcluded(playlist._id)
-								"
-								@click="includePlaylist(playlist)"
-								class="material-icons play-icon"
-								:content="'Play songs from this playlist'"
-								v-tippy
-								>play_arrow</i
-							>
-							<confirm
-								v-if="
-									isOwnerOrAdmin() &&
-										!isExcluded(playlist._id)
-								"
-								@confirm="blacklistPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Blacklist Playlist"
-									v-tippy
-									>block</i
-								>
-							</confirm>
-							<confirm
-								v-if="
-									isOwnerOrAdmin() && isExcluded(playlist._id)
-								"
-								@confirm="removeExcludedPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Stop blacklisting songs from this playlist"
-									v-tippy
-								>
-									stop
-								</i>
-							</confirm>
-							<i
-								v-if="playlist.createdBy === myUserId"
-								@click="showPlaylist(playlist._id)"
-								class="material-icons edit-icon"
-								content="Edit Playlist"
-								v-tippy
-								>edit</i
-							>
-							<i
-								v-if="
-									playlist.createdBy !== myUserId &&
-										(playlist.privacy === 'public' ||
-											isAdmin())
-								"
-								@click="showPlaylist(playlist._id)"
-								class="material-icons edit-icon"
-								content="View Playlist"
-								v-tippy
-								>visibility</i
-							>
-						</div>
-					</playlist-item>
-					<button
-						v-if="resultsLeftCount > 0"
-						class="button is-primary load-more-button"
-						@click="searchForPlaylists(search.page + 1)"
-					>
-						Load {{ nextPageResultsCount }} more results
-					</button>
-				</div>
-			</div>
-			<div
-				v-if="station.type === 'community'"
-				class="tab"
-				v-show="tab === 'my-playlists'"
-			>
-				<button
-					class="button is-primary"
-					id="create-new-playlist-button"
-					@click="openModal('createPlaylist')"
-				>
-					Create new playlist
-				</button>
-				<draggable
-					class="menu-list scrollable-list"
-					v-if="playlists.length > 0"
-					v-model="playlists"
-					v-bind="dragOptions"
-					@start="drag = true"
-					@end="drag = false"
-					@change="savePlaylistOrder"
-				>
-					<transition-group
-						type="transition"
-						:name="!drag ? 'draggable-list-transition' : null"
-					>
-						<playlist-item
-							class="item-draggable"
-							v-for="playlist in playlists"
-							:key="playlist._id"
-							:playlist="playlist"
-						>
-							<i
-								class="material-icons"
-								slot="item-icon"
-								v-if="
-									isAllowedToParty() &&
-										isSelected(playlist._id)
-								"
-								content="This playlist is currently selected"
-								v-tippy
-							>
-								radio
-							</i>
-							<i
-								class="material-icons"
-								slot="item-icon"
-								v-else-if="
-									isOwnerOrAdmin() &&
-										isPlaylistMode() &&
-										isIncluded(playlist._id)
-								"
-								content="This playlist is currently included"
-								v-tippy
-							>
-								play_arrow
-							</i>
-							<i
-								class="material-icons excluded-icon"
-								slot="item-icon"
-								v-else-if="
-									isOwnerOrAdmin() && isExcluded(playlist._id)
-								"
-								content="This playlist is currently excluded"
-								v-tippy
-							>
-								block
-							</i>
-							<i
-								class="material-icons"
-								slot="item-icon"
-								v-else
-								:content="
-									isPartyMode()
-										? 'This playlist is currently not selected or excluded'
-										: 'This playlist is currently not included or excluded'
-								"
-								v-tippy
-							>
-								play_disabled
-							</i>
-							<div slot="actions">
-								<!-- <i
-									v-if="isExcluded(playlist._id)"
-									class="material-icons stop-icon"
-									content="This playlist is blacklisted in this station"
-									v-tippy="{ theme: 'info' }"
-									>play_disabled</i
-								> -->
-								<i
-									v-if="
-										isPartyMode() &&
-											!isSelected(playlist._id)
-									"
-									@click="selectPartyPlaylist(playlist)"
-									class="material-icons play-icon"
-									content="Request songs from this playlist"
-									v-tippy
-									>play_arrow</i
-								>
-								<i
-									v-if="
-										isPlaylistMode() &&
-											isOwnerOrAdmin() &&
-											!isSelected(playlist._id)
-									"
-									@click="includePlaylist(playlist)"
-									class="material-icons play-icon"
-									content="Play songs from this playlist"
-									v-tippy
-									>play_arrow</i
-								>
-								<confirm
-									v-if="
-										isPartyMode() &&
-											isSelected(playlist._id)
-									"
-									@confirm="
-										deselectPartyPlaylist(playlist._id)
-									"
-								>
-									<i
-										class="material-icons stop-icon"
-										content="Stop requesting songs from this playlist"
-										v-tippy
-										>stop</i
-									>
-								</confirm>
-								<confirm
-									v-if="
-										isPlaylistMode() &&
-											isOwnerOrAdmin() &&
-											isIncluded(playlist._id)
-									"
-									@confirm="
-										removeIncludedPlaylist(playlist._id)
-									"
-								>
-									<i
-										class="material-icons stop-icon"
-										content="Stop playing songs from this playlist"
-										v-tippy
-										>stop</i
-									>
-								</confirm>
-								<confirm
-									v-if="
-										isOwnerOrAdmin() &&
-											!isExcluded(playlist._id)
-									"
-									@confirm="blacklistPlaylist(playlist._id)"
-								>
-									<i
-										class="material-icons stop-icon"
-										content="Blacklist Playlist"
-										v-tippy
-										>block</i
-									>
-								</confirm>
-								<confirm
-									v-if="
-										isOwnerOrAdmin() &&
-											isExcluded(playlist._id)
-									"
-									@confirm="
-										removeExcludedPlaylist(playlist._id)
-									"
-								>
-									<i
-										class="material-icons stop-icon"
-										content="Stop blacklisting songs from this playlist"
-										v-tippy
-									>
-										stop
-									</i>
-								</confirm>
-								<i
-									@click="showPlaylist(playlist._id)"
-									class="material-icons edit-icon"
-									content="Edit Playlist"
-									v-tippy
-									>edit</i
-								>
-							</div>
-						</playlist-item>
-					</transition-group>
-				</draggable>
-				<p v-else class="has-text-centered scrollable-list">
-					You don't have any playlists!
-				</p>
-			</div>
-			<div class="tab" v-show="tab === 'party'" v-if="isPartyMode()">
-				<div v-if="partyPlaylists.length > 0">
-					<playlist-item
-						v-for="playlist in partyPlaylists"
-						:key="`key-${playlist._id}`"
-						:playlist="playlist"
-						:show-owner="true"
-					>
-						<i
-							class="material-icons"
-							slot="item-icon"
-							content="This playlist is currently selected"
-							v-tippy
-						>
-							radio
-						</i>
-						<div class="icons-group" slot="actions">
-							<confirm
-								v-if="isOwnerOrAdmin()"
-								@confirm="deselectPartyPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Stop playing songs from this playlist"
-									v-tippy
-								>
-									stop
-								</i>
-							</confirm>
-							<confirm
-								v-if="isOwnerOrAdmin()"
-								@confirm="blacklistPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Blacklist Playlist"
-									v-tippy
-									>block</i
-								>
-							</confirm>
-							<i
-								v-if="playlist.createdBy === myUserId"
-								@click="showPlaylist(playlist._id)"
-								class="material-icons edit-icon"
-								content="Edit Playlist"
-								v-tippy
-								>edit</i
-							>
-							<i
-								v-if="
-									playlist.createdBy !== myUserId &&
-										(playlist.privacy === 'public' ||
-											isAdmin())
-								"
-								@click="showPlaylist(playlist._id)"
-								class="material-icons edit-icon"
-								content="View Playlist"
-								v-tippy
-								>visibility</i
-							>
-						</div>
-					</playlist-item>
-				</div>
-				<p v-else class="has-text-centered scrollable-list">
-					No playlists currently being played.
-				</p>
-			</div>
-			<div
-				class="tab"
-				v-show="tab === 'included'"
-				v-if="isPlaylistMode()"
-			>
-				<div v-if="includedPlaylists.length > 0">
-					<playlist-item
-						v-for="playlist in includedPlaylists"
-						:key="`key-${playlist._id}`"
-						:playlist="playlist"
-						:show-owner="true"
-					>
-						<i
-							class="material-icons"
-							slot="item-icon"
-							content="This playlist is currently included"
-							v-tippy
-						>
-							play_arrow
-						</i>
-						<div class="icons-group" slot="actions">
-							<confirm
-								v-if="isOwnerOrAdmin()"
-								@confirm="removeIncludedPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Stop playing songs from this playlist"
-									v-tippy
-								>
-									stop
-								</i>
-							</confirm>
-							<confirm
-								v-if="isOwnerOrAdmin()"
-								@confirm="blacklistPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Blacklist Playlist"
-									v-tippy
-									>block</i
-								>
-							</confirm>
-							<i
-								v-if="playlist.createdBy === myUserId"
-								@click="showPlaylist(playlist._id)"
-								class="material-icons edit-icon"
-								content="Edit Playlist"
-								v-tippy
-								>edit</i
-							>
-							<i
-								v-if="
-									playlist.createdBy !== myUserId &&
-										(playlist.privacy === 'public' ||
-											isAdmin())
-								"
-								@click="showPlaylist(playlist._id)"
-								class="material-icons edit-icon"
-								content="View Playlist"
-								v-tippy
-								>visibility</i
-							>
-						</div>
-					</playlist-item>
-				</div>
-				<p v-else class="has-text-centered scrollable-list">
-					No playlists currently included.
-				</p>
-			</div>
-			<div
-				class="tab"
-				v-show="tab === 'excluded'"
-				v-if="isOwnerOrAdmin()"
-			>
-				<div v-if="excludedPlaylists.length > 0">
-					<playlist-item
-						:playlist="playlist"
-						v-for="playlist in excludedPlaylists"
-						:key="`key-${playlist._id}`"
-					>
-						<i
-							class="material-icons excluded-icon"
-							slot="item-icon"
-							content="This playlist is currently excluded"
-							v-tippy
-						>
-							block
-						</i>
-						<div class="icons-group" slot="actions">
-							<confirm
-								@confirm="removeExcludedPlaylist(playlist._id)"
-							>
-								<i
-									class="material-icons stop-icon"
-									content="Stop blacklisting songs from this playlist
-							"
-									v-tippy
-									>stop</i
-								>
-							</confirm>
-							<i
-								v-if="playlist.createdBy === userId"
-								@click="showPlaylist(playlist._id)"
-								class="material-icons edit-icon"
-								content="Edit Playlist"
-								v-tippy
-								>edit</i
-							>
-							<i
-								v-else
-								@click="showPlaylist(playlist._id)"
-								class="material-icons edit-icon"
-								content="View Playlist"
-								v-tippy
-								>visibility</i
-							>
-						</div>
-					</playlist-item>
-				</div>
-				<p v-else class="has-text-centered scrollable-list">
-					No playlists currently excluded.
-				</p>
-			</div>
-		</div>
-	</div>
-</template>
-<script>
-import { mapActions, mapState, mapGetters } from "vuex";
-
-import Toast from "toasters";
-import PlaylistItem from "@/components/PlaylistItem.vue";
-import Confirm from "@/components/Confirm.vue";
-
-import SortablePlaylists from "@/mixins/SortablePlaylists.vue";
-
-export default {
-	components: {
-		PlaylistItem,
-		Confirm
-	},
-	mixins: [SortablePlaylists],
-	data() {
-		return {
-			tab: "included",
-			search: {
-				query: "",
-				searchedQuery: "",
-				page: 0,
-				count: 0,
-				resultsLeft: 0,
-				results: []
-			}
-		};
-	},
-	computed: {
-		resultsLeftCount() {
-			return this.search.count - this.search.results.length;
-		},
-		nextPageResultsCount() {
-			return Math.min(this.search.pageSize, this.resultsLeftCount);
-		},
-		...mapState({
-			loggedIn: state => state.user.auth.loggedIn,
-			role: state => state.user.auth.role,
-			userId: state => state.user.auth.userId,
-			partyPlaylists: state => state.station.partyPlaylists
-		}),
-		...mapState("modals/manageStation", {
-			parentTab: state => state.tab,
-			originalStation: state => state.originalStation,
-			station: state => state.station,
-			includedPlaylists: state => state.includedPlaylists,
-			excludedPlaylists: state => state.excludedPlaylists,
-			songsList: state => state.songsList
-		}),
-		...mapGetters({
-			socket: "websockets/getSocket"
-		})
-	},
-	watch: {
-		// eslint-disable-next-line func-names
-		parentTab(value) {
-			if (value === "playlists") {
-				if (this.tab === "included" && this.isPartyMode()) {
-					this.showTab("party");
-				} else if (this.tab === "party" && this.isPlaylistMode()) {
-					this.showTab("included");
-				}
-			}
-		}
-	},
-	mounted() {
-		if (this.station.type === "community" && this.station.partyMode)
-			this.showTab("search");
-
-		this.socket.dispatch("playlists.indexMyPlaylists", true, res => {
-			if (res.status === "success") this.setPlaylists(res.data.playlists);
-			this.orderOfPlaylists = this.calculatePlaylistOrder(); // order in regards to the database
-		});
-
-		this.socket.dispatch(
-			`stations.getStationIncludedPlaylistsById`,
-			this.station._id,
-			res => {
-				if (res.status === "success") {
-					this.station.includedPlaylists = res.data.playlists;
-					this.originalStation.includedPlaylists = res.data.playlists;
-				}
-			}
-		);
-
-		this.socket.dispatch(
-			`stations.getStationExcludedPlaylistsById`,
-			this.station._id,
-			res => {
-				if (res.status === "success") {
-					this.station.excludedPlaylists = res.data.playlists;
-					this.originalStation.excludedPlaylists = res.data.playlists;
-				}
-			}
-		);
-	},
-	methods: {
-		showTab(tab) {
-			this.$refs[`${tab}-tab`].scrollIntoView();
-			this.tab = tab;
-		},
-		isOwner() {
-			return (
-				this.loggedIn &&
-				this.station &&
-				this.userId === this.station.owner
-			);
-		},
-		isAdmin() {
-			return this.loggedIn && this.role === "admin";
-		},
-		isOwnerOrAdmin() {
-			return this.isOwner() || this.isAdmin();
-		},
-		isPartyMode() {
-			return (
-				this.station &&
-				this.station.type === "community" &&
-				this.station.partyMode
-			);
-		},
-		isAllowedToParty() {
-			return (
-				this.station &&
-				this.isPartyMode() &&
-				(!this.station.locked || this.isOwnerOrAdmin()) &&
-				this.loggedIn
-			);
-		},
-		isPlaylistMode() {
-			return this.station && !this.isPartyMode();
-		},
-		showPlaylist(playlistId) {
-			this.editPlaylist(playlistId);
-			this.openModal("editPlaylist");
-		},
-		selectPartyPlaylist(playlist) {
-			if (!this.isSelected(playlist.id)) {
-				this.partyPlaylists.push(playlist);
-				this.addPartyPlaylistSongToQueue();
-				new Toast(
-					"Successfully selected playlist to auto request songs."
-				);
-			} else {
-				new Toast("Error: Playlist already selected.");
-			}
-		},
-		includePlaylist(playlist) {
-			this.socket.dispatch(
-				"stations.includePlaylist",
-				this.station._id,
-				playlist._id,
-				res => {
-					new Toast(res.message);
-				}
-			);
-		},
-		deselectPartyPlaylist(id) {
-			return new Promise(resolve => {
-				let selected = false;
-				this.partyPlaylists.forEach((playlist, index) => {
-					if (playlist._id === id) {
-						selected = true;
-						this.partyPlaylists.splice(index, 1);
-					}
-				});
-				if (selected) {
-					new Toast("Successfully deselected playlist.");
-					resolve();
-				} else {
-					new Toast("Playlist not selected.");
-					resolve();
-				}
-			});
-		},
-		removeIncludedPlaylist(id) {
-			return new Promise(resolve => {
-				this.socket.dispatch(
-					"stations.removeIncludedPlaylist",
-					this.station._id,
-					id,
-					res => {
-						new Toast(res.message);
-						resolve();
-					}
-				);
-			});
-		},
-		removeExcludedPlaylist(id) {
-			return new Promise(resolve => {
-				this.socket.dispatch(
-					"stations.removeExcludedPlaylist",
-					this.station._id,
-					id,
-					res => {
-						new Toast(res.message);
-						resolve();
-					}
-				);
-			});
-		},
-		isSelected(id) {
-			let selected = false;
-			this.partyPlaylists.forEach(playlist => {
-				if (playlist._id === id) selected = true;
-			});
-			return selected;
-		},
-		isIncluded(id) {
-			let included = false;
-			this.includedPlaylists.forEach(playlist => {
-				if (playlist._id === id) included = true;
-			});
-			return included;
-		},
-		isExcluded(id) {
-			let selected = false;
-			this.excludedPlaylists.forEach(playlist => {
-				if (playlist._id === id) selected = true;
-			});
-			return selected;
-		},
-		searchForPlaylists(page) {
-			if (
-				this.search.page >= page ||
-				this.search.searchedQuery !== this.search.query
-			) {
-				this.search.results = [];
-				this.search.page = 0;
-				this.search.count = 0;
-				this.search.resultsLeft = 0;
-				this.search.pageSize = 0;
-			}
-
-			const { query } = this.search;
-			const action =
-				this.station.type === "official"
-					? "playlists.searchOfficial"
-					: "playlists.searchCommunity";
-
-			this.search.searchedQuery = this.search.query;
-			this.socket.dispatch(action, query, page, res => {
-				const { data } = res;
-				const { count, pageSize, playlists } = data;
-				if (res.status === "success") {
-					this.search.results = [
-						...this.search.results,
-						...playlists
-					];
-					this.search.page = page;
-					this.search.count = count;
-					this.search.resultsLeft =
-						count - this.search.results.length;
-					this.search.pageSize = pageSize;
-				} else if (res.status === "error") {
-					this.search.results = [];
-					this.search.page = 0;
-					this.search.count = 0;
-					this.search.resultsLeft = 0;
-					this.search.pageSize = 0;
-					new Toast(res.message);
-				}
-			});
-		},
-		async blacklistPlaylist(id) {
-			if (this.isIncluded(id)) await this.removeIncludedPlaylist(id);
-
-			this.socket.dispatch(
-				"stations.excludePlaylist",
-				this.station._id,
-				id,
-				res => {
-					new Toast(res.message);
-				}
-			);
-		},
-		addPartyPlaylistSongToQueue() {
-			let isInQueue = false;
-			if (
-				this.station.type === "community" &&
-				this.station.partyMode === true
-			) {
-				this.songsList.forEach(queueSong => {
-					if (queueSong.requestedBy === this.userId) isInQueue = true;
-				});
-				if (!isInQueue && this.partyPlaylists) {
-					const selectedPlaylist = this.partyPlaylists[
-						Math.floor(Math.random() * this.partyPlaylists.length)
-					];
-					if (
-						selectedPlaylist._id &&
-						selectedPlaylist.songs.length > 0
-					) {
-						const selectedSong =
-							selectedPlaylist.songs[
-								Math.floor(
-									Math.random() *
-										selectedPlaylist.songs.length
-								)
-							];
-						if (selectedSong.youtubeId) {
-							this.socket.dispatch(
-								"stations.addToQueue",
-								this.station._id,
-								selectedSong.youtubeId,
-								data => {
-									if (data.status !== "success")
-										new Toast("Error auto queueing song");
-								}
-							);
-						}
-					}
-				}
-			}
-		},
-		...mapActions("station", ["updatePartyPlaylists"]),
-		...mapActions("modalVisibility", ["openModal"]),
-		...mapActions("user/playlists", ["editPlaylist", "setPlaylists"])
-	}
-};
-</script>
-
-<style lang="scss" scoped>
-.excluded-icon {
-	color: var(--red);
-}
-
-.included-icon {
-	color: var(--green);
-}
-
-.selected-icon {
-	color: var(--purple);
-}
-
-.station-playlists {
-	.tabs-container {
-		.tab-selection {
-			display: flex;
-			overflow-x: auto;
-			.button {
-				border-radius: 0;
-				border: 0;
-				text-transform: uppercase;
-				font-size: 14px;
-				color: var(--dark-grey-3);
-				background-color: var(--light-grey-2);
-				flex-grow: 1;
-				height: 32px;
-
-				&:not(:first-of-type) {
-					margin-left: 5px;
-				}
-			}
-
-			.selected {
-				background-color: var(--primary-color) !important;
-				color: var(--white) !important;
-				font-weight: 600;
-			}
-		}
-		.tab {
-			padding: 15px 0;
-			border-radius: 0;
-			.playlist-item:not(:last-of-type),
-			.item.item-draggable:not(:last-of-type) {
-				margin-bottom: 10px;
-			}
-			.load-more-button {
-				width: 100%;
-				margin-top: 10px;
-			}
-		}
-	}
-}
-.draggable-list-transition-move {
-	transition: transform 0.5s;
-}
-
-.draggable-list-ghost {
-	opacity: 0.5;
-	filter: brightness(95%);
-}
-</style>

+ 0 - 477
frontend/src/components/modals/ManageStationKris/Tabs/Songs.vue

@@ -1,477 +0,0 @@
-<template>
-	<div class="songs">
-		<div class="tabs-container">
-			<div class="tab-selection">
-				<button
-					class="button is-default"
-					:class="{ selected: tab === 'search' }"
-					v-if="isAllowedToParty()"
-					@click="showTab('search')"
-				>
-					Search
-				</button>
-				<button
-					class="button is-default"
-					:class="{ selected: tab === 'included' }"
-					v-if="isOwnerOrAdmin() && isPlaylistMode()"
-					@click="showTab('included')"
-				>
-					Included
-				</button>
-				<button
-					class="button is-default"
-					:class="{ selected: tab === 'excluded' }"
-					v-if="isOwnerOrAdmin()"
-					@click="showTab('excluded')"
-				>
-					Excluded
-				</button>
-			</div>
-			<div
-				class="tab"
-				v-show="tab === 'search'"
-				v-if="
-					station.type === 'community' &&
-						station.partyMode &&
-						(isOwnerOrAdmin() || !station.locked)
-				"
-			>
-				<div class="musare-songs">
-					<label class="label"> Search for a song on Musare </label>
-					<div class="control is-grouped input-with-button">
-						<p class="control is-expanded">
-							<input
-								class="input"
-								type="text"
-								placeholder="Enter your song query here..."
-								v-model="musareSearch.query"
-								@keyup.enter="searchForMusareSongs(1)"
-							/>
-						</p>
-						<p class="control">
-							<a
-								class="button is-info"
-								@click="searchForMusareSongs(1)"
-								><i class="material-icons icon-with-button"
-									>search</i
-								>Search</a
-							>
-						</p>
-					</div>
-					<div v-if="musareSearch.results.length > 0">
-						<song-item
-							v-for="song in musareSearch.results"
-							:key="song._id"
-							:song="song"
-						>
-							<div class="song-actions" slot="actions">
-								<i
-									class="material-icons add-to-queue-icon"
-									v-if="station.partyMode && !station.locked"
-									@click="addSongToQueue(song.youtubeId)"
-									content="Add Song to Queue"
-									v-tippy
-									>queue</i
-								>
-							</div>
-						</song-item>
-						<button
-							v-if="resultsLeftCount > 0"
-							class="button is-primary load-more-button"
-							@click="searchForMusareSongs(musareSearch.page + 1)"
-						>
-							Load {{ nextPageResultsCount }} more results
-						</button>
-					</div>
-				</div>
-				<div class="youtube-search">
-					<label class="label"> Search for a song on YouTube </label>
-					<div class="control is-grouped input-with-button">
-						<p class="control is-expanded">
-							<input
-								class="input"
-								type="text"
-								placeholder="Enter your YouTube query here..."
-								v-model="search.songs.query"
-								autofocus
-								@keyup.enter="searchForSongs()"
-							/>
-						</p>
-						<p class="control">
-							<a
-								class="button is-info"
-								@click.prevent="searchForSongs()"
-								><i class="material-icons icon-with-button"
-									>search</i
-								>Search</a
-							>
-						</p>
-					</div>
-
-					<div
-						v-if="search.songs.results.length > 0"
-						id="song-query-results"
-					>
-						<search-query-item
-							v-for="(result, index) in search.songs.results"
-							:key="result.id"
-							:result="result"
-						>
-							<div slot="actions">
-								<transition
-									name="search-query-actions"
-									mode="out-in"
-								>
-									<a
-										class="button is-success"
-										v-if="result.isAddedToQueue"
-										key="added-to-queue"
-									>
-										<i
-											class="material-icons icon-with-button"
-											>done</i
-										>
-										Added to queue
-									</a>
-									<a
-										class="button is-dark"
-										v-else
-										@click.prevent="
-											addSongToQueue(result.id, index)
-										"
-										key="add-to-queue"
-									>
-										<i
-											class="material-icons icon-with-button"
-											>add</i
-										>
-										Add to queue
-									</a>
-								</transition>
-							</div>
-						</search-query-item>
-
-						<a
-							class="button is-primary load-more-button"
-							@click.prevent="loadMoreSongs()"
-						>
-							Load more...
-						</a>
-					</div>
-				</div>
-			</div>
-			<div
-				class="tab"
-				v-show="tab === 'included'"
-				v-if="
-					isOwnerOrAdmin() &&
-						!(station.type === 'community' && station.partyMode)
-				"
-			>
-				<div v-if="stationPlaylist.songs.length > 0">
-					<div id="playlist-info-section">
-						<h5>Song Count: {{ stationPlaylist.songs.length }}</h5>
-						<h5>Duration: {{ totalLength(stationPlaylist) }}</h5>
-					</div>
-					<song-item
-						v-for="song in stationPlaylist.songs"
-						:key="song._id"
-						:song="song"
-					>
-					</song-item>
-				</div>
-				<p v-else class="has-text-centered scrollable-list">
-					No songs currently included. To include songs, include a
-					playlist.
-				</p>
-			</div>
-			<div
-				class="tab"
-				v-show="tab === 'excluded'"
-				v-if="isOwnerOrAdmin()"
-			>
-				<div v-if="excludedSongs.length > 0">
-					<div id="playlist-info-section" class="section">
-						<h5>Song Count: {{ excludedSongs.length }}</h5>
-					</div>
-					<song-item
-						v-for="song in excludedSongs"
-						:key="song._id"
-						:song="song"
-					>
-					</song-item>
-				</div>
-				<p v-else class="has-text-centered scrollable-list">
-					No songs currently excluded. To excluded songs, exclude a
-					playlist.
-				</p>
-			</div>
-		</div>
-	</div>
-</template>
-
-<script>
-import { mapState, mapGetters } from "vuex";
-
-import Toast from "toasters";
-import SearchYoutube from "@/mixins/SearchYoutube.vue";
-
-import SongItem from "@/components/SongItem.vue";
-import SearchQueryItem from "../../../SearchQueryItem.vue";
-
-import utils from "../../../../../js/utils";
-
-export default {
-	components: {
-		SongItem,
-		SearchQueryItem
-	},
-	mixins: [SearchYoutube],
-	data() {
-		return {
-			utils,
-			tab: "search",
-			musareSearch: {
-				query: "",
-				searchedQuery: "",
-				page: 0,
-				count: 0,
-				resultsLeft: 0,
-				results: []
-			}
-		};
-	},
-	computed: {
-		resultsLeftCount() {
-			return this.musareSearch.count - this.musareSearch.results.length;
-		},
-		nextPageResultsCount() {
-			return Math.min(this.musareSearch.pageSize, this.resultsLeftCount);
-		},
-		excludedSongs() {
-			return this.excludedPlaylists
-				.map(playlist => playlist.songs)
-				.flat()
-				.filter((song, index, self) => self.indexOf(song) === index);
-		},
-		excludedSongIds() {
-			return this.excludedSongs.map(excludedSong => excludedSong._id);
-		},
-		...mapState({
-			loggedIn: state => state.user.auth.loggedIn,
-			userId: state => state.user.auth.userId,
-			role: state => state.user.auth.role
-		}),
-		...mapState("modals/manageStation", {
-			parentTab: state => state.tab,
-			station: state => state.station,
-			originalStation: state => state.originalStation,
-			excludedPlaylists: state => state.excludedPlaylists,
-			stationPlaylist: state => state.stationPlaylist
-		}),
-		...mapGetters({
-			socket: "websockets/getSocket"
-		})
-	},
-	watch: {
-		// eslint-disable-next-line func-names
-		parentTab(value) {
-			if (value === "songs") {
-				if (this.tab === "search" && this.isPlaylistMode()) {
-					this.showTab("included");
-				} else if (this.tab === "included" && this.isPartyMode()) {
-					this.showTab("search");
-				}
-			}
-		}
-	},
-	methods: {
-		showTab(tab) {
-			this.tab = tab;
-		},
-		isOwner() {
-			return (
-				this.loggedIn &&
-				this.station &&
-				this.userId === this.station.owner
-			);
-		},
-		isAdmin() {
-			return this.loggedIn && this.role === "admin";
-		},
-		isOwnerOrAdmin() {
-			return this.isOwner() || this.isAdmin();
-		},
-		isPartyMode() {
-			return (
-				this.station &&
-				this.station.type === "community" &&
-				this.station.partyMode
-			);
-		},
-		isAllowedToParty() {
-			return (
-				this.station &&
-				this.isPartyMode() &&
-				(!this.station.locked || this.isOwnerOrAdmin()) &&
-				this.loggedIn
-			);
-		},
-		isPlaylistMode() {
-			return this.station && !this.isPartyMode();
-		},
-		totalLength(playlist) {
-			let length = 0;
-			playlist.songs.forEach(song => {
-				length += song.duration;
-			});
-			return this.utils.formatTimeLong(length);
-		},
-		addSongToQueue(youtubeId, index) {
-			if (this.station.type === "community") {
-				this.socket.dispatch(
-					"stations.addToQueue",
-					this.station._id,
-					youtubeId,
-					res => {
-						if (res.status !== "success")
-							new Toast(`Error: ${res.message}`);
-						else {
-							if (index)
-								this.search.songs.results[
-									index
-								].isAddedToQueue = true;
-
-							new Toast(res.message);
-						}
-					}
-				);
-			} else {
-				this.socket.dispatch("songs.request", youtubeId, res => {
-					if (res.status !== "success")
-						new Toast(`Error: ${res.message}`);
-					else {
-						this.search.songs.results[index].isAddedToQueue = true;
-
-						new Toast(res.message);
-					}
-				});
-			}
-		},
-		searchForMusareSongs(page) {
-			if (
-				this.musareSearch.page >= page ||
-				this.musareSearch.searchedQuery !== this.musareSearch.query
-			) {
-				this.musareSearch.results = [];
-				this.musareSearch.page = 0;
-				this.musareSearch.count = 0;
-				this.musareSearch.resultsLeft = 0;
-				this.musareSearch.pageSize = 0;
-			}
-
-			this.musareSearch.searchedQuery = this.musareSearch.query;
-			this.socket.dispatch(
-				"songs.searchOfficial",
-				this.musareSearch.query,
-				page,
-				res => {
-					const { data } = res;
-					const { count, pageSize, songs } = data;
-					if (res.status === "success") {
-						this.musareSearch.results = [
-							...this.musareSearch.results,
-							...songs
-						];
-						this.musareSearch.page = page;
-						this.musareSearch.count = count;
-						this.musareSearch.resultsLeft =
-							count - this.musareSearch.results.length;
-						this.musareSearch.pageSize = pageSize;
-					} else if (res.status === "error") {
-						this.musareSearch.results = [];
-						this.musareSearch.page = 0;
-						this.musareSearch.count = 0;
-						this.musareSearch.resultsLeft = 0;
-						this.musareSearch.pageSize = 0;
-						new Toast(res.message);
-					}
-				}
-			);
-		}
-	}
-};
-</script>
-
-<style lang="scss" scoped>
-.songs {
-	.tabs-container {
-		.tab-selection {
-			display: flex;
-			overflow-x: auto;
-			.button {
-				border-radius: 0;
-				border: 0;
-				text-transform: uppercase;
-				font-size: 14px;
-				color: var(--dark-grey-3);
-				background-color: var(--light-grey-2);
-				flex-grow: 1;
-				height: 32px;
-
-				&:not(:first-of-type) {
-					margin-left: 5px;
-				}
-			}
-
-			.selected {
-				background-color: var(--primary-color) !important;
-				color: var(--white) !important;
-				font-weight: 600;
-			}
-		}
-		.tab {
-			padding: 15px 0;
-			border-radius: 0;
-			.playlist-item:not(:last-of-type),
-			.item.item-draggable:not(:last-of-type) {
-				margin-bottom: 10px;
-			}
-			.load-more-button {
-				width: 100%;
-				margin-top: 10px;
-			}
-		}
-	}
-
-	.musare-songs,
-	.universal-item:not(:last-of-type) {
-		margin-bottom: 10px;
-	}
-	.load-more-button {
-		width: 100%;
-		margin-top: 10px;
-	}
-
-	#playlist-info-section {
-		border: 1px solid var(--light-grey-3);
-		border-radius: 3px;
-		padding: 15px !important;
-		margin-bottom: 16px;
-
-		h3 {
-			font-weight: 600;
-			font-size: 30px;
-		}
-
-		h5 {
-			font-size: 18px;
-		}
-
-		h3,
-		h5 {
-			margin: 0;
-		}
-	}
-}
-</style>

+ 0 - 842
frontend/src/components/modals/ManageStationKris/index.vue

@@ -1,842 +0,0 @@
-<template>
-	<modal
-		v-if="station"
-		:title="
-			!isOwnerOrAdmin() && station.partyMode
-				? 'Add Song to Queue'
-				: 'Manage Station'
-		"
-		:style="`--primary-color: var(--${station.theme})`"
-		class="manage-station-modal"
-	>
-		<template #body>
-			<div class="custom-modal-body" v-if="station && station._id">
-				<div class="left-section">
-					<div class="section">
-						<div id="about-station-container">
-							<div id="station-info">
-								<div id="station-name">
-									<h1>{{ station.displayName }}</h1>
-									<i
-										v-if="station.type === 'official'"
-										class="material-icons verified-station"
-										content="Verified Station"
-										v-tippy
-									>
-										check_circle
-									</i>
-									<i
-										class="material-icons stationMode"
-										:content="
-											station.partyMode
-												? 'Station in Party mode'
-												: 'Station in Playlist mode'
-										"
-										v-tippy
-										>{{
-											station.partyMode
-												? "emoji_people"
-												: "playlist_play"
-										}}</i
-									>
-								</div>
-								<p>{{ station.description }}</p>
-							</div>
-
-							<div id="admin-buttons" v-if="isOwnerOrAdmin()">
-								<!-- (Admin) Pause/Resume Button -->
-								<button
-									class="button is-danger"
-									v-if="stationPaused"
-									@click="resumeStation()"
-								>
-									<i class="material-icons icon-with-button"
-										>play_arrow</i
-									>
-									<span class="optional-desktop-only-text">
-										Resume Station
-									</span>
-								</button>
-								<button
-									class="button is-danger"
-									@click="pauseStation()"
-									v-else
-								>
-									<i class="material-icons icon-with-button"
-										>pause</i
-									>
-									<span class="optional-desktop-only-text">
-										Pause Station
-									</span>
-								</button>
-
-								<!-- (Admin) Skip Button -->
-								<button
-									class="button is-danger"
-									@click="skipStation()"
-								>
-									<i class="material-icons icon-with-button"
-										>skip_next</i
-									>
-									<span class="optional-desktop-only-text">
-										Force Skip
-									</span>
-								</button>
-
-								<!-- Station Settings Button -->
-								<!-- <button
-									class="button is-primary"
-									@click="openModal('manageStation')"
-								>
-									<i class="material-icons icon-with-button"
-										>settings</i
-									>
-									<span class="optional-desktop-only-text">
-										Manage Station
-									</span>
-								</button> -->
-								<router-link
-									v-if="sector !== 'station' && station.name"
-									:to="{
-										name: 'station',
-										params: { id: station.name }
-									}"
-									class="button is-primary"
-								>
-									Go To Station
-								</router-link>
-							</div>
-						</div>
-						<div class="tab-selection">
-							<button
-								v-if="isOwnerOrAdmin()"
-								class="button is-default"
-								:class="{ selected: tab === 'settings' }"
-								ref="settings-tab"
-								@click="showTab('settings')"
-							>
-								Settings
-							</button>
-							<button
-								v-if="isAllowedToParty() || isOwnerOrAdmin()"
-								class="button is-default"
-								:class="{ selected: tab === 'playlists' }"
-								ref="playlists-tab"
-								@click="showTab('playlists')"
-							>
-								Playlists
-							</button>
-							<button
-								v-if="isAllowedToParty() || isOwnerOrAdmin()"
-								class="button is-default"
-								:class="{ selected: tab === 'songs' }"
-								ref="songs-tab"
-								@click="showTab('songs')"
-							>
-								Songs
-							</button>
-						</div>
-						<settings
-							v-if="isOwnerOrAdmin()"
-							class="tab"
-							v-show="tab === 'settings'"
-						/>
-						<playlists
-							v-if="isAllowedToParty() || isOwnerOrAdmin()"
-							class="tab"
-							v-show="tab === 'playlists'"
-						/>
-						<songs
-							v-if="isAllowedToParty() || isOwnerOrAdmin()"
-							class="tab"
-							v-show="tab === 'songs'"
-						/>
-					</div>
-				</div>
-				<div class="right-section">
-					<div class="section">
-						<div class="queue-title">
-							<h4 class="section-title">Queue</h4>
-						</div>
-						<hr class="section-horizontal-rule" />
-						<song-item
-							v-if="currentSong._id"
-							:song="currentSong"
-							:requested-by="
-								station.type === 'community' &&
-									station.partyMode === true
-							"
-							header="Currently Playing.."
-							class="currently-playing"
-						/>
-						<queue sector="manageStation" />
-					</div>
-				</div>
-			</div>
-		</template>
-		<template #footer>
-			<!-- <router-link
-				v-if="sector !== 'station' && station.name"
-				:to="{
-					name: 'station',
-					params: { id: station.name }
-				}"
-				class="button is-primary"
-			>
-				Go To Station
-			</router-link> -->
-			<button
-				class="button is-primary tab-actionable-button"
-				v-if="loggedIn && station.type === 'official'"
-				@click="openModal('requestSong')"
-			>
-				<i class="material-icons icon-with-button">queue</i>
-				<span class="optional-desktop-only-text"> Request Song </span>
-			</button>
-			<div v-if="isOwnerOrAdmin()" class="right">
-				<confirm @confirm="clearAndRefillStationQueue()">
-					<a class="button is-danger">
-						Clear and refill station queue
-					</a>
-				</confirm>
-				<confirm
-					v-if="station && station.type === 'community'"
-					@confirm="removeStation()"
-				>
-					<button class="button is-danger">Delete station</button>
-				</confirm>
-			</div>
-		</template>
-	</modal>
-</template>
-
-<script>
-import { mapState, mapGetters, mapActions } from "vuex";
-
-import Toast from "toasters";
-
-import Confirm from "@/components/Confirm.vue";
-import Queue from "@/components/Queue.vue";
-import SongItem from "@/components/SongItem.vue";
-import Modal from "../../Modal.vue";
-
-import Settings from "./Tabs/Settings.vue";
-import Playlists from "./Tabs/Playlists.vue";
-import Songs from "./Tabs/Songs.vue";
-
-export default {
-	components: {
-		Modal,
-		Confirm,
-		Queue,
-		SongItem,
-		Settings,
-		Playlists,
-		Songs
-	},
-	props: {
-		stationId: { type: String, default: "" },
-		sector: { type: String, default: "admin" }
-	},
-	computed: {
-		...mapState({
-			loggedIn: state => state.user.auth.loggedIn,
-			userId: state => state.user.auth.userId,
-			role: state => state.user.auth.role
-		}),
-		...mapState("modals/manageStation", {
-			tab: state => state.tab,
-			station: state => state.station,
-			originalStation: state => state.originalStation,
-			songsList: state => state.songsList,
-			stationPlaylist: state => state.stationPlaylist,
-			includedPlaylists: state => state.includedPlaylists,
-			excludedPlaylists: state => state.excludedPlaylists,
-			stationPaused: state => state.stationPaused,
-			currentSong: state => state.currentSong
-		}),
-		...mapGetters({
-			socket: "websockets/getSocket"
-		})
-	},
-	mounted() {
-		this.socket.dispatch(`stations.getStationById`, this.stationId, res => {
-			if (res.status === "success") {
-				const { station } = res.data;
-				this.editStation(station);
-
-				if (!this.isOwnerOrAdmin() && this.station.partyMode)
-					this.showTab("songs");
-
-				const currentSong = res.data.station.currentSong
-					? res.data.station.currentSong
-					: {};
-
-				this.updateCurrentSong(currentSong);
-
-				this.updateStationPaused(res.data.station.paused);
-
-				this.socket.dispatch(
-					"stations.getStationIncludedPlaylistsById",
-					this.stationId,
-					res => {
-						if (res.status === "success")
-							this.setIncludedPlaylists(res.data.playlists);
-					}
-				);
-
-				this.socket.dispatch(
-					"stations.getStationExcludedPlaylistsById",
-					this.stationId,
-					res => {
-						if (res.status === "success")
-							this.setExcludedPlaylists(res.data.playlists);
-					}
-				);
-
-				if (this.isOwnerOrAdmin()) {
-					this.socket.dispatch(
-						"playlists.getPlaylistForStation",
-						this.station._id,
-						true,
-						res => {
-							if (res.status === "success") {
-								this.updateStationPlaylist(res.data.playlist);
-							}
-						}
-					);
-				}
-
-				this.socket.dispatch(
-					"stations.getQueue",
-					this.stationId,
-					res => {
-						if (res.status === "success")
-							this.updateSongsList(res.data.queue);
-					}
-				);
-
-				this.socket.dispatch(
-					"apis.joinRoom",
-					`manage-station.${this.stationId}`
-				);
-
-				this.socket.on(
-					"event:station.name.updated",
-					res => {
-						this.station.name = res.data.name;
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.displayName.updated",
-					res => {
-						this.station.displayName = res.data.displayName;
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.description.updated",
-					res => {
-						this.station.description = res.data.description;
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.partyMode.updated",
-					res => {
-						if (this.station.type === "community")
-							this.station.partyMode = res.data.partyMode;
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.playMode.updated",
-					res => {
-						this.station.playMode = res.data.playMode;
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.theme.updated",
-					res => {
-						const { theme } = res.data;
-						this.station.theme = theme;
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.privacy.updated",
-					res => {
-						this.station.privacy = res.data.privacy;
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.queue.lock.toggled",
-					res => {
-						this.station.locked = res.data.locked;
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.includedPlaylist",
-					res => {
-						const { playlist } = res.data;
-						const playlistIndex = this.includedPlaylists
-							.map(includedPlaylist => includedPlaylist._id)
-							.indexOf(playlist._id);
-						if (playlistIndex === -1)
-							this.includedPlaylists.push(playlist);
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.excludedPlaylist",
-					res => {
-						const { playlist } = res.data;
-						const playlistIndex = this.excludedPlaylists
-							.map(excludedPlaylist => excludedPlaylist._id)
-							.indexOf(playlist._id);
-						if (playlistIndex === -1)
-							this.excludedPlaylists.push(playlist);
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.removedIncludedPlaylist",
-					res => {
-						const { playlistId } = res.data;
-						const playlistIndex = this.includedPlaylists
-							.map(playlist => playlist._id)
-							.indexOf(playlistId);
-						if (playlistIndex >= 0)
-							this.includedPlaylists.splice(playlistIndex, 1);
-					},
-					{ modal: "manageStation" }
-				);
-
-				this.socket.on(
-					"event:station.removedExcludedPlaylist",
-					res => {
-						const { playlistId } = res.data;
-						const playlistIndex = this.excludedPlaylists
-							.map(playlist => playlist._id)
-							.indexOf(playlistId);
-						if (playlistIndex >= 0)
-							this.excludedPlaylists.splice(playlistIndex, 1);
-					},
-					{ modal: "manageStation" }
-				);
-			} else {
-				new Toast(`Station with that ID not found`);
-				this.closeModal("manageStation");
-			}
-		});
-
-		this.socket.on(
-			"event:station.queue.updated",
-			res => this.updateSongsList(res.data.queue),
-			{ modal: "manageStation" }
-		);
-
-		this.socket.on(
-			"event:station.queue.song.repositioned",
-			res => this.repositionSongInList(res.data.song),
-			{ modal: "manageStation" }
-		);
-
-		this.socket.on(
-			"event:station.pause",
-			() => this.updateStationPaused(true),
-			{ modal: "manageStation" }
-		);
-
-		this.socket.on(
-			"event:station.resume",
-			() => this.updateStationPaused(false),
-			{ modal: "manageStation" }
-		);
-
-		this.socket.on(
-			"event:station.nextSong",
-			res => {
-				const { currentSong } = res.data;
-				this.updateCurrentSong(currentSong || {});
-			},
-			{ modal: "manageStation" }
-		);
-
-		if (this.isOwnerOrAdmin()) {
-			this.socket.on(
-				"event:playlist.song.added",
-				res => {
-					if (this.stationPlaylist._id === res.data.playlistId)
-						this.stationPlaylist.songs.push(res.data.song);
-				},
-				{
-					modal: "manageStation"
-				}
-			);
-
-			this.socket.on(
-				"event:playlist.song.removed",
-				res => {
-					if (this.stationPlaylist._id === res.data.playlistId) {
-						// remove song from array of playlists
-						this.stationPlaylist.songs.forEach((song, index) => {
-							if (song.youtubeId === res.data.youtubeId)
-								this.stationPlaylist.songs.splice(index, 1);
-						});
-					}
-				},
-				{
-					modal: "manageStation"
-				}
-			);
-
-			this.socket.on(
-				"event:playlist.songs.repositioned",
-				res => {
-					if (this.stationPlaylist._id === res.data.playlistId) {
-						// for each song that has a new position
-						res.data.songsBeingChanged.forEach(changedSong => {
-							this.stationPlaylist.songs.forEach(
-								(song, index) => {
-									// find song locally
-									if (
-										song.youtubeId === changedSong.youtubeId
-									) {
-										// change song position attribute
-										this.stationPlaylist.songs[
-											index
-										].position = changedSong.position;
-
-										// reposition in array if needed
-										if (index !== changedSong.position - 1)
-											this.stationPlaylist.songs.splice(
-												changedSong.position - 1,
-												0,
-												this.stationPlaylist.songs.splice(
-													index,
-													1
-												)[0]
-											);
-									}
-								}
-							);
-						});
-					}
-				},
-				{
-					modal: "manageStation"
-				}
-			);
-		}
-	},
-	beforeDestroy() {
-		this.socket.dispatch(
-			"apis.leaveRoom",
-			`manage-station.${this.stationId}`,
-			() => {}
-		);
-
-		this.repositionSongInList([]);
-		this.clearStation();
-		this.showTab("settings");
-	},
-	methods: {
-		isOwner() {
-			return (
-				this.loggedIn &&
-				this.station &&
-				this.userId === this.station.owner
-			);
-		},
-		isAdmin() {
-			return this.loggedIn && this.role === "admin";
-		},
-		isOwnerOrAdmin() {
-			return this.isOwner() || this.isAdmin();
-		},
-		isPartyMode() {
-			return (
-				this.station &&
-				this.station.type === "community" &&
-				this.station.partyMode
-			);
-		},
-		isAllowedToParty() {
-			return (
-				this.station &&
-				this.isPartyMode() &&
-				(!this.station.locked || this.isOwnerOrAdmin()) &&
-				this.loggedIn
-			);
-		},
-		isPlaylistMode() {
-			return this.station && !this.isPartyMode();
-		},
-		removeStation() {
-			this.socket.dispatch("stations.remove", this.station._id, res => {
-				new Toast(res.message);
-				if (res.status === "success") {
-					this.closeModal("manageStation");
-				}
-			});
-		},
-		resumeStation() {
-			this.socket.dispatch("stations.resume", this.station._id, res => {
-				if (res.status !== "success")
-					new Toast(`Error: ${res.message}`);
-				else new Toast("Successfully resumed the station.");
-			});
-		},
-		pauseStation() {
-			this.socket.dispatch("stations.pause", this.station._id, res => {
-				if (res.status !== "success")
-					new Toast(`Error: ${res.message}`);
-				else new Toast("Successfully paused the station.");
-			});
-		},
-		skipStation() {
-			this.socket.dispatch(
-				"stations.forceSkip",
-				this.station._id,
-				res => {
-					if (res.status !== "success")
-						new Toast(`Error: ${res.message}`);
-					else
-						new Toast(
-							"Successfully skipped the station's current song."
-						);
-				}
-			);
-		},
-		clearAndRefillStationQueue() {
-			this.socket.dispatch(
-				"stations.clearAndRefillStationQueue",
-				this.station._id,
-				res => {
-					if (res.status !== "success")
-						new Toast({
-							content: `Error: ${res.message}`,
-							timeout: 8000
-						});
-					else new Toast({ content: res.message, timeout: 4000 });
-				}
-			);
-		},
-		...mapActions("modals/manageStation", [
-			"editStation",
-			"setIncludedPlaylists",
-			"setExcludedPlaylists",
-			"clearStation",
-			"updateSongsList",
-			"updateStationPlaylist",
-			"repositionSongInList",
-			"updateStationPaused",
-			"updateCurrentSong"
-		]),
-		...mapActions({
-			showTab(dispatch, payload) {
-				this.$refs[`${payload}-tab`].scrollIntoView();
-				return dispatch("modals/manageStation/showTab", payload);
-			}
-		}),
-		...mapActions("modalVisibility", ["openModal", "closeModal"]),
-		...mapActions("user/playlists", ["editPlaylist"])
-	}
-};
-</script>
-
-<style lang="scss">
-.manage-station-modal.modal {
-	z-index: 1800;
-	.modal-card {
-		width: 1300px;
-		height: 100%;
-		overflow: auto;
-		.tab > button {
-			width: 100%;
-			margin-bottom: 10px;
-		}
-		.currently-playing.song-item {
-			.song-info {
-				width: calc(100% - 150px);
-			}
-			.thumbnail {
-				min-width: 130px;
-				width: 130px;
-				height: 130px;
-			}
-		}
-	}
-}
-</style>
-
-<style lang="scss" scoped>
-.night-mode {
-	#about-station-container {
-		background-color: var(--dark-grey-3) !important;
-	}
-}
-
-.manage-station-modal.modal .modal-card-body .custom-modal-body {
-	display: flex;
-	flex-wrap: wrap;
-	height: 100%;
-
-	.section {
-		display: flex;
-		flex-direction: column;
-		flex-grow: 1;
-		width: auto;
-		padding: 15px !important;
-		margin: 0 10px;
-	}
-
-	.left-section {
-		flex-basis: 50%;
-		height: 100%;
-		overflow-y: auto;
-		flex-grow: 1;
-
-		#about-station-container {
-			padding: 20px;
-			display: flex;
-			flex-direction: column;
-			flex-grow: unset;
-			border-radius: 5px;
-			margin: 0 0 20px 0;
-			background-color: var(--white);
-			border: 1px solid var(--light-grey-3);
-
-			#station-info {
-				#station-name {
-					flex-direction: row !important;
-					display: flex;
-					flex-direction: row;
-					max-width: 100%;
-
-					h1 {
-						margin: 0;
-						font-size: 36px;
-						line-height: 0.8;
-					}
-
-					i {
-						margin-left: 10px;
-						font-size: 30px;
-						color: var(--yellow);
-						&.stationMode {
-							padding-left: 10px;
-							margin-left: auto;
-							color: var(--primary-color);
-						}
-					}
-
-					.verified-station {
-						color: var(--primary-color);
-					}
-				}
-
-				p {
-					max-width: 700px;
-					margin-bottom: 10px;
-				}
-			}
-
-			#admin-buttons {
-				display: flex;
-
-				.button {
-					margin: 3px;
-				}
-			}
-		}
-
-		.tab-selection {
-			display: flex;
-			overflow-x: auto;
-
-			.button {
-				border-radius: 5px 5px 0 0;
-				border: 0;
-				text-transform: uppercase;
-				font-size: 14px;
-				color: var(--dark-grey-3);
-				background-color: var(--light-grey-2);
-				flex-grow: 1;
-				height: 32px;
-
-				&:not(:first-of-type) {
-					margin-left: 5px;
-				}
-			}
-
-			.selected {
-				background-color: var(--primary-color) !important;
-				color: var(--white) !important;
-				font-weight: 600;
-			}
-		}
-		.tab {
-			border: 1px solid var(--light-grey-3);
-			padding: 15px;
-			border-radius: 0 0 5px 5px;
-		}
-	}
-	.right-section {
-		flex-basis: 50%;
-		height: 100%;
-		overflow-y: auto;
-		flex-grow: 1;
-		.section {
-			.queue-title {
-				display: flex;
-				line-height: 30px;
-				.material-icons {
-					margin-left: 5px;
-					margin-bottom: 5px;
-					font-size: 28px;
-					cursor: pointer;
-					&:first-of-type {
-						margin-left: auto;
-					}
-					&.skip-station {
-						color: var(--red);
-					}
-					&.resume-station,
-					&.pause-station {
-						color: var(--primary-color);
-					}
-				}
-			}
-			.currently-playing {
-				margin-bottom: 10px;
-			}
-		}
-	}
-}
-
-@media screen and (max-width: 1100px) {
-	.manage-station-modal.modal .modal-card-body .custom-modal-body {
-		.left-section,
-		.right-section {
-			flex-basis: unset;
-			height: auto;
-		}
-	}
-}
-</style>

+ 0 - 595
frontend/src/components/modals/ManageStationOwen/Tabs/Settings.vue

@@ -1,595 +0,0 @@
-<template>
-	<div class="station-settings">
-		<label class="label">Name</label>
-		<div class="control is-grouped input-with-button">
-			<p class="control is-expanded">
-				<input class="input" type="text" v-model="station.name" />
-			</p>
-			<p class="control">
-				<a class="button is-info" @click.prevent="updateName()">Save</a>
-			</p>
-		</div>
-		<label class="label">Display Name</label>
-		<div class="control is-grouped input-with-button">
-			<p class="control is-expanded">
-				<input
-					class="input"
-					type="text"
-					v-model="station.displayName"
-				/>
-			</p>
-			<p class="control">
-				<a class="button is-info" @click.prevent="updateDisplayName()"
-					>Save</a
-				>
-			</p>
-		</div>
-		<label class="label">Description</label>
-		<div class="control is-grouped input-with-button">
-			<p class="control is-expanded">
-				<input
-					class="input"
-					type="text"
-					v-model="station.description"
-				/>
-			</p>
-			<p class="control">
-				<a class="button is-info" @click.prevent="updateDescription()"
-					>Save</a
-				>
-			</p>
-		</div>
-		<div class="settings-buttons">
-			<div class="small-section">
-				<label class="label">Theme</label>
-				<tippy
-					class="button-wrapper"
-					theme="addToPlaylist"
-					interactive="true"
-					touch="true"
-					placement="bottom"
-					trigger="click"
-					append-to="parent"
-				>
-					<template #trigger>
-						<button :class="station.theme">
-							<i class="material-icons">palette</i>
-							{{ station.theme }}
-						</button>
-					</template>
-					<button
-						class="blue"
-						v-if="station.theme !== 'blue'"
-						@click="updateTheme('blue')"
-					>
-						<i class="material-icons">palette</i>
-						Blue
-					</button>
-					<button
-						class="purple"
-						v-if="station.theme !== 'purple'"
-						@click="updateTheme('purple')"
-					>
-						<i class="material-icons">palette</i>
-						Purple
-					</button>
-					<button
-						class="teal"
-						v-if="station.theme !== 'teal'"
-						@click="updateTheme('teal')"
-					>
-						<i class="material-icons">palette</i>
-						Teal
-					</button>
-					<button
-						class="orange"
-						v-if="station.theme !== 'orange'"
-						@click="updateTheme('orange')"
-					>
-						<i class="material-icons">palette</i>
-						Orange
-					</button>
-				</tippy>
-			</div>
-			<div class="small-section">
-				<label class="label">Privacy</label>
-				<tippy
-					class="button-wrapper"
-					theme="addToPlaylist"
-					interactive="true"
-					touch="true"
-					placement="bottom"
-					trigger="click"
-					append-to="parent"
-				>
-					<template #trigger>
-						<button :class="privacyButtons[station.privacy].style">
-							<i class="material-icons">{{
-								privacyButtons[station.privacy].iconName
-							}}</i>
-							{{ station.privacy }}
-						</button>
-					</template>
-					<button
-						class="green"
-						v-if="station.privacy !== 'public'"
-						@click="updatePrivacy('public')"
-					>
-						<i class="material-icons">{{
-							privacyButtons["public"].iconName
-						}}</i>
-						Public
-					</button>
-					<button
-						class="orange"
-						v-if="station.privacy !== 'unlisted'"
-						@click="updatePrivacy('unlisted')"
-					>
-						<i class="material-icons">{{
-							privacyButtons["unlisted"].iconName
-						}}</i>
-						Unlisted
-					</button>
-					<button
-						class="red"
-						v-if="station.privacy !== 'private'"
-						@click="updatePrivacy('private')"
-					>
-						<i class="material-icons">{{
-							privacyButtons["private"].iconName
-						}}</i>
-						Private
-					</button>
-				</tippy>
-			</div>
-			<div class="small-section">
-				<label class="label">Station Mode</label>
-				<tippy
-					v-if="station.type === 'community'"
-					class="button-wrapper"
-					theme="addToPlaylist"
-					touch="true"
-					interactive="true"
-					placement="bottom"
-					trigger="click"
-					append-to="parent"
-				>
-					<template #trigger>
-						<button
-							:class="{
-								blue: !station.partyMode,
-								yellow: station.partyMode
-							}"
-						>
-							<i class="material-icons">{{
-								station.partyMode
-									? "emoji_people"
-									: "playlist_play"
-							}}</i>
-							{{ station.partyMode ? "Party" : "Playlist" }}
-						</button>
-					</template>
-					<button
-						class="blue"
-						v-if="station.partyMode"
-						@click="updatePartyMode(false)"
-					>
-						<i class="material-icons">playlist_play</i>
-						Playlist
-					</button>
-					<button
-						class="yellow"
-						v-if="!station.partyMode"
-						@click="updatePartyMode(true)"
-					>
-						<i class="material-icons">emoji_people</i>
-						Party
-					</button>
-				</tippy>
-				<div v-else class="button-wrapper">
-					<button
-						class="blue"
-						content="Can not be changed on official stations."
-						v-tippy="{ theme: 'info' }"
-					>
-						<i class="material-icons">playlist_play</i>
-						Playlist
-					</button>
-				</div>
-			</div>
-			<div v-if="!station.partyMode" class="small-section">
-				<label class="label">Play Mode</label>
-				<tippy
-					v-if="station.type === 'community'"
-					class="button-wrapper"
-					theme="addToPlaylist"
-					touch="true"
-					interactive="true"
-					placement="bottom"
-					trigger="click"
-					append-to="parent"
-				>
-					<template #trigger>
-						<button class="blue">
-							<i class="material-icons">{{
-								station.playMode === "random"
-									? "shuffle"
-									: "format_list_numbered"
-							}}</i>
-							{{
-								station.playMode === "random"
-									? "Random"
-									: "Sequential"
-							}}
-						</button>
-					</template>
-					<button
-						class="blue"
-						v-if="station.playMode === 'sequential'"
-						@click="updatePlayMode('random')"
-					>
-						<i class="material-icons">shuffle</i>
-						Random
-					</button>
-					<button
-						class="blue"
-						v-if="station.playMode === 'random'"
-						@click="updatePlayMode('sequential')"
-					>
-						<i class="material-icons">format_list_numbered</i>
-						Sequential
-					</button>
-				</tippy>
-				<div v-else class="button-wrapper">
-					<button
-						class="blue"
-						content="Can not be changed on official stations."
-						v-tippy="{ theme: 'info' }"
-					>
-						<i class="material-icons">shuffle</i>
-						Random
-					</button>
-				</div>
-			</div>
-			<div
-				v-if="
-					station.type === 'community' && station.partyMode === true
-				"
-				class="small-section"
-			>
-				<label class="label">Queue lock</label>
-				<tippy
-					class="button-wrapper"
-					theme="addToPlaylist"
-					interactive="true"
-					touch="true"
-					placement="bottom"
-					trigger="click"
-					append-to="parent"
-				>
-					<template #trigger>
-						<button
-							:class="{
-								green: station.locked,
-								red: !station.locked
-							}"
-						>
-							<i class="material-icons">{{
-								station.locked ? "lock" : "lock_open"
-							}}</i>
-							{{ station.locked ? "Locked" : "Unlocked" }}
-						</button>
-					</template>
-					<button
-						class="green"
-						v-if="!station.locked"
-						@click="updateQueueLock(true)"
-					>
-						<i class="material-icons">lock</i>
-						Locked
-					</button>
-					<button
-						class="red"
-						v-if="station.locked"
-						@click="updateQueueLock(false)"
-					>
-						<i class="material-icons">lock_open</i>
-						Unlocked
-					</button>
-				</tippy>
-			</div>
-		</div>
-	</div>
-</template>
-
-<script>
-import { mapState, mapGetters } from "vuex";
-
-import Toast from "toasters";
-
-import validation from "@/validation";
-
-export default {
-	data() {
-		return {
-			privacyButtons: {
-				public: {
-					style: "green",
-					iconName: "public"
-				},
-				private: {
-					style: "red",
-					iconName: "lock"
-				},
-				unlisted: {
-					style: "orange",
-					iconName: "link"
-				}
-			}
-		};
-	},
-	computed: {
-		...mapState("modals/manageStation", {
-			station: state => state.station,
-			originalStation: state => state.originalStation
-		}),
-		...mapGetters({
-			socket: "websockets/getSocket"
-		})
-	},
-	methods: {
-		updateName() {
-			if (this.originalStation.name !== this.station.name) {
-				const { name } = this.station;
-				if (!validation.isLength(name, 2, 16)) {
-					new Toast("Name must have between 2 and 16 characters.");
-				} else if (!validation.regex.az09_.test(name)) {
-					new Toast(
-						"Invalid name format. Allowed characters: a-z, 0-9 and _."
-					);
-				} else {
-					this.socket.dispatch(
-						"stations.updateName",
-						this.station._id,
-						name,
-						res => {
-							new Toast(res.message);
-
-							if (res.status === "success") {
-								this.station.name = name;
-								this.originalStation.name = name;
-							}
-						}
-					);
-				}
-			} else {
-				new Toast("Please make a change before saving.");
-			}
-		},
-		updateDisplayName() {
-			if (this.originalStation.displayName !== this.station.displayName) {
-				const { displayName } = this.station;
-				if (!validation.isLength(displayName, 2, 32)) {
-					new Toast(
-						"Display name must have between 2 and 32 characters."
-					);
-				} else if (!validation.regex.ascii.test(displayName)) {
-					new Toast(
-						"Invalid display name format. Only ASCII characters are allowed."
-					);
-				} else {
-					this.socket.dispatch(
-						"stations.updateDisplayName",
-						this.station._id,
-						displayName,
-						res => {
-							new Toast(res.message);
-
-							if (res.status === "success") {
-								this.station.displayName = displayName;
-								this.originalStation.displayName = displayName;
-							}
-						}
-					);
-				}
-			} else {
-				new Toast("Please make a change before saving.");
-			}
-		},
-		updateDescription() {
-			if (this.originalStation.description !== this.station.description) {
-				const { description } = this.station;
-				const characters = description.split("").filter(character => {
-					return character.charCodeAt(0) === 21328;
-				});
-				if (!validation.isLength(description, 2, 200)) {
-					new Toast(
-						"Description must have between 2 and 200 characters."
-					);
-				} else if (characters.length !== 0) {
-					new Toast("Invalid description format.");
-				} else {
-					this.socket.dispatch(
-						"stations.updateDescription",
-						this.station._id,
-						description,
-						res => {
-							new Toast(res.message);
-
-							if (res.status === "success") {
-								this.station.description = description;
-								this.originalStation.description = description;
-							}
-						}
-					);
-				}
-			} else {
-				new Toast("Please make a change before saving.");
-			}
-		},
-		updateTheme(theme) {
-			if (this.station.theme !== theme) {
-				this.socket.dispatch(
-					"stations.updateTheme",
-					this.station._id,
-					theme,
-					res => {
-						new Toast(res.message);
-
-						if (res.status === "success") {
-							this.station.theme = theme;
-							this.originalStation.theme = theme;
-						}
-					}
-				);
-			}
-		},
-		updatePrivacy(privacy) {
-			if (this.station.privacy !== privacy) {
-				this.socket.dispatch(
-					"stations.updatePrivacy",
-					this.station._id,
-					privacy,
-					res => {
-						new Toast(res.message);
-
-						if (res.status === "success") {
-							this.station.privacy = privacy;
-							this.originalStation.privacy = privacy;
-						}
-					}
-				);
-			}
-		},
-		updatePartyMode(partyMode) {
-			if (this.station.partyMode !== partyMode) {
-				this.socket.dispatch(
-					"stations.updatePartyMode",
-					this.station._id,
-					partyMode,
-					res => {
-						new Toast(res.message);
-
-						if (res.status === "success") {
-							this.station.partyMode = partyMode;
-							this.originalStation.partyMode = partyMode;
-						}
-					}
-				);
-			}
-		},
-		updatePlayMode(playMode) {
-			if (this.station.playMode !== playMode) {
-				this.socket.dispatch(
-					"stations.updatePlayMode",
-					this.station._id,
-					playMode,
-					res => {
-						new Toast(res.message);
-
-						if (res.status === "success") {
-							this.station.playMode = playMode;
-							this.originalStation.playMode = playMode;
-						}
-					}
-				);
-			}
-		},
-		updateQueueLock(locked) {
-			if (this.station.locked !== locked) {
-				this.socket.dispatch(
-					"stations.toggleLock",
-					this.station._id,
-					res => {
-						if (res.status === "success") {
-							if (this.originalStation) {
-								this.station.locked = res.data.locked;
-								this.originalStation.locked = res.data.locked;
-							}
-
-							new Toast(
-								`Toggled queue lock successfully to ${res.data.locked}`
-							);
-						} else {
-							new Toast("Failed to toggle queue lock.");
-						}
-					}
-				);
-			}
-		}
-	}
-};
-</script>
-
-<style lang="scss" scoped>
-.station-settings {
-	.settings-buttons {
-		display: flex;
-		justify-content: center;
-		flex-wrap: wrap;
-		.small-section {
-			width: calc(50% - 10px);
-			min-width: 150px;
-			margin: 5px auto;
-		}
-	}
-	.button-wrapper {
-		display: flex;
-		flex-direction: column;
-
-		button {
-			width: 100%;
-			height: 36px;
-			border: 0;
-			border-radius: 3px;
-			font-size: 18px;
-			color: var(--white);
-			box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.25);
-			display: block;
-			text-align: center;
-			justify-content: center;
-			display: inline-flex;
-			-ms-flex-align: center;
-			align-items: center;
-			-moz-user-select: none;
-			user-select: none;
-			cursor: pointer;
-			padding: 0;
-			text-transform: capitalize;
-
-			&.red {
-				background-color: var(--red);
-			}
-
-			&.green {
-				background-color: var(--green);
-			}
-
-			&.blue {
-				background-color: var(--blue);
-			}
-
-			&.orange {
-				background-color: var(--orange);
-			}
-
-			&.yellow {
-				background-color: var(--yellow);
-			}
-
-			&.purple {
-				background-color: var(--purple);
-			}
-
-			&.teal {
-				background-color: var(--teal);
-			}
-
-			i {
-				font-size: 20px;
-				margin-right: 4px;
-			}
-		}
-	}
-}
-</style>

+ 4 - 11
frontend/src/pages/Admin/tabs/Stations.vue

@@ -180,13 +180,8 @@
 		<request-song v-if="modals.requestSong" />
 		<edit-playlist v-if="modals.editPlaylist" />
 		<create-playlist v-if="modals.createPlaylist" />
-		<manage-station-owen
-			v-if="modals.manageStation && manageStationVersion === 'owen'"
-			:station-id="editingStationId"
-			sector="admin"
-		/>
-		<manage-station-kris
-			v-if="modals.manageStation && manageStationVersion === 'kris'"
+		<manage-station
+			v-if="modals.manageStation"
 			:station-id="editingStationId"
 			sector="admin"
 		/>
@@ -208,10 +203,8 @@ export default {
 		RequestSong: () => import("@/components/modals/RequestSong.vue"),
 		EditPlaylist: () => import("@/components/modals/EditPlaylist"),
 		CreatePlaylist: () => import("@/components/modals/CreatePlaylist.vue"),
-		ManageStationOwen: () =>
-			import("@/components/modals/ManageStationOwen/index.vue"),
-		ManageStationKris: () =>
-			import("@/components/modals/ManageStationKris/index.vue"),
+		ManageStation: () =>
+			import("@/components/modals/ManageStation/index.vue"),
 		Report: () => import("@/components/modals/Report.vue"),
 		EditSong: () => import("@/components/modals/EditSong"),
 		UserIdToUsername,

+ 4 - 15
frontend/src/pages/Station/index.vue

@@ -558,17 +558,8 @@
 				<request-song v-if="modals.requestSong" />
 				<edit-playlist v-if="modals.editPlaylist" />
 				<create-playlist v-if="modals.createPlaylist" />
-				<manage-station-owen
-					v-if="
-						modals.manageStation && manageStationVersion === 'owen'
-					"
-					:station-id="station._id"
-					sector="station"
-				/>
-				<manage-station-kris
-					v-if="
-						modals.manageStation && manageStationVersion === 'kris'
-					"
+				<manage-station
+					v-if="modals.manageStation"
 					:station-id="station._id"
 					sector="station"
 				/>
@@ -648,10 +639,8 @@ export default {
 		RequestSong: () => import("@/components/modals/RequestSong.vue"),
 		EditPlaylist: () => import("@/components/modals/EditPlaylist"),
 		CreatePlaylist: () => import("@/components/modals/CreatePlaylist.vue"),
-		ManageStationOwen: () =>
-			import("@/components/modals/ManageStationOwen/index.vue"),
-		ManageStationKris: () =>
-			import("@/components/modals/ManageStationKris/index.vue"),
+		ManageStation: () =>
+			import("@/components/modals/ManageStation/index.vue"),
 		Report: () => import("@/components/modals/Report.vue"),
 		Z404,
 		FloatingBox,