Browse Source

Added pagination to manage station playlist and musare song search

Kristian Vos 3 years ago
parent
commit
0eaee1e059

+ 6 - 6
backend/logic/actions/playlists.js

@@ -246,21 +246,21 @@ export default {
 						page
 					})
 						.then(response => {
-							next(null, response.playlists);
+							next(null, response);
 						})
 						.catch(err => {
 							next(err);
 						});
 				}
 			],
-			async (err, playlists) => {
+			async (err, data) => {
 				if (err) {
 					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 					this.log("ERROR", "PLAYLISTS_SEARCH_COMMUNITY", `Searching playlists failed. "${err}"`);
 					return cb({ status: "error", message: err });
 				}
 				this.log("SUCCESS", "PLAYLISTS_SEARCH_COMMUNITY", "Searching playlists successful.");
-				return cb({ status: "success", data: { playlists } });
+				return cb({ status: "success", data });
 			}
 		);
 	}),
@@ -290,21 +290,21 @@ export default {
 						page
 					})
 						.then(response => {
-							next(null, response.playlists);
+							next(null, response);
 						})
 						.catch(err => {
 							next(err);
 						});
 				}
 			],
-			async (err, playlists) => {
+			async (err, data) => {
 				if (err) {
 					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 					this.log("ERROR", "PLAYLISTS_SEARCH_OFFICIAL", `Searching playlists failed. "${err}"`);
 					return cb({ status: "error", message: err });
 				}
 				this.log("SUCCESS", "PLAYLISTS_SEARCH_OFFICIAL", "Searching playlists successful.");
-				return cb({ status: "success", data: { playlists } });
+				return cb({ status: "success", data });
 			}
 		);
 	}),

+ 3 - 3
backend/logic/actions/songs.js

@@ -591,21 +591,21 @@ export default {
 						page
 					})
 						.then(response => {
-							next(null, response.songs);
+							next(null, response);
 						})
 						.catch(err => {
 							next(err);
 						});
 				}
 			],
-			async (err, songs) => {
+			async (err, data) => {
 				if (err) {
 					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
 					this.log("ERROR", "SONGS_SEARCH_OFFICIAL", `Searching songs failed. "${err}"`);
 					return cb({ status: "error", message: err });
 				}
 				this.log("SUCCESS", "SONGS_SEARCH_OFFICIAL", "Searching songs successful.");
-				return cb({ status: "success", data: { songs } });
+				return cb({ status: "success", data });
 			}
 		);
 	}),

+ 28 - 9
backend/logic/playlists.js

@@ -1029,21 +1029,40 @@ class _PlaylistsModule extends CoreClass {
 
 					(filterArray, includeObject, next) => {
 						const page = payload.page ? payload.page : 1;
-						PlaylistsModule.playlistModel
-							.find({ $or: filterArray }, includeObject)
-							.skip(15 * (page - 1))
-							.limit(15)
-							.exec(next);
+						const pageSize = 15;
+						const skipAmount = pageSize * (page - 1);
+
+						PlaylistsModule.playlistModel.find({ $or: filterArray }).count((err, count) => {
+							if (err) next(err);
+							else {
+								PlaylistsModule.playlistModel
+									.find({ $or: filterArray }, includeObject)
+									.skip(skipAmount)
+									.limit(pageSize)
+									.exec((err, playlists) => {
+										if (err) next(err);
+										else {
+											next(null, {
+												playlists,
+												page,
+												pageSize,
+												skipAmount,
+												count
+											});
+										}
+									});
+							}
+						});
 					},
 
-					(playlists, next) => {
-						if (playlists.length > 0) next(null, playlists);
+					(data, next) => {
+						if (data.playlists.length > 0) next(null, data);
 						else next("No playlists found");
 					}
 				],
-				(err, playlists) => {
+				(err, data) => {
 					if (err && err !== true) return reject(new Error(err));
-					return resolve({ playlists });
+					return resolve(data);
 				}
 			)
 		);

