end of home

This commit is contained in:
Thomas Demirdjian
2025-10-01 10:49:03 +02:00
parent 4097143559
commit 167e62fcfc
18 changed files with 928 additions and 558 deletions
@@ -0,0 +1,148 @@
import React, { useCallback, useEffect, useMemo, useRef } from "react";
import { FlatList, StyleSheet, View, useWindowDimensions } from "react-native";
import PersonaCard from "../cards/PersonaCard/PersonaCard";
import { ai } from "../../assets";
import { getCreationStageStates } from "../../utils/projectStages";
const STAGE_CARD_CONTENT = [
{
key: "songwriter",
title: "Nathalie",
description: "Lets write lyrics together !",
image: ai.nathalie,
},
{
key: "beatmaker",
title: "Theo",
description: "Come back, when you'll have lyrics!",
image: ai.theo,
},
{
key: "designer",
title: "Bena",
description: "Come back when you want to generate cover!",
image: ai.bena,
},
{
key: "director",
title: "John",
description: "Come back when your audio is ready!",
image: ai.john,
},
];
const FeatureCarousel = ({
style,
selectedProject,
activeIndex,
onActiveIndexChange,
}) => {
const stageStates = useMemo(
() => getCreationStageStates(selectedProject),
[selectedProject],
);
const carouselItems = useMemo(
() =>
STAGE_CARD_CONTENT.map((item, index) => ({
...item,
isLocked: stageStates[index]?.isLocked ?? true,
})),
[stageStates],
);
const { height: windowHeight } = useWindowDimensions();
const itemHeight = Math.max(windowHeight, 1);
const listRef = useRef(null);
const keyExtractor = useCallback((item) => item.key, []);
const renderItem = useCallback(
({ item }) => <PersonaCard item={item} isLock={item.isLocked} />,
[],
);
const getItemLayout = useCallback(
(_data, index) => ({
length: itemHeight,
offset: itemHeight * index,
index,
}),
[itemHeight],
);
const viewabilityConfig = useRef({ viewAreaCoveragePercentThreshold: 60 });
const handleViewableItemsChanged = useCallback(
({ viewableItems }) => {
if (!onActiveIndexChange) {
return;
}
const firstVisible = viewableItems?.[0];
if (firstVisible?.index != null) {
onActiveIndexChange(firstVisible.index);
}
},
[onActiveIndexChange],
);
useEffect(() => {
if (
listRef.current == null ||
typeof activeIndex !== "number" ||
activeIndex < 0 ||
activeIndex >= carouselItems.length
) {
return;
}
try {
listRef.current.scrollToIndex({ index: activeIndex, animated: true });
} catch (_error) {
// Ignore scroll errors when list is not ready yet.
}
}, [activeIndex, carouselItems.length]);
return (
<View style={[styles.container, style]}>
<FlatList
ref={listRef}
data={carouselItems}
keyExtractor={keyExtractor}
renderItem={renderItem}
onViewableItemsChanged={handleViewableItemsChanged}
viewabilityConfig={viewabilityConfig.current}
getItemLayout={getItemLayout}
showsVerticalScrollIndicator={false}
pagingEnabled
initialNumToRender={1}
maxToRenderPerBatch={2}
windowSize={3}
scrollEventThrottle={16}
snapToAlignment="start"
snapToInterval={itemHeight}
decelerationRate="fast"
style={styles.list}
contentContainerStyle={styles.listContent}
/>
</View>
);
};
export default FeatureCarousel;
const styles = StyleSheet.create({
container: {
flex: 1,
width: "100%",
},
list: {
flex: 1,
},
listContent: {
flexGrow: 1,
},
cardRight: {
flexDirection: "row-reverse",
alignItems: "center",
},
});