import { Routes } from "../navigation/Routes"; export const CREATION_STAGE_KEYS = [ "songwriter", "beatmaker", "director", "publisher", ]; const getSectionLyrics = (section) => { if (typeof section === "string") { return section.trim(); } if (section && typeof section === "object") { const value = typeof section.lyrics === "string" ? section.lyrics.trim() : ""; return value; } return ""; }; const getLyricsCount = (project) => { if (!project) return 0; const { lyrics } = project; if (Array.isArray(lyrics)) { return lyrics.reduce( (count, section) => (getSectionLyrics(section) ? count + 1 : count), 0, ); } if (lyrics && typeof lyrics === "object") { return Object.values(lyrics).reduce( (count, value) => (getSectionLyrics(value) ? count + 1 : count), 0, ); } return getSectionLyrics(lyrics) ? 1 : 0; }; const getStageMetadata = (project) => { const lyricsCount = getLyricsCount(project); const hasLyrics = !!(project?.hasLyrics || lyricsCount > 0); const hasSongUrl = !!project?.songUrl; const cover = project?.cover || {}; const hasCoverUrl = !!project?.coverUrl; const hasPlaybackAsset = !!project?.playbackUrl; const hasPlayback = hasPlaybackAsset || hasSongUrl; const youtubeUrl = project?.youtubeUrl ?? null; const youtubeStatus = project?.youtubeStatus ?? null; const youtubeError = project?.youtubeError ?? null; const hasYoutubePublication = !!youtubeUrl; const isYoutubePublishing = [ "PUBLISHING", "UPLOADING", "PROCESSING", "QUEUED", ].includes(youtubeStatus); const musicUrls = Array.isArray(project?.musicUrls) ? project.musicUrls.filter(Boolean) : []; const musicStatus = project?.musicStatus || null; const coverStatus = project?.coverStatus || null; const playbackStatus = project?.playbackStatus || null; const isPlaybackGenerating = project?.playbackGenerating === true || project?.isPlaybackGenerating === true || playbackStatus === "GENERATING"; return { lyricsCount, hasLyrics, hasSongUrl, hasCover: hasCoverUrl, hasPlayback, hasPlaybackAsset, hasMusicDraft: musicUrls.length > 0, musicStatus, coverStatus, playbackStatus, youtubeStatus, youtubeError, isMusicGenerating: musicStatus === "GENERATING", isCoverGenerating: coverStatus === "GENERATING", isPlaybackGenerating, hasYoutubePublication, isYoutubePublishing, }; }; const getStageLockState = (key, metadata) => { switch (key) { case "songwriter": return metadata.hasSongUrl; case "beatmaker": if (metadata.hasCover) { return true; } return metadata.lyricsCount <= 0; case "director": if (metadata.hasPlaybackAsset) { return true; } return !metadata.hasCover; case "publisher": return !metadata.hasPlaybackAsset; default: return true; } }; const getStageDescription = (key, metadata) => { const { hasLyrics, hasSongUrl, hasCover, hasPlaybackAsset, hasMusicDraft, isMusicGenerating, isPlaybackGenerating, } = metadata; switch (key) { case "songwriter": if (!hasLyrics) { return "Commencer à créer des paroles pour votre chanson"; } if (!hasSongUrl) { return "Continuer la création de paroles"; } return "Modifier les paroles créées"; case "beatmaker": if (metadata.hasCover) { return "Impossible de modifier la cover ou la production musicale"; } if (!hasLyrics) { return "Écrivez vos paroles pour débloquer la musique"; } if (isMusicGenerating) { return "Votre morceau est en cours de création"; } if (hasSongUrl) { if (!hasCover) { return "Créer ou modifier la cover de votre morceau"; } return "Modifier la cover ou la production musicale"; } if (hasMusicDraft) { return "Modifier la production musicale"; } return "Commencer la création de votre morceau"; case "director": if (!hasCover) { return "Générez une cover pour débloquer le playback"; } if (isPlaybackGenerating) { return "Votre playback est en cours de préparation"; } if (hasPlaybackAsset) { return "Modifier le playback généré"; } return "Commencer la création de votre playback"; case "publisher": if (!hasPlaybackAsset) { return "Créez un playback pour débloquer la publication"; } if (metadata.isYoutubePublishing) { return "Publication de votre vidéo en cours"; } if (metadata.youtubeError) { return "La publication a échoué, réessayez."; } if (metadata.hasYoutubePublication) { return "Votre vidéo est en ligne et prête à être partagée"; } return "Publier votre vidéo sur la chaîne YouTube MusicLand"; default: return ""; } }; const getStageLockedDescription = (key, metadata) => { switch (key) { case "songwriter": return metadata.hasSongUrl ? "Impossible de modifier les paroles" : undefined; case "beatmaker": if (metadata.hasCover) { return "Impossible de modifier la cover ou la production musicale"; } return metadata.lyricsCount > 0 ? undefined : "Créez vos paroles pour débloquer le studio"; case "director": return metadata.hasPlaybackAsset ? "Impossible de modifier le playback" : undefined; case "publisher": if (!metadata.hasPlaybackAsset) { return "Générez un playback pour débloquer la publication"; } return metadata.hasYoutubePublication ? "La vidéo est déjà publiée" : undefined; default: return undefined; } }; const getStageCompletionState = (key, metadata) => { switch (key) { case "songwriter": return metadata.hasLyrics; case "beatmaker": return metadata.hasSongUrl || metadata.musicStatus === "GENERATED"; case "director": return metadata.hasPlaybackAsset; case "publisher": return metadata.hasYoutubePublication; default: return false; } }; export const getCreationStageStates = (project) => { const metadata = getStageMetadata(project); return CREATION_STAGE_KEYS.map((key, index) => { const isLocked = getStageLockState(key, metadata); const description = getStageDescription(key, metadata); const lockedDescription = getStageLockedDescription(key, metadata); return { key, index, isLocked, isCompleted: getStageCompletionState(key, metadata), description: isLocked && lockedDescription ? lockedDescription : description, lockedDescription, }; }); }; export const getStageAction = (key, project) => { switch (key) { case "songwriter": return { route: getLyricsCount(project) > 0 ? Routes.Lyrics : Routes.WritingLyrics, }; case "beatmaker": { if (!project) { return { route: Routes.Compose }; } const musicStatus = project?.musicStatus || null; const songUrl = project?.songUrl || null; const coverStatus = project?.coverStatus || null; const cover = project?.cover || {}; const hasCoverBackground = !!cover?.generatedBackground; const hasCoverResult = !!cover?.result; const hasFinalCover = !!project?.coverUrl; if (musicStatus === "GENERATING") { return { route: Routes.GeneratingSong }; } if (!songUrl) { if (musicStatus === "GENERATED") { return { route: Routes.SongReady }; } return { route: Routes.Compose }; } if (coverStatus === "GENERATING") { return { route: Routes.PouchReady }; } if (!hasCoverBackground) { return { route: Routes.ChooseCoverType }; } if (!hasCoverResult) { return { route: Routes.PouchReady }; } if (!hasFinalCover) { return { route: Routes.ValidateCover }; } return { route: Routes.ChooseCoverType }; } case "director": return { route: Routes.Playback, params: project ? { project } : undefined, }; case "publisher": { if (!project?.id) { return { route: Routes.PublishYoutube }; } return { route: Routes.PublishYoutube, params: { projectId: project.id }, }; } default: return {}; } }; export const findFirstUnlockedStageIndex = (project) => { const stages = getCreationStageStates(project); if (!stages.length) { return 0; } const actionableIndex = stages.findIndex( (stage) => !stage.isCompleted && !stage.isLocked ); if (actionableIndex !== -1) { return actionableIndex; } const firstIncomplete = stages.findIndex((stage) => !stage.isCompleted); if (firstIncomplete !== -1) { return firstIncomplete; } const firstUnlocked = stages.findIndex((stage) => !stage.isLocked); if (firstUnlocked !== -1) { return firstUnlocked; } return stages.length - 1; };