firtname and lastname before username
This commit is contained in:
@@ -1,26 +1,128 @@
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import React, { useState } from "react";
|
||||
import { Image, View } from "react-native";
|
||||
import { BlurView } from "expo-blur";
|
||||
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 { ai, background } from "../../assets";
|
||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
|
||||
import GradientButton from "../../components/GradientButton";
|
||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||
import { Input } from "../../components/Input";
|
||||
import firebase, { projectsRef, usersRef } from "../../config/firebase";
|
||||
import { uploadFileToFirebase } from "../../helpers/uploadToFirebase";
|
||||
import Page from "../../layouts/Page";
|
||||
import { Routes } from "../../navigation";
|
||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||
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 = () => {
|
||||
const [showIntro, setShowIntro] = useState(true);
|
||||
const { selectedProject, selectedProjectId, updateProjectData } =
|
||||
useUserData();
|
||||
const { setIsLoading } = useMinuit();
|
||||
const [choiceVisible, setChoiceVisible] = useState(false);
|
||||
const [pseudoVisible, setPseudoVisible] = useState(false);
|
||||
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 {
|
||||
await setIsLoading(true);
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
@@ -33,7 +135,7 @@ export const ChooseCoverType = () => {
|
||||
const uri = result?.assets?.[0]?.uri || null;
|
||||
if (!uri) return;
|
||||
|
||||
const projectId = selectedProject?.id || selectedProjectId;
|
||||
if (!projectId) return;
|
||||
const path = `musics/${projectId}/userSelectedCover.png`;
|
||||
|
||||
const { resultURI } = await uploadFileToFirebase({
|
||||
@@ -57,7 +159,120 @@ export const ChooseCoverType = () => {
|
||||
} finally {
|
||||
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 (
|
||||
<Page backgroundImg={background.studioBG2} headerType="NONE">
|
||||
@@ -85,11 +300,11 @@ export const ChooseCoverType = () => {
|
||||
>
|
||||
<BorderGradientButton
|
||||
title="Choisir une image"
|
||||
onPress={onPickUserImage}
|
||||
onPress={handlePickUserImage}
|
||||
/>
|
||||
<GradientButton
|
||||
title="Générer une pochette"
|
||||
onPress={() => navigate(Routes.PouchReady)}
|
||||
onPress={handleGenerateCover}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
@@ -97,6 +312,131 @@ export const ChooseCoverType = () => {
|
||||
visible={showIntro}
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
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,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user