+ 33 - 14
backend/logic/songs.js

@@ -446,18 +446,36 @@ class _SongsModule extends CoreClass {
 
 					(filterArray, next) => {
 						const page = payload.page ? payload.page : 1;
-						SongsModule.SongModel.find({ $or: filterArray })
-							.skip(15 * (page - 1))
-							.limit(15)
-							.exec(next);
+						const pageSize = 15;
+						const skipAmount = pageSize * (page - 1);
+
+						SongsModule.SongModel.find({ $or: filterArray }).count((err, count) => {
+							if (err) next(err);
+							else {
+								SongsModule.SongModel.find({ $or: filterArray })
+									.skip(skipAmount)
+									.limit(pageSize)
+									.exec((err, songs) => {
+										if (err) next(err);
+										else {
+											next(null, {
+												songs,
+												page,
+												pageSize,
+												skipAmount,
+												count
+											});
+										}
+									});
+							}
+						});
 					},
 
-					(songs, next) => {
-						if (songs.length === 0) next("No songs found");
+					(data, next) => {
+						if (data.songs.length === 0) next("No songs found");
 						else if (payload.trimmed) {
-							next(
-								null,
-								songs.map(song => {
+							next(null, {
+								songs: data.songs.map(song => {
 									const { _id, youtubeId, title, artists, thumbnail, duration, status } = song;
 									return {
 										_id,
@@ -468,14 +486,15 @@ class _SongsModule extends CoreClass {
 										duration,
 										status
 									};
-								})
-							);
-						} else next(null, songs);
+								}),
+								...data
+							});
+						} else next(null, data);
 					}
 				],
-				(err, songs) => {
+				(err, data) => {
 					if (err && err !== true) return reject(new Error(err));
-					return resolve({ songs });
+					return resolve(data);
 				}
 			)
 		);

+ 44 - 1
frontend/src/components/modals/ManageStation/Tabs/Playlists.vue

@@ -179,6 +179,13 @@
 							>
 						</div>
 					</playlist-item>
+					<button
+						v-if="resultsLeftCount > 0"
+						class="button is-primary"
+						@click="searchForPlaylists(search.page + 1)"
+					>
+						Load {{ nextPageResultsCount }} more results
+					</button>
 				</div>
 			</div>
 			<div
@@ -302,6 +309,10 @@ export default {
 			tab: "current",
 			search: {
 				query: "",
+				searchedQuery: "",
+				page: 0,
+				count: 0,
+				resultsLeft: 0,
 				results: []
 			}
 		};
@@ -321,6 +332,12 @@ export default {
 			}
 			return this.includedPlaylists;
 		},
+		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,
@@ -504,17 +521,43 @@ export default {
 			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 = res.data.playlists;
+					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);
 				}
 			});

+ 54 - 8
frontend/src/components/modals/ManageStation/Tabs/Search.vue

@@ -36,6 +36,13 @@
 						>
 					</div>
 				</song-item>
+				<button
+					v-if="resultsLeftCount > 0"
+					class="button is-primary"
+					@click="searchForMusareSongs(musareSearch.page + 1)"
+				>
+					Load {{ nextPageResultsCount }} more results
+				</button>
 			</div>
 		</div>
 		<div class="youtube-search">
@@ -130,11 +137,21 @@ export default {
 		return {
 			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);
+		},
 		...mapState("modals/manageStation", {
 			station: state => state.station,
 			originalStation: state => state.originalStation
@@ -176,16 +193,45 @@ export default {
 			}
 		},
 		searchForMusareSongs(page) {
-			const { query } = this.musareSearch;
+			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.socket.dispatch("songs.searchOfficial", query, page, res => {
-				if (res.status === "success") {
-					this.musareSearch.results = res.data.songs;
-				} else if (res.status === "error") {
-					this.musareSearch.results = [];
-					new Toast(res.message);
+			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);
+					}
 				}
-			});
+			);
 		}
 	}
 };