last tickets

This commit is contained in:
Thomas Demirdjian
2025-11-24 15:35:14 +01:00
parent 471a3177e8
commit 72852ad92b
40 changed files with 1749 additions and 667 deletions
+2
View File
@@ -56,6 +56,8 @@ const AppActionSheet = ({
width: 50,
zIndex: 2,
}}
closeOnTouchBackdrop
closeOnPressBack
onClose={onClose}
{...sheetProps}
>
@@ -0,0 +1,99 @@
import React from "react";
import { StyleSheet, Text, View } from "react-native";
import { gutters, Palette } from "../styles";
import { FONT_FAMILY } from "../styles/Fonts";
import BorderGradientButton from "./BorderGradientButton";
import GradientButton from "./GradientButton";
import Overlay from "./Overlay";
const SubscriptionConfirmModal = ({
isVisible,
setIsVisible,
onJoinClub,
onContinue,
continueLabel = "Continuer vers la création de playback",
}) => {
const handleJoinClub = () => {
if (typeof setIsVisible === "function") {
setIsVisible(false);
}
if (typeof onJoinClub === "function") {
onJoinClub();
}
};
const handleContinue = () => {
if (typeof setIsVisible === "function") {
setIsVisible(false);
}
if (typeof onContinue === "function") {
onContinue();
}
};
return (
<Overlay
isVisible={isVisible}
setIsVisible={setIsVisible}
blurIntensity={15}
>
<View style={styles.modalCard}>
<Text style={styles.modalTitle}>
Continuer sans générer de revenus ?
</Text>
<Text style={styles.modalDescription}>
Rejoins le Club Musicland pour monétiser tes écoutes et accéder aux
concours.
</Text>
<View style={styles.modalActions}>
<GradientButton
title="Rejoindre le club"
onPress={handleJoinClub}
containerStyle={styles.modalAction}
/>
<BorderGradientButton
title={continueLabel}
onPress={handleContinue}
containerStyle={styles.modalAction}
/>
</View>
</View>
</Overlay>
);
};
export default SubscriptionConfirmModal;
const styles = StyleSheet.create({
modalCard: {
width: "90%",
maxWidth: 420,
alignSelf: "center",
padding: gutters * 1.4,
borderRadius: 20,
backgroundColor: "rgba(37, 36, 56, 0.96)",
borderWidth: 1,
borderColor: "rgba(255, 255, 255, 0.12)",
gap: gutters * 0.8,
},
modalTitle: {
fontFamily: FONT_FAMILY.InterSemiBold,
fontSize: 18,
color: Palette.white,
textAlign: "center",
},
modalDescription: {
fontFamily: FONT_FAMILY.InterRegular,
fontSize: 14,
lineHeight: 20,
color: Palette.grayMid,
textAlign: "center",
},
modalActions: {
gap: gutters * 0.6,
marginTop: gutters * 0.6,
},
modalAction: {
width: "100%",
},
});
+42 -2
View File
@@ -1,4 +1,10 @@
import React, { useCallback, useMemo, useState } from "react";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import {
Image,
Pressable,
@@ -6,6 +12,7 @@ import {
StyleSheet,
Text,
View,
findNodeHandle,
} from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import AppActionSheet from "../AppActionSheet";
@@ -25,6 +32,7 @@ const PlaybackPickerModal = () => {
const { userProjects = [], createNewProject } = useUserData();
const [isCreating, setIsCreating] = useState(false);
const [webVisible, setWebVisible] = useState(true);
const modalRef = useRef(null);
const sanitizedProjects = useMemo(() => {
if (!Array.isArray(userProjects)) {
@@ -101,13 +109,45 @@ const PlaybackPickerModal = () => {
const hasProjects = sanitizedProjects.length > 0;
useEffect(() => {
if (!isWeb || !webVisible || typeof document === "undefined") {
return;
}
const handlePointerDown = (event) => {
const node = modalRef.current;
if (!node) {
return;
}
const domNode = findNodeHandle(node);
if (domNode && typeof domNode.contains === "function") {
if (domNode.contains(event.target)) {
return;
}
}
if (domNode === event.target) {
return;
}
hideSheet();
};
document.addEventListener("pointerdown", handlePointerDown);
return () => {
document.removeEventListener("pointerdown", handlePointerDown);
};
}, [hideSheet, webVisible]);
if (isWeb && !webVisible) {
return null;
}
return (
<AppActionSheet id={SHEET_ID} webModal onClose={hideSheet}>
<View style={{ gap: 18 }}>
<View ref={modalRef} style={{ gap: 18 }} collapsable={false}>
<Text style={styles.title}>Ajouter un playback</Text>
<Text style={styles.description}>
Choisis une musique déjà créée pour y ajouter un playback ou lance un
+22 -8
View File
@@ -6,7 +6,16 @@ import { FONT_FAMILY } from "../../styles/Fonts";
import BorderGradientButton from "../BorderGradientButton";
import GradientButton from "../GradientButton";
const ValidateModal = ({ visible, onClose, onPressValidate }) => {
const ValidateModal = ({
visible,
onClose,
onPressValidate,
onPressSecondary,
title = "Attention !",
description = "Lorsque tu clique sur valider, tu ne pourra plus changer ni le texte ni la mélodie.",
primaryLabel = "Valider",
secondaryLabel = "Retour",
}) => {
return (
<Modal
animationType="slide"
@@ -36,7 +45,7 @@ const ValidateModal = ({ visible, onClose, onPressValidate }) => {
textAlign: "center",
}}
>
Attention !
{title}
</Text>
<Text
style={{
@@ -46,17 +55,22 @@ const ValidateModal = ({ visible, onClose, onPressValidate }) => {
textAlign: "center",
}}
>
Lorsque tu clique sur valider, tu ne pourra plus changer ni le
texte ni la mélodie.
{description}
</Text>
</View>
</View>
<View style={{ width: "85%", alignSelf: "center", gap: 15 }}>
<BorderGradientButton title="Retour" onPress={onClose} />
<GradientButton
title="Valider"
<BorderGradientButton
title={secondaryLabel}
onPress={() => {
onClose();
onClose?.();
onPressSecondary?.();
}}
/>
<GradientButton
title={primaryLabel}
onPress={() => {
onClose?.();
onPressValidate?.();
}}
/>
+15 -10
View File
@@ -4,7 +4,7 @@ import { Image, Pressable, StyleSheet, Text, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { icons, img } from "../../assets";
import { arrayRemove, arrayUnion, projectsRef } from "../../config/firebase";
import { projectsRef } from "../../config/firebase";
import useDataFromRef from "../../hooks/useDataFromRef";
import { isWeb } from "../../hooks/useLayoutType";
import usePlayer from "../../hooks/usePlayer";
@@ -13,6 +13,11 @@ import { useUser } from "../../providers/UserDataProvider";
import { gutters, Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import { ensureAuthenticated } from "../../utils/authRedirect";
import {
getProjectLikes,
LIKE_TARGET,
toggleProjectLike,
} from "../../utils/likes";
import { responsiveHeight } from "react-native-responsive-dimensions";
const formatDuration = (ms) => {
@@ -60,9 +65,9 @@ const GlobalAudioPlayer = () => {
refreshArray: [projectId],
});
const likedByList = Array.isArray(projectData?.likedBy)
? projectData.likedBy
: [];
const likedByList = useMemo(() => {
return getProjectLikes(projectData, LIKE_TARGET.SONG);
}, [projectData]);
const likedFromDoc = useMemo(() => {
if (!projectId || !currentUID) return false;
@@ -100,12 +105,12 @@ const GlobalAudioPlayer = () => {
const next = !effectiveIsLiked;
setPendingLike(next);
try {
await projectsRef.doc(projectId).set(
{
likedBy: next ? arrayUnion(currentUID) : arrayRemove(currentUID),
},
{ merge: true },
);
await toggleProjectLike({
projectId,
target: LIKE_TARGET.SONG,
currentUID,
next,
});
} catch (_error) {
setPendingLike(null);
}