minuit ticket
This commit is contained in:
@@ -89,6 +89,27 @@ const App = () => {
|
|||||||
return subscriber;
|
return subscriber;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (Platform.OS === "web") {
|
||||||
|
const s = document.createElement("script");
|
||||||
|
s.src = "https://minuit.app/embed/report-a-problem.js";
|
||||||
|
s.async = true;
|
||||||
|
s.setAttribute("data-project-id", "playbackproduction");
|
||||||
|
s.setAttribute("data-position", "right");
|
||||||
|
s.setAttribute("data-offset", "16");
|
||||||
|
s.setAttribute("data-primary-color", "#FB68A8");
|
||||||
|
s.setAttribute("data-bg-primary-color", "#0E0E12");
|
||||||
|
s.setAttribute("data-bg-secondary-color", "#1D1825");
|
||||||
|
s.setAttribute("data-text-color", "#F3F0F5");
|
||||||
|
|
||||||
|
document.body.appendChild(s);
|
||||||
|
return () => {
|
||||||
|
try {
|
||||||
|
s.remove();
|
||||||
|
} catch (_) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
const onAuthStateChanged = async (user) => {
|
const onAuthStateChanged = async (user) => {
|
||||||
if (isInitializing) {
|
if (isInitializing) {
|
||||||
setInitializing(false);
|
setInitializing(false);
|
||||||
@@ -112,7 +133,6 @@ const App = () => {
|
|||||||
if (!loaded || isInitializing) {
|
if (!loaded || isInitializing) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StatusBar style="light" />
|
<StatusBar style="light" />
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
import { Image, StyleSheet, View, Text } from "react-native";
|
||||||
|
import Animated, { useAnimatedRef } from "react-native-reanimated";
|
||||||
|
import Sortable from "react-native-sortables";
|
||||||
|
import CreateLyricsHeader from "./components/CreateLyricsHeader";
|
||||||
|
import { Palette } from "../../styles";
|
||||||
|
import { FONT_FAMILY } from "../../styles/Fonts";
|
||||||
|
import { icons } from "../../assets";
|
||||||
|
|
||||||
|
const VALID_SEGMENTS = ["couplet", "refrain"];
|
||||||
|
|
||||||
|
const sanitizeStructure = (structure = []) =>
|
||||||
|
structure
|
||||||
|
.map((segment) => `${segment}`.trim().toLowerCase())
|
||||||
|
.filter((segment) => VALID_SEGMENTS.includes(segment));
|
||||||
|
|
||||||
|
const buildItems = (structure = []) => {
|
||||||
|
const counters = { couplet: 0, refrain: 0 };
|
||||||
|
return structure.map((segment, index) => {
|
||||||
|
counters[segment] += 1;
|
||||||
|
const label = `${segment === "couplet" ? "Couplet" : "Refrain"} ${counters[segment]}`;
|
||||||
|
return {
|
||||||
|
id: `${segment}-${index}-${counters[segment]}`,
|
||||||
|
value: segment,
|
||||||
|
label,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomizeSongStructure = ({ baseStructure = [], onChange }) => {
|
||||||
|
const sanitized = useMemo(() => sanitizeStructure(baseStructure), [baseStructure]);
|
||||||
|
const [items, setItems] = useState(() => buildItems(sanitized));
|
||||||
|
const scrollRef = useAnimatedRef();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setItems((prev) => {
|
||||||
|
if (
|
||||||
|
prev.length === sanitized.length &&
|
||||||
|
prev.every((item, index) => item.value === sanitized[index])
|
||||||
|
) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
return buildItems(sanitized);
|
||||||
|
});
|
||||||
|
}, [sanitized]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onChange?.(items.map((item) => item.value));
|
||||||
|
}, [items, onChange]);
|
||||||
|
|
||||||
|
const renderItem = useCallback(({ item }) => {
|
||||||
|
return (
|
||||||
|
<View style={styles.itemContainer}>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text style={styles.rowText}>{item.label}</Text>
|
||||||
|
<Sortable.Handle>
|
||||||
|
<Image source={icons.dragDots} style={styles.handleIcon} />
|
||||||
|
</Sortable.Handle>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!items.length) {
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1, gap: 10, marginTop: 16 }}>
|
||||||
|
<CreateLyricsHeader
|
||||||
|
title="Personnalise la structure de ta chanson"
|
||||||
|
subTitle="Sélectionne une structure pour commencer"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1, gap: 10, marginTop: 16 }}>
|
||||||
|
<CreateLyricsHeader
|
||||||
|
title="Personnalise la structure de ta chanson"
|
||||||
|
subTitle="Glisse-dépose pour réorganiser"
|
||||||
|
/>
|
||||||
|
<View style={styles.listContainer}>
|
||||||
|
<Animated.ScrollView
|
||||||
|
ref={scrollRef}
|
||||||
|
contentContainerStyle={styles.scrollContent}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
>
|
||||||
|
<Sortable.Grid
|
||||||
|
columns={1}
|
||||||
|
data={items}
|
||||||
|
keyExtractor={(item) => item.id}
|
||||||
|
renderItem={renderItem}
|
||||||
|
rowGap={12}
|
||||||
|
customHandle
|
||||||
|
scrollableRef={scrollRef}
|
||||||
|
onDragEnd={({ data: nextItems }) => {
|
||||||
|
const nextOrder = nextItems.map((item) => item.value);
|
||||||
|
setItems(buildItems(nextOrder));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Animated.ScrollView>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CustomizeSongStructure;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
listContainer: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
scrollContent: {
|
||||||
|
paddingVertical: 4,
|
||||||
|
paddingBottom: 24,
|
||||||
|
},
|
||||||
|
itemContainer: {
|
||||||
|
height: 54,
|
||||||
|
borderRadius: 14,
|
||||||
|
backgroundColor: Palette.glass,
|
||||||
|
shadowColor: "#00000040",
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
shadowOpacity: 0.25,
|
||||||
|
shadowRadius: 3.84,
|
||||||
|
elevation: 5,
|
||||||
|
overflow: "hidden",
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flex: 1,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
},
|
||||||
|
rowText: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: Palette.white,
|
||||||
|
fontFamily: FONT_FAMILY.InterRegular,
|
||||||
|
},
|
||||||
|
handleIcon: {
|
||||||
|
width: 22,
|
||||||
|
height: 22,
|
||||||
|
tintColor: Palette.white,
|
||||||
|
cursor: "grab",
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import { View, Image, StyleSheet } from "react-native";
|
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Page from "../../layouts/Page";
|
import { Image, StyleSheet, View } from "react-native";
|
||||||
import { ai } from "../../assets";
|
|
||||||
import GradientButton from "../../components/GradientButton";
|
|
||||||
import { gutters } from "../../styles";
|
|
||||||
import BorderGradientButton from "../../components/BorderGradientButton";
|
|
||||||
import MusicLandHeader from "../../components/MusicLandHeader";
|
|
||||||
import { goBack, navigate } from "../../navigation/NavigationService";
|
|
||||||
import { Routes } from "../../navigation";
|
|
||||||
import { useUserData } from "../../providers/UserDataProvider";
|
|
||||||
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
|
||||||
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
|
import { ai } from "../../assets";
|
||||||
|
import BorderGradientButton from "../../components/BorderGradientButton";
|
||||||
|
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo.web";
|
||||||
|
import GradientButton from "../../components/GradientButton";
|
||||||
|
import MusicLandHeader from "../../components/MusicLandHeader";
|
||||||
|
import Page from "../../layouts/Page";
|
||||||
|
import { Routes } from "../../navigation";
|
||||||
|
import { goBack, navigate } from "../../navigation/NavigationService";
|
||||||
|
import { useUserData } from "../../providers/UserDataProvider";
|
||||||
|
import { gutters } from "../../styles";
|
||||||
|
|
||||||
const WritingLyrics = () => {
|
const WritingLyrics = () => {
|
||||||
const { createNewProject, selectedProject, updateProjectData } =
|
const { createNewProject, selectedProject, updateProjectData } =
|
||||||
|
|||||||
Reference in New Issue
Block a user