217 lines
7.0 KiB
JavaScript
217 lines
7.0 KiB
JavaScript
import { BlurView } from 'expo-blur'
|
|
import { useRoute } from '@react-navigation/native'
|
|
import React, { useCallback, useMemo, useState } from 'react'
|
|
import { Image, Pressable, Text, View } from 'react-native'
|
|
import { SheetManager } from 'react-native-actions-sheet'
|
|
import { useDataFromRef } from 'react-native-minuit/src/hooks'
|
|
import useDataFromArrayId from 'react-native-minuit/src/hooks/useDataFromArrayId'
|
|
import { useGlobal } from 'reactn'
|
|
import { background, icons } from '../../assets'
|
|
import MoreMenu from '../../components/MoreMenu'
|
|
import { playlistsRef, projectsRef } from '../../config/firebase'
|
|
import useNavigateToMusicDetails from '../../hooks/useNavigateToMusicDetails'
|
|
import usePlayer from '../../hooks/usePlayer'
|
|
import Page from '../../layouts/Page'
|
|
import { goBack } from '../../navigation/NavigationService'
|
|
import { gutters, Palette } from '../../styles'
|
|
import { FONT_FAMILY } from '../../styles/Fonts'
|
|
import { getProjectLikes, LIKE_TARGET } from '../../utils/likes'
|
|
import MusicCard from './components/MusicCard'
|
|
|
|
const PlaylistDetails = () => {
|
|
const [, setTooltip] = useGlobal('_tooltip')
|
|
const route = useRoute()
|
|
const playlistId = route?.params?.playlistId
|
|
|
|
// Fetch the playlist document
|
|
const { data: playlist } = useDataFromRef({
|
|
ref: playlistId ? playlistsRef.doc(playlistId) : null,
|
|
simpleRef: true,
|
|
listener: true,
|
|
condition: !!playlistId,
|
|
refreshArray: [playlistId],
|
|
})
|
|
|
|
// Fetch projects by ids from playlist.musics
|
|
const { data: musics } = useDataFromArrayId({
|
|
ref: projectsRef,
|
|
arrayId: Array.isArray(playlist?.musics) ? playlist.musics : [],
|
|
condition: Array.isArray(playlist?.musics) && playlist.musics.length > 0,
|
|
refreshArray: [playlistId, playlist?.musics?.length || 0],
|
|
})
|
|
|
|
const [menuPosition, setMenuPosition] = useState(null)
|
|
const [showMenu, setShowMenu] = useState(false)
|
|
const [selectedProjectId, setSelectedProjectId] = useState(null)
|
|
const navigateToMusicDetails = useNavigateToMusicDetails()
|
|
const { setQueue } = usePlayer() || {}
|
|
|
|
const playlistQueueItems = useMemo(() => {
|
|
if (!Array.isArray(musics)) return []
|
|
return musics
|
|
.map((project) => {
|
|
const projectId =
|
|
typeof project?.id === 'string' ? project.id : (project?.projectId ?? null)
|
|
const songUrl =
|
|
typeof project?.songUrl === 'string' && project.songUrl.length > 0
|
|
? project.songUrl
|
|
: null
|
|
if (!songUrl) return null
|
|
const descriptorId = projectId ? `project-${projectId}` : songUrl
|
|
return {
|
|
id: descriptorId,
|
|
uri: songUrl,
|
|
songUrl,
|
|
title: project?.title || 'Sans titre',
|
|
artist: project?.userName || '',
|
|
artwork: project?.coverUrl ?? null,
|
|
coverUrl: project?.coverUrl ?? null,
|
|
metadata: {
|
|
projectId,
|
|
playlistId: playlistId ?? null,
|
|
playlistName: playlist?.name ?? null,
|
|
},
|
|
context: {
|
|
projectId,
|
|
playlistId: playlistId ?? null,
|
|
playlistName: playlist?.name ?? null,
|
|
},
|
|
}
|
|
})
|
|
.filter(Boolean)
|
|
}, [musics, playlist?.name, playlistId])
|
|
|
|
const handlePlayFromPlaylist = useCallback(
|
|
(project) => {
|
|
if (!project?.id) return
|
|
if (Array.isArray(playlistQueueItems) && playlistQueueItems.length > 0) {
|
|
const queueIndex = playlistQueueItems.findIndex(
|
|
(item) => item?.metadata?.projectId === project.id
|
|
)
|
|
if (queueIndex >= 0 && typeof setQueue === 'function') {
|
|
setQueue({
|
|
items: playlistQueueItems,
|
|
id: playlistId,
|
|
type: 'playlist',
|
|
name: playlist?.name ?? null,
|
|
index: queueIndex,
|
|
})
|
|
}
|
|
}
|
|
navigateToMusicDetails({
|
|
projectId: project.id,
|
|
songUrl: project?.songUrl,
|
|
project,
|
|
})
|
|
},
|
|
[navigateToMusicDetails, playlist?.name, playlistId, playlistQueueItems, setQueue]
|
|
)
|
|
|
|
const confirmDelete = () => {
|
|
SheetManager.show('Delete', {
|
|
payload: {
|
|
title: 'Supprimer la playlist',
|
|
message: 'Es-tu sûr de vouloir supprimer cette playlist ?',
|
|
onConfirm: async () => {
|
|
try {
|
|
if (playlistId) {
|
|
await playlistsRef.doc(playlistId).delete()
|
|
setTooltip({ type: 'success', text: 'Playlist supprimée' })
|
|
}
|
|
} catch (e) {
|
|
console.log('Delete playlist error', e?.message)
|
|
setTooltip({
|
|
type: 'error',
|
|
text: e?.message || 'Suppression impossible',
|
|
})
|
|
} finally {
|
|
goBack()
|
|
}
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
const openAddTracks = useCallback(() => {
|
|
if (!playlistId) return
|
|
|
|
SheetManager.show('PlaylistAddTracks', {
|
|
payload: {
|
|
playlistId,
|
|
existingMusicIds: Array.isArray(playlist?.musics) ? playlist.musics : [],
|
|
},
|
|
})
|
|
}, [playlist?.musics, playlistId])
|
|
|
|
return (
|
|
<Page
|
|
headerType="NAVIGATION"
|
|
backgroundImg={background.libraryBG}
|
|
title={playlist?.name || 'Playlist'}
|
|
rightComponent={() => (
|
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
|
|
<Pressable onPress={openAddTracks}>
|
|
<BlurView intensity={20} tint="dark" style={styles.addTracksButton}>
|
|
<Text numberOfLines={1} style={styles.addTracksText}>
|
|
Ajouter des morceaux
|
|
</Text>
|
|
</BlurView>
|
|
</Pressable>
|
|
<Pressable onPress={confirmDelete}>
|
|
<Image source={icons.trash} style={{ width: 24, height: 24 }} />
|
|
</Pressable>
|
|
</View>
|
|
)}
|
|
contentContainerStyle={{ paddingBottom: gutters * 2 }}
|
|
>
|
|
<View style={{ flex: 1, gap: 10 }}>
|
|
{Array.isArray(musics) &&
|
|
musics.map((p) => (
|
|
<MusicCard
|
|
key={p.id}
|
|
title={p?.title}
|
|
subtitle={p?.userName}
|
|
imageUri={p?.coverUrl || null}
|
|
projectId={p?.id}
|
|
likedBy={getProjectLikes(p, LIKE_TARGET.SONG)}
|
|
likeTarget={LIKE_TARGET.SONG}
|
|
onPress={() => handlePlayFromPlaylist(p)}
|
|
onPressMore={(posTop) => {
|
|
setSelectedProjectId(p.id)
|
|
setMenuPosition(posTop)
|
|
setShowMenu((prev) => !prev || posTop?.top !== (menuPosition?.top ?? null))
|
|
}}
|
|
/>
|
|
))}
|
|
|
|
<MoreMenu
|
|
visible={showMenu}
|
|
top={menuPosition?.top ?? 0}
|
|
position={menuPosition}
|
|
onClose={() => setShowMenu(false)}
|
|
inPlaylist
|
|
playlistId={playlistId}
|
|
projectId={selectedProjectId}
|
|
/>
|
|
</View>
|
|
</Page>
|
|
)
|
|
}
|
|
|
|
export default PlaylistDetails
|
|
|
|
const styles = {
|
|
addTracksButton: {
|
|
paddingHorizontal: 12,
|
|
paddingVertical: 8,
|
|
borderRadius: 999,
|
|
overflow: 'hidden',
|
|
backgroundColor: Palette.glass,
|
|
},
|
|
addTracksText: {
|
|
color: Palette.white,
|
|
fontSize: 12,
|
|
fontFamily: FONT_FAMILY.InterSemiBold,
|
|
},
|
|
}
|