fix web flow

This commit is contained in:
2025-10-02 14:24:19 +02:00
parent 0ccdcf3084
commit 6f25cad83f
6 changed files with 194 additions and 91 deletions
@@ -12,9 +12,9 @@ import {
View, View,
useWindowDimensions, useWindowDimensions,
} from "react-native"; } from "react-native";
import PersonaCard from "../cards/PersonaCard/PersonaCard";
import { ai } from "../../assets"; import { ai } from "../../assets";
import { getCreationStageStates } from "../../utils/projectStages"; import { getCreationStageStates } from "../../utils/projectStages";
import PersonaCard from "../cards/PersonaCard/PersonaCard";
const STAGE_CARD_CONTENT = [ const STAGE_CARD_CONTENT = [
{ {
@@ -43,6 +43,8 @@ const STAGE_CARD_CONTENT = [
}, },
]; ];
const WEB_SCROLL_INACTIVE_DELTA = 0.05;
const FeatureCarousel = ({ const FeatureCarousel = ({
style, style,
selectedProject, selectedProject,
@@ -63,14 +65,14 @@ const FeatureCarousel = ({
...item, ...item,
isLocked: stageStates[index]?.isLocked ?? true, isLocked: stageStates[index]?.isLocked ?? true,
})), })),
[stageStates], [stageStates]
); );
const { height: windowHeight } = useWindowDimensions(); const { height: windowHeight } = useWindowDimensions();
const isWeb = Platform.OS === "web"; const isWeb = Platform.OS === "web";
const [viewportHeight, setViewportHeight] = useState(() => const [viewportHeight, setViewportHeight] = useState(() =>
Math.max(windowHeight, 1), Math.max(windowHeight, 1)
); );
const updateSnapHeight = useCallback((height) => { const updateSnapHeight = useCallback((height) => {
@@ -95,7 +97,7 @@ const FeatureCarousel = ({
const pendingScrollRef = useRef(false); const pendingScrollRef = useRef(false);
const alignTimeoutRef = useRef(null); const alignTimeoutRef = useRef(null);
const activeIndexRef = useRef( const activeIndexRef = useRef(
typeof activeIndex === "number" ? activeIndex : 0, typeof activeIndex === "number" ? activeIndex : 0
); );
const onActiveIndexChangeRef = useRef(onActiveIndexChange); const onActiveIndexChangeRef = useRef(onActiveIndexChange);
@@ -122,12 +124,12 @@ const FeatureCarousel = ({
} }
return index; return index;
}, },
[carouselItems.length], [carouselItems.length]
); );
const clearPendingAlignment = useCallback(() => { const clearPendingAlignment = useCallback(() => {
if (alignTimeoutRef.current != null) { if (alignTimeoutRef.current != null) {
clearTimeout(alignTimeoutRef.current); globalThis.clearTimeout(alignTimeoutRef.current);
alignTimeoutRef.current = null; alignTimeoutRef.current = null;
} }
}, []); }, []);
@@ -151,7 +153,7 @@ const FeatureCarousel = ({
} }
updateSnapHeight(height); updateSnapHeight(height);
try { try {
ref.scrollToOffset({ offset: clamped * height, animated: false }); ref.scrollToOffset({ offset: clamped * height, animated });
} catch (_error) { } catch (_error) {
// Ignore scroll errors when list is not ready yet. // Ignore scroll errors when list is not ready yet.
} }
@@ -167,7 +169,7 @@ const FeatureCarousel = ({
pendingScrollRef.current = false; pendingScrollRef.current = false;
} }
}, },
[clampIndex, isWeb, itemHeight, updateSnapHeight], [clampIndex, isWeb, itemHeight, updateSnapHeight]
); );
useEffect(() => { useEffect(() => {
@@ -200,7 +202,23 @@ const FeatureCarousel = ({
updateSnapHeight(height); updateSnapHeight(height);
const nextIndex = clampIndex(Math.round(offset / height)); const currentIndex = activeIndexRef.current;
const rawIndex = height ? offset / height : currentIndex;
let nextIndex = currentIndex;
if (isWeb) {
const delta = rawIndex - currentIndex;
if (Math.abs(delta) > WEB_SCROLL_INACTIVE_DELTA) {
if (Math.abs(delta) <= 1) {
nextIndex = clampIndex(currentIndex + (delta > 0 ? 1 : -1));
} else {
nextIndex = clampIndex(currentIndex + Math.round(delta));
}
}
} else {
nextIndex = clampIndex(Math.round(rawIndex));
}
const hasChanged = nextIndex !== activeIndexRef.current; const hasChanged = nextIndex !== activeIndexRef.current;
if (hasChanged) { if (hasChanged) {
@@ -212,10 +230,11 @@ const FeatureCarousel = ({
} }
if (isWeb || hasChanged) { if (isWeb || hasChanged) {
scrollToIndex(nextIndex, !isWeb, height); const shouldAnimate = isWeb ? true : !isWeb;
scrollToIndex(nextIndex, shouldAnimate, height);
} }
}, },
[clampIndex, isWeb, itemHeight, scrollToIndex, updateSnapHeight], [clampIndex, isWeb, itemHeight, scrollToIndex, updateSnapHeight]
); );
const handleScrollEnd = useCallback( const handleScrollEnd = useCallback(
@@ -225,7 +244,7 @@ const FeatureCarousel = ({
const layoutHeight = event?.nativeEvent?.layoutMeasurement?.height; const layoutHeight = event?.nativeEvent?.layoutMeasurement?.height;
alignToOffset(offsetY, layoutHeight); alignToOffset(offsetY, layoutHeight);
}, },
[alignToOffset, clearPendingAlignment], [alignToOffset, clearPendingAlignment]
); );
const handleScroll = useCallback( const handleScroll = useCallback(
@@ -236,12 +255,12 @@ const FeatureCarousel = ({
const offsetY = event?.nativeEvent?.contentOffset?.y ?? 0; const offsetY = event?.nativeEvent?.contentOffset?.y ?? 0;
const layoutHeight = event?.nativeEvent?.layoutMeasurement?.height; const layoutHeight = event?.nativeEvent?.layoutMeasurement?.height;
clearPendingAlignment(); clearPendingAlignment();
alignTimeoutRef.current = setTimeout(() => { alignTimeoutRef.current = globalThis.setTimeout(() => {
alignToOffset(offsetY, layoutHeight); alignToOffset(offsetY, layoutHeight);
alignTimeoutRef.current = null; alignTimeoutRef.current = null;
}, 80); }, 80);
}, },
[alignToOffset, clearPendingAlignment, isWeb], [alignToOffset, clearPendingAlignment, isWeb]
); );
const handleLayout = useCallback( const handleLayout = useCallback(
@@ -251,7 +270,7 @@ const FeatureCarousel = ({
updateSnapHeight(layoutHeight); updateSnapHeight(layoutHeight);
} }
}, },
[updateSnapHeight], [updateSnapHeight]
); );
const keyExtractor = useCallback((item) => item.key, []); const keyExtractor = useCallback((item) => item.key, []);
@@ -265,7 +284,7 @@ const FeatureCarousel = ({
height={itemHeight} height={itemHeight}
/> />
), ),
[itemHeight], [itemHeight]
); );
const getItemLayout = useCallback( const getItemLayout = useCallback(
@@ -274,7 +293,7 @@ const FeatureCarousel = ({
offset: itemHeight * index, offset: itemHeight * index,
index, index,
}), }),
[itemHeight], [itemHeight]
); );
const viewabilityConfig = useRef({ viewAreaCoveragePercentThreshold: 60 }); const viewabilityConfig = useRef({ viewAreaCoveragePercentThreshold: 60 });
@@ -303,7 +322,7 @@ const FeatureCarousel = ({
return undefined; return undefined;
} }
return carouselItems.map((_, index) => index * itemHeight); return carouselItems.map((_, index) => index * itemHeight);
}, [carouselItems.length, isWeb, itemHeight]); }, [carouselItems, isWeb, itemHeight]);
return ( return (
<View style={[styles.container, style]} onLayout={handleLayout}> <View style={[styles.container, style]} onLayout={handleLayout}>
+8
View File
@@ -1,3 +1,6 @@
export const OTHER_OBJECTIVE_OPTION = "Autre objectif";
export const OTHER_STYLE_OPTION = "Autre style";
export const GOALS = [ export const GOALS = [
"Envoyer un message universel", "Envoyer un message universel",
"Souhaiter un joyeux anniversaire à un ami", "Souhaiter un joyeux anniversaire à un ami",
@@ -6,6 +9,7 @@ export const GOALS = [
"Pour un mariage", "Pour un mariage",
"Pour mon entreprise", "Pour mon entreprise",
"Envoyer un message politique", "Envoyer un message politique",
OTHER_OBJECTIVE_OPTION,
]; ];
export const EMOTION_CONVEY = [ export const EMOTION_CONVEY = [
@@ -182,6 +186,10 @@ export const SONG_STYLE = [
title: "Melancholic", title: "Melancholic",
description: "ambiance mélancolique", description: "ambiance mélancolique",
}, },
{
title: OTHER_STYLE_OPTION,
description: "Décris ton style personnalisé",
},
]; ];
export const CUSTOM_SONG_STRUCTURE = [ export const CUSTOM_SONG_STRUCTURE = [
+63 -32
View File
@@ -5,6 +5,7 @@ import { SwiperFlatList } from "react-native-swiper-flatlist";
import { background } from "../../assets"; import { background } from "../../assets";
import GradientButton from "../../components/GradientButton"; import GradientButton from "../../components/GradientButton";
import MusicLandHeader from "../../components/MusicLandHeader"; import MusicLandHeader from "../../components/MusicLandHeader";
import { OTHER_OBJECTIVE_OPTION, OTHER_STYLE_OPTION } from "../../data/data";
import useLayoutType from "../../hooks/useLayoutType"; import useLayoutType from "../../hooks/useLayoutType";
import Page from "../../layouts/Page"; import Page from "../../layouts/Page";
import { Routes } from "../../navigation"; import { Routes } from "../../navigation";
@@ -44,6 +45,18 @@ const CreateLyricsWithAi = () => {
const [rhymes, setRhymes] = useState(null); const [rhymes, setRhymes] = useState(null);
const [customStructure, setCustomStructure] = useState(null); // array like ['couplet','refrain'] const [customStructure, setCustomStructure] = useState(null); // array like ['couplet','refrain']
const trimmedOtherObjective =
typeof otherObjective === "string" ? otherObjective.trim() : "";
const shouldUseOtherObjective = objective === OTHER_OBJECTIVE_OPTION;
const persistedOtherObjective = shouldUseOtherObjective
? trimmedOtherObjective
: "";
const trimmedOtherStyle =
typeof otherStyle === "string" ? otherStyle.trim() : "";
const shouldUseOtherStyle = style === OTHER_STYLE_OPTION;
const persistedOtherStyle = shouldUseOtherStyle ? trimmedOtherStyle : "";
// Pré-remplir les états depuis le projet sélectionné si disponibles // Pré-remplir les états depuis le projet sélectionné si disponibles
React.useEffect(() => { React.useEffect(() => {
if (!selectedProject) return; if (!selectedProject) return;
@@ -52,19 +65,28 @@ const CreateLyricsWithAi = () => {
const rawOtherObjective = const rawOtherObjective =
typeof sel.otherObjective === "string" ? sel.otherObjective : ""; typeof sel.otherObjective === "string" ? sel.otherObjective : "";
const hasSavedOtherObjective = rawOtherObjective.trim().length > 0; const trimmedSavedOtherObjective = rawOtherObjective.trim();
const hasSavedOtherObjective = trimmedSavedOtherObjective.length > 0;
const savedObjective = const savedObjective =
typeof sel.objective === "string" && sel.objective.trim().length > 0 typeof sel.objective === "string" && sel.objective.trim().length > 0
? sel.objective ? sel.objective.trim()
: null; : null;
if (!otherObjective && hasSavedOtherObjective) { if (!otherObjective && hasSavedOtherObjective) {
setOtherObjective(rawOtherObjective); setOtherObjective(rawOtherObjective);
if (objective !== null) { }
setObjective(null);
} const shouldSelectOtherObjective =
} else if (!hasSavedOtherObjective && objective == null && savedObjective) { hasSavedOtherObjective &&
setObjective(savedObjective); (!savedObjective || savedObjective === OTHER_OBJECTIVE_OPTION);
const resolvedSavedObjective = shouldSelectOtherObjective
? OTHER_OBJECTIVE_OPTION
: savedObjective;
if (resolvedSavedObjective && objective !== resolvedSavedObjective) {
setObjective(resolvedSavedObjective);
} else if (!resolvedSavedObjective && objective !== null) {
setObjective(null);
} }
if (!context && typeof sel.context === "string") setContext(sel.context); if (!context && typeof sel.context === "string") setContext(sel.context);
@@ -86,19 +108,24 @@ const CreateLyricsWithAi = () => {
const rawOtherStyle = const rawOtherStyle =
typeof sel.otherStyle === "string" ? sel.otherStyle : ""; typeof sel.otherStyle === "string" ? sel.otherStyle : "";
const hasSavedOtherStyle = rawOtherStyle.trim().length > 0; const trimmedSavedOtherStyle = rawOtherStyle.trim();
const hasSavedOtherStyle = trimmedSavedOtherStyle.length > 0;
const savedStyle = const savedStyle =
typeof sel.style === "string" && sel.style.trim().length > 0 typeof sel.style === "string" && sel.style.trim().length > 0
? sel.style ? sel.style.trim()
: null; : null;
if (!otherStyle && hasSavedOtherStyle) { if (!otherStyle && hasSavedOtherStyle) {
setOtherStyle(rawOtherStyle); setOtherStyle(rawOtherStyle);
if (style !== null) { }
setStyle(null); const shouldSelectOtherStyle =
} hasSavedOtherStyle && (!savedStyle || savedStyle === OTHER_STYLE_OPTION);
} else if (!hasSavedOtherStyle && style == null && savedStyle) { const resolvedSavedStyle = shouldSelectOtherStyle
setStyle(savedStyle); ? OTHER_STYLE_OPTION
: savedStyle;
if (resolvedSavedStyle && style !== resolvedSavedStyle) {
setStyle(resolvedSavedStyle);
} else if (!resolvedSavedStyle && style !== null) {
setStyle(null);
} }
if (!audience && typeof sel.audience === "string") if (!audience && typeof sel.audience === "string")
setAudience(sel.audience); setAudience(sel.audience);
@@ -154,16 +181,21 @@ const CreateLyricsWithAi = () => {
}, [hasLyrics]); }, [hasLyrics]);
const lyricsConfig = useMemo(() => { const lyricsConfig = useMemo(() => {
const resolvedObjective = shouldUseOtherObjective
? persistedOtherObjective || undefined
: objective || undefined;
const resolvedStyle = shouldUseOtherStyle
? persistedOtherStyle || undefined
: style || undefined;
return { return {
objective: otherObjective?.trim() objective: resolvedObjective,
? otherObjective.trim()
: objective || undefined,
context: context?.trim() ? context.trim() : undefined, context: context?.trim() ? context.trim() : undefined,
emotion: emotion:
emotion?.title && emotion?.description emotion?.title && emotion?.description
? `${emotion.title} : ${emotion.description}` ? `${emotion.title} : ${emotion.description}`
: undefined, : undefined,
style: otherStyle?.trim() ? otherStyle.trim() : style || undefined, style: resolvedStyle,
audience: audience?.trim() ? audience.trim() : undefined, audience: audience?.trim() ? audience.trim() : undefined,
structure: structure:
(customStructure && (customStructure &&
@@ -174,12 +206,14 @@ const CreateLyricsWithAi = () => {
rhymes: rhymes || undefined, rhymes: rhymes || undefined,
}; };
}, [ }, [
shouldUseOtherObjective,
persistedOtherObjective,
objective, objective,
otherObjective, shouldUseOtherStyle,
persistedOtherStyle,
context, context,
emotion, emotion,
style, style,
otherStyle,
audience, audience,
parsedStructure, parsedStructure,
rhymes, rhymes,
@@ -191,9 +225,7 @@ const CreateLyricsWithAi = () => {
case 0: { case 0: {
const hasObjective = const hasObjective =
typeof objective === "string" && objective.length > 0; typeof objective === "string" && objective.length > 0;
const hasOther = const hasOther = trimmedOtherObjective.length > 0;
typeof otherObjective === "string" &&
otherObjective.trim().length > 0;
return !(hasObjective || hasOther); return !(hasObjective || hasOther);
} }
case 1: { case 1: {
@@ -209,8 +241,7 @@ const CreateLyricsWithAi = () => {
} }
case 3: { case 3: {
const hasStyle = typeof style === "string" && style.length > 0; const hasStyle = typeof style === "string" && style.length > 0;
const hasOther = const hasOther = trimmedOtherStyle.length > 0;
typeof otherStyle === "string" && otherStyle.trim().length > 0;
return !(hasStyle || hasOther); return !(hasStyle || hasOther);
} }
case 4: { case 4: {
@@ -233,11 +264,11 @@ const CreateLyricsWithAi = () => {
}, [ }, [
selectedIndex, selectedIndex,
objective, objective,
otherObjective, trimmedOtherObjective,
context, context,
emotion, emotion,
style, style,
otherStyle, trimmedOtherStyle,
audience, audience,
structure, structure,
rhymes, rhymes,
@@ -257,11 +288,11 @@ const CreateLyricsWithAi = () => {
config: { structure: chosenStructure }, config: { structure: chosenStructure },
selections: { selections: {
objective, objective,
otherObjective, otherObjective: persistedOtherObjective,
context, context,
emotion, emotion,
style, style,
otherStyle, otherStyle: persistedOtherStyle,
audience, audience,
structure, structure,
parsedStructure, parsedStructure,
@@ -433,11 +464,11 @@ const CreateLyricsWithAi = () => {
config={lyricsConfig} config={lyricsConfig}
selections={{ selections={{
objective, objective,
otherObjective, otherObjective: persistedOtherObjective,
context, context,
emotion, emotion,
style, style,
otherStyle, otherStyle: persistedOtherStyle,
audience, audience,
structure, structure,
parsedStructure, parsedStructure,
+63 -32
View File
@@ -4,6 +4,7 @@ import { responsiveHeight } from "react-native-responsive-dimensions";
import { background } from "../../assets"; import { background } from "../../assets";
import GradientButton from "../../components/GradientButton"; import GradientButton from "../../components/GradientButton";
import MusicLandHeader from "../../components/MusicLandHeader"; import MusicLandHeader from "../../components/MusicLandHeader";
import { OTHER_OBJECTIVE_OPTION, OTHER_STYLE_OPTION } from "../../data/data";
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";
@@ -42,6 +43,18 @@ const CreateLyricsWithAi = () => {
const [rhymes, setRhymes] = useState(null); const [rhymes, setRhymes] = useState(null);
const [customStructure, setCustomStructure] = useState(null); // array like ['couplet','refrain'] const [customStructure, setCustomStructure] = useState(null); // array like ['couplet','refrain']
const trimmedOtherObjective =
typeof otherObjective === "string" ? otherObjective.trim() : "";
const shouldUseOtherObjective = objective === OTHER_OBJECTIVE_OPTION;
const persistedOtherObjective = shouldUseOtherObjective
? trimmedOtherObjective
: "";
const trimmedOtherStyle =
typeof otherStyle === "string" ? otherStyle.trim() : "";
const shouldUseOtherStyle = style === OTHER_STYLE_OPTION;
const persistedOtherStyle = shouldUseOtherStyle ? trimmedOtherStyle : "";
// Pré-remplir les états depuis le projet sélectionné si disponibles // Pré-remplir les états depuis le projet sélectionné si disponibles
React.useEffect(() => { React.useEffect(() => {
if (!selectedProject) return; if (!selectedProject) return;
@@ -50,19 +63,28 @@ const CreateLyricsWithAi = () => {
const rawOtherObjective = const rawOtherObjective =
typeof sel.otherObjective === "string" ? sel.otherObjective : ""; typeof sel.otherObjective === "string" ? sel.otherObjective : "";
const hasSavedOtherObjective = rawOtherObjective.trim().length > 0; const trimmedSavedOtherObjective = rawOtherObjective.trim();
const hasSavedOtherObjective = trimmedSavedOtherObjective.length > 0;
const savedObjective = const savedObjective =
typeof sel.objective === "string" && sel.objective.trim().length > 0 typeof sel.objective === "string" && sel.objective.trim().length > 0
? sel.objective ? sel.objective.trim()
: null; : null;
if (!otherObjective && hasSavedOtherObjective) { if (!otherObjective && hasSavedOtherObjective) {
setOtherObjective(rawOtherObjective); setOtherObjective(rawOtherObjective);
if (objective !== null) { }
setObjective(null);
} const shouldSelectOtherObjective =
} else if (!hasSavedOtherObjective && objective == null && savedObjective) { hasSavedOtherObjective &&
setObjective(savedObjective); (!savedObjective || savedObjective === OTHER_OBJECTIVE_OPTION);
const resolvedSavedObjective = shouldSelectOtherObjective
? OTHER_OBJECTIVE_OPTION
: savedObjective;
if (resolvedSavedObjective && objective !== resolvedSavedObjective) {
setObjective(resolvedSavedObjective);
} else if (!resolvedSavedObjective && objective !== null) {
setObjective(null);
} }
if (!context && typeof sel.context === "string") setContext(sel.context); if (!context && typeof sel.context === "string") setContext(sel.context);
@@ -84,19 +106,24 @@ const CreateLyricsWithAi = () => {
const rawOtherStyle = const rawOtherStyle =
typeof sel.otherStyle === "string" ? sel.otherStyle : ""; typeof sel.otherStyle === "string" ? sel.otherStyle : "";
const hasSavedOtherStyle = rawOtherStyle.trim().length > 0; const trimmedSavedOtherStyle = rawOtherStyle.trim();
const hasSavedOtherStyle = trimmedSavedOtherStyle.length > 0;
const savedStyle = const savedStyle =
typeof sel.style === "string" && sel.style.trim().length > 0 typeof sel.style === "string" && sel.style.trim().length > 0
? sel.style ? sel.style.trim()
: null; : null;
if (!otherStyle && hasSavedOtherStyle) { if (!otherStyle && hasSavedOtherStyle) {
setOtherStyle(rawOtherStyle); setOtherStyle(rawOtherStyle);
if (style !== null) { }
setStyle(null); const shouldSelectOtherStyle =
} hasSavedOtherStyle && (!savedStyle || savedStyle === OTHER_STYLE_OPTION);
} else if (!hasSavedOtherStyle && style == null && savedStyle) { const resolvedSavedStyle = shouldSelectOtherStyle
setStyle(savedStyle); ? OTHER_STYLE_OPTION
: savedStyle;
if (resolvedSavedStyle && style !== resolvedSavedStyle) {
setStyle(resolvedSavedStyle);
} else if (!resolvedSavedStyle && style !== null) {
setStyle(null);
} }
if (!audience && typeof sel.audience === "string") if (!audience && typeof sel.audience === "string")
setAudience(sel.audience); setAudience(sel.audience);
@@ -159,16 +186,21 @@ const CreateLyricsWithAi = () => {
}, [hasLyrics]); }, [hasLyrics]);
const lyricsConfig = useMemo(() => { const lyricsConfig = useMemo(() => {
const resolvedObjective = shouldUseOtherObjective
? persistedOtherObjective || undefined
: objective || undefined;
const resolvedStyle = shouldUseOtherStyle
? persistedOtherStyle || undefined
: style || undefined;
return { return {
objective: otherObjective?.trim() objective: resolvedObjective,
? otherObjective.trim()
: objective || undefined,
context: context?.trim() ? context.trim() : undefined, context: context?.trim() ? context.trim() : undefined,
emotion: emotion:
emotion?.title && emotion?.description emotion?.title && emotion?.description
? `${emotion.title} : ${emotion.description}` ? `${emotion.title} : ${emotion.description}`
: undefined, : undefined,
style: otherStyle?.trim() ? otherStyle.trim() : style || undefined, style: resolvedStyle,
audience: audience?.trim() ? audience.trim() : undefined, audience: audience?.trim() ? audience.trim() : undefined,
structure: structure:
(customStructure && (customStructure &&
@@ -179,12 +211,14 @@ const CreateLyricsWithAi = () => {
rhymes: rhymes || undefined, rhymes: rhymes || undefined,
}; };
}, [ }, [
shouldUseOtherObjective,
persistedOtherObjective,
objective, objective,
otherObjective, shouldUseOtherStyle,
persistedOtherStyle,
context, context,
emotion, emotion,
style, style,
otherStyle,
audience, audience,
parsedStructure, parsedStructure,
rhymes, rhymes,
@@ -196,9 +230,7 @@ const CreateLyricsWithAi = () => {
case 0: { case 0: {
const hasObjective = const hasObjective =
typeof objective === "string" && objective.length > 0; typeof objective === "string" && objective.length > 0;
const hasOther = const hasOther = trimmedOtherObjective.length > 0;
typeof otherObjective === "string" &&
otherObjective.trim().length > 0;
return !(hasObjective || hasOther); return !(hasObjective || hasOther);
} }
case 1: { case 1: {
@@ -214,8 +246,7 @@ const CreateLyricsWithAi = () => {
} }
case 3: { case 3: {
const hasStyle = typeof style === "string" && style.length > 0; const hasStyle = typeof style === "string" && style.length > 0;
const hasOther = const hasOther = trimmedOtherStyle.length > 0;
typeof otherStyle === "string" && otherStyle.trim().length > 0;
return !(hasStyle || hasOther); return !(hasStyle || hasOther);
} }
case 4: { case 4: {
@@ -238,11 +269,11 @@ const CreateLyricsWithAi = () => {
}, [ }, [
selectedIndex, selectedIndex,
objective, objective,
otherObjective, trimmedOtherObjective,
context, context,
emotion, emotion,
style, style,
otherStyle, trimmedOtherStyle,
audience, audience,
structure, structure,
rhymes, rhymes,
@@ -262,11 +293,11 @@ const CreateLyricsWithAi = () => {
config: { structure: chosenStructure }, config: { structure: chosenStructure },
selections: { selections: {
objective, objective,
otherObjective, otherObjective: persistedOtherObjective,
context, context,
emotion, emotion,
style, style,
otherStyle, otherStyle: persistedOtherStyle,
audience, audience,
structure, structure,
parsedStructure, parsedStructure,
@@ -365,11 +396,11 @@ const CreateLyricsWithAi = () => {
config={lyricsConfig} config={lyricsConfig}
selections={{ selections={{
objective, objective,
otherObjective, otherObjective: persistedOtherObjective,
context, context,
emotion, emotion,
style, style,
otherStyle, otherStyle: persistedOtherStyle,
audience, audience,
structure, structure,
parsedStructure, parsedStructure,
+11 -4
View File
@@ -1,8 +1,8 @@
import React, { useState } from "react"; import React, { useMemo, useState } from "react";
import { StyleSheet, View } from "react-native"; import { StyleSheet, View } from "react-native";
import ItemContainer from "../../components/ItemContainer/ItemContainer"; import ItemContainer from "../../components/ItemContainer/ItemContainer";
import ListSelection from "../../components/ListSelection/ListSelection"; import ListSelection from "../../components/ListSelection/ListSelection";
import { GOALS } from "../../data/data"; import { GOALS, OTHER_OBJECTIVE_OPTION } from "../../data/data";
import { Palette } from "../../styles"; import { Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts"; import { FONT_FAMILY } from "../../styles/Fonts";
import CreateLyricsHeader from "./components/CreateLyricsHeader"; import CreateLyricsHeader from "./components/CreateLyricsHeader";
@@ -19,9 +19,16 @@ const Goals = ({
const selected = selectedProp ?? internalSelected; const selected = selectedProp ?? internalSelected;
const setSelected = setSelectedProp ?? setInternalSelected; const setSelected = setSelectedProp ?? setInternalSelected;
const goalsOptions = useMemo(() => GOALS ?? [], []);
const handleOtherObjectiveChange = (value) => { const handleOtherObjectiveChange = (value) => {
setOtherObjective?.(value); setOtherObjective?.(value);
if (value?.trim()?.length && selected != null) { const trimmed = value?.trim() ?? "";
if (trimmed.length) {
if (selected !== OTHER_OBJECTIVE_OPTION) {
setSelected(OTHER_OBJECTIVE_OPTION);
}
} else if (selected === OTHER_OBJECTIVE_OPTION) {
setSelected(null); setSelected(null);
} }
}; };
@@ -34,7 +41,7 @@ const Goals = ({
<CreateLyricsHeader title="Quel est ton objectif ?" /> <CreateLyricsHeader title="Quel est ton objectif ?" />
<ItemContainer> <ItemContainer>
<ListSelection <ListSelection
options={GOALS} options={goalsOptions}
variant="simple" variant="simple"
selected={selected} selected={selected}
setSelected={setSelected} setSelected={setSelected}
+12 -5
View File
@@ -1,7 +1,7 @@
import { View, StyleSheet } from "react-native"; import { View, StyleSheet } from "react-native";
import React, { useState } from "react"; import React, { useMemo, useState } from "react";
import CreateLyricsHeader from "./components/CreateLyricsHeader"; import CreateLyricsHeader from "./components/CreateLyricsHeader";
import { SONG_STYLE } from "../../data/data"; import { OTHER_STYLE_OPTION, SONG_STYLE } from "../../data/data";
import { Palette } from "../../styles"; import { Palette } from "../../styles";
import CustomInput from "./components/CustomInput"; import CustomInput from "./components/CustomInput";
import { FONT_FAMILY } from "../../styles/Fonts"; import { FONT_FAMILY } from "../../styles/Fonts";
@@ -18,9 +18,16 @@ const SongStyle = ({
const selected = selectedProp ?? internalSelected; const selected = selectedProp ?? internalSelected;
const setSelected = setSelectedProp ?? setInternalSelected; const setSelected = setSelectedProp ?? setInternalSelected;
const songStyleOptions = useMemo(() => SONG_STYLE ?? [], []);
const handleOtherStyleChange = (value) => { const handleOtherStyleChange = (value) => {
setOtherStyle?.(value); setOtherStyle?.(value);
if (value?.trim()?.length && selected != null) { const trimmed = value?.trim() ?? "";
if (trimmed.length) {
if (selected !== OTHER_STYLE_OPTION) {
setSelected(OTHER_STYLE_OPTION);
}
} else if (selected === OTHER_STYLE_OPTION) {
setSelected(null); setSelected(null);
} }
}; };
@@ -36,7 +43,7 @@ const SongStyle = ({
/> />
<ItemContainer> <ItemContainer>
<ListSelection <ListSelection
options={SONG_STYLE} options={songStyleOptions}
variant="titleDescription" variant="titleDescription"
selected={selected} selected={selected}
setSelected={setSelected} setSelected={setSelected}
@@ -47,7 +54,7 @@ const SongStyle = ({
</View> </View>
<CustomInput <CustomInput
label="Tu as un autre style de chanson ?" label="Tu as un autre style de chanson ?"
placeholder="Décrire lobjectif" placeholder="Décrire le style"
value={otherStyle} value={otherStyle}
setValue={handleOtherStyleChange} setValue={handleOtherStyleChange}
/> />