Files
musicland/src/screens/Writing/SongStyle.js
T
2025-11-05 11:18:43 +01:00

263 lines
7.4 KiB
JavaScript

import { Platform, Pressable, StyleSheet, Text, View } from "react-native";
import React, { useMemo, useState } from "react";
import CreateLyricsHeader from "./components/CreateLyricsHeader";
import { OTHER_STYLE_OPTION, SONG_STYLE } from "../../data/data";
import { Palette } from "../../styles";
import CustomInput from "./components/CustomInput";
import { FONT_FAMILY } from "../../styles/Fonts";
import ItemContainer from "../../components/ItemContainer/ItemContainer";
import ListSelection from "../../components/ListSelection/ListSelection";
import { BaseButton } from "../../components/Button";
import Overlay from "../../components/Overlay";
const SongStyle = ({
selected: selectedProp,
setSelected: setSelectedProp,
otherStyle,
setOtherStyle,
}) => {
const normalizedOtherStyle =
typeof otherStyle === "string" ? otherStyle : "";
const [internalSelected, setInternalSelected] = useState(null);
const [otherStyleModalVisible, setOtherStyleModalVisible] = useState(false);
const [previousSelection, setPreviousSelection] = useState(null);
const [previousOtherStyle, setPreviousOtherStyle] = useState(
normalizedOtherStyle
);
const selected = selectedProp ?? internalSelected;
const setSelectedBase = setSelectedProp ?? setInternalSelected;
const trimmedOtherStyle = normalizedOtherStyle.trim();
const hasOtherStyleValue = trimmedOtherStyle.length > 0;
const songStyleOptions = useMemo(() => SONG_STYLE ?? [], []);
const handleOtherStyleChange = (value) => {
setOtherStyle?.(value);
const trimmed = value?.trim() ?? "";
if (trimmed.length) {
if (selected !== OTHER_STYLE_OPTION) {
setSelectedBase(OTHER_STYLE_OPTION);
}
} else if (selected === OTHER_STYLE_OPTION) {
setSelectedBase(null);
setPreviousSelection(null);
}
};
const handleStyleSelect = (value) => {
if (value === OTHER_STYLE_OPTION) {
setPreviousSelection(selected ?? null);
setPreviousOtherStyle(normalizedOtherStyle);
setSelectedBase(value);
setOtherStyleModalVisible(true);
return;
}
setSelectedBase(value);
setOtherStyleModalVisible(false);
setPreviousSelection(null);
};
const handleOpenOtherStyleModal = () => {
setPreviousSelection(selected ?? null);
setPreviousOtherStyle(normalizedOtherStyle);
setOtherStyleModalVisible(true);
};
const handleCancelOtherStyle = () => {
setOtherStyleModalVisible(false);
setOtherStyle?.(previousOtherStyle);
if (selected === OTHER_STYLE_OPTION) {
setSelectedBase(previousSelection ?? null);
}
setPreviousSelection(null);
};
const handleConfirmOtherStyle = () => {
if (!hasOtherStyleValue) {
const fallback =
previousSelection && previousSelection !== OTHER_STYLE_OPTION
? previousSelection
: null;
setOtherStyle?.(previousOtherStyle);
setSelectedBase(fallback);
setOtherStyleModalVisible(false);
setPreviousSelection(null);
return;
}
if (selected !== OTHER_STYLE_OPTION) {
setSelectedBase(OTHER_STYLE_OPTION);
}
setOtherStyleModalVisible(false);
setPreviousSelection(OTHER_STYLE_OPTION);
};
return (
<>
<View style={{ flex: 1, gap: 16, marginTop: 16 }}>
<View style={{ gap: 10 }}>
<CreateLyricsHeader
title={`Quel est le style de ta chanson ?`}
subTitle="Choisis l'ambiance émotions que tu veux faire passer."
/>
<ItemContainer>
<ListSelection
options={songStyleOptions}
variant="titleDescription"
selected={selected}
setSelected={handleStyleSelect}
contentContainerStyle={styles.contentContainer}
itemContainerStyle={styles.itemContainer}
/>
</ItemContainer>
</View>
{selected === OTHER_STYLE_OPTION ? (
<View style={styles.otherStyleSummary}>
<View style={{ flex: 1, gap: 4 }}>
<Text style={styles.summaryLabel}>
Tu as un autre style de chanson ?
</Text>
<Text
style={[
styles.summaryValue,
!hasOtherStyleValue && styles.summaryPlaceholder,
]}
numberOfLines={3}
>
{hasOtherStyleValue ? trimmedOtherStyle : "Décrire le style"}
</Text>
</View>
<Pressable
style={styles.summaryButton}
onPress={handleOpenOtherStyleModal}
>
<Text style={styles.summaryButtonText}>
{hasOtherStyleValue ? "Modifier" : "Ajouter"}
</Text>
</Pressable>
</View>
) : null}
</View>
<Overlay
isVisible={otherStyleModalVisible}
setIsVisible={handleCancelOtherStyle}
>
<View style={styles.modalContent}>
<Text style={styles.modalTitle}>
Tu as un autre style de chanson ?
</Text>
<CustomInput
placeholder="Décrire le style"
value={otherStyle}
setValue={handleOtherStyleChange}
height={Platform.OS === "web" ? 160 : undefined}
/>
<View style={styles.modalActions}>
<BaseButton
type="secondary"
text="Annuler"
onPress={handleCancelOtherStyle}
containerStyle={styles.modalActionButton}
/>
<BaseButton
text="Valider"
onPress={handleConfirmOtherStyle}
containerStyle={styles.modalActionButton}
/>
</View>
</View>
</Overlay>
</>
);
};
export default SongStyle;
const styles = StyleSheet.create({
contentContainer: {
flexGrow: 1,
padding: 8,
gap: 10,
backgroundColor: "#FFFFFF00",
paddingBottom: 50,
},
itemContainer: {
borderRadius: 14,
shadowColor: "#00000040",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
itemText: {
fontSize: 16,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
textAlign: "center",
},
otherStyleSummary: {
backgroundColor: Palette.ultraLightWhite,
borderRadius: 12,
padding: 12,
flexDirection: "row",
alignItems: "flex-start",
gap: 12,
},
summaryLabel: {
fontSize: 14,
color: Palette.white,
fontFamily: FONT_FAMILY.InterMedium,
},
summaryValue: {
fontSize: 14,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
lineHeight: 20,
},
summaryPlaceholder: {
color: Palette.grayMid,
fontStyle: "italic",
},
summaryButton: {
alignSelf: "flex-start",
paddingVertical: 6,
paddingHorizontal: 12,
borderRadius: 999,
borderWidth: 1,
borderColor: Palette.white,
backgroundColor: "#FFFFFF10",
},
summaryButtonText: {
fontSize: 12,
color: Palette.white,
fontFamily: FONT_FAMILY.InterMedium,
},
modalContent: {
width: "90%",
maxWidth: 420,
padding: 20,
borderRadius: 16,
backgroundColor: Palette.darkPurple,
gap: 16,
},
modalTitle: {
fontSize: 18,
color: Palette.white,
fontFamily: FONT_FAMILY.InterSemiBold,
textAlign: "center",
},
modalActions: {
flexDirection: "row",
gap: 12,
},
modalActionButton: {
flex: 1,
},
});