259 lines
8.4 KiB
JavaScript
259 lines
8.4 KiB
JavaScript
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="Qu’en 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;
|