Files
musicland/src/screens/cover/PouchReady.js
T
2025-10-23 10:16:36 +02:00

259 lines
8.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Image as ExpoImage } from "expo-image";
import React, { useCallback, useEffect, useState } from "react";
import { ActivityIndicator, Text, View } from "react-native";
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
import { background, icons } from "../../assets";
import BorderGradientButton from "../../components/BorderGradientButton";
import GradientButton from "../../components/GradientButton";
import MusicLandHeader from "../../components/MusicLandHeader";
import alert from "../../components/Alert";
import firebase, { tasksRef } from "../../config/firebase";
import loaderMessages from "../../config/loaderMessages";
import { isWeb } from "../../hooks/useLayoutType";
import Page from "../../layouts/Page";
import { Routes } from "../../navigation";
import { goBack, navigate } from "../../navigation/NavigationService";
import { useUser } from "../../providers/UserDataProvider";
import { gutters, Palette, Style } from "../../styles";
import CreateLyricsHeader from "../Writing/components/CreateLyricsHeader";
import CustomInput from "../Writing/components/CustomInput";
const PouchReady = () => {
const { selectedProjectId, selectedProject, updateProjectData } = useUser();
const { setIsLoading } = useMinuit();
const isGenerating = selectedProject?.coverStatus === "GENERATING";
const coverOptions = Array.isArray(selectedProject?.cover?.options)
? selectedProject.cover.options
: [];
const hasGeneratedOptions = coverOptions.length > 0;
const coverBackgroundMessage = isWeb
? loaderMessages.pouchReadyGenerationWeb
: "";
const [coverStyle, setCoverStyle] = useState(
selectedProject?.coverStyle || ""
);
useEffect(() => {
setCoverStyle(selectedProject?.coverStyle || "");
}, [selectedProject?.coverStyle]);
const generateCover = useCallback(async (styleValue) => {
if (!selectedProjectId) return;
if (hasGeneratedOptions) {
return;
}
const trimmedStyle = String(styleValue || "").trim();
if (!trimmedStyle) {
alert("Attention", "Merci de renseigner un style pour la pochette.", [
{ text: "OK" },
]);
return;
}
try {
await setIsLoading(true);
await updateProjectData(
{
coverStyle: trimmedStyle,
},
{ merge: true }
);
await tasksRef.add({
type: "cover",
projectId: selectedProjectId,
status: "PENDING",
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
});
} catch (e) {
console.log("Cover task error", e?.message);
} finally {
setIsLoading(false);
}
}, [hasGeneratedOptions, selectedProjectId, setIsLoading, updateProjectData]);
const requestCoverGeneration = useCallback(() => {
const trimmedStyle = (coverStyle || "").trim();
if (!trimmedStyle) {
alert("Attention", "Merci de renseigner un style pour la pochette.", [
{ text: "OK" },
]);
return;
}
alert("Attention", "Générer une pochette ?", [
{
text: "Annuler",
style: "cancel",
},
{
text: "Oui",
onPress: () => generateCover(trimmedStyle),
},
]);
}, [coverStyle, generateCover]);
const validateCover = () => {
navigate(Routes.ValidateCover);
};
const coverPreviewUrl =
selectedProject?.cover?.result ||
selectedProject?.cover?.generatedBackground ||
null;
const displayOptions = hasGeneratedOptions
? coverOptions
: coverPreviewUrl
? [
{
id: "preview",
finalUrl: selectedProject?.cover?.result || null,
generatedUrl: coverPreviewUrl,
},
]
: [];
return (
<Page backgroundImg={background.studioBG2} headerType="NONE">
<MusicLandHeader onPressBack={goBack} progress={72} />
<View style={{ flex: 1, marginTop: 16 }}>
<CreateLyricsHeader
title={
selectedProject?.cover?.backgroundGenerated
? "Ta pochette est prête!"
: "Génération de la pochette"
}
// subTitle="Quen penses-tu ?"
/>
<View style={{ flex: 1, ...Style.containerCenter }}>
<View style={{ width: "80%", gap: 24 }}>
<View
style={{
width: "100%",
flexDirection: isWeb ? "row" : "column",
gap: 16,
justifyContent: "center",
flexWrap: "wrap",
}}
>
{displayOptions.length > 0 ? (
displayOptions.map((option, index) => {
const optionUri = option?.finalUrl || option?.generatedUrl || "";
if (!optionUri) return null;
return (
<View
key={option?.id || index}
style={{
width: isWeb ? 280 : "100%",
alignItems: "center",
gap: 8,
}}
>
<ExpoImage
source={{ uri: optionUri }}
cachePolicy="memory-disk"
priority="high"
contentFit="cover"
transition={120}
style={{
width: "100%",
height: 260,
borderRadius: 20,
}}
/>
{hasGeneratedOptions && (
<Text
style={{
color: Palette.white,
opacity: 0.7,
}}
>
Pochette {index + 1}
</Text>
)}
</View>
);
})
) : (
<View
style={{
width: isWeb ? 300 : "100%",
height: 300,
borderRadius: 20,
backgroundColor: "#00000040",
alignSelf: "center",
...Style.containerCenter,
}}
>
{isGenerating && (
<View style={{ alignItems: "center", gap: 8 }}>
<ActivityIndicator color={Palette.white} />
{isWeb ? (
coverBackgroundMessage ? (
<Text
style={{
color: Palette.white,
marginTop: 6,
textAlign: "center",
opacity: 0.9,
}}
>
{coverBackgroundMessage}
</Text>
) : null
) : (
<Text
style={{
color: Palette.white,
marginTop: 6,
textAlign: "center",
opacity: 0.9,
}}
>
Génération en cours.
</Text>
)}
</View>
)}
</View>
)}
</View>
<CustomInput
label="Style de la pochette"
placeholder="Exemple : Collage rétro futuriste lumineux"
value={coverStyle}
setValue={setCoverStyle}
multiline={false}
height={55}
maxLength={120}
/>
</View>
</View>
</View>
<View
style={{
paddingBottom: gutters * 2,
width: "80%",
alignSelf: "center",
gap: 12,
}}
>
{!hasGeneratedOptions && (
<BorderGradientButton
title={isGenerating ? "Génération en cours..." : "Générer la pochette"}
icon={icons.stars}
onPress={requestCoverGeneration}
disabled={isGenerating}
/>
)}
<GradientButton
title={isGenerating ? "Veuillez patienter..." : "Valider"}
disabled={isGenerating || !coverPreviewUrl}
onPress={() => validateCover()}
/>
</View>
</Page>
);
};
export default PouchReady;