This commit is contained in:
2025-09-03 14:55:01 +02:00
parent 2b24900e0c
commit 64fd988d2f
9 changed files with 187 additions and 123 deletions
+2
View File
@@ -36,6 +36,7 @@ import {
import "./src/utils/Sheet"; import "./src/utils/Sheet";
import {LogBox} from "react-native"; import {LogBox} from "react-native";
import CommentsBottomSheet from "./src/components/bottomsheets/CommentsBottomSheet";
console.disableYellowBox = true; console.disableYellowBox = true;
console.reportErrorsAsExceptions = false; console.reportErrorsAsExceptions = false;
@@ -142,6 +143,7 @@ const App = () => {
> >
<MainStack /> <MainStack />
</NavigationContainer> </NavigationContainer>
<CommentsBottomSheet />
</AppLayout> </AppLayout>
</MenuProvider> </MenuProvider>
</Providers> </Providers>
+5 -18
View File
@@ -16,14 +16,7 @@
"fallbackToCacheTimeout": 0 "fallbackToCacheTimeout": 0
}, },
"packagerOpts": { "packagerOpts": {
"sourceExts": [ "sourceExts": ["js", "json", "ts", "tsx", "jsx", "vue"]
"js",
"json",
"ts",
"tsx",
"jsx",
"vue"
]
}, },
"splash": { "splash": {
"image": "./assets/splash.png", "image": "./assets/splash.png",
@@ -35,9 +28,7 @@
"supportsTablet": true, "supportsTablet": true,
"requireFullScreen": true, "requireFullScreen": true,
"userInterfaceStyle": "dark", "userInterfaceStyle": "dark",
"associatedDomains": [ "associatedDomains": ["applinks:minuit.starter"],
"applinks:minuit.starter"
],
"bundleIdentifier": "com.minuit.starter", "bundleIdentifier": "com.minuit.starter",
"infoPlist": { "infoPlist": {
"UISupportedInterfaceOrientations": [ "UISupportedInterfaceOrientations": [
@@ -48,10 +39,7 @@
"UIInterfaceOrientationLandscapeLeft", "UIInterfaceOrientationLandscapeLeft",
"UIInterfaceOrientationLandscapeRight" "UIInterfaceOrientationLandscapeRight"
], ],
"LSApplicationQueriesSchemes": [ "LSApplicationQueriesSchemes": ["itms-apps", "minuit"]
"itms-apps",
"minuit"
]
}, },
"config": { "config": {
"usesNonExemptEncryption": false "usesNonExemptEncryption": false
@@ -62,15 +50,14 @@
"appleTeamId": "W2QZ9CTMYJ" "appleTeamId": "W2QZ9CTMYJ"
}, },
"android": { "android": {
"softwareKeyboardLayoutMode": "resize",
"googleServicesFile": "./config/google-services.json", "googleServicesFile": "./config/google-services.json",
"adaptiveIcon": { "adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png", "foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#0A0D12" "backgroundColor": "#0A0D12"
}, },
"package": "com.minuit.starter", "package": "com.minuit.starter",
"permissions": [ "permissions": ["android.permission.RECORD_AUDIO"]
"android.permission.RECORD_AUDIO"
]
}, },
"web": { "web": {
"bundler": "metro" "bundler": "metro"
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+53 -55
View File
@@ -1,52 +1,52 @@
import home from "./UI/tabs/home.png";
import tasks from "./UI/tabs/tasks.png";
import chat from "./UI/tabs/chat.png";
import design from "./UI/tabs/design.png";
import quotes from "./UI/tabs/quotes.png";
import settings from "./UI/tabs/settings.png";
import addTab from "./UI/tabs/add.png"; import addTab from "./UI/tabs/add.png";
import albums from "./UI/tabs/albums.png"; import albums from "./UI/tabs/albums.png";
import ribbon from "./UI/tabs/ribbon.png"; import chat from "./UI/tabs/chat.png";
import design from "./UI/tabs/design.png";
import home from "./UI/tabs/home.png";
import mic from "./UI/tabs/mic.png"; import mic from "./UI/tabs/mic.png";
import person from "./UI/tabs/person.png"; import person from "./UI/tabs/person.png";
import quotes from "./UI/tabs/quotes.png";
import ribbon from "./UI/tabs/ribbon.png";
import settings from "./UI/tabs/settings.png";
import tasks from "./UI/tabs/tasks.png";
import bell from "./UI/bell.png"; import bell from "./UI/bell.png";
import sort from "./UI/sort.png"; import sort from "./UI/sort.png";
import chevronDown from "./UI/chevronDown.png";
import arrowRight from "./UI/arrowRight.png"; import arrowRight from "./UI/arrowRight.png";
import chevronDown from "./UI/chevronDown.png";
import threeDots from "./UI/threeDots.png"; import threeDots from "./UI/threeDots.png";
import thumbUp from "./UI/thumbUp.png";
import thumbDown from "./UI/thumbDown.png"; import thumbDown from "./UI/thumbDown.png";
import thumbUp from "./UI/thumbUp.png";
import add from "./UI/add.png"; import add from "./UI/add.png";
import search from "./UI/search.png";
import addFile from "./UI/addFile.png"; import addFile from "./UI/addFile.png";
import send from "./UI/send.png";
import eye from "./UI/eye.png";
import edit from "./UI/edit.png";
import trash from "./UI/trash.png";
import message from "./UI/message.png";
import check from "./UI/check.png"; import check from "./UI/check.png";
import checkCircle from "./UI/checkCircle.png"; import checkCircle from "./UI/checkCircle.png";
import undo from "./UI/undo.png";
import shoppingBag from "./UI/shoppingBag.png";
import lock from "./UI/lock.png";
import deliveryTime from "./UI/deliveryTime.png"; import deliveryTime from "./UI/deliveryTime.png";
import edit from "./UI/edit.png";
import eye from "./UI/eye.png";
import lock from "./UI/lock.png";
import message from "./UI/message.png";
import search from "./UI/search.png";
import send from "./UI/send.png";
import shoppingBag from "./UI/shoppingBag.png";
import tools from "./UI/tools.png"; import tools from "./UI/tools.png";
import trash from "./UI/trash.png";
import undo from "./UI/undo.png";
import focus from "./UI/focus.png";
import picture from "./UI/picture.png"; import picture from "./UI/picture.png";
import screenshot from "./UI/screenshot.png"; import screenshot from "./UI/screenshot.png";
import focus from "./UI/focus.png";
import android from "./UI/android.png"; import android from "./UI/android.png";
import ios from "./UI/ios.png"; import ios from "./UI/ios.png";
import web from "./UI/web.png"; import web from "./UI/web.png";
import user from "./UI/user.png";
import law from "./UI/law.png"; import law from "./UI/law.png";
import support from "./UI/support.png"; import support from "./UI/support.png";
import user from "./UI/user.png";
import attachment from "./UI/attachment.png"; import attachment from "./UI/attachment.png";
@@ -54,65 +54,63 @@ import cloud from "./icons/cloud.png";
import dashboard from "./icons/dashboard.png"; import dashboard from "./icons/dashboard.png";
import file from "./icons/file.png"; import file from "./icons/file.png";
import figma from "./icons/figma.png"; import circle from "./art/circle.png";
import gitlab from "./icons/gitlab.png"; import gradientTriangle from "./art/gradientTriangle.png";
import square from "./art/square.png";
import triangle from "./art/triangle.png";
import algolia from "./icons/algolia.png"; import algolia from "./icons/algolia.png";
import play from "./icons/play.png"; import calendar from "./icons/calendar.png";
import disk from "./icons/disk.png"; import chatBubble from "./icons/chatBubble.png";
import stars from "./icons/stars.png";
import musicLandLogo from "./icons/musicLandLogo.png";
import close from "./icons/close.png"; import close from "./icons/close.png";
import coin from "./icons/coin.png";
import disk from "./icons/disk.png";
import figma from "./icons/figma.png";
import forward from "./icons/forward.png";
import gitlab from "./icons/gitlab.png";
import heart from "./icons/heart.png"; import heart from "./icons/heart.png";
import heartOutline from "./icons/heartOutline.png"; import heartOutline from "./icons/heartOutline.png";
import more from "./icons/more.png";
import forward from "./icons/forward.png";
import pause from "./icons/pause.png";
import share from "./icons/share.png";
import hitParadeLogo from "./icons/hitParadeLogo.png"; import hitParadeLogo from "./icons/hitParadeLogo.png";
import calendar from "./icons/calendar.png"; import more from "./icons/more.png";
import coin from "./icons/coin.png"; import musicLandLogo from "./icons/musicLandLogo.png";
import pause from "./icons/pause.png";
import play from "./icons/play.png";
import share from "./icons/share.png";
import stars from "./icons/stars.png";
import triangle from "./art/triangle.png";
import circle from "./art/circle.png";
import square from "./art/square.png";
import gradientTriangle from "./art/gradientTriangle.png";
import threeCoins from "./art/threeCoins.png";
import boost from "./art/boost.png"; import boost from "./art/boost.png";
import boostBig from "./art/boostBig.png"; import boostBig from "./art/boostBig.png";
import threeCoins from "./art/threeCoins.png";
import welcome from "./tutorial/welcome.png";
import tutorialChat from "./tutorial/chat.png"; import tutorialChat from "./tutorial/chat.png";
import coins from "./tutorial/coins.png"; import coins from "./tutorial/coins.png";
import followProgress from "./tutorial/followProgress.png"; import followProgress from "./tutorial/followProgress.png";
import tutorialTasks from "./tutorial/tasks.png"; import tutorialTasks from "./tutorial/tasks.png";
import welcome from "./tutorial/welcome.png";
import loginAppDashboard from "./mockups/loginAppDashboard.png";
import writingBG from "./UI/writingBG.png";
import studioBG from "./UI/studioBG.png";
import studioBG2 from "./UI/studioBG2.png";
import productionBG from "./UI/productionBG.png";
import productionBG2 from "./UI/productionBG2.png";
import playbackBG from "./UI/playbackBG.png";
import playbackBG2 from "./UI/playbackBG2.png";
import libraryBG from "./UI/libraryBG.png";
import libraryBG2 from "./UI/libraryBG2.png";
import profileBG from "./UI/profileBG.png";
import hitParadeBG from "./UI/hitParadeBG.png"; import hitParadeBG from "./UI/hitParadeBG.png";
import homeBG from "./UI/homeBG.png"; import homeBG from "./UI/homeBG.png";
import libraryBG from "./UI/libraryBG.png";
import libraryBG2 from "./UI/libraryBG2.png";
import playbackBG from "./UI/playbackBG.png";
import playbackBG2 from "./UI/playbackBG2.png";
import productionBG from "./UI/productionBG.png";
import productionBG2 from "./UI/productionBG2.png";
import profileBG from "./UI/profileBG.png";
import studioBG from "./UI/studioBG.png";
import studioBG2 from "./UI/studioBG2.png";
import writingBG from "./UI/writingBG.png";
import nathalie from "./UI/nathalie.png";
import theo from "./UI/theo.png";
import bena from "./UI/bena.png"; import bena from "./UI/bena.png";
import john from "./UI/john.png"; import john from "./UI/john.png";
import nathalie from "./UI/nathalie.png";
import theo from "./UI/theo.png";
import goodVibe from "./UI/goodVibe.png";
import placeholder from "./UI/placeholder.jpg"; import placeholder from "./UI/placeholder.jpg";
import placeholder2 from "./UI/placeholder2.jpg"; import placeholder2 from "./UI/placeholder2.jpg";
import placeholder3 from "./UI/placeholder3.png"; import placeholder3 from "./UI/placeholder3.png";
import placeholder4 from "./UI/placeholder4.jpg"; import placeholder4 from "./UI/placeholder4.jpg";
import profile from "./UI/profile.jpg"; import profile from "./UI/profile.jpg";
import goodVibe from "./UI/goodVibe.png";
export const tabs = { export const tabs = {
home, home,
@@ -139,7 +137,7 @@ export const icons = {
thumbUp, thumbUp,
thumbDown, thumbDown,
chatBubble,
add, add,
search, search,
addFile, addFile,
+4 -4
View File
@@ -1,9 +1,9 @@
import { View, Text, Platform } from "react-native";
import React from "react";
import ActionSheet from "react-native-actions-sheet";
import { gutters, Palette } from "../styles";
import { BlurView } from "expo-blur"; import { BlurView } from "expo-blur";
import React from "react";
import { Platform } from "react-native";
import ActionSheet from "react-native-actions-sheet";
import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useSafeAreaInsets } from "react-native-safe-area-context";
import { gutters, Palette } from "../styles";
const AppActionSheet = ({ children, props }) => { const AppActionSheet = ({ children, props }) => {
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
@@ -1,5 +1,18 @@
// CommentsBottomSheet.jsx
import {
BottomSheetBackdrop,
BottomSheetModal,
BottomSheetScrollView,
} from "@gorhom/bottom-sheet";
import { BlurView } from "expo-blur"; import { BlurView } from "expo-blur";
import React, { useMemo, useState } from "react"; import { Image as ExpoImage } from "expo-image";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { import {
Image, Image,
Platform, Platform,
@@ -8,6 +21,7 @@ import {
TextInput, TextInput,
View, View,
} from "react-native"; } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { icons } from "../../assets"; import { icons } from "../../assets";
import { projectsRef, serverTimestamp } from "../../config/firebase"; import { projectsRef, serverTimestamp } from "../../config/firebase";
import useDataFromRef from "../../hooks/useDataFromRef"; import useDataFromRef from "../../hooks/useDataFromRef";
@@ -15,7 +29,11 @@ import { useUser } from "../../providers/UserDataProvider";
import { Palette } from "../../styles"; import { Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts"; import { FONT_FAMILY } from "../../styles/Fonts";
import { size } from "../../styles/Style"; import { size } from "../../styles/Style";
import AppActionSheet from "../AppActionSheet";
let externalOpen;
export const openComments = (projectId) => {
if (typeof externalOpen === "function") externalOpen(projectId);
};
const formatRelativeTime = (date) => { const formatRelativeTime = (date) => {
try { try {
@@ -35,10 +53,26 @@ const formatRelativeTime = (date) => {
} }
}; };
const CommentsModal = ({ sheetId, payload }) => { const CommentsBottomSheet = () => {
const projectId = payload?.projectId || null; const modalRef = useRef(null);
const insets = useSafeAreaInsets();
const { currentUID, currentUserData } = useUser(); const { currentUID, currentUserData } = useUser();
const [projectId, setProjectId] = useState(null);
const [text, setText] = useState(""); const [text, setText] = useState("");
const [typing, setTyping] = useState(false);
useEffect(() => {
externalOpen = (pid) => {
setProjectId(pid || null);
requestAnimationFrame(() => modalRef.current?.present());
};
return () => {
externalOpen = undefined;
};
}, []);
const snapPoints = useMemo(() => ["50%", "90%"], []);
const commentsRef = useMemo(() => { const commentsRef = useMemo(() => {
try { try {
@@ -48,7 +82,7 @@ const CommentsModal = ({ sheetId, payload }) => {
.collection("comments") .collection("comments")
.orderBy("createdAt", "desc") .orderBy("createdAt", "desc")
: null; : null;
} catch (e) { } catch {
return null; return null;
} }
}, [projectId]); }, [projectId]);
@@ -66,22 +100,56 @@ const CommentsModal = ({ sheetId, payload }) => {
if (!value || !projectId || !currentUID) return; if (!value || !projectId || !currentUID) return;
try { try {
setText(""); setText("");
const docRef = projectsRef.doc(projectId).collection("comments"); await projectsRef
await docRef.add({ .doc(projectId)
.collection("comments")
.add({
userId: currentUID, userId: currentUID,
userName: currentUserData?.userName || "", userName: currentUserData?.userName || "",
profilePicture: currentUserData?.profilePictureURL || "", profilePicture: currentUserData?.profilePictureURL || "",
text: value, text: value,
createdAt: serverTimestamp(), createdAt: serverTimestamp(),
}); });
} catch (e) { } catch {
// Ignore // ignore
} }
}; };
const renderBackdrop = useCallback(
(props) => (
<BottomSheetBackdrop
{...props}
appearsOnIndex={0}
disappearsOnIndex={-1}
pressBehavior={typing ? "none" : "close"}
/>
),
[typing]
);
return ( return (
<AppActionSheet id="Comments" props={{ gestureEnabled: true }}> <BottomSheetModal
<View style={{ gap: 14 }}> ref={modalRef}
snapPoints={snapPoints}
keyboardBehavior="interactive" // linput est dans le contenu → mode interactif OK
keyboardBlurBehavior="restore"
enablePanDownToClose={!typing} // évite un dismiss pendant la frappe
enableContentPanningGesture={!typing}
stackBehavior="push"
topInset={insets.top}
bottomInset={insets.bottom}
backdropComponent={renderBackdrop}
handleIndicatorStyle={{ backgroundColor: Palette.white }}
backgroundStyle={{ backgroundColor: "transparent" }}
>
<BlurView
intensity={20}
style={{ flex: 1, backgroundColor: Palette.glass }}
experimentalBlurMethod={
Platform.OS !== "ios" ? "dimezisBlurView" : "none"
}
>
<View style={{ paddingTop: 10, paddingBottom: 8 }}>
<Text <Text
style={{ style={{
fontSize: 22, fontSize: 22,
@@ -92,12 +160,24 @@ const CommentsModal = ({ sheetId, payload }) => {
> >
Commentaires Commentaires
</Text> </Text>
<View style={{ gap: 14, maxHeight: 400 }}> </View>
<BottomSheetScrollView
keyboardShouldPersistTaps="handled"
contentContainerStyle={{
paddingHorizontal: 14,
paddingBottom: (insets?.bottom || 0) + 12,
}}
showsVerticalScrollIndicator
>
{Array.isArray(comments) && comments.length > 0 ? ( {Array.isArray(comments) && comments.length > 0 ? (
comments.map((c) => ( comments.map((c) => (
<View key={c.id} style={{ flexDirection: "row", gap: 12 }}> <View
key={c.id}
style={{ flexDirection: "row", gap: 12, marginBottom: 14 }}
>
{c?.profilePicture ? ( {c?.profilePicture ? (
<Image <ExpoImage
source={{ uri: c.profilePicture }} source={{ uri: c.profilePicture }}
cachePolicy="memory-disk" cachePolicy="memory-disk"
priority="high" priority="high"
@@ -168,9 +248,9 @@ const CommentsModal = ({ sheetId, payload }) => {
Aucun commentaire pour le moment Aucun commentaire pour le moment
</Text> </Text>
)} )}
</View>
<View style={{ marginTop: 6 }}> {/* INPUT en bas du contenu */}
<View style={{ height: 12 }} />
<BlurView <BlurView
intensity={20} intensity={20}
style={{ style={{
@@ -179,9 +259,9 @@ const CommentsModal = ({ sheetId, payload }) => {
gap: 10, gap: 10,
paddingHorizontal: 16, paddingHorizontal: 16,
backgroundColor: Palette.glass, backgroundColor: Palette.glass,
borderRadius: 16,
overflow: "hidden", overflow: "hidden",
height: 54, height: 54,
borderRadius: 16,
}} }}
experimentalBlurMethod={ experimentalBlurMethod={
Platform.OS !== "ios" ? "dimezisBlurView" : "none" Platform.OS !== "ios" ? "dimezisBlurView" : "none"
@@ -192,6 +272,8 @@ const CommentsModal = ({ sheetId, payload }) => {
placeholderTextColor="#FFFFFFAA" placeholderTextColor="#FFFFFFAA"
value={text} value={text}
onChangeText={setText} onChangeText={setText}
onFocus={() => setTyping(true)}
onBlur={() => setTyping(false)}
style={{ style={{
flex: 1, flex: 1,
color: Palette.white, color: Palette.white,
@@ -207,10 +289,11 @@ const CommentsModal = ({ sheetId, payload }) => {
/> />
</Pressable> </Pressable>
</BlurView> </BlurView>
</View> <View style={{ height: (insets?.bottom || 0) + 8 }} />
</View> </BottomSheetScrollView>
</AppActionSheet> </BlurView>
</BottomSheetModal>
); );
}; };
export default CommentsModal; export default CommentsBottomSheet;
+2
View File
@@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import { ActionSheetProvider } from "@expo/react-native-action-sheet"; import { ActionSheetProvider } from "@expo/react-native-action-sheet";
import { SafeAreaProvider } from "react-native-safe-area-context"; import { SafeAreaProvider } from "react-native-safe-area-context";
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
import UserDataProvider from "./UserDataProvider"; import UserDataProvider from "./UserDataProvider";
import WebViewProvider from "./WebViewProvider"; import WebViewProvider from "./WebViewProvider";
@@ -18,6 +19,7 @@ const SharedProviders = ({ children }) => {
[UserDataProvider, {}], [UserDataProvider, {}],
[StripeEmbeddedProvider, {}], [StripeEmbeddedProvider, {}],
[UniversalLinkProvider, {}], [UniversalLinkProvider, {}],
[BottomSheetModalProvider, {}],
[SheetProvider, {}], [SheetProvider, {}],
]; ];
+3 -9
View File
@@ -10,10 +10,10 @@ import React, {
useState, useState,
} from "react"; } from "react";
import { Image, Platform, Pressable, Text, View } from "react-native"; import { Image, Platform, Pressable, Text, View } from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import Carousel from "react-native-reanimated-carousel"; import Carousel from "react-native-reanimated-carousel";
import { responsiveHeight } from "react-native-responsive-dimensions"; import { responsiveHeight } from "react-native-responsive-dimensions";
import { icons, img } from "../assets"; import { icons, img } from "../assets";
import { openComments } from "../components/bottomsheets/CommentsBottomSheet";
import KaraokeLyrics from "../components/KaraokeLyrics"; import KaraokeLyrics from "../components/KaraokeLyrics";
import { import {
arrayRemove, arrayRemove,
@@ -355,16 +355,10 @@ const PlaybackItem = ({ item, isActive, userCache, getUserByUid }) => {
)} )}
</Pressable> </Pressable>
<Pressable <Pressable
onPress={() => { onPress={() => item?.id && openComments(item.id)}
if (item?.id) {
SheetManager.show("Comments", {
payload: { projectId: item.id },
});
}
}}
style={{ alignItems: "center" }} style={{ alignItems: "center" }}
> >
<Image source={icons.message} style={size({ size: 26 })} /> <Image source={icons.chatBubble} style={size({ size: 26 })} />
</Pressable> </Pressable>
<Pressable> <Pressable>
<Image source={icons.share} style={size({ size: 26 })} /> <Image source={icons.share} style={size({ size: 26 })} />
-2
View File
@@ -5,7 +5,6 @@ import DeleteAccountModal from "../components/modal/DeleteAccountModal";
import DeletePlaybackModal from "../components/modal/DeletePlaybackModal"; import DeletePlaybackModal from "../components/modal/DeletePlaybackModal";
import DeleteAudioModal from "../components/modal/DeleteAudioModal"; import DeleteAudioModal from "../components/modal/DeleteAudioModal";
import PlaylistModal from "../components/modal/PlaylistModal"; import PlaylistModal from "../components/modal/PlaylistModal";
import CommentsModal from "../components/modal/CommentsModal";
registerSheet("Delete", DeleteModal); registerSheet("Delete", DeleteModal);
registerSheet("ProfileSettings", ProfileSettingsModal); registerSheet("ProfileSettings", ProfileSettingsModal);
@@ -13,6 +12,5 @@ registerSheet("DeleteAccount", DeleteAccountModal);
registerSheet("DeletePlayback", DeletePlaybackModal); registerSheet("DeletePlayback", DeletePlaybackModal);
registerSheet("DeleteAudio", DeleteAudioModal); registerSheet("DeleteAudio", DeleteAudioModal);
registerSheet("Playlist", PlaylistModal); registerSheet("Playlist", PlaylistModal);
registerSheet("Comments", CommentsModal);
export {}; export {};