diff --git a/functions/package-lock.json b/functions/package-lock.json
index 33c787a..0e8567f 100644
--- a/functions/package-lock.json
+++ b/functions/package-lock.json
@@ -2734,9 +2734,9 @@
"license": "MIT"
},
"node_modules/axios": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
- "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
+ "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
diff --git a/src/assets/UI/homeBGWeb.png b/src/assets/UI/homeBGWeb.png
new file mode 100644
index 0000000..569c477
Binary files /dev/null and b/src/assets/UI/homeBGWeb.png differ
diff --git a/src/assets/index.js b/src/assets/index.js
index 119c57d..b56e3b8 100644
--- a/src/assets/index.js
+++ b/src/assets/index.js
@@ -111,6 +111,7 @@ import placeholder2 from "./UI/placeholder2.jpg";
import placeholder3 from "./UI/placeholder3.png";
import placeholder4 from "./UI/placeholder4.jpg";
import profile from "./UI/profile.jpg";
+import { Platform } from "react-native";
export const tabs = {
home,
@@ -221,6 +222,7 @@ export const background = {
profileBG,
hitParadeBG,
homeBG,
+ homeBGWeb: require("./UI/homeBGWeb.png"),
};
export const ai = {
@@ -231,7 +233,10 @@ export const ai = {
};
export const videos = {
- test: require("./video/testVideo.mp4"),
+ test:
+ Platform.OS === "web"
+ ? require("./video/testVideoWeb.mp4")
+ : require("./video/testVideo.mp4"),
};
export const img = {
diff --git a/src/assets/video/testVideoWeb.mp4 b/src/assets/video/testVideoWeb.mp4
new file mode 100644
index 0000000..9c913ee
Binary files /dev/null and b/src/assets/video/testVideoWeb.mp4 differ
diff --git a/src/components/FullscreenIntroVideo.js b/src/components/FullscreenIntroVideo.native.js
similarity index 100%
rename from src/components/FullscreenIntroVideo.js
rename to src/components/FullscreenIntroVideo.native.js
diff --git a/src/components/FullscreenIntroVideo.web.js b/src/components/FullscreenIntroVideo.web.js
new file mode 100644
index 0000000..ba7417c
--- /dev/null
+++ b/src/components/FullscreenIntroVideo.web.js
@@ -0,0 +1,172 @@
+import React, { useEffect, useMemo, useRef, useState } from "react";
+import { Pressable, Text, View } from "react-native";
+import { Asset } from "expo-asset";
+
+import { videos } from "../assets";
+
+const overlayStyle = {
+ position: "fixed",
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0,
+ backgroundColor: "black",
+ justifyContent: "center",
+ alignItems: "center",
+ zIndex: 9999,
+};
+
+const videoStyle = {
+ position: "absolute",
+ top: 0,
+ left: 0,
+ width: "100%",
+ height: "100%",
+ objectFit: "cover",
+};
+
+const closeButtonStyle = {
+ position: "absolute",
+ top: 50,
+ right: 20,
+ backgroundColor: "#00000080",
+ paddingVertical: 10,
+ paddingHorizontal: 14,
+ borderRadius: 20,
+ borderWidth: 1,
+ borderColor: "#FFFFFF55",
+ cursor: "pointer",
+};
+
+const closeTextStyle = {
+ color: "#FFF",
+ fontSize: 14,
+};
+
+const resolveModuleUri = async (module) => {
+ const asset = Asset.fromModule(module);
+
+ if (!asset.localUri && !asset.uri) {
+ await asset.downloadAsync();
+ }
+
+ return asset.localUri ?? asset.uri ?? null;
+};
+
+const FullscreenIntroVideo = ({ url, visible = true, onClose }) => {
+ const videoRef = useRef(null);
+ const [uri, setUri] = useState(null);
+ const [muted, setMuted] = useState(false);
+
+ const resolvedSource = useMemo(() => url ?? videos.test, [url]);
+
+ useEffect(() => {
+ let isMounted = true;
+
+ const assignUri = (nextUri) => {
+ if (isMounted) {
+ setMuted(false);
+ setUri(nextUri);
+ }
+ };
+
+ if (typeof resolvedSource === "string") {
+ assignUri(resolvedSource);
+ return () => {
+ isMounted = false;
+ };
+ }
+
+ const load = async () => {
+ try {
+ const nextUri = await resolveModuleUri(resolvedSource);
+ assignUri(nextUri);
+ } catch {
+ if (isMounted) {
+ setUri(null);
+ }
+ }
+ };
+
+ load();
+
+ return () => {
+ isMounted = false;
+ };
+ }, [resolvedSource]);
+
+ useEffect(() => {
+ if (!visible) {
+ return undefined;
+ }
+
+ const video = videoRef.current;
+
+ if (!video || !uri) {
+ return undefined;
+ }
+
+ const handleEnded = () => onClose?.();
+ video.addEventListener("ended", handleEnded);
+
+ video.currentTime = 0;
+ const attemptPlay = () => {
+ const result = video.play();
+
+ if (result?.catch) {
+ result.catch((error) => {
+ if (error?.name === "NotAllowedError" && !muted) {
+ setMuted(true);
+ }
+ });
+ }
+ };
+
+ attemptPlay();
+
+ return () => {
+ video.pause();
+ video.removeEventListener("ended", handleEnded);
+ };
+ }, [muted, onClose, uri, visible]);
+
+ useEffect(() => {
+ const video = videoRef.current;
+
+ if (!video || !muted) {
+ return;
+ }
+
+ const result = video.play();
+
+ if (result?.catch) {
+ result.catch(() => {});
+ }
+ }, [muted]);
+
+ if (!visible) {
+ return null;
+ }
+
+ return (
+
+ {uri ? (
+
+ ) : null}
+ onClose?.()} style={closeButtonStyle}>
+ Passer la vidéo
+
+
+ );
+};
+
+export default FullscreenIntroVideo;
diff --git a/src/components/GradientButton.js b/src/components/GradientButton.js
index dbd5545..aefc304 100644
--- a/src/components/GradientButton.js
+++ b/src/components/GradientButton.js
@@ -1,4 +1,4 @@
-import { View, Text, Pressable, Image } from "react-native";
+import { View, Text, Pressable, Image, FlatList } from "react-native";
import React from "react";
import { LinearGradient } from "./LinearGradient/LinearGradient";
import { Palette, Style } from "../styles";
@@ -15,7 +15,11 @@ const GradientButton = ({
disabled = false,
}) => {
return (
-
+
{
const [isFocused, setIsFocused] = useState(false);
const [showPassword, setShowPassword] = useState(false);
- const [showCountryPicker, setShowCountryPicker] = useState(false);
- const isDefaultLayout = layout === 'default';
+ const isDefaultLayout = layout === "default";
const mainColor =
- theme === 'radioactiv' ? Palette.radioactivGreen : Palette.primary;
+ theme === "radioactiv" ? Palette.radioactivGreen : Palette.primary;
const isRoundedRectangle =
- ['textarea', 'coinAmount'].includes(type) || layout === 'default';
+ ["textarea", "coinAmount"].includes(type) || layout === "default";
- const inputAccessoryViewID = 'uniqueID';
+ const inputAccessoryViewID = "uniqueID";
const { places } = usePlaceApi({
- query: type === 'autoCompleteAddress' ? value : '',
+ query: type === "autoCompleteAddress" ? value : "",
apiKey: GOOGLE_API_KEY, // Your Google API Key
- queryFields: 'formatted_address,geometry,name,address_components',
- queryCountries: ['fr'],
- language: 'fr-FR',
+ queryFields: "formatted_address,geometry,name,address_components",
+ queryCountries: ["fr"],
+ language: "fr-FR",
minChars: 2,
});
@@ -72,23 +71,25 @@ const Input = ({
<>
+ }}
+ >
{label?.length > 0 && (
+ }}
+ >
{label}
)}
- {type === 'search' ? (
+ width: "100%",
+ }}
+ >
+ {type === "search" ? (
) : null}
- {/* {type === "countryPicker" ? (
- {
- console.log(country);
- setValue(country.cca2);
- }}
- visible={showCountryPicker}
- theme={{
- ...DARK_THEME,
- primaryColor: Palette.primary,
- backgroundColor: Palette.darkPurple,
- ...fontTypeList.default,
- }}
- closeButtonImage={icons.arrowRight}
- closeButtonStyle={[Style.mirrorHorizontal]}
- withEmoji={true}
- withFilter={true}
- withAlphaFilter={false}
- withCountryNameButton={true}
- containerButtonStyle={{ padding: 0, margin: 0 }}
- translation="fra"
- placeholder={"Sélectionnez un pays"}
- countryName={value}
- preferredCountries={["FR", "BE", "CH", "LU", "CA", "US", "GB"]}
- filterProps={{
- placeholder: "Rechercher un pays",
- style: {
- ...Fonts({}),
- },
- }}
- />
- ) : */}
- {type !== 'countryPicker' && (
+ {type !== "countryPicker" && (
setIsFocused(true)}
onBlur={() => setIsFocused(false)}
style={{
- width: '100%',
+ width: "100%",
...(isRoundedRectangle
? {
- height: '100%',
+ height: "100%",
flex: 1,
- textAlignVertical: type === 'textarea' ? 'top' : 'center',
+ textAlignVertical: type === "textarea" ? "top" : "center",
}
- : { textAlign: 'center' }),
+ : { textAlign: "center" }),
fontSize: 14,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
...(isWeb
? {
- lineHeight: 'auto',
+ lineHeight: "auto",
}
: {}),
...textInputStyle,
}}
- {...(type === 'password'
+ {...(type === "password"
? {
secureTextEntry: !showPassword,
- autoCapitalize: 'none',
- autoCompleteType: 'password',
- textContentType: 'password',
+ autoCapitalize: "none",
+ autoCompleteType: "password",
+ textContentType: "password",
}
: {})}
- {...(type === 'email'
+ {...(type === "email"
? {
- keyboardType: 'email-address',
- autoCapitalize: 'none',
- autoCompleteType: 'email',
- textContentType: 'emailAddress',
+ keyboardType: "email-address",
+ autoCapitalize: "none",
+ autoCompleteType: "email",
+ textContentType: "emailAddress",
}
: {})}
- keyboardType={isNumeric ? 'numeric' : 'default'}
- keyboardAppearance='dark'
+ keyboardType={isNumeric ? "numeric" : "default"}
+ keyboardAppearance="dark"
inputAccessoryViewID={inputAccessoryViewID}
{...textInputProps}
/>
)}
- {type === 'password' ? (
+ {type === "password" ? (
setShowPassword(!showPassword)}>
- ) : type === 'coinAmount' ? (
+ ) : type === "coinAmount" ? (
) : null}
- {type === 'autoCompleteAddress' &&
+ {type === "autoCompleteAddress" &&
places?.[0]?.description &&
places?.[0]?.description !== value &&
places.map((place, index) => (
@@ -247,32 +216,36 @@ const Input = ({
style={{
...Style.containerSpaceBetween,
marginBottom: index !== places.length - 1 ? gutters / 2 : 0,
- }}>
+ }}
+ >
- {place?.description || '-'}
+ }}
+ >
+ {place?.description || "-"}
))}
- {(type === 'textarea' || isNumeric) && !isWeb && (
+ {(type === "textarea" || isNumeric) && !isWeb && (
Keyboard.dismiss()}
style={{
...Style.containerRow,
- justifyContent: 'flex-end',
+ justifyContent: "flex-end",
backgroundColor: Palette.transparentPrimary,
padding: gutters,
paddingVertical: gutters / 2,
- }}>
+ }}
+ >
+ }}
+ >
Fermer
diff --git a/src/components/ItemContainer/ItemContainer.js b/src/components/ItemContainer/ItemContainer.js
index 15b77c0..4a1066c 100644
--- a/src/components/ItemContainer/ItemContainer.js
+++ b/src/components/ItemContainer/ItemContainer.js
@@ -1,10 +1,9 @@
-import { View, Text, StyleSheet, Platform } from 'react-native';
-import React from 'react';
-import BorderGradient from '../BorderGradient/BorderGradient';
-import { BlurView } from 'expo-blur';
-import { responsiveHeight } from 'react-native-responsive-dimensions';
-import { useKeyboard } from '@react-native-community/hooks';
-import { isWeb } from '../../hooks/useLayoutType';
+import { View, StyleSheet, Platform } from "react-native";
+import React from "react";
+import BorderGradient from "../BorderGradient/BorderGradient";
+import { BlurView } from "expo-blur";
+import { responsiveHeight } from "react-native-responsive-dimensions";
+import { useKeyboard } from "@react-native-community/hooks";
const ItemContainer = ({
height = responsiveHeight(40),
@@ -18,7 +17,7 @@ const ItemContainer = ({
return (
+ }}
+ >
{children}
@@ -55,7 +56,7 @@ const styles = StyleSheet.create({
borderGradientStyle: {
borderWidth: 1,
borderRadius: 20,
- shadowColor: '#000',
+ shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
@@ -67,7 +68,7 @@ const styles = StyleSheet.create({
blurContainer: {
flex: 1,
borderRadius: 20,
- overflow: 'hidden',
+ overflow: "hidden",
zIndex: 1,
},
});
diff --git a/src/components/ItemContainer/ItemContainer.web.js b/src/components/ItemContainer/ItemContainer.web.js
index ac29d31..e818e0c 100644
--- a/src/components/ItemContainer/ItemContainer.web.js
+++ b/src/components/ItemContainer/ItemContainer.web.js
@@ -1,4 +1,4 @@
-import { View, Text, StyleSheet, Platform } from "react-native";
+import { View, StyleSheet } from "react-native";
import React, { useState } from "react";
import BorderGradient from "../BorderGradient/BorderGradient";
import { responsiveHeight } from "react-native-responsive-dimensions";
@@ -46,7 +46,7 @@ const ItemContainer = ({
}}
>
{children}
diff --git a/src/components/ProjectDropDown/ProjectDropDown.js b/src/components/ProjectDropDown/ProjectDropDown.js
new file mode 100644
index 0000000..a8c4f3a
--- /dev/null
+++ b/src/components/ProjectDropDown/ProjectDropDown.js
@@ -0,0 +1,375 @@
+import React, { useEffect, useMemo, useRef, useState } from "react";
+import {
+ FlatList,
+ Image,
+ Pressable,
+ StyleSheet,
+ Text,
+ View,
+} from "react-native";
+import { BlurView } from "expo-blur";
+import { icons, img } from "../../assets";
+import { Palette } from "../../styles";
+import { FONT_FAMILY } from "../../styles/Fonts";
+import GradientButton from "../GradientButton";
+
+const BUTTON_BLUR_INTENSITY = 20;
+const ROW_BLUR_INTENSITY = 5;
+const ROW_BLUR_SELECTED_INTENSITY = 45;
+
+const defaultFormatDate = (timestamp) => {
+ try {
+ const value = timestamp?.toDate ? timestamp.toDate() : timestamp;
+ const date = value ? new Date(value) : null;
+ if (!date || Number.isNaN(date.getTime())) {
+ return "";
+ }
+ const day = date.getDate().toString().padStart(2, "0");
+ const month = (date.getMonth() + 1).toString().padStart(2, "0");
+ return `${day}/${month}`;
+ } catch (error) {
+ console.warn("ProjectDropDown: unable to format date", error);
+ return "";
+ }
+};
+
+const ProjectDropDown = ({
+ style,
+ projects = [],
+ selectedProject,
+ onSelectProject,
+ onModifyProject,
+ onCreateProject,
+ formatDate = defaultFormatDate,
+}) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [triggerLayout, setTriggerLayout] = useState(null);
+
+ const normalizedProjects = Array.isArray(projects) ? projects : [];
+ const isDisabled = normalizedProjects.length === 0;
+
+ const currentProject = selectedProject?.id
+ ? selectedProject
+ : normalizedProjects[0] || null;
+
+ const dropdownProjects = currentProject
+ ? normalizedProjects.filter((project) => {
+ if (!project) return false;
+ if (currentProject.id && project.id) {
+ return project.id !== currentProject.id;
+ }
+ return project !== currentProject;
+ })
+ : normalizedProjects;
+
+ const toggleDropdown = () => {
+ if (isDisabled) {
+ return;
+ }
+ setIsOpen((prev) => !prev);
+ };
+
+ const closeDropdown = () => setIsOpen(false);
+
+ const handleSelect = (project) => {
+ if (!project?.id) return;
+ onSelectProject?.(project);
+ closeDropdown();
+ };
+
+ const handleModify = (project, topPosition) => {
+ if (!project?.id) return;
+ onModifyProject?.(project, topPosition);
+ };
+
+ const handleCreate = () => {
+ onCreateProject?.();
+ closeDropdown();
+ };
+
+ const dropdownWidth = useMemo(
+ () => triggerLayout?.width || 0,
+ [triggerLayout],
+ );
+
+ return (
+
+ {isOpen ? (
+
+ ) : null}
+
+ setTriggerLayout(event.nativeEvent.layout)}
+ >
+
+
+
+
+ {isOpen && (
+
+
+
+
+
+ project?.id || project?.title || `project-${index}`
+ }
+ ItemSeparatorComponent={() => }
+ renderItem={({ item: project }) => (
+
+ )}
+ showsVerticalScrollIndicator={false}
+ contentContainerStyle={styles.dropdownListContent}
+ style={styles.dropdownList}
+ />
+
+
+
+ )}
+
+
+ );
+};
+
+export default ProjectDropDown;
+
+const ProjectRow = ({
+ project,
+ formatDate,
+ isSelected,
+ onSelect,
+ onModify,
+ isTitle = false,
+ isOpen,
+}) => {
+ const rowRef = useRef(null);
+ const [layout, setLayout] = useState(null);
+ const [menuPos, setMenuPos] = useState(0);
+
+ useEffect(() => {
+ if (!layout) return;
+ const top = (layout?.y || 0) + 45;
+ setMenuPos(top);
+ }, [layout]);
+
+ const onPressMenu = () => {
+ if (!project?.id) return;
+
+ if (rowRef?.current?.measureInWindow) {
+ try {
+ rowRef.current.measureInWindow((x, y) => {
+ const top = (y || 0) + 45;
+ setMenuPos(top);
+ onModify?.(project, top);
+ });
+ return;
+ } catch (error) {
+ // Fallback to layout-derived position
+ }
+ }
+
+ onModify?.(project, menuPos);
+ };
+ const coverUri =
+ project?.coverUrl ||
+ project?.coverUri ||
+ (typeof project?.cover === "string" ? project.cover : project?.cover?.uri);
+ const title = project?.title || "Sans titre";
+ const formattedDate = formatDate(project?.updatedAt || project?.createdAt);
+
+ return (
+ onSelect(project)}
+ onLayout={(event) => setLayout(event.nativeEvent.layout)}
+ style={styles.projectRowPressable}
+ >
+
+
+
+
+ {title}
+
+
+ {formattedDate ? `Modifié le ${formattedDate}` : "MusicLand"}
+
+
+ {isTitle ? (
+
+ ) : (
+ {
+ event.stopPropagation?.();
+ onPressMenu();
+ }}
+ >
+
+
+ )}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ maxWidth: 450,
+ position: "relative",
+ },
+ dropdownBlur: {
+ borderRadius: 15,
+ padding: 8,
+ position: "relative",
+ },
+ dropdownBlurDisabled: {
+ opacity: 0.6,
+ },
+ dropdownBlurHidden: {
+ opacity: 0,
+ pointerEvents: "none",
+ },
+ triggerWrapper: {
+ position: "relative",
+ zIndex: 3,
+ },
+ dropdownOverlayBlur: {
+ position: "absolute",
+ top: 0,
+ left: 0,
+ borderRadius: 16,
+ paddingHorizontal: 8,
+ paddingVertical: 8,
+ gap: 9,
+ maxHeight: 400,
+ zIndex: 4,
+ elevation: 4,
+ },
+ dropdownOverlayContent: {
+ maxHeight: 260,
+ width: "100%",
+ gap: 12,
+ },
+ dropdownList: {
+ maxHeight: 220,
+ width: "100%",
+ },
+ dropdownListContent: {
+ paddingBottom: 4,
+ },
+ createButtonContainer: {
+ width: 200,
+ alignSelf: "center",
+ },
+ chevron: {
+ width: 18,
+ height: 18,
+ tintColor: Palette.white,
+ transform: [{ rotate: "0deg" }],
+ },
+ chevronOpen: {
+ transform: [{ rotate: "180deg" }],
+ },
+ backdrop: {
+ ...StyleSheet.absoluteFillObject,
+ zIndex: 1,
+ backgroundColor: "transparent",
+ },
+ projectRowPressable: {
+ flexDirection: "row",
+ alignItems: "center",
+ gap: 5,
+ width: "100%",
+ },
+ projectInfo: {
+ flex: 1,
+ flexDirection: "row",
+ alignItems: "center",
+ paddingHorizontal: 18,
+ paddingVertical: 12,
+ borderRadius: 10,
+ },
+ projectImage: {
+ width: 60,
+ height: 60,
+ borderRadius: 8,
+ },
+ projectTexts: {
+ flex: 1,
+ gap: 4,
+ },
+ projectTitle: {
+ fontSize: 15,
+ color: Palette.white,
+ fontFamily: FONT_FAMILY.InterSemiBold,
+ },
+ projectSubtitle: {
+ fontSize: 13,
+ color: "rgba(255, 255, 255, 0.7)",
+ fontFamily: FONT_FAMILY.InterRegular,
+ },
+ moreIcon: {
+ width: 18,
+ height: 18,
+ tintColor: Palette.white,
+ transform: [{ rotate: "90deg" }],
+ },
+});
diff --git a/src/components/ShareBtnWeb.js b/src/components/ShareBtnWeb.js
new file mode 100644
index 0000000..365d1ff
--- /dev/null
+++ b/src/components/ShareBtnWeb.js
@@ -0,0 +1,68 @@
+import React from "react";
+import { Alert, Pressable, Platform, Text } from "react-native";
+import { BlurView } from "expo-blur";
+import { Palette } from "../styles";
+import { FONT_FAMILY } from "../styles/Fonts";
+import { icons } from "../assets";
+import { Image } from "expo-image";
+
+export default function ShareBtnWeb({ style }) {
+ const handleShare = () => {
+ const shareUrl =
+ typeof window !== "undefined" ? window.location.href : undefined;
+ if (typeof navigator !== "undefined" && navigator.share) {
+ navigator
+ .share({
+ title: "MusicLand",
+ text: "Découvre mon expérience sur MusicLand",
+ ...(shareUrl ? { url: shareUrl } : {}),
+ })
+ .catch(() => {
+ Alert.alert("Partage", "Le partage a été annulé.");
+ });
+ return;
+ }
+ Alert.alert("Partage", "Fonctionnalité disponible prochainement.");
+ };
+
+ return (
+
+
+
+ Partager l'expérience
+
+
+
+
+ );
+}
diff --git a/src/layouts/Page.js b/src/layouts/Page.js
index 00d29e6..0d94adc 100644
--- a/src/layouts/Page.js
+++ b/src/layouts/Page.js
@@ -1,19 +1,18 @@
/* eslint-disable react/display-name */
-import { Image, View } from "react-native";
+import { Alert, Image, Pressable, Text, View, Platform } from "react-native";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import { SafeAreaView } from "react-native-safe-area-context";
-import React, { setGlobal, useEffect, useState } from "reactn";
-
+import React, { setGlobal, useEffect } from "reactn";
import { responsiveHeight } from "../actions/responsiveSizes.js";
-
-import { gutters } from "../styles";
-
+import { gutters, Palette } from "../styles";
import BaseHeader from "../components/BaseHeader";
import NavigateHeader from "../components/NavigateHeader";
-
-import { background } from "../assets/index.js";
+import { background, icons } from "../assets";
import { isDesktop, isWeb } from "../hooks/useLayoutType.js";
import { useUserData } from "../providers/UserDataProvider.js";
+import { BlurView } from "expo-blur";
+import { FONT_FAMILY } from "../styles/Fonts";
+import ShareBtnWeb from "../components/ShareBtnWeb";
export default ({
children,
@@ -37,21 +36,15 @@ export default ({
backgroundImg = background.writingBG,
headerTitleStyle = {},
hideBackButton = false,
+ shareBtn = false,
}) => {
const { currentUID } = useUserData();
- const [scrollPosition, setScrollPosition] = useState(0);
-
const PageContainer =
containerType === "SAFE_AREA_VIEW" ? SafeAreaView : View;
const ContentContainer = scrollEnabled ? KeyboardAwareScrollView : View;
- const handleScroll = (event) => {
- const position = event.nativeEvent.contentOffset.y;
- setScrollPosition(position);
- };
-
// On web, push the background image to a global so AppLayout can render
// a full-screen background behind the phone frame. We avoid rendering
// the per-screen background inside the phone on web to prevent duplication.
@@ -104,7 +97,6 @@ export default ({
style={{ flex: 1, ...contentContainerStyle }}
{...(scrollEnabled
? {
- onScroll: handleScroll,
scrollEventThrottle: 80,
showsVerticalScrollIndicator: false,
contentContainerStyle: { paddingBottom: responsiveHeight(55) },
@@ -117,6 +109,9 @@ export default ({
{bottomStickyContent?.()}
+ {shareBtn && (
+
+ )}
>
);
};
diff --git a/src/navigation/HomeStack.js b/src/navigation/HomeStack.js
index 71b82cb..cbf05b5 100644
--- a/src/navigation/HomeStack.js
+++ b/src/navigation/HomeStack.js
@@ -5,8 +5,8 @@ import { createStackNavigator } from "@react-navigation/stack";
import { Palette } from "../styles";
import { Routes } from "./Routes";
-import Home from "../screens/Home";
import CreateSongs from "../screens/CreateSongs";
+import Home from "../screens/Home/Home";
const isWeb = Platform.OS === "web";
@@ -46,7 +46,7 @@ export default function HomeStackScreen() {
component={Home}
options={{ headerShown: false }}
/>
- {
useEffect(() => {
const handleDeepLink = async (event) => {
- console.log("event", event);
+ // console.log("event", event);
const { path = "", queryParams } = Linking.parse(event.url);
- console.log("path", path);
- console.log("queryParams", queryParams);
+ // console.log("path", path);
+ // console.log("queryParams", queryParams);
const appSchemeURL = `${
appJson.expo.scheme
@@ -66,7 +64,7 @@ const UniversalLinkProvider = ({ children }) => {
const initDeepLinkHandling = async () => {
const initialUrl = await Linking.getInitialURL();
if (initialUrl) {
- console.log("Initial URL:", initialUrl);
+ // console.log("Initial URL:", initialUrl);
handleDeepLink({ url: initialUrl });
}
@@ -82,14 +80,14 @@ const UniversalLinkProvider = ({ children }) => {
useEffect(() => {
if (tempTaskData && currentUID && isFullyLoaded) {
- console.log("try to navigate to task");
+ // console.log("try to navigate to task");
navigateToTask(tempTaskData);
setTempTaskData(null);
}
}, [tempTaskData, currentUID, isFullyLoaded]);
const handleParams = (path) => {
- console.log("path", path);
+ // console.log("path", path);
cleanURL();
};
@@ -98,7 +96,7 @@ const UniversalLinkProvider = ({ children }) => {
if (isWeb) {
const url = new URL(window.location);
- console.log(url);
+ // console.log(url);
url.search = "";
window.history.replaceState({}, document.title, url.origin.toString());
diff --git a/src/providers/UserDataProvider.js b/src/providers/UserDataProvider.js
index b3ac8c2..5ad6957 100644
--- a/src/providers/UserDataProvider.js
+++ b/src/providers/UserDataProvider.js
@@ -3,7 +3,7 @@ import { useDataFromRef } from "react-native-minuit/src/hooks";
import useMinuit from "react-native-minuit/src/hooks/useMinuit";
import { createContext, useContext, useGlobal } from "reactn";
-import { useState } from "react";
+import { useCallback, useEffect, useState } from "react";
import { checkIfEmailIsValid } from "../actions/signupActions";
import firebase, {
arrayRemove,
@@ -104,11 +104,49 @@ export default ({ children }) => {
refreshArray: [selectedProjectId],
});
- const resetSelectedProject = () => {
- setSelectedProjectId(null);
- setSelectedProject(null);
- };
- const selectProject = (projectId) => setSelectedProjectId(projectId || null);
+ const persistSelectedProjectId = useCallback(
+ async (projectId) => {
+ if (!currentUID) return;
+ try {
+ await usersRef.doc(currentUID).set(
+ {
+ selectedProjectId: projectId || null,
+ },
+ { merge: true },
+ );
+ } catch (error) {
+ console.log(
+ "UserDataProvider: unable to persist selectedProjectId",
+ error?.message || error,
+ );
+ }
+ },
+ [currentUID],
+ );
+
+ const selectProject = useCallback(
+ (projectId) => {
+ const safeId = projectId || null;
+ setSelectedProjectId(safeId);
+ if (!safeId) {
+ setSelectedProject(null);
+ }
+
+ if (currentUID) {
+ persistSelectedProjectId(safeId).catch((error) => {
+ console.log(
+ "UserDataProvider: persist selectedProjectId failed",
+ error?.message || error,
+ );
+ });
+ }
+ },
+ [currentUID, persistSelectedProjectId, setSelectedProject],
+ );
+
+ const resetSelectedProject = useCallback(() => {
+ selectProject(null);
+ }, [selectProject]);
// Ancienne variante de création de projet supprimée pour éviter les doublons.
@@ -139,7 +177,7 @@ export default ({ children }) => {
updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
};
const { id } = await projectsRef.add(payload);
- setSelectedProjectId(id);
+ selectProject(id);
return id;
} catch (e) {
console.log("createNewProject error", e?.message);
@@ -294,6 +332,37 @@ export default ({ children }) => {
const isSuperAdmin = currentUserRoles.some((role) => role === "SUPERADMIN");
+ useEffect(() => {
+ const remoteSelectedId = currentUserDoc?.selectedProjectId;
+ if (!remoteSelectedId) {
+ if (remoteSelectedId === null && selectedProjectId !== null) {
+ setSelectedProjectId(null);
+ setSelectedProject(null);
+ }
+ return;
+ }
+
+ if (remoteSelectedId !== selectedProjectId) {
+ setSelectedProjectId(remoteSelectedId);
+ }
+ }, [currentUserDoc?.selectedProjectId, selectedProjectId, setSelectedProject]);
+
+ useEffect(() => {
+ if (!Array.isArray(userProjects) || userProjects.length === 0) return;
+ if (selectedProjectId) return;
+ if (currentUserDoc?.selectedProjectId) return;
+
+ const fallbackProjectId = userProjects[0]?.id;
+ if (!fallbackProjectId) return;
+
+ selectProject(fallbackProjectId);
+ }, [
+ currentUserDoc?.selectedProjectId,
+ selectProject,
+ selectedProjectId,
+ userProjects,
+ ]);
+
return (
{
unfollowUser,
resetSelectedProject,
selectProject,
- setSelectedProjectId,
+ setSelectedProjectId: selectProject,
updateProjectData,
createNewProject,
}}
diff --git a/src/screens/Home.js b/src/screens/Home/Home.js
similarity index 88%
rename from src/screens/Home.js
rename to src/screens/Home/Home.js
index e771329..a2abc35 100644
--- a/src/screens/Home.js
+++ b/src/screens/Home/Home.js
@@ -1,26 +1,26 @@
import { View, Text, Image, Platform } from "react-native";
import React, { useMemo, useState } from "react";
-import Page from "../layouts/Page";
-import { background, img } from "../assets";
+import Page from "../../layouts/Page";
+import { background, img } from "../../assets";
import { responsiveHeight } from "react-native-responsive-dimensions";
-import { Palette } from "../styles";
-import { FONT_FAMILY } from "../styles/Fonts";
-import { navigate } from "../navigation/NavigationService";
-import { Routes } from "../navigation";
+import { Palette } from "../../styles";
+import { FONT_FAMILY } from "../../styles/Fonts";
+import { navigate } from "../../navigation/NavigationService";
+import { Routes } from "../../navigation";
import { FlatList, Alert } from "react-native";
import { BlurView } from "expo-blur";
-import { useUser } from "../providers/UserDataProvider";
-import MusicCard from "./Library/components/MusicCard";
-import GradientButton from "../components/GradientButton";
-import MoreMenu from "../components/MoreMenu";
-import { projectsRef } from "../config/firebase";
+import { useUser } from "../../providers/UserDataProvider";
+import MusicCard from "../Library/components/MusicCard";
+import GradientButton from "../../components/GradientButton";
+import MoreMenu from "../../components/MoreMenu";
+import { projectsRef } from "../../config/firebase";
import { useGlobal } from "reactn";
const Home = () => {
const { userProjects = [], resetSelectedProject, selectProject } = useUser();
const projects = useMemo(
() => (Array.isArray(userProjects) ? userProjects : []),
- [userProjects]
+ [userProjects],
);
const [, setTooltip] = useGlobal("_tooltip");
const [menuTop, setMenuTop] = useState(0);
@@ -124,7 +124,7 @@ const Home = () => {
},
},
],
- { cancelable: true }
+ { cancelable: true },
),
},
]}
diff --git a/src/screens/Home/Home.web.js b/src/screens/Home/Home.web.js
new file mode 100644
index 0000000..6841bca
--- /dev/null
+++ b/src/screens/Home/Home.web.js
@@ -0,0 +1,333 @@
+import React, { useCallback, useMemo } from "react";
+import {
+ FlatList,
+ Image,
+ StyleSheet,
+ Text,
+ View,
+ useWindowDimensions,
+} from "react-native";
+import { BlurView } from "expo-blur";
+import Page from "../../layouts/Page";
+import { background, img } from "../../assets";
+import { Palette } from "../../styles";
+import { FONT_FAMILY } from "../../styles/Fonts";
+import { navigate } from "../../navigation/NavigationService";
+import { Routes } from "../../navigation";
+import { useUser } from "../../providers/UserDataProvider";
+import ProjectDropDown from "../../components/ProjectDropDown/ProjectDropDown";
+
+const ITEM_SPACING = 24;
+
+const Home = () => {
+ const {
+ userProjects = [],
+ resetSelectedProject,
+ selectProject,
+ selectedProject,
+ selectedProjectId,
+ } = useUser();
+
+ const projects = useMemo(
+ () => (Array.isArray(userProjects) ? userProjects : []),
+ [userProjects],
+ );
+
+ const { width: windowWidth } = useWindowDimensions();
+
+ const carouselItems = useMemo(
+ () => [
+ {
+ id: "project-vision",
+ title: "Composez sans limites",
+ description:
+ "Créez instantanément des maquettes professionnelles et explorez de nouveaux genres.",
+ image: img.placeholder,
+ },
+ {
+ id: "project-community",
+ title: "Collaborez en équipe",
+ description:
+ "Partagez vos projets, échangez des idées et co-créez en temps réel.",
+ image: img.placeholder2,
+ },
+ {
+ id: "project-ai",
+ title: "Optimisé par l'IA",
+ description:
+ "Accédez à des suggestions intelligentes pour les paroles, arrangements et mixages.",
+ image: img.placeholder3,
+ },
+ {
+ id: "project-stage",
+ title: "Prêt pour la scène",
+ description:
+ "Finalisez vos titres et exportez-les facilement pour le live ou le streaming.",
+ image: img.placeholder4,
+ },
+ ],
+ [],
+ );
+
+ const carouselItemWidth = useMemo(() => {
+ const baseWidth = Math.min(windowWidth * 0.9, 640);
+ return Math.max(baseWidth, 320);
+ }, [windowWidth]);
+
+ const carouselItemHeight = useMemo(() => {
+ const baseHeight = Math.min(windowWidth * 0.6, 360);
+ return Math.max(baseHeight, 240);
+ }, [windowWidth]);
+
+ const snapInterval = useMemo(
+ () => carouselItemHeight + ITEM_SPACING,
+ [carouselItemHeight],
+ );
+
+ const currentProject = useMemo(() => {
+ if (!projects.length) return null;
+ const activeId = selectedProject?.id || selectedProjectId;
+ if (!activeId) {
+ return projects[0];
+ }
+ return projects.find((project) => project?.id === activeId) || projects[0];
+ }, [projects, selectedProject?.id, selectedProjectId]);
+
+ const formatDate = useCallback((timestamp) => {
+ try {
+ const value = timestamp?.toDate ? timestamp.toDate() : timestamp;
+ const date = value ? new Date(value) : null;
+ if (!date || Number.isNaN(date.getTime())) {
+ return "";
+ }
+ const day = date.getDate().toString().padStart(2, "0");
+ const month = (date.getMonth() + 1).toString().padStart(2, "0");
+ return `${day}/${month}`;
+ } catch (error) {
+ console.warn("Home.web: formatDate error", error);
+ return "";
+ }
+ }, []);
+
+ const handleSelectProject = (project) => {
+ if (!project?.id) return;
+ selectProject(project.id);
+ };
+
+ const handleModifyProject = (project) => {
+ if (!project?.id) return;
+ selectProject(project.id);
+ navigate(Routes.FlowSelection);
+ };
+
+ const handleCreateNew = () => {
+ resetSelectedProject();
+ navigate(Routes.FlowSelection);
+ };
+
+ const renderCarouselItem = useCallback(
+ ({ item, index }) => {
+ const isImageOnRight = index % 2 === 1;
+
+ let imageSize = Math.min(carouselItemHeight - 24, 280);
+ let availableWidth = carouselItemWidth - imageSize - 48;
+
+ if (availableWidth < 140) {
+ const minImageSize = Math.max(carouselItemWidth - 140 - 48, 140);
+ imageSize = Math.min(imageSize, minImageSize);
+ availableWidth = carouselItemWidth - imageSize - 48;
+ }
+
+ const blurWidth = Math.min(Math.max(availableWidth, 120), 260);
+ const blurHeight = Math.max(
+ Math.min(imageSize * 0.75, carouselItemHeight - 48),
+ 140,
+ );
+
+ return (
+
+
+
+
+ {item.title}
+ {item.description}
+
+
+
+ );
+ },
+ [carouselItemHeight, carouselItemWidth],
+ );
+
+ const keyExtractor = useCallback((item) => item.id, []);
+
+ return (
+
+
+
+
+
+
+ (
+
+ )}
+ />
+
+
+
+ );
+};
+
+export default Home;
+
+const styles = StyleSheet.create({
+ root: {
+ flex: 1,
+ paddingHorizontal: 24,
+ position: "relative",
+ justifyContent: "flex-start",
+ alignItems: "center",
+ width: "100%",
+ },
+ heroImage: {
+ position: "absolute",
+ top: -60,
+ alignSelf: "center",
+ width: "80%",
+ maxWidth: 920,
+ height: 420,
+ opacity: 0.9,
+ },
+ dropdownArea: {
+ width: "100%",
+ alignItems: "center",
+ justifyContent: "center",
+ paddingTop: 72,
+ zIndex: 2,
+ },
+ dropdownContainer: {
+ width: "100%",
+ },
+ shareIcon: {
+ width: 18,
+ height: 18,
+ tintColor: Palette.white,
+ },
+ carouselSection: {
+ width: "100%",
+ marginTop: 48,
+ },
+ carouselList: {
+ width: "100%",
+ },
+ carouselItem: {
+ borderRadius: 18,
+ backgroundColor: "rgba(0, 0, 0, 0.18)",
+ borderWidth: 1,
+ borderColor: "rgba(255, 255, 255, 0.1)",
+ paddingVertical: 24,
+ paddingHorizontal: 16,
+ alignItems: "center",
+ justifyContent: "center",
+ },
+ carouselItemRight: {
+ flexDirection: "row-reverse",
+ alignItems: "center",
+ },
+ carouselItemLeft: {
+ flexDirection: "row",
+ alignItems: "center",
+ },
+ carouselImage: {
+ borderRadius: 28,
+ shadowColor: "#000",
+ shadowOffset: { width: 0, height: 8 },
+ shadowOpacity: 0.25,
+ shadowRadius: 20,
+ },
+ carouselImageRight: {
+ marginLeft: 20,
+ },
+ carouselImageLeft: {
+ marginRight: 20,
+ },
+ carouselBlur: {
+ borderRadius: 20,
+ overflow: "hidden",
+ paddingHorizontal: 18,
+ paddingVertical: 16,
+ justifyContent: "center",
+ alignItems: "flex-start",
+ backgroundColor: "rgba(0, 0, 0, 0.25)",
+ gap: 8,
+ },
+ carouselBlurRight: {
+ marginRight: 12,
+ },
+ carouselBlurLeft: {
+ marginLeft: 12,
+ },
+ carouselTextContainer: {
+ width: "100%",
+ },
+ carouselTitle: {
+ fontSize: 20,
+ color: Palette.white,
+ fontFamily: FONT_FAMILY.InterSemiBold,
+ marginBottom: 8,
+ },
+ carouselDescription: {
+ fontSize: 14,
+ lineHeight: 20,
+ color: "rgba(255, 255, 255, 0.7)",
+ fontFamily: FONT_FAMILY.InterRegular,
+ },
+});
diff --git a/src/screens/Library/components/MusicCard.js b/src/screens/Library/components/MusicCard.js
index 4d2e664..6527fb4 100644
--- a/src/screens/Library/components/MusicCard.js
+++ b/src/screens/Library/components/MusicCard.js
@@ -1,7 +1,6 @@
import { BlurView } from "expo-blur";
import React, { useEffect, useRef, useState } from "react";
import {
- Platform,
Pressable,
StyleSheet,
Text,
diff --git a/src/screens/Login.js b/src/screens/Login.js
index 37a0567..745697d 100644
--- a/src/screens/Login.js
+++ b/src/screens/Login.js
@@ -1,34 +1,32 @@
-/* eslint-disable react/display-name */
-import { GoogleSigninButton } from "@react-native-google-signin/google-signin";
-import * as AuthSession from "expo-auth-session";
-import * as GoogleAuth from "expo-auth-session/providers/google";
-import * as WebBrowser from "expo-web-browser";
-import React, { useEffect, useState } from "react";
-import { Pressable, Text, View } from "react-native";
-import { useGlobal } from "reactn";
-import { background } from "../assets";
-import GradientButton from "../components/GradientButton.js";
-import { Input } from "../components/Input.js";
-import ItemContainer from "../components/ItemContainer/ItemContainer.js";
-import firebase, { usersRef } from "../config/firebase";
-
+import { GoogleSigninButton } from '@react-native-google-signin/google-signin';
+import * as AuthSession from 'expo-auth-session';
+import * as GoogleAuth from 'expo-auth-session/providers/google';
+import * as WebBrowser from 'expo-web-browser';
+import React, { useEffect, useState } from 'react';
+import { Pressable, Text, View } from 'react-native';
+import { useGlobal } from 'reactn';
+import { background } from '../assets';
+import GradientButton from '../components/GradientButton.js';
+import { Input } from '../components/Input.js';
+import ItemContainer from '../components/ItemContainer/ItemContainer.js';
+import firebase, { usersRef } from '../config/firebase';
import {
GOOGLE_ANDROID_CLIENT_ID,
GOOGLE_IOS_CLIENT_ID,
GOOGLE_WEB_CLIENT_ID,
-} from "../data/keys";
-import { isWeb } from "../hooks/useLayoutType";
-import Page from "../layouts/Page.js";
-import { Routes } from "../navigation";
-import { navigate } from "../navigation/NavigationService.js";
-import { FONT_FAMILY } from "../styles/Fonts.js";
-import Palette from "../styles/Palette.js";
+} from '../data/keys';
+import { isWeb } from '../hooks/useLayoutType';
+import Page from '../layouts/Page.js';
+import { Routes } from '../navigation';
+import { navigate } from '../navigation/NavigationService.js';
+import { FONT_FAMILY } from '../styles/Fonts.js';
+import Palette from '../styles/Palette.js';
export default ({ navigation }) => {
WebBrowser.maybeCompleteAuthSession();
- const [, setTooltip] = useGlobal("_tooltip");
- const [email, setEmail] = useState("");
- const [password, setPassword] = useState("");
+ const [, setTooltip] = useGlobal('_tooltip');
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
// Let the provider compute a compliant redirect URI for native (com.googleusercontent.apps.:/oauth2redirect)
// Avoid forcing a custom scheme like musicland:// which Google can reject for native apps.
@@ -41,12 +39,12 @@ export default ({ navigation }) => {
// Use Authorization Code + PKCE to comply with Google OAuth for native apps
responseType: AuthSession.ResponseType.Code,
usePKCE: true,
- scopes: ["openid", "profile", "email"],
+ scopes: ['openid', 'profile', 'email'],
});
const afterLoginNavigate = async () => {
const uid = firebase.auth().currentUser?.uid;
- if (!uid) throw new Error("Aucun utilisateur après connexion");
+ if (!uid) throw new Error('Aucun utilisateur après connexion');
const snap = await usersRef.doc(uid).get();
const hasUserName = !!snap.data()?.userName;
if (hasUserName) {
@@ -62,8 +60,8 @@ export default ({ navigation }) => {
await firebase.auth().signInWithEmailAndPassword(email.trim(), password);
await afterLoginNavigate();
} catch (e) {
- console.log("Login error", e?.message);
- setTooltip({ text: e?.message || "Connexion impossible", type: "error" });
+ console.log('Login error', e?.message);
+ setTooltip({ text: e?.message || 'Connexion impossible', type: 'error' });
} finally {
setLoading(false);
}
@@ -74,24 +72,24 @@ export default ({ navigation }) => {
setLoading(true);
if (isWeb) {
const provider = new firebase.auth.GoogleAuthProvider();
- provider.addScope("profile");
- provider.addScope("email");
+ provider.addScope('profile');
+ provider.addScope('email');
await firebase.auth().signInWithPopup(provider);
await afterLoginNavigate();
setLoading(false);
} else {
// Use defaults from the request; don't override with proxy here
const result = await promptAsync();
- if (result?.type !== "success") {
+ if (result?.type !== 'success') {
// Cancelled or errored during the browser flow
setLoading(false);
}
}
} catch (e) {
- console.log("Google Login error", e?.message);
+ console.log('Google Login error', e?.message);
setTooltip({
- text: e?.message || "Connexion Google impossible. Merci de réessayer.",
- type: "error",
+ text: e?.message || 'Connexion Google impossible. Merci de réessayer.',
+ type: 'error',
});
setLoading(false);
}
@@ -101,7 +99,7 @@ export default ({ navigation }) => {
useEffect(() => {
const handleNativeGoogleResponse = async () => {
try {
- if (response?.type === "success") {
+ if (response?.type === 'success') {
// If using Expo proxy, tokens can be present already.
let idToken =
response?.authentication?.idToken || response?.params?.id_token;
@@ -116,13 +114,13 @@ export default ({ navigation }) => {
const clientId = request?.clientId;
const discovery = {
authorizationEndpoint:
- "https://accounts.google.com/o/oauth2/v2/auth",
- tokenEndpoint: "https://oauth2.googleapis.com/token",
- revocationEndpoint: "https://oauth2.googleapis.com/revoke",
+ 'https://accounts.google.com/o/oauth2/v2/auth',
+ tokenEndpoint: 'https://oauth2.googleapis.com/token',
+ revocationEndpoint: 'https://oauth2.googleapis.com/revoke',
};
// Light debug: helps identify redirect/client mismatches in dev.
- console.log("Google token exchange", {
+ console.log('Google token exchange', {
clientId,
redirectUri: request?.redirectUri,
hasCodeVerifier: !!request?.codeVerifier,
@@ -135,13 +133,13 @@ export default ({ navigation }) => {
redirectUri: request?.redirectUri,
extraParams: { code_verifier: request?.codeVerifier },
},
- discovery
+ discovery,
);
idToken = tokenResponse?.id_token;
}
if (!idToken)
- throw new Error("Jeton Google manquant (échange/retour)");
+ throw new Error('Jeton Google manquant (échange/retour)');
const credential =
firebase.auth.GoogleAuthProvider.credential(idToken);
@@ -149,10 +147,10 @@ export default ({ navigation }) => {
await afterLoginNavigate();
}
} catch (e) {
- console.log("Google native sign-in error", e?.message);
+ console.log('Google native sign-in error', e?.message);
setTooltip({
- text: e?.message || "Connexion Google impossible",
- type: "error",
+ text: e?.message || 'Connexion Google impossible',
+ type: 'error',
});
} finally {
setLoading(false);
@@ -230,8 +228,8 @@ export default ({ navigation }) => {
{
onPress={onLoginWithGoogle}
disabled={loading}
/> */}
-
+ {/**/}
@@ -266,7 +264,7 @@ export default ({ navigation }) => {
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
}}
>
- Pas encore de compte?{" "}
+ Pas encore de compte?{' '}
{
title: result?.title || "",
titleLower: (result?.title || "").toLowerCase(),
lyrics: Array.isArray(result?.lyrics) ? result.lyrics : [],
+ description: result?.lyricsDescription,
config: config || null,
selections: selections || null,
hasLyrics: false,