diff --git a/src/navigation/MainStack.js b/src/navigation/MainStack.js
index 0c02dfb..c28162d 100644
--- a/src/navigation/MainStack.js
+++ b/src/navigation/MainStack.js
@@ -52,7 +52,7 @@ import AllMyLikedMusic from "../screens/Library/AllMyLikedMusic";
import Research from "../screens/Library/Research";
import MusicDetails from "../screens/Library/MusicDetails";
import PlaylistDetails from "../screens/Library/PlaylistDetails";
-import SingerProfile from "../screens/Profile/SingerProfile";
+import Profile from "../screens/Profile/Profile";
import EditProfile from "../screens/Profile/EditProfile";
import Settings from "../screens/Profile/Settings";
import ChangeEmailAddress from "../screens/Profile/ChangeEmailAddress";
@@ -252,7 +252,7 @@ const screens = [
},
{
name: Routes.SingerProfile,
- component: SingerProfile,
+ component: Profile,
},
{
name: Routes.EditProfile,
diff --git a/src/screens/Profile/Profile.js b/src/screens/Profile/Profile.js
index bae65f9..7a6ff07 100644
--- a/src/screens/Profile/Profile.js
+++ b/src/screens/Profile/Profile.js
@@ -1,6 +1,7 @@
+import { useRoute } from "@react-navigation/native";
import { BlurView } from "expo-blur";
import { Image as ExpoImage } from "expo-image";
-import React, { useState } from "react";
+import React, { useEffect, useMemo, useState } from "react";
import {
FlatList,
Image,
@@ -17,7 +18,8 @@ import { useGlobal } from "reactn";
import { background, icons, img } from "../../assets";
import BorderGradient from "../../components/BorderGradient/BorderGradient";
import MoreMenu from "../../components/MoreMenu";
-import { projectsRef } from "../../config/firebase";
+import { projectsRef, usersRef } from "../../config/firebase";
+import useDataFromRef from "../../hooks/useDataFromRef";
import Page from "../../layouts/Page";
import { Routes } from "../../navigation";
import { navigate, push } from "../../navigation/NavigationService";
@@ -28,10 +30,25 @@ import Style, { gutters, size } from "../../styles/Style";
import MusicCard from "../Library/components/MusicCard";
const Profile = () => {
+ const { params } = useRoute();
const [selected, setSelected] = useState("Chansons");
- const { userProjects, userPlaybacks, followingCount, currentUserData } =
- useUser();
+ const {
+ userProjects: selfProjects,
+ userPlaybacks: selfPlaybacks,
+ followingCount,
+ currentUserData,
+ getUserByUid,
+ followUser,
+ unfollowUser,
+ } = useUser();
+ const [currentUID] = useGlobal("currentUID");
+ const targetUserId = params?.userId || currentUID || null;
+ const isSelf = !!currentUID && targetUserId === currentUID;
const [, setTooltip] = useGlobal("_tooltip");
+ const [userData, setUserData] = useState(null);
+ const [isFollowing, setIsFollowing] = useState(false);
+ const [followers, setFollowers] = useState(0);
+ const [following, setFollowing] = useState(0);
const [menuTop, setMenuTop] = useState(0);
const [showMenu, setShowMenu] = useState(false);
const [selectedProjectId, setSelectedProjectId] = useState(null);
@@ -39,6 +56,61 @@ const Profile = () => {
setSelected(item);
};
+ // Chargement des données utilisateur si on consulte un autre profil
+ useEffect(() => {
+ const fetch = async () => {
+ if (!targetUserId) return;
+ if (isSelf) {
+ setUserData(currentUserData || null);
+ setFollowers(
+ Array.isArray(currentUserData?.followedBy)
+ ? currentUserData.followedBy.length
+ : 0
+ );
+ return;
+ }
+ const data = await getUserByUid(targetUserId);
+ setUserData(data || null);
+ const list = Array.isArray(data?.followedBy) ? data.followedBy : [];
+ setFollowers(list.length);
+ setIsFollowing(currentUID ? list.includes(currentUID) : false);
+ };
+ fetch();
+ }, [targetUserId, isSelf, currentUserData?.followedBy?.length || 0]);
+
+ // Live following count pour l'utilisateur consulté (autre que soi)
+ const followingQueryRef = useMemo(() => {
+ try {
+ return targetUserId
+ ? usersRef.where("followedBy", "array-contains", targetUserId)
+ : null;
+ } catch (e) {
+ return null;
+ }
+ }, [targetUserId]);
+
+ useDataFromRef({
+ ref: followingQueryRef,
+ simpleRef: false,
+ listener: true,
+ condition: !!followingQueryRef && !isSelf,
+ refreshArray: [targetUserId],
+ onUpdate: (list) => setFollowing(Array.isArray(list) ? list.length : 0),
+ });
+
+ const handleFollowUser = async () => {
+ if (!currentUID || !targetUserId || isSelf) return;
+ if (isFollowing) {
+ await unfollowUser(targetUserId);
+ setIsFollowing(false);
+ setFollowers((v) => Math.max(0, (v || 0) - 1));
+ } else {
+ await followUser(targetUserId);
+ setIsFollowing(true);
+ setFollowers((v) => (v || 0) + 1);
+ }
+ };
+
// Composant factorisé pour afficher la liste de musiques
const MusicListSection = ({ data, emptyText }) => (
@@ -52,7 +124,10 @@ const Profile = () => {
renderItem={({ item }) => (
{
onClose={() => setShowMenu(false)}
inPlaylist={false}
projectId={selectedProjectId}
- extraItems={[
- {
- label: "Supprimer",
- onPress: () =>
- SheetManager.show("Delete", {
- payload: {
- title: "Supprimer le projet",
- message: "Cette action supprimera définitivement ce projet.",
- onConfirm: async () => {
- try {
- if (!selectedProjectId) return;
- await projectsRef.doc(selectedProjectId).delete();
- setTooltip({
- type: "success",
- text: "Projet supprimé",
- });
- } catch (e) {
- setTooltip({
- type: "error",
- text: e?.message || "Suppression impossible",
- });
- }
- },
+ extraItems={
+ isSelf
+ ? [
+ {
+ label: "Supprimer",
+ onPress: () =>
+ SheetManager.show("Delete", {
+ payload: {
+ title: "Supprimer le projet",
+ message:
+ "Cette action supprimera définitivement ce projet.",
+ onConfirm: async () => {
+ try {
+ if (!selectedProjectId) return;
+ await projectsRef.doc(selectedProjectId).delete();
+ setTooltip({
+ type: "success",
+ text: "Projet supprimé",
+ });
+ } catch (e) {
+ setTooltip({
+ type: "error",
+ text: e?.message || "Suppression impossible",
+ });
+ }
+ },
+ },
+ }),
},
- }),
- },
- ]}
+ ]
+ : []
+ }
/>
);
@@ -122,22 +202,47 @@ const Profile = () => {
);
+ // Données projets/profils selon si c'est soi ou un autre utilisateur
+ const projectsQueryRef = useMemo(() => {
+ try {
+ if (!targetUserId || isSelf) return null;
+ return projectsRef
+ .where("userId", "==", targetUserId)
+ .orderBy("updatedAt", "desc");
+ } catch (e) {
+ return null;
+ }
+ }, [targetUserId, isSelf]);
+
+ const { data: otherUserProjects = [] } = useDataFromRef({
+ ref: projectsQueryRef,
+ simpleRef: false,
+ listener: true,
+ condition: !!projectsQueryRef,
+ refreshArray: [targetUserId],
+ });
+
+ const displayedProjects = isSelf ? selfProjects : otherUserProjects;
+ const displayedPlaybacks = isSelf ? selfPlaybacks : [];
+
return (
(
- SheetManager.show("ProfileSettings")}>
-
-
- )}
+ rightComponent={() =>
+ isSelf ? (
+ SheetManager.show("ProfileSettings")}>
+
+
+ ) : null
+ }
>
@@ -155,9 +260,15 @@ const Profile = () => {
{
fontFamily: FONT_FAMILY.InterSemiBold,
}}
>
- {currentUserData?.userName}
+ {(isSelf ? currentUserData?.userName : userData?.userName) ||
+ "Profil"}
- {userProjects?.length || 0}
+
+ {Array.isArray(displayedProjects)
+ ? displayedProjects.length
+ : 0}
+
projets
push(Routes.Follows, { selected: "Abonnés" })}
+ onPress={() =>
+ push(Routes.Follows, {
+ selected: "Abonnés",
+ ...(isSelf ? {} : { userId: targetUserId }),
+ })
+ }
>
- {currentUserData?.followedBy?.length || 0}
+ {isSelf
+ ? currentUserData?.followedBy?.length || 0
+ : followers}
abonnés
- push(Routes.Follows, { selected: "Abonnements" })
+ push(Routes.Follows, {
+ selected: "Abonnements",
+ ...(isSelf ? {} : { userId: targetUserId }),
+ })
}
>
- {followingCount}
+
+ {isSelf ? followingCount : following}
+
abonnements
+ {!isSelf && (
+
+
+
+ {isFollowing ? "Ne plus suivre" : "Suivre"}
+
+
+
+ )}
{
{selected === "Playbacks" && (
)}
{selected === "Chansons" && (
)}
diff --git a/src/screens/Profile/SingerProfile.js b/src/screens/Profile/SingerProfile.js
deleted file mode 100644
index fc70484..0000000
--- a/src/screens/Profile/SingerProfile.js
+++ /dev/null
@@ -1,352 +0,0 @@
-import React, { useEffect, useMemo, useState } from "react";
-import {
- FlatList,
- Image,
- Platform,
- Pressable,
- StyleSheet,
- Text,
- View,
-} from "react-native";
-import { Image as ExpoImage } from "expo-image";
-import { responsiveHeight } from "react-native-responsive-dimensions";
-import { useGlobal } from "reactn";
-import { background, icons, img } from "../../assets";
-import BorderGradient from "../../components/BorderGradient/BorderGradient";
-import GradientButton from "../../components/GradientButton";
-import MoreMenu from "../../components/MoreMenu";
-import { projectsRef } from "../../config/firebase";
-import Page from "../../layouts/Page";
-import { Routes } from "../../navigation";
-import { navigate, push } from "../../navigation/NavigationService";
-import { useUser } from "../../providers/UserDataProvider";
-import useDataFromRef from "../../hooks/useDataFromRef";
-import { usersRef } from "../../config/firebase";
-import { gutters, Palette } from "../../styles";
-import { FONT_FAMILY } from "../../styles/Fonts";
-import Style, { size } from "../../styles/Style";
-import MusicCard from "../Library/components/MusicCard";
-import { BlurView } from "expo-blur";
-
-const SingerProfile = ({ route }) => {
- const { userId } = route.params;
- const { getUserByUid, followUser, unfollowUser } = useUser();
- const [currentUID] = useGlobal("currentUID");
- const [selected, setSelected] = useState("Chansons");
- const [userData, setUserData] = useState(null);
- const [following, setFollowing] = useState(0);
- const [followers, setFollowers] = useState(0);
- const fetchUserData = async () => {
- const data = userId ? await getUserByUid(userId) : {};
- setUserData(data);
- const list = Array.isArray(data?.followedBy) ? data.followedBy : [];
- setFollowers(list.length);
- setIsFollowing(currentUID ? list.includes(currentUID) : false);
- };
- useEffect(() => {
- fetchUserData();
- }, [userId]);
- // Live following count for the viewed user
- const followingQueryRef = React.useMemo(() => {
- try {
- return userId
- ? usersRef.where("followedBy", "array-contains", userId)
- : null;
- } catch (e) {
- return null;
- }
- }, [userId]);
-
- useDataFromRef({
- ref: followingQueryRef,
- simpleRef: false,
- listener: true,
- condition: !!followingQueryRef,
- refreshArray: [userId],
- onUpdate: (list) => setFollowing(Array.isArray(list) ? list.length : 0),
- });
- const onPressMenu = (item) => {
- if (selected === item) {
- setSelected(null);
- } else {
- setSelected(item);
- }
- };
- const [isFollowing, setIsFollowing] = useState(false);
- const [menuTop, setMenuTop] = useState(0);
- const [showMenu, setShowMenu] = useState(false);
- const [selectedProjectId, setSelectedProjectId] = useState(null);
- const userProjectsQueryRef = useMemo(() => {
- try {
- if (!userId) return null;
- return projectsRef
- .where("userId", "==", userId)
- .orderBy("updatedAt", "desc");
- } catch (e) {
- return null;
- }
- }, [userId]);
-
- const { data: userProjects = [] } = useDataFromRef({
- ref: userProjectsQueryRef,
- simpleRef: false,
- listener: true,
- condition: !!userProjectsQueryRef,
- refreshArray: [userId],
- });
-
- const EmptyText = ({ text }) => (
-
-
- {text}
-
-
- );
- const handleFollowUser = async () => {
- if (!currentUID || !userId || currentUID === userId) return;
- if (isFollowing) {
- await unfollowUser(userId);
- setIsFollowing(false);
- setFollowers((v) => Math.max(0, (v || 0) - 1));
- } else {
- await followUser(userId);
- setIsFollowing(true);
- setFollowers((v) => (v || 0) + 1);
- }
- };
- return (
- (
-
-
-
- )}
- >
-
-
-
-
-
-
- {userData?.userName}
-
-
-
-
-
- {Array.isArray(userProjects) ? userProjects.length : 0}
-
- projets
-
-
- push(Routes.Follows, { selected: "Abonnés", userId })
- }
- >
- {followers}
- abonnés
-
-
- push(Routes.Follows, { selected: "Abonnements", userId })
- }
- >
- {following}
- abonnements
-
-
- {currentUID !== userId && (
-
- )}
-
-
-
- {["Playbacks", "Clips", "Chansons"].map((item, index) => (
- onPressMenu(item)}
- style={{ flex: 1 }}
- >
-
-
-
- {item}
-
-
-
- ))}
-
- {selected === "Playbacks" && (
-
-
-
- )}
- {selected === "Chansons" && (
-
- {Array.isArray(userProjects) && userProjects.length > 0 ? (
- item.id}
- renderItem={({ item }) => (
-
- navigate(Routes.MusicDetails, { projectId: item.id })
- }
- onPressMore={(posTop) => {
- setSelectedProjectId(item.id);
- setMenuTop(posTop);
- setShowMenu((prev) => !prev || posTop !== menuTop);
- }}
- />
- )}
- />
- ) : (
-
- )}
-
- )}
-
- {selected === "Clips" && (
-
-
-
- )}
- setShowMenu(false)}
- inPlaylist={false}
- projectId={selectedProjectId}
- />
-
-
- );
-};
-
-export default SingerProfile;
-
-const styles = StyleSheet.create({
- value: {
- fontSize: 16,
- color: Palette.white,
- fontFamily: FONT_FAMILY.InterRegular,
- },
- label: {
- fontSize: 12,
- color: Palette.white,
- fontFamily: FONT_FAMILY.InterRegular,
- },
- menu: {
- fontSize: 12,
- color: Palette.white,
- fontFamily: FONT_FAMILY.InterRegular,
- },
- borderGradient: {
- borderWidth: 1,
- borderRadius: 10,
- height: 33,
- position: "absolute",
- zIndex: 1,
- width: "100%",
- },
- blurContainer: {
- height: 33,
- zIndex: -1,
- borderRadius: 10,
- overflow: "hidden",
- backgroundColor: Palette.glass,
- },
- blurView: {
- width: "100%",
- height: "100%",
- paddingHorizontal: 10,
- ...Style.containerCenter,
- },
-});