firtname and lastname before username
This commit is contained in:
@@ -27,6 +27,7 @@ import { icons } from '../../assets';
|
|||||||
import { increment, projectsRef, serverTimestamp } from '../../config/firebase';
|
import { increment, projectsRef, serverTimestamp } from '../../config/firebase';
|
||||||
import useDataFromRef from '../../hooks/useDataFromRef';
|
import useDataFromRef from '../../hooks/useDataFromRef';
|
||||||
import { useUser } from '../../providers/UserDataProvider';
|
import { useUser } from '../../providers/UserDataProvider';
|
||||||
|
import { getArtistDisplayName } from '../../utils/artistName';
|
||||||
import { Palette } from '../../styles';
|
import { Palette } from '../../styles';
|
||||||
import { FONT_FAMILY } from '../../styles/Fonts';
|
import { FONT_FAMILY } from '../../styles/Fonts';
|
||||||
import { size } from '../../styles/Style';
|
import { size } from '../../styles/Style';
|
||||||
@@ -62,6 +63,10 @@ const CommentsBottomSheet = () => {
|
|||||||
const modalRef = useRef(null);
|
const modalRef = useRef(null);
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
const { currentUID, currentUserData } = useUser();
|
const { currentUID, currentUserData } = useUser();
|
||||||
|
const currentUserDisplayName = useMemo(
|
||||||
|
() => getArtistDisplayName(currentUserData, ''),
|
||||||
|
[currentUserData]
|
||||||
|
);
|
||||||
const scrollRef = useRef(null);
|
const scrollRef = useRef(null);
|
||||||
|
|
||||||
const [projectId, setProjectId] = useState(null);
|
const [projectId, setProjectId] = useState(null);
|
||||||
@@ -131,7 +136,7 @@ const CommentsBottomSheet = () => {
|
|||||||
.collection('comments')
|
.collection('comments')
|
||||||
.add({
|
.add({
|
||||||
userId: currentUID,
|
userId: currentUID,
|
||||||
userName: currentUserData?.userName || '',
|
userName: currentUserDisplayName,
|
||||||
profilePicture: currentUserData?.profilePictureURL || '',
|
profilePicture: currentUserData?.profilePictureURL || '',
|
||||||
text: value,
|
text: value,
|
||||||
createdAt: serverTimestamp(),
|
createdAt: serverTimestamp(),
|
||||||
@@ -145,7 +150,7 @@ const CommentsBottomSheet = () => {
|
|||||||
const optimistic = {
|
const optimistic = {
|
||||||
id: docRef?.id || Math.random().toString(36).slice(2),
|
id: docRef?.id || Math.random().toString(36).slice(2),
|
||||||
userId: currentUID,
|
userId: currentUID,
|
||||||
userName: currentUserData?.userName || '',
|
userName: currentUserDisplayName,
|
||||||
profilePicture: currentUserData?.profilePictureURL || '',
|
profilePicture: currentUserData?.profilePictureURL || '',
|
||||||
text: value,
|
text: value,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import firebase, {
|
|||||||
projectsRef,
|
projectsRef,
|
||||||
usersRef,
|
usersRef,
|
||||||
} from "../config/firebase";
|
} from "../config/firebase";
|
||||||
|
import { getUserPreferredArtistName } from "../utils/artistName";
|
||||||
|
|
||||||
export const UserDataContext = createContext();
|
export const UserDataContext = createContext();
|
||||||
|
|
||||||
@@ -182,9 +183,12 @@ export default ({ children }) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await setIsLoading(true);
|
await setIsLoading(true);
|
||||||
|
const artistDisplayName = getUserPreferredArtistName(
|
||||||
|
currentUserDoc || currentUserData || {}
|
||||||
|
);
|
||||||
const payload = {
|
const payload = {
|
||||||
userId: currentUID || null,
|
userId: currentUID || null,
|
||||||
userName: currentUserData?.userName || null,
|
userName: artistDisplayName,
|
||||||
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
|
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||||
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ const CreatePassword = () => {
|
|||||||
{ merge: true }
|
{ merge: true }
|
||||||
);
|
);
|
||||||
setTooltip({ text: "Compte créé, continuons", type: "success" });
|
setTooltip({ text: "Compte créé, continuons", type: "success" });
|
||||||
navigate(Routes.CreatePseudo);
|
navigate(Routes.BottomTab);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Register error", e?.message);
|
console.log("Register error", e?.message);
|
||||||
const message =
|
const message =
|
||||||
|
|||||||
@@ -12,16 +12,26 @@ import Page from "../../layouts/Page";
|
|||||||
import { Routes } from "../../navigation";
|
import { Routes } from "../../navigation";
|
||||||
import { navigate } from "../../navigation/NavigationService";
|
import { navigate } from "../../navigation/NavigationService";
|
||||||
import { useUser } from "../../providers/UserDataProvider";
|
import { useUser } from "../../providers/UserDataProvider";
|
||||||
|
import { getArtistDisplayName } from "../../utils/artistName";
|
||||||
import { Palette } from "../../styles";
|
import { Palette } from "../../styles";
|
||||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||||
import MusicCard from "../Library/components/MusicCard";
|
import MusicCard from "../Library/components/MusicCard";
|
||||||
|
|
||||||
const HomeSave = () => {
|
const HomeSave = () => {
|
||||||
const { userProjects = [], resetSelectedProject, selectProject } = useUser();
|
const {
|
||||||
|
userProjects = [],
|
||||||
|
resetSelectedProject,
|
||||||
|
selectProject,
|
||||||
|
currentUserData,
|
||||||
|
} = useUser();
|
||||||
const projects = useMemo(
|
const projects = useMemo(
|
||||||
() => (Array.isArray(userProjects) ? userProjects : []),
|
() => (Array.isArray(userProjects) ? userProjects : []),
|
||||||
[userProjects]
|
[userProjects]
|
||||||
);
|
);
|
||||||
|
const ownerDisplayName = useMemo(
|
||||||
|
() => getArtistDisplayName(currentUserData, "MusicLand"),
|
||||||
|
[currentUserData]
|
||||||
|
);
|
||||||
const [, setTooltip] = useGlobal("_tooltip");
|
const [, setTooltip] = useGlobal("_tooltip");
|
||||||
const [menuPosition, setMenuPosition] = useState(null);
|
const [menuPosition, setMenuPosition] = useState(null);
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
@@ -73,7 +83,7 @@ const HomeSave = () => {
|
|||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<MusicCard
|
<MusicCard
|
||||||
title={item?.title || "Sans titre"}
|
title={item?.title || "Sans titre"}
|
||||||
subtitle={item?.userName}
|
subtitle={item?.userName || ownerDisplayName}
|
||||||
imageUri={item?.coverUrl || null}
|
imageUri={item?.coverUrl || null}
|
||||||
projectId={item?.id}
|
projectId={item?.id}
|
||||||
likedBy={item?.likedBy || []}
|
likedBy={item?.likedBy || []}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import Page from "../../layouts/Page";
|
|||||||
import { Palette } from "../../styles";
|
import { Palette } from "../../styles";
|
||||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||||
import Style, { gutters, size } from "../../styles/Style";
|
import Style, { gutters, size } from "../../styles/Style";
|
||||||
|
import { getArtistDisplayName } from "../../utils/artistName";
|
||||||
|
|
||||||
// 20 secondes
|
// 20 secondes
|
||||||
const timeBeforeIncrement = 20000;
|
const timeBeforeIncrement = 20000;
|
||||||
@@ -69,7 +70,11 @@ const MusicDetails = ({ route }) => {
|
|||||||
}, [project?.likedBy, currentUID]);
|
}, [project?.likedBy, currentUID]);
|
||||||
|
|
||||||
const title = project?.title || "Sans titre";
|
const title = project?.title || "Sans titre";
|
||||||
const artist = owner?.userName || "MusicLand";
|
const artist = useMemo(() => {
|
||||||
|
const ownerName = getArtistDisplayName(owner, "");
|
||||||
|
if (ownerName) return ownerName;
|
||||||
|
return getArtistDisplayName(project, "MusicLand");
|
||||||
|
}, [owner, project]);
|
||||||
const coverUrl = project?.coverUrl || null;
|
const coverUrl = project?.coverUrl || null;
|
||||||
const songUrl = project?.songUrl || null;
|
const songUrl = project?.songUrl || null;
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import Page from "../../layouts/Page";
|
|||||||
import { Palette } from "../../styles";
|
import { Palette } from "../../styles";
|
||||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||||
import Style, { gutters, size } from "../../styles/Style";
|
import Style, { gutters, size } from "../../styles/Style";
|
||||||
|
import { getArtistDisplayName } from "../../utils/artistName";
|
||||||
import {
|
import {
|
||||||
formatStructureLabel,
|
formatStructureLabel,
|
||||||
getPromptLabelForStructure,
|
getPromptLabelForStructure,
|
||||||
@@ -86,7 +87,11 @@ const MusicDetails = ({ route }) => {
|
|||||||
}, [project?.likedBy, currentUID]);
|
}, [project?.likedBy, currentUID]);
|
||||||
|
|
||||||
const title = project?.title || "Sans titre";
|
const title = project?.title || "Sans titre";
|
||||||
const artist = owner?.userName || "MusicLand";
|
const artist = useMemo(() => {
|
||||||
|
const ownerName = getArtistDisplayName(owner, "");
|
||||||
|
if (ownerName) return ownerName;
|
||||||
|
return getArtistDisplayName(project, "MusicLand");
|
||||||
|
}, [owner, project]);
|
||||||
const coverUrl = project?.coverUrl || null;
|
const coverUrl = project?.coverUrl || null;
|
||||||
const songUrl = project?.songUrl || null;
|
const songUrl = project?.songUrl || null;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { navigate } from "../../../navigation/NavigationService";
|
|||||||
import { Palette, Style } from "../../../styles";
|
import { Palette, Style } from "../../../styles";
|
||||||
import { FONT_FAMILY } from "../../../styles/Fonts";
|
import { FONT_FAMILY } from "../../../styles/Fonts";
|
||||||
import { size } from "../../../styles/Style";
|
import { size } from "../../../styles/Style";
|
||||||
|
import { getArtistDisplayName } from "../../../utils/artistName";
|
||||||
import CreateLyricsHeader from "../../Writing/components/CreateLyricsHeader";
|
import CreateLyricsHeader from "../../Writing/components/CreateLyricsHeader";
|
||||||
import MusicCard from "./MusicCard";
|
import MusicCard from "./MusicCard";
|
||||||
|
|
||||||
@@ -232,7 +233,7 @@ const SearchResultsList = ({
|
|||||||
fontFamily: FONT_FAMILY.InterRegular,
|
fontFamily: FONT_FAMILY.InterRegular,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{user?.userName || "Utilisateur"}
|
{getArtistDisplayName(user, "Utilisateur")}
|
||||||
</Text>
|
</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { background } from "../assets";
|
|||||||
import GradientButton from "../components/GradientButton.js";
|
import GradientButton from "../components/GradientButton.js";
|
||||||
import { Input } from "../components/Input.js";
|
import { Input } from "../components/Input.js";
|
||||||
import ItemContainer from "../components/ItemContainer/ItemContainer";
|
import ItemContainer from "../components/ItemContainer/ItemContainer";
|
||||||
import firebase, { usersRef } from "../config/firebase";
|
import firebase from "../config/firebase";
|
||||||
import {
|
import {
|
||||||
GOOGLE_ANDROID_CLIENT_ID,
|
GOOGLE_ANDROID_CLIENT_ID,
|
||||||
GOOGLE_IOS_CLIENT_ID,
|
GOOGLE_IOS_CLIENT_ID,
|
||||||
@@ -63,13 +63,7 @@ export default ({ navigation }) => {
|
|||||||
const afterLoginNavigate = async () => {
|
const afterLoginNavigate = async () => {
|
||||||
const uid = firebase.auth().currentUser?.uid;
|
const uid = firebase.auth().currentUser?.uid;
|
||||||
if (!uid) throw new Error("Aucun utilisateur après connexion");
|
if (!uid) throw new Error("Aucun utilisateur après connexion");
|
||||||
const snap = await usersRef.doc(uid).get();
|
|
||||||
const hasUserName = !!snap.data()?.userName;
|
|
||||||
if (hasUserName) {
|
|
||||||
navigation.reset({ index: 0, routes: [{ name: Routes.BottomTab }] });
|
navigation.reset({ index: 0, routes: [{ name: Routes.BottomTab }] });
|
||||||
} else {
|
|
||||||
navigation.reset({ index: 0, routes: [{ name: Routes.CreatePseudo }] });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onLogin = async () => {
|
const onLogin = async () => {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
} from "../../../config/firebase";
|
} from "../../../config/firebase";
|
||||||
import useDataFromRef from "../../../hooks/useDataFromRef";
|
import useDataFromRef from "../../../hooks/useDataFromRef";
|
||||||
import { useUser } from "../../../providers/UserDataProvider";
|
import { useUser } from "../../../providers/UserDataProvider";
|
||||||
|
import { getArtistDisplayName } from "../../../utils/artistName";
|
||||||
import { Palette } from "../../../styles";
|
import { Palette } from "../../../styles";
|
||||||
import { FONT_FAMILY } from "../../../styles/Fonts";
|
import { FONT_FAMILY } from "../../../styles/Fonts";
|
||||||
import { size } from "../../../styles/Style";
|
import { size } from "../../../styles/Style";
|
||||||
@@ -51,6 +52,10 @@ const CommentsPanel = ({
|
|||||||
panelHeight,
|
panelHeight,
|
||||||
}) => {
|
}) => {
|
||||||
const { currentUID, currentUserData } = useUser() || {};
|
const { currentUID, currentUserData } = useUser() || {};
|
||||||
|
const currentUserDisplayName = useMemo(
|
||||||
|
() => getArtistDisplayName(currentUserData, ""),
|
||||||
|
[currentUserData]
|
||||||
|
);
|
||||||
const [text, setText] = useState("");
|
const [text, setText] = useState("");
|
||||||
const scrollRef = useRef(null);
|
const scrollRef = useRef(null);
|
||||||
|
|
||||||
@@ -114,7 +119,7 @@ const CommentsPanel = ({
|
|||||||
.collection("comments")
|
.collection("comments")
|
||||||
.add({
|
.add({
|
||||||
userId: currentUID,
|
userId: currentUID,
|
||||||
userName: currentUserData?.userName || "",
|
userName: currentUserDisplayName,
|
||||||
profilePicture: currentUserData?.profilePictureURL || "",
|
profilePicture: currentUserData?.profilePictureURL || "",
|
||||||
text: value,
|
text: value,
|
||||||
createdAt: serverTimestamp(),
|
createdAt: serverTimestamp(),
|
||||||
@@ -127,7 +132,7 @@ const CommentsPanel = ({
|
|||||||
const optimistic = {
|
const optimistic = {
|
||||||
id: docRef?.id || Math.random().toString(36).slice(2),
|
id: docRef?.id || Math.random().toString(36).slice(2),
|
||||||
userId: currentUID,
|
userId: currentUID,
|
||||||
userName: currentUserData?.userName || "",
|
userName: currentUserDisplayName,
|
||||||
profilePicture: currentUserData?.profilePictureURL || "",
|
profilePicture: currentUserData?.profilePictureURL || "",
|
||||||
text: value,
|
text: value,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import useDataFromRef from "../../hooks/useDataFromRef";
|
|||||||
import { Routes } from "../../navigation";
|
import { Routes } from "../../navigation";
|
||||||
import { useRoute } from "@react-navigation/native";
|
import { useRoute } from "@react-navigation/native";
|
||||||
import { navigate } from "../../navigation/NavigationService";
|
import { navigate } from "../../navigation/NavigationService";
|
||||||
|
import { getArtistDisplayName } from "../../utils/artistName";
|
||||||
|
|
||||||
const Follows = () => {
|
const Follows = () => {
|
||||||
const { params } = useRoute();
|
const { params } = useRoute();
|
||||||
@@ -84,7 +85,9 @@ const Follows = () => {
|
|||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
const UserRow = ({ user }) => (
|
const UserRow = ({ user }) => {
|
||||||
|
const displayName = getArtistDisplayName(user, "Utilisateur");
|
||||||
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
style={{ gap: 14, ...Style.containerRow }}
|
style={{ gap: 14, ...Style.containerRow }}
|
||||||
onPress={() => navigate(Routes.SingerProfile, { userId: user?.id })}
|
onPress={() => navigate(Routes.SingerProfile, { userId: user?.id })}
|
||||||
@@ -108,10 +111,11 @@ const Follows = () => {
|
|||||||
fontFamily: FONT_FAMILY.InterRegular,
|
fontFamily: FONT_FAMILY.InterRegular,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{user?.userName || "Utilisateur"}
|
{displayName}
|
||||||
</Text>
|
</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const list = selected === "Abonnés" ? followers : following;
|
const list = selected === "Abonnés" ? followers : following;
|
||||||
const loading = selected === "Abonnés" ? followersLoading : followingLoading;
|
const loading = selected === "Abonnés" ? followersLoading : followingLoading;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import Page from "../../layouts/Page";
|
|||||||
import { Routes } from "../../navigation";
|
import { Routes } from "../../navigation";
|
||||||
import { push } from "../../navigation/NavigationService";
|
import { push } from "../../navigation/NavigationService";
|
||||||
import { useUser } from "../../providers/UserDataProvider";
|
import { useUser } from "../../providers/UserDataProvider";
|
||||||
|
import { getArtistDisplayName } from "../../utils/artistName";
|
||||||
import { Palette } from "../../styles";
|
import { Palette } from "../../styles";
|
||||||
import { FONT_FAMILY } from "../../styles/Fonts";
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||||
import Style, { gutters, size } from "../../styles/Style";
|
import Style, { gutters, size } from "../../styles/Style";
|
||||||
@@ -64,6 +65,18 @@ const Profile = () => {
|
|||||||
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
const [selectedProjectId, setSelectedProjectId] = useState(null);
|
||||||
const [updatingPhoto, setUpdatingPhoto] = useState(false);
|
const [updatingPhoto, setUpdatingPhoto] = useState(false);
|
||||||
const [webUploadMessage, setWebUploadMessage] = useState("");
|
const [webUploadMessage, setWebUploadMessage] = useState("");
|
||||||
|
const selfDisplayName = useMemo(
|
||||||
|
() => getArtistDisplayName(currentUserData, "MusicLand"),
|
||||||
|
[currentUserData]
|
||||||
|
);
|
||||||
|
const targetDisplayName = useMemo(
|
||||||
|
() => getArtistDisplayName(userData, "MusicLand"),
|
||||||
|
[userData]
|
||||||
|
);
|
||||||
|
const profileTitle = useMemo(
|
||||||
|
() => getArtistDisplayName(isSelf ? currentUserData : userData, "Profil"),
|
||||||
|
[currentUserData, isSelf, userData]
|
||||||
|
);
|
||||||
const navigateToMusicDetails = useNavigateToMusicDetails();
|
const navigateToMusicDetails = useNavigateToMusicDetails();
|
||||||
const onPressMenu = (item) => {
|
const onPressMenu = (item) => {
|
||||||
setSelected(item);
|
setSelected(item);
|
||||||
@@ -191,10 +204,7 @@ const Profile = () => {
|
|||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<MusicCard
|
<MusicCard
|
||||||
title={item?.title || "Sans titre"}
|
title={item?.title || "Sans titre"}
|
||||||
subtitle={
|
subtitle={isSelf ? selfDisplayName : targetDisplayName}
|
||||||
(isSelf ? currentUserData?.userName : userData?.userName) ||
|
|
||||||
"MusicLand"
|
|
||||||
}
|
|
||||||
imageUri={item?.coverUrl || null}
|
imageUri={item?.coverUrl || null}
|
||||||
projectId={item?.id}
|
projectId={item?.id}
|
||||||
likedBy={item?.likedBy || []}
|
likedBy={item?.likedBy || []}
|
||||||
@@ -409,8 +419,7 @@ const Profile = () => {
|
|||||||
fontFamily: FONT_FAMILY.InterSemiBold,
|
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(isSelf ? currentUserData?.userName : userData?.userName) ||
|
{profileTitle}
|
||||||
"Profil"}
|
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View
|
<View
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ const Register = () => {
|
|||||||
title="Inscription"
|
title="Inscription"
|
||||||
>
|
>
|
||||||
<View style={styles.pageContent}>
|
<View style={styles.pageContent}>
|
||||||
<ItemContainer height={520} disableKeyboardHeight>
|
<ItemContainer height={620} disableKeyboardHeight>
|
||||||
<View style={styles.formContent}>
|
<View style={styles.formContent}>
|
||||||
<Text style={styles.title}>Renseigne tes informations</Text>
|
<Text style={styles.title}>Renseigne tes informations</Text>
|
||||||
{preferredLanguage && (
|
{preferredLanguage && (
|
||||||
@@ -287,7 +287,7 @@ const styles = StyleSheet.create({
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
maxWidth: 420,
|
maxWidth: 420,
|
||||||
maxHeight: "80%",
|
maxHeight: "80%",
|
||||||
backgroundColor: Palette.darkPurple,
|
backgroundColor: Palette.ultraLightWhite,
|
||||||
borderRadius: 20,
|
borderRadius: 20,
|
||||||
padding: 16,
|
padding: 16,
|
||||||
gap: 12,
|
gap: 12,
|
||||||
|
|||||||
@@ -24,12 +24,11 @@ export default ({ navigation }) => {
|
|||||||
const user = userSnap?.data() || {};
|
const user = userSnap?.data() || {};
|
||||||
if (userSnap.exists) setCurrentUserData(user);
|
if (userSnap.exists) setCurrentUserData(user);
|
||||||
|
|
||||||
const hasUserName = !!user?.userName;
|
|
||||||
navigation.reset({
|
navigation.reset({
|
||||||
index: 0,
|
index: 0,
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
name: hasUserName ? Routes.BottomTab : Routes.CreatePseudo,
|
name: Routes.BottomTab,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -78,11 +78,11 @@ const SongReady = () => {
|
|||||||
|
|
||||||
// Sync progression depuis les players
|
// Sync progression depuis les players
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// expo-audio returns seconds on native, but on web values can be milliseconds
|
// Ensure we consistently work with milliseconds whatever the platform
|
||||||
const toMs = (t) => {
|
const toMs = (t) => {
|
||||||
const n = Number(t || 0);
|
const n = Number(t || 0);
|
||||||
if (!isFinite(n) || n <= 0) return 0;
|
if (!isFinite(n) || n <= 0) return 0;
|
||||||
return Platform.OS === "web" ? n : n * 1000;
|
return n >= 1000 ? n : n * 1000;
|
||||||
};
|
};
|
||||||
|
|
||||||
const id = setInterval(() => {
|
const id = setInterval(() => {
|
||||||
|
|||||||
@@ -1,26 +1,128 @@
|
|||||||
import * as ImagePicker from "expo-image-picker";
|
import * as ImagePicker from "expo-image-picker";
|
||||||
import React, { useState } from "react";
|
import { BlurView } from "expo-blur";
|
||||||
import { Image, View } from "react-native";
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
import {
|
||||||
|
Image,
|
||||||
|
Modal,
|
||||||
|
Pressable,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
} from "react-native";
|
||||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit";
|
import useMinuit from "react-native-minuit/src/hooks/useMinuit";
|
||||||
import { ai, background } from "../../assets";
|
import { ai, background } from "../../assets";
|
||||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||||
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
|
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
|
||||||
import GradientButton from "../../components/GradientButton";
|
import GradientButton from "../../components/GradientButton";
|
||||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||||
|
import { Input } from "../../components/Input";
|
||||||
|
import firebase, { projectsRef, usersRef } from "../../config/firebase";
|
||||||
import { uploadFileToFirebase } from "../../helpers/uploadToFirebase";
|
import { uploadFileToFirebase } from "../../helpers/uploadToFirebase";
|
||||||
import Page from "../../layouts/Page";
|
import Page from "../../layouts/Page";
|
||||||
import { Routes } from "../../navigation";
|
import { Routes } from "../../navigation";
|
||||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||||
import { useUserData } from "../../providers/UserDataProvider";
|
import { useUserData } from "../../providers/UserDataProvider";
|
||||||
import { gutters } from "../../styles";
|
import { buildFullName } from "../../utils/artistName";
|
||||||
|
import { gutters, Palette } from "../../styles";
|
||||||
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||||
|
|
||||||
export const ChooseCoverType = () => {
|
export const ChooseCoverType = () => {
|
||||||
const [showIntro, setShowIntro] = useState(true);
|
const [showIntro, setShowIntro] = useState(true);
|
||||||
const { selectedProject, selectedProjectId, updateProjectData } =
|
const [choiceVisible, setChoiceVisible] = useState(false);
|
||||||
useUserData();
|
const [pseudoVisible, setPseudoVisible] = useState(false);
|
||||||
const { setIsLoading } = useMinuit();
|
const [pseudo, setPseudo] = useState("");
|
||||||
|
const [pendingAction, setPendingAction] = useState(null);
|
||||||
|
const [savingChoice, setSavingChoice] = useState(false);
|
||||||
|
const [savingPseudo, setSavingPseudo] = useState(false);
|
||||||
|
|
||||||
const onPickUserImage = async () => {
|
const {
|
||||||
|
selectedProject,
|
||||||
|
selectedProjectId,
|
||||||
|
updateProjectData,
|
||||||
|
currentUserData,
|
||||||
|
currentUID,
|
||||||
|
} = useUserData();
|
||||||
|
const { setIsLoading, setTooltip } = useMinuit();
|
||||||
|
|
||||||
|
const projectId = selectedProject?.id || selectedProjectId || null;
|
||||||
|
|
||||||
|
const hasArtistPreference = useMemo(() => {
|
||||||
|
if (currentUserData?.userName) return true;
|
||||||
|
const pref = currentUserData?.artistNamePreference;
|
||||||
|
return pref === "REAL_NAME" || pref === "CUSTOM";
|
||||||
|
}, [currentUserData?.artistNamePreference, currentUserData?.userName]);
|
||||||
|
|
||||||
|
const realName = useMemo(() => buildFullName(currentUserData), [
|
||||||
|
currentUserData?.firstName,
|
||||||
|
currentUserData?.lastName,
|
||||||
|
currentUserData?.displayName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (pseudoVisible) {
|
||||||
|
setPseudo(currentUserData?.userName || "");
|
||||||
|
}
|
||||||
|
}, [currentUserData?.userName, pseudoVisible]);
|
||||||
|
|
||||||
|
const ensureArtistPreference = useCallback(
|
||||||
|
(nextAction) => {
|
||||||
|
if (hasArtistPreference) {
|
||||||
|
if (typeof nextAction === "function") {
|
||||||
|
nextAction();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setPendingAction(() => nextAction);
|
||||||
|
setChoiceVisible(true);
|
||||||
|
},
|
||||||
|
[hasArtistPreference]
|
||||||
|
);
|
||||||
|
|
||||||
|
const runPendingAction = useCallback(async () => {
|
||||||
|
if (typeof pendingAction === "function") {
|
||||||
|
const action = pendingAction;
|
||||||
|
setPendingAction(null);
|
||||||
|
await action();
|
||||||
|
} else {
|
||||||
|
setPendingAction(null);
|
||||||
|
}
|
||||||
|
}, [pendingAction]);
|
||||||
|
|
||||||
|
const applyDisplayNameToProjects = useCallback(
|
||||||
|
async (displayName) => {
|
||||||
|
if (!currentUID) return;
|
||||||
|
const safeName =
|
||||||
|
typeof displayName === "string" && displayName.trim().length > 0
|
||||||
|
? displayName.trim()
|
||||||
|
: null;
|
||||||
|
try {
|
||||||
|
const snapshot = await projectsRef
|
||||||
|
.where("userId", "==", currentUID)
|
||||||
|
.get();
|
||||||
|
if (!snapshot.empty) {
|
||||||
|
const batch = firebase.firestore().batch();
|
||||||
|
snapshot.docs.forEach((doc) => {
|
||||||
|
batch.set(doc.ref, { userName: safeName }, { merge: true });
|
||||||
|
});
|
||||||
|
await batch.commit();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("applyDisplayNameToProjects error", error?.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!projectId) return;
|
||||||
|
try {
|
||||||
|
await projectsRef
|
||||||
|
.doc(projectId)
|
||||||
|
.set({ userName: safeName }, { merge: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.log("update current project userName error", error?.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[currentUID, projectId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const pickUserImage = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
await setIsLoading(true);
|
await setIsLoading(true);
|
||||||
const result = await ImagePicker.launchImageLibraryAsync({
|
const result = await ImagePicker.launchImageLibraryAsync({
|
||||||
@@ -33,7 +135,7 @@ export const ChooseCoverType = () => {
|
|||||||
const uri = result?.assets?.[0]?.uri || null;
|
const uri = result?.assets?.[0]?.uri || null;
|
||||||
if (!uri) return;
|
if (!uri) return;
|
||||||
|
|
||||||
const projectId = selectedProject?.id || selectedProjectId;
|
if (!projectId) return;
|
||||||
const path = `musics/${projectId}/userSelectedCover.png`;
|
const path = `musics/${projectId}/userSelectedCover.png`;
|
||||||
|
|
||||||
const { resultURI } = await uploadFileToFirebase({
|
const { resultURI } = await uploadFileToFirebase({
|
||||||
@@ -57,7 +159,120 @@ export const ChooseCoverType = () => {
|
|||||||
} finally {
|
} finally {
|
||||||
await setIsLoading(false);
|
await setIsLoading(false);
|
||||||
}
|
}
|
||||||
|
}, [projectId, setIsLoading, updateProjectData]);
|
||||||
|
|
||||||
|
const handlePickUserImage = useCallback(() => {
|
||||||
|
ensureArtistPreference(pickUserImage);
|
||||||
|
}, [ensureArtistPreference, pickUserImage]);
|
||||||
|
|
||||||
|
const handleGenerateCover = useCallback(() => {
|
||||||
|
ensureArtistPreference(() => navigate(Routes.PouchReady));
|
||||||
|
}, [ensureArtistPreference]);
|
||||||
|
|
||||||
|
const closeChoiceModal = useCallback(() => {
|
||||||
|
setChoiceVisible(false);
|
||||||
|
setPendingAction(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const openPseudoModal = useCallback(() => {
|
||||||
|
setChoiceVisible(false);
|
||||||
|
setPseudoVisible(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleUseRealName = useCallback(async () => {
|
||||||
|
if (!currentUID) return;
|
||||||
|
if (!realName) {
|
||||||
|
setTooltip({
|
||||||
|
type: "error",
|
||||||
|
text:
|
||||||
|
"Renseigne ton prénom et nom dans ton profil ou crée un nom d'artiste.",
|
||||||
|
});
|
||||||
|
setChoiceVisible(false);
|
||||||
|
setPseudoVisible(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setSavingChoice(true);
|
||||||
|
const updates = {
|
||||||
|
artistNamePreference: "REAL_NAME",
|
||||||
|
userName: realName,
|
||||||
|
userNameLower: realName.toLowerCase(),
|
||||||
|
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||||
};
|
};
|
||||||
|
await usersRef.doc(currentUID).set(updates, { merge: true });
|
||||||
|
await applyDisplayNameToProjects(realName);
|
||||||
|
setTooltip({ type: "success", text: "Nom d'artiste mis à jour" });
|
||||||
|
setChoiceVisible(false);
|
||||||
|
await runPendingAction();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("handleUseRealName error", e?.message);
|
||||||
|
setTooltip({
|
||||||
|
type: "error",
|
||||||
|
text: e?.message || "Impossible de mettre à jour le nom",
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setSavingChoice(false);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
applyDisplayNameToProjects,
|
||||||
|
currentUID,
|
||||||
|
currentUserData?.userName,
|
||||||
|
currentUserData?.userNameLower,
|
||||||
|
realName,
|
||||||
|
runPendingAction,
|
||||||
|
setTooltip,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleCancelPseudo = useCallback(() => {
|
||||||
|
setPseudoVisible(false);
|
||||||
|
setPendingAction(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSavePseudo = useCallback(async () => {
|
||||||
|
const value = (pseudo || "").trim();
|
||||||
|
if (!value || !currentUID) return;
|
||||||
|
try {
|
||||||
|
setSavingPseudo(true);
|
||||||
|
const lower = value.toLowerCase();
|
||||||
|
const existing = await usersRef
|
||||||
|
.where("userNameLower", "==", lower)
|
||||||
|
.limit(1)
|
||||||
|
.get();
|
||||||
|
if (!existing.empty && existing.docs[0].id !== currentUID) {
|
||||||
|
setTooltip({ text: "Ce pseudo est déjà pris", type: "error" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await usersRef.doc(currentUID).set(
|
||||||
|
{
|
||||||
|
userName: value,
|
||||||
|
userNameLower: lower,
|
||||||
|
artistNamePreference: "CUSTOM",
|
||||||
|
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
|
||||||
|
},
|
||||||
|
{ merge: true }
|
||||||
|
);
|
||||||
|
await applyDisplayNameToProjects(value);
|
||||||
|
setTooltip({ type: "success", text: "Pseudo enregistré" });
|
||||||
|
setPseudoVisible(false);
|
||||||
|
await runPendingAction();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("handleSavePseudo error", e?.message);
|
||||||
|
setTooltip({
|
||||||
|
type: "error",
|
||||||
|
text: e?.message || "Enregistrement impossible",
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setSavingPseudo(false);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
applyDisplayNameToProjects,
|
||||||
|
currentUID,
|
||||||
|
pseudo,
|
||||||
|
runPendingAction,
|
||||||
|
setTooltip,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page backgroundImg={background.studioBG2} headerType="NONE">
|
<Page backgroundImg={background.studioBG2} headerType="NONE">
|
||||||
@@ -85,11 +300,11 @@ export const ChooseCoverType = () => {
|
|||||||
>
|
>
|
||||||
<BorderGradientButton
|
<BorderGradientButton
|
||||||
title="Choisir une image"
|
title="Choisir une image"
|
||||||
onPress={onPickUserImage}
|
onPress={handlePickUserImage}
|
||||||
/>
|
/>
|
||||||
<GradientButton
|
<GradientButton
|
||||||
title="Générer une pochette"
|
title="Générer une pochette"
|
||||||
onPress={() => navigate(Routes.PouchReady)}
|
onPress={handleGenerateCover}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@@ -97,6 +312,131 @@ export const ChooseCoverType = () => {
|
|||||||
visible={showIntro}
|
visible={showIntro}
|
||||||
onClose={() => setShowIntro(false)}
|
onClose={() => setShowIntro(false)}
|
||||||
/>
|
/>
|
||||||
|
<Modal
|
||||||
|
visible={choiceVisible}
|
||||||
|
transparent
|
||||||
|
animationType="fade"
|
||||||
|
onRequestClose={closeChoiceModal}
|
||||||
|
>
|
||||||
|
<View style={styles.modalBackdrop}>
|
||||||
|
<Pressable
|
||||||
|
style={styles.modalOverlay}
|
||||||
|
onPress={closeChoiceModal}
|
||||||
|
accessibilityRole="button"
|
||||||
|
/>
|
||||||
|
<BlurView intensity={20} style={styles.modalCard}>
|
||||||
|
<View style={styles.modalContent}>
|
||||||
|
<Text style={styles.modalTitle}>Nom d'artiste</Text>
|
||||||
|
<Text style={styles.modalDescription}>
|
||||||
|
Veux-tu utiliser ton prénom et nom pour tes musiques ou créer un
|
||||||
|
nom d'artiste ?
|
||||||
|
</Text>
|
||||||
|
<View style={styles.modalButtons}>
|
||||||
|
<BorderGradientButton
|
||||||
|
title={
|
||||||
|
savingChoice ? "Chargement..." : "Utiliser prénom/nom"
|
||||||
|
}
|
||||||
|
onPress={handleUseRealName}
|
||||||
|
disabled={savingChoice}
|
||||||
|
/>
|
||||||
|
<GradientButton
|
||||||
|
title="Créer un nom d'artiste"
|
||||||
|
onPress={openPseudoModal}
|
||||||
|
disabled={savingChoice}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</BlurView>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
visible={pseudoVisible}
|
||||||
|
transparent
|
||||||
|
animationType="fade"
|
||||||
|
onRequestClose={handleCancelPseudo}
|
||||||
|
>
|
||||||
|
<View style={styles.modalBackdrop}>
|
||||||
|
<Pressable
|
||||||
|
style={styles.modalOverlay}
|
||||||
|
onPress={handleCancelPseudo}
|
||||||
|
accessibilityRole="button"
|
||||||
|
/>
|
||||||
|
<BlurView intensity={20} style={styles.modalCard}>
|
||||||
|
<View style={styles.modalContent}>
|
||||||
|
<Text style={styles.modalTitle}>Créer un nom d'artiste</Text>
|
||||||
|
<Text style={styles.modalDescription}>
|
||||||
|
Choisis le nom qui sera visible sur tes musiques.
|
||||||
|
</Text>
|
||||||
|
<View style={styles.inputWrapper}>
|
||||||
|
<Input
|
||||||
|
placeholder="Nom d'artiste"
|
||||||
|
label="Nom d'artiste"
|
||||||
|
value={pseudo}
|
||||||
|
setValue={setPseudo}
|
||||||
|
isBlur
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.modalButtons}>
|
||||||
|
<BorderGradientButton
|
||||||
|
title="Annuler"
|
||||||
|
onPress={handleCancelPseudo}
|
||||||
|
disabled={savingPseudo}
|
||||||
|
/>
|
||||||
|
<GradientButton
|
||||||
|
title={savingPseudo ? "Enregistrement..." : "Valider"}
|
||||||
|
onPress={handleSavePseudo}
|
||||||
|
disabled={savingPseudo || !(pseudo || "").trim()}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</BlurView>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
modalBackdrop: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "rgba(0,0,0,0.65)",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
padding: gutters,
|
||||||
|
},
|
||||||
|
modalOverlay: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
},
|
||||||
|
modalCard: {
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 420,
|
||||||
|
borderRadius: 24,
|
||||||
|
overflow: "hidden",
|
||||||
|
backgroundColor: Palette.glass,
|
||||||
|
},
|
||||||
|
modalContent: {
|
||||||
|
paddingHorizontal: 24,
|
||||||
|
paddingVertical: 28,
|
||||||
|
gap: 18,
|
||||||
|
},
|
||||||
|
modalTitle: {
|
||||||
|
fontSize: 22,
|
||||||
|
color: Palette.white,
|
||||||
|
fontFamily: FONT_FAMILY.InterSemiBold,
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
modalDescription: {
|
||||||
|
fontSize: 15,
|
||||||
|
color: Palette.gray,
|
||||||
|
fontFamily: FONT_FAMILY.InterRegular,
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
modalButtons: {
|
||||||
|
width: "80%",
|
||||||
|
alignSelf: "center",
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
inputWrapper: {
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
export const buildFullName = ({ firstName, lastName, displayName } = {}) => {
|
||||||
|
const first =
|
||||||
|
typeof firstName === "string" && firstName.trim().length > 0
|
||||||
|
? firstName.trim()
|
||||||
|
: "";
|
||||||
|
const last =
|
||||||
|
typeof lastName === "string" && lastName.trim().length > 0
|
||||||
|
? lastName.trim()
|
||||||
|
: "";
|
||||||
|
const nameFromParts = [first, last].filter(Boolean).join(" ").trim();
|
||||||
|
if (nameFromParts) return nameFromParts;
|
||||||
|
|
||||||
|
const fallbackDisplay =
|
||||||
|
typeof displayName === "string" && displayName.trim().length > 0
|
||||||
|
? displayName.trim()
|
||||||
|
: "";
|
||||||
|
return fallbackDisplay || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getArtistDisplayName = (source, fallback = "") => {
|
||||||
|
if (!source) return fallback;
|
||||||
|
const rawUserName =
|
||||||
|
typeof source?.userName === "string" ? source.userName.trim() : "";
|
||||||
|
if (rawUserName) return rawUserName;
|
||||||
|
|
||||||
|
const nameFromParts = buildFullName({
|
||||||
|
firstName: source?.firstName,
|
||||||
|
lastName: source?.lastName,
|
||||||
|
displayName: source?.displayName,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (nameFromParts) return nameFromParts;
|
||||||
|
return fallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getUserPreferredArtistName = (user) => {
|
||||||
|
const display = getArtistDisplayName(user, "");
|
||||||
|
return display || null;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user