import firebase, { tasksRef } from '../../config/firebase' import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { ActivityIndicator, Alert, StyleSheet, Text, View } from 'react-native' import { background } from '../../assets' import BorderGradientButton from '../../components/BorderGradientButton' import GradientButton from '../../components/GradientButton' import MusiclandPlaybackCover from '../../components/MusiclandPlaybackCover' import MusicLandHeader from '../../components/MusicLandHeader' import { uploadFileToFirebase } from '../../helpers/uploadToFirebase' import { isWeb } from '../../hooks/useLayoutType' import Page from '../../layouts/Page' import { Routes } from '../../navigation' import { goBack, navigate } from '../../navigation/NavigationService' import { useUser } from '../../providers/UserDataProvider' import { gutters, Palette, Style } from '../../styles' import { FONT_FAMILY } from '../../styles/Fonts' import { createMusiclandPlaybackCover } from '../../utils/createMusiclandPlaybackCover' import CreateLyricsHeader from '../Writing/components/CreateLyricsHeader' const COVER_TEMPLATE = 'MUSICLAND_PLAYBACKER' const COVER_OPTION_ID = 'musicland-playbacker' const PouchReady = () => { const { selectedProjectId, selectedProject, currentUserData, updateProjectData, } = useUser() const requestStartedRef = useRef(false) const [isSaving, setIsSaving] = useState(false) const templateCover = selectedProject?.cover?.template === COVER_TEMPLATE ? selectedProject.cover : null const coverUrl = templateCover?.result || null const isPreparing = selectedProject?.coverStatus === 'GENERATING' const hasPreparationError = selectedProject?.coverStatus === 'ERROR' const artistName = typeof selectedProject?.userName === 'string' && selectedProject.userName.trim() ? selectedProject.userName.trim() : currentUserData?.userName || 'MusicLand' const profilePictureURL = currentUserData?.profilePictureURL || null const centerImageURL = selectedProject?.coverCenterImageURL || profilePictureURL const selectedOption = useMemo(() => { if (!coverUrl) { return isWeb ? { id: COVER_OPTION_ID, finalUrl: null, generatedUrl: null, } : null } const savedOption = Array.isArray(templateCover?.options) ? templateCover.options[0] : null return ( savedOption || { id: COVER_TEMPLATE, finalUrl: coverUrl, generatedUrl: null, } ) }, [coverUrl, templateCover?.options]) const requestCoverPreparation = useCallback(async () => { if (!selectedProjectId || requestStartedRef.current || isPreparing) { return } requestStartedRef.current = true try { await updateProjectData( { coverStatus: 'PENDING', cover: { template: COVER_TEMPLATE, result: null, selectedOptionId: COVER_TEMPLATE, options: [], }, }, { merge: true } ) await tasksRef.add({ type: 'cover', projectId: selectedProjectId, status: 'PENDING', createdAt: firebase.firestore.FieldValue.serverTimestamp(), }) } catch (error) { requestStartedRef.current = false console.log('PouchReady: unable to prepare cover', error?.message) } }, [isPreparing, selectedProjectId, updateProjectData]) useEffect(() => { if (isWeb || coverUrl || isPreparing || hasPreparationError) { return } requestCoverPreparation() }, [coverUrl, hasPreparationError, isPreparing, requestCoverPreparation]) const retryPreparation = useCallback(() => { requestStartedRef.current = false requestCoverPreparation() }, [requestCoverPreparation]) const onValidatePicture = useCallback(async () => { if (!selectedOption) { return } try { setIsSaving(true) let optionToSave = selectedOption let projectToSave = selectedProject if (isWeb && !coverUrl) { const userId = selectedProject?.userId if (!userId || !selectedProjectId) { throw new Error('cover_project_identity_missing') } const coverBlob = await createMusiclandPlaybackCover({ artistName, profilePictureURL: centerImageURL, }) const storagePath = `users/${userId}/projects/${selectedProjectId}/cover-musicland-playbacker.png` const { resultURI } = await uploadFileToFirebase({ path: storagePath, fileType: 'IMAGE', blob: coverBlob, }) optionToSave = { id: COVER_OPTION_ID, finalUrl: resultURI, generatedUrl: null, } const cover = { template: COVER_TEMPLATE, result: resultURI, generatedBackground: null, selectedOptionId: COVER_OPTION_ID, options: [optionToSave], } await updateProjectData( { cover, coverStatus: 'GENERATED', }, { merge: true } ) projectToSave = { ...selectedProject, cover, coverStatus: 'GENERATED', } } navigate(Routes.SongDownload, { project: projectToSave, selectedOption: optionToSave, coverOptions: [optionToSave], backRoute: Routes.PouchReady, }) } catch (error) { console.log('PouchReady: unable to save cover', error?.message) Alert.alert( 'Enregistrement impossible', 'La pochette n’a pas pu être enregistrée. Réessaie dans quelques instants.' ) } finally { setIsSaving(false) } }, [ artistName, coverUrl, centerImageURL, selectedOption, selectedProject, selectedProjectId, updateProjectData, ]) return ( {!isWeb && !coverUrl && !hasPreparationError ? ( Préparation de ta pochette… ) : null} {hasPreparationError ? ( La pochette n’a pas pu être préparée. Tu peux réessayer. ) : null} ) } const styles = StyleSheet.create({ pageContent: { flex: 1, marginTop: 8, }, previewArea: { flex: 1, width: '100%', paddingHorizontal: gutters, gap: 16, }, coverWeb: { width: 360, maxWidth: '70%', }, coverMobile: { width: '86%', maxWidth: 380, }, preparingRow: { minHeight: 24, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 10, }, preparingText: { color: Palette.white, fontFamily: FONT_FAMILY.InterRegular, fontSize: 14, }, errorPanel: { width: isWeb ? 360 : '86%', maxWidth: 380, gap: 12, }, errorText: { color: Palette.white, fontFamily: FONT_FAMILY.InterRegular, fontSize: 14, lineHeight: 20, textAlign: 'center', }, footer: { width: '80%', maxWidth: 520, alignSelf: 'center', paddingBottom: gutters * 2, }, }) export default PouchReady