From bc227fb0ea5ba942ea3b2b632e07cf6eae42f07d Mon Sep 17 00:00:00 2001 From: danis Date: Mon, 18 Sep 2023 16:45:03 +0200 Subject: [PATCH] pretty + better handling + handling in artist detail view --- front/API.ts | 46 ++++++++++++------------- front/components/FavSongRow.tsx | 17 ++++++--- front/components/SearchResult.tsx | 57 +++++++++++++++++-------------- front/components/SongRow.tsx | 25 +++++++------- front/models/LikedSong.ts | 12 ++++--- front/views/ArtistDetailsView.tsx | 19 ++++++++--- front/views/GenreDetailsView.tsx | 6 ++-- front/views/SearchView.tsx | 8 ++--- 8 files changed, 106 insertions(+), 84 deletions(-) diff --git a/front/API.ts b/front/API.ts index 3b311cc..e84d6a3 100644 --- a/front/API.ts +++ b/front/API.ts @@ -665,21 +665,17 @@ export default class API { } public static async addLikedSong(songId: number): Promise { - await API.fetch( - { - route: `/auth/me/likes/${songId}`, - method: 'POST', - } - ) + await API.fetch({ + route: `/auth/me/likes/${songId}`, + method: 'POST', + }); } public static async removeLikedSong(songId: number): Promise { - await API.fetch( - { - route: `/auth/me/likes/${songId}`, - method: 'DELETE', - } - ) + await API.fetch({ + route: `/auth/me/likes/${songId}`, + method: 'DELETE', + }); } public static getLikedSongs(): Query { @@ -690,21 +686,21 @@ export default class API { { route: '/auth/me/likes', }, - { handler: ListHandler(LikedSongHandler)} + { handler: ListHandler(LikedSongHandler) } ), }; } - public static getUserPlaayHistory(): Query { - return { - key: ['history'], - exec: () => - API.fetch( - { - route: '/history', - }, - { handler: ListHandler(SongHistoryItemHandler) } - ), - }; - } + public static getUserPlaayHistory(): Query { + return { + key: ['history'], + exec: () => + API.fetch( + { + route: '/history', + }, + { handler: ListHandler(SongHistoryItemHandler) } + ), + }; + } } diff --git a/front/components/FavSongRow.tsx b/front/components/FavSongRow.tsx index 9010a88..c015b2a 100644 --- a/front/components/FavSongRow.tsx +++ b/front/components/FavSongRow.tsx @@ -55,11 +55,18 @@ const FavSongRow = ({ FavSong, onPress }: FavSongRowProps) => { {FavSong.addedDate.toLocaleDateString()} - {API.removeLikedSong(FavSong.songId)}} + { + API.removeLikedSong(FavSong.songId); + }} _icon={{ - as: MaterialIcons, - name: "favorite" - }} /> + as: MaterialIcons, + name: 'favorite', + }} + /> { ); }; -export default FavSongRow; \ No newline at end of file +export default FavSongRow; diff --git a/front/components/SearchResult.tsx b/front/components/SearchResult.tsx index cc45ebb..ef4c1ee 100644 --- a/front/components/SearchResult.tsx +++ b/front/components/SearchResult.tsx @@ -25,7 +25,6 @@ import Song, { SongWithArtist } from '../models/Song'; import { useNavigation } from '../Navigation'; import Artist from '../models/Artist'; import SongRow from '../components/SongRow'; -import RowCustom from './RowCustom'; import FavSongRow from './FavSongRow'; import { LikedSongWithDetails } from '../models/LikedSong'; @@ -116,10 +115,11 @@ const SongsSearchComponent = (props: SongsSearchComponentProps) => { const navigation = useNavigation(); const { songData } = React.useContext(SearchContext); const favoritesQuery = useQuery(API.getLikedSongs()); - // const songQueryWithFavorite = songData?.map((songs) => ({ - // ...songs, - // isLiked: !favoritesQuery.data?.find((query) => query?.songId == songs.id) - // })) + + const handleFavoriteButton = async (state: boolean, songId: number): Promise => { + if (state == false) await API.removeLikedSong(songId); + else await API.addLikedSong(songId); + }; return ( @@ -132,7 +132,12 @@ const SongsSearchComponent = (props: SongsSearchComponentProps) => { query?.songId == comp.id)} + isLiked={ + !favoritesQuery.data?.find((query) => query?.songId == comp.id) + } + handleLike={(state: boolean, songId: number) => + handleFavoriteButton(state, songId) + } onPress={() => { API.createSearchHistoryEntry(comp.name, 'song'); navigation.navigate('Song', { songId: comp.id }); @@ -211,23 +216,22 @@ const GenreSearchComponent = (props: ItemSearchComponentProps) => { ); }; -type FavoriteComponentProps = { - maxRows?: number; -}; - -const FavoritesComponent = (props: FavoriteComponentProps) => { +const FavoritesComponent = () => { const navigation = useNavigation(); const favoritesQuery = useQuery(API.getLikedSongs()); const songQueries = useQueries( - favoritesQuery.data?.map((favorite) => favorite.songId).map((songId) => API.getSong(songId)) ?? - [] + favoritesQuery.data + ?.map((favorite) => favorite.songId) + .map((songId) => API.getSong(songId)) ?? [] ); const favSongWithDetails = favoritesQuery?.data ?.map((favorite) => ({ ...favorite, details: songQueries.find((query) => query.data?.id == favorite.songId)?.data, - })).filter((favorite) => favorite.details !== undefined).map((likedSong) => likedSong as LikedSongWithDetails); + })) + .filter((favorite) => favorite.details !== undefined) + .map((likedSong) => likedSong as LikedSongWithDetails); if (favoritesQuery.isError) { navigation.navigate('Error'); @@ -243,19 +247,20 @@ const FavoritesComponent = (props: FavoriteComponentProps) => { {translate('songsFilter')} - {favSongWithDetails?.map((songData) => ( - { - API.createSearchHistoryEntry(songData.details!.name, 'song'); //todo - navigation.navigate('Song', { songId: songData.details!.id }); //todo - }} - /> - ))} - + {favSongWithDetails?.map((songData) => ( + { + API.createSearchHistoryEntry(songData.details!.name, 'song'); //todo + navigation.navigate('Song', { songId: songData.details!.id }); //todo + }} + /> + ))} + ); -} +}; const AllComponent = () => { const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); @@ -311,7 +316,7 @@ const FilterSwitch = () => { export const SearchResultComponent = () => { const { stringQuery } = React.useContext(SearchContext); - const {filter} = React.useContext(SearchContext) + const { filter } = React.useContext(SearchContext); const shouldOutput = !!stringQuery.trim() || filter == 'favorites'; return shouldOutput ? ( diff --git a/front/components/SongRow.tsx b/front/components/SongRow.tsx index b661a63..a2c0588 100644 --- a/front/components/SongRow.tsx +++ b/front/components/SongRow.tsx @@ -3,21 +3,15 @@ import Song, { SongWithArtist } from '../models/Song'; import RowCustom from './RowCustom'; import TextButton from './TextButton'; import { MaterialIcons } from '@expo/vector-icons'; -import API from '../API'; type SongRowProps = { song: Song | SongWithArtist; // TODO: remove Song isLiked: boolean; onPress: () => void; - handleLike: () => void; + handleLike: (state: boolean, songId: number) => Promise; }; -const handleFavoriteButton = (state: boolean, songId: number): void => { - if (state == false) API.removeLikedSong(songId); - else API.addLikedSong(songId); -} - -const SongRow = ({ song, onPress, isLiked }: SongRowProps) => { +const SongRow = ({ song, onPress, handleLike, isLiked }: SongRowProps) => { return ( @@ -62,11 +56,18 @@ const SongRow = ({ song, onPress, isLiked }: SongRowProps) => { {song.artistId ?? 'artist'} - { handleFavoriteButton(isLiked, song.id)}} + { + await handleLike(isLiked, song.id); + }} _icon={{ - as: MaterialIcons, - name: isLiked ? "favorite-outline" : "favorite" - }} /> + as: MaterialIcons, + name: isLiked ? 'favorite-outline' : 'favorite', + }} + /> , LikedSong> = { +export const LikedSongHandler: ResponseHandler< + yup.InferType, + LikedSong +> = { validator: LikedSongValidator, transformer: (likedSong) => ({ id: likedSong.id, @@ -20,10 +24,10 @@ export const LikedSongHandler: ResponseHandler) => const artistQuery = useQuery(API.getArtist(artistId)); const songsQuery = useQuery(API.getSongsByArtist(artistId)); const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); - const fadeColor = useColorModeValue('#ffffff', '#000000'); const isMobileView = screenSize == 'small'; const navigation = useNavigation(); + const favoritesQuery = useQuery(API.getLikedSongs()); + + const handleFavoriteButton = async (state: boolean, songId: number): Promise => { + if (state == false) await API.removeLikedSong(songId); + else await API.addLikedSong(songId); + }; + if (artistQuery.isError || songsQuery.isError) { navigation.navigate('Error'); return <>; @@ -33,8 +39,7 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => - + > {artistQuery.data.name} @@ -45,6 +50,12 @@ const ArtistDetailsView = ({ artistId }: RouteProps) => query?.songId == comp.id) + } + handleLike={(state: boolean, songId: number) => + handleFavoriteButton(state, songId) + } onPress={() => { API.createSearchHistoryEntry(comp.name, 'song'); navigation.navigate('Song', { songId: comp.id }); diff --git a/front/views/GenreDetailsView.tsx b/front/views/GenreDetailsView.tsx index c9f4486..e9c632e 100644 --- a/front/views/GenreDetailsView.tsx +++ b/front/views/GenreDetailsView.tsx @@ -1,4 +1,4 @@ -import { Flex, Heading, useBreakpointValue, ScrollView, useColorModeValue } from 'native-base'; +import { Flex, Heading, useBreakpointValue, ScrollView } from 'native-base'; import { useQueries, useQuery } from '../Queries'; import { LoadingView } from '../components/Loading'; import { RouteProps, useNavigation } from '../Navigation'; @@ -28,7 +28,6 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { const screenSize = useBreakpointValue({ base: 'small', md: 'big' }); const isMobileView = screenSize == 'small'; - const fadeColor = useColorModeValue('#ffffff', '#000000'); const navigation = useNavigation(); if (genreQuery.isError || songsQuery.isError) { @@ -44,8 +43,7 @@ const GenreDetailsView = ({ genreId }: RouteProps) => { - + > {genreQuery.data.name} diff --git a/front/views/SearchView.tsx b/front/views/SearchView.tsx index ddb7fc4..4c5bd35 100644 --- a/front/views/SearchView.tsx +++ b/front/views/SearchView.tsx @@ -24,6 +24,7 @@ interface SearchContextType { isLoadingSong: boolean; isLoadingArtist: boolean; isLoadingGenre: boolean; + isLoadingFavorite: boolean; } export const SearchContext = React.createContext({ @@ -38,6 +39,7 @@ export const SearchContext = React.createContext({ isLoadingSong: false, isLoadingArtist: false, isLoadingGenre: false, + isLoadingFavorite: false, }); type SearchViewProps = { @@ -66,7 +68,7 @@ const SearchView = (props: RouteProps) => { const { isLoading: isLoadingFavorite, data: favoriteData = [] } = useQuery( API.getLikedSongs(), { enabled: true } - ) + ); const updateFilter = (newData: Filter) => { // called when the filter is changed @@ -92,6 +94,7 @@ const SearchView = (props: RouteProps) => { isLoadingSong, isLoadingArtist, isLoadingGenre, + isLoadingFavorite, updateFilter, updateStringQuery, }} @@ -105,6 +108,3 @@ const SearchView = (props: RouteProps) => { }; export default SearchView; - - -