diff --git a/src/providers/UserDataProvider.js b/src/providers/UserDataProvider.js index a0efcb5..fdcced1 100644 --- a/src/providers/UserDataProvider.js +++ b/src/providers/UserDataProvider.js @@ -38,7 +38,10 @@ export default ({ children }) => { }); // Subscribe to user's projects (musics) - const { data: userProjects = [] } = useDataFromRef({ + const { + data: userProjects = [], + loading: userProjectsLoading = true, + } = useDataFromRef({ ref: currentUID ? projectsRef .where("userId", "==", currentUID) @@ -54,7 +57,10 @@ export default ({ children }) => { ? userProjects.filter((project) => project.playbackUrl) : []; // Subscribe to user's liked projects - const { data: userLikedProjects = [] } = useDataFromRef({ + const { + data: userLikedProjects = [], + loading: userLikedProjectsLoading = true, + } = useDataFromRef({ ref: currentUID ? projectsRef .where("likedBy", "array-contains", currentUID) @@ -394,9 +400,13 @@ export default ({ children }) => { currentUID, currentUserData: currentUserDoc, userProjects, + userProjectsLoading, userPlaybacks, + userPlaybacksLoading: userProjectsLoading, userLikedProjects, + userLikedProjectsLoading, userLikedPlaybacks, + userLikedPlaybacksLoading: userLikedProjectsLoading, userPlaylists, selectedProjectId, selectedProject, diff --git a/src/screens/Library/AllMyList.js b/src/screens/Library/AllMyList.js index 5a54004..1f1d31c 100644 --- a/src/screens/Library/AllMyList.js +++ b/src/screens/Library/AllMyList.js @@ -1,14 +1,16 @@ import { useRoute } from "@react-navigation/native"; -import React, { useState } from "react"; -import { View } from "react-native"; +import React, { useMemo, useState } from "react"; +import { ActivityIndicator, Text, View } from "react-native"; import { background } from "../../assets"; +import GradientButton from "../../components/GradientButton"; import MoreMenu from "../../components/MoreMenu"; import useNavigateToMusicDetails from "../../hooks/useNavigateToMusicDetails"; import Page from "../../layouts/Page"; import { Routes } from "../../navigation"; import { navigate } from "../../navigation/NavigationService"; import { useUser } from "../../providers/UserDataProvider"; -import { gutters } from "../../styles"; +import { Palette, Style, gutters } from "../../styles"; +import { FONT_FAMILY } from "../../styles/Fonts"; import MusicCard from "./components/MusicCard"; export default function AllMyList() { @@ -19,11 +21,17 @@ export default function AllMyList() { liked = false, } = route?.params || {}; - const { userProjects, userLikedProjects, userPlaybacks, userLikedPlaybacks } = - useUser(); + const { + userProjects, + userProjectsLoading, + userLikedProjects, + userLikedProjectsLoading, + userPlaybacks, + userLikedPlaybacks, + } = useUser(); const navigateToMusicDetails = useNavigateToMusicDetails(); - const items = (() => { + const items = useMemo(() => { if (scope === "playback") { return Array.isArray(liked ? userLikedPlaybacks : userPlaybacks) ? liked @@ -37,7 +45,101 @@ export default function AllMyList() { ? userLikedProjects : userProjects : []; - })(); + }, [ + liked, + scope, + userLikedPlaybacks, + userPlaybacks, + userLikedProjects, + userProjects, + ]); + + const sanitizedItems = Array.isArray(items) ? items : []; + const itemsLoading = liked + ? userLikedProjectsLoading + : userProjectsLoading; + + const emptyStateContent = useMemo(() => { + const variant = liked ? "liked" : "default"; + const scopeKey = scope === "playback" ? "playback" : "music"; + + const content = { + music: { + default: { + title: "Aucune musique pour le moment", + description: + "Créez un nouveau titre ou explorez la bibliothèque pour alimenter votre collection.", + cta: { + label: "Créer une musique", + action: () => navigate(Routes.WritingLyrics), + }, + }, + liked: { + title: "Aucune musique likée pour le moment", + description: + "Likez les morceaux qui vous inspirent pour les garder à portée de main.", + cta: { + label: "Explorer la bibliothèque", + action: () => navigate(Routes.Research), + }, + }, + }, + playback: { + default: { + title: "Aucun playback pour le moment", + description: + "Enregistrez ou importez un playback pour le retrouver facilement ici.", + cta: { + label: "Créer un playback", + action: () => navigate(Routes.PlaybackOnboarding), + }, + }, + liked: { + title: "Aucun playback liké pour le moment", + description: + "Ajoutez vos playbacks favoris à vos likes pour les retrouver instantanément.", + cta: { + label: "Voir les playbacks", + action: () => navigate(Routes.Playbacks), + }, + }, + }, + }; + + return content[scopeKey][variant]; + }, [liked, scope]); + + const loadingMessage = useMemo(() => { + const target = scope === "playback" ? "playbacks" : "musiques"; + return liked + ? `Chargement des ${target} likés…` + : `Chargement des ${target}…`; + }, [liked, scope]); + + const placeholderBaseStyle = { + gap: 16, + paddingVertical: 52, + paddingHorizontal: 32, + backgroundColor: Palette.glass, + borderRadius: 16, + alignSelf: "stretch", + }; + + const placeholderTitleStyle = { + fontSize: 20, + color: Palette.white, + fontFamily: FONT_FAMILY.InterSemiBold, + textAlign: "center", + }; + + const placeholderDescriptionStyle = { + fontSize: 14, + color: Palette.white, + fontFamily: FONT_FAMILY.InterRegular, + opacity: 0.8, + textAlign: "center", + maxWidth: 420, + }; const [menuPosition, setMenuPosition] = useState(null); const [showMenu, setShowMenu] = useState(false); @@ -63,8 +165,13 @@ export default function AllMyList() { > - {Array.isArray(items) && - items.map((item) => ( + {itemsLoading ? ( + + + {loadingMessage} + + ) : sanitizedItems.length > 0 ? ( + sanitizedItems.map((item) => ( - ))} + )) + ) : ( + + + {emptyStateContent.title} + + + {emptyStateContent.description} + + {emptyStateContent?.cta ? ( + + ) : null} + + )}