From f2659b9f71884840e6cd8afeef03854f89968916 Mon Sep 17 00:00:00 2001 From: ITurres Date: Tue, 24 Feb 2026 13:29:37 -0300 Subject: [PATCH 1/3] feat(studio/releases): gate pricing dialog for release creation Move the pricing dialog to the Releases CTA for Phase Two and gate '/releases/new' routing on 'dspPlanSubscribed'. When Phase Two is off, preserve the legacy 'upload-song' flow and 'mint' toggle behavior in 'BasicSongDetails'/'BasicTrackDetails'. --- .../src/pages/home/releases/Discography.tsx | 45 ++++++++++++++++++- .../src/pages/home/releases/Releases.tsx | 16 +++++++ .../release/tracks/BasicTrackDetails.tsx | 8 +++- .../home/uploadSong/BasicSongDetails.tsx | 12 +++-- 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/apps/studio/src/pages/home/releases/Discography.tsx b/apps/studio/src/pages/home/releases/Discography.tsx index 8228c9a8..9455219e 100644 --- a/apps/studio/src/pages/home/releases/Discography.tsx +++ b/apps/studio/src/pages/home/releases/Discography.tsx @@ -1,4 +1,5 @@ -import { FunctionComponent, useState } from "react"; +import { FunctionComponent, useMemo, useState } from "react"; +import { useNavigate } from "react-router-dom"; import { Box, Typography } from "@mui/material"; @@ -14,27 +15,66 @@ import { AddSong } from "@newm-web/assets"; import SongList from "./SongList"; import OfficialStatementCTA from "../../../components/OfficialStatementCTA"; -import { SearchBox } from "../../../components"; +import { DistributionPricingDialog, SearchBox } from "../../../components"; +import { emptyProfile, useGetProfileQuery } from "../../../modules/session"; import { useGetSongCountQuery } from "../../../modules/song"; const Discography: FunctionComponent = () => { + const navigate = useNavigate(); // TODO(webStudioAlbumPhaseTwo): Remove flag once flag is retired. const { webStudioAlbumPhaseTwo, webStudioDisableDistributionAndSales } = useFlags(); + const { + data: { + dspPlanSubscribed: isArtistPricePlanSelected = false, + } = emptyProfile, + } = useGetProfileQuery(); + const [query, setQuery] = useState(""); + const [isPricingDialogOpen, setIsPricingDialogOpen] = useState(false); const { data: { count: totalCountOfSongs = 0 } = {} } = useGetSongCountQuery({ ownerIds: ["me"], phrase: query, }); + const shouldGatePricingDialog = useMemo(() => { + return webStudioAlbumPhaseTwo && !isArtistPricePlanSelected; + }, [isArtistPricePlanSelected, webStudioAlbumPhaseTwo]); + const handleSearch = (searched: string) => { setQuery(searched); }; + const handleCreateReleaseClick = ( + event: React.MouseEvent + ) => { + if (!webStudioAlbumPhaseTwo) return; + if (!shouldGatePricingDialog) return; + event.preventDefault(); + setIsPricingDialogOpen(true); + }; + + const handlePricingDialogCancel = () => { + setIsPricingDialogOpen(false); + }; + + const handlePricingDialogConfirm = () => { + setIsPricingDialogOpen(false); + navigate("/home/releases/new"); + }; + return ( <> + { webStudioAlbumPhaseTwo && !isArtistPricePlanSelected && ( + + ) } + RELEASES @@ -66,6 +106,7 @@ const Discography: FunctionComponent = () => { ? "/home/releases/new" : "/home/upload-song" } + onClick={ handleCreateReleaseClick } > } message="Create New Release" /> diff --git a/apps/studio/src/pages/home/releases/Releases.tsx b/apps/studio/src/pages/home/releases/Releases.tsx index a9143d66..d94f547a 100644 --- a/apps/studio/src/pages/home/releases/Releases.tsx +++ b/apps/studio/src/pages/home/releases/Releases.tsx @@ -13,6 +13,7 @@ import TrackDetailsRouter from "./release/tracks/TrackDetailsRouter"; import Distribute from "./release/distribute/Distribute"; import NewTrack from "./release/tracks/NewTrack"; import NotFoundPage from "../../NotFoundPage"; +import { emptyProfile, useGetProfileQuery } from "../../../modules/session"; const Releases: FunctionComponent = () => { // TODO(webStudioAlbumPhaseTwo): Remove flag once flag is retired. @@ -20,6 +21,17 @@ const Releases: FunctionComponent = () => { const { webStudioAlbumPhaseTwo, webStudioDisableDistributionAndSales } = useFlags(); + const { + data: { + dspPlanSubscribed: isArtistPricePlanSelected = false, + } = emptyProfile, + } = useGetProfileQuery(); + + const shouldBlockReleaseCreation = + webStudioAlbumPhaseTwo && + !webStudioDisableDistributionAndSales && + !isArtistPricePlanSelected; + return ( { element={ webStudioDisableDistributionAndSales ? ( + ) : shouldBlockReleaseCreation ? ( + ) : ( ) @@ -58,6 +72,8 @@ const Releases: FunctionComponent = () => { element={ webStudioDisableDistributionAndSales ? ( + ) : shouldBlockReleaseCreation ? ( + ) : ( ) diff --git a/apps/studio/src/pages/home/releases/release/tracks/BasicTrackDetails.tsx b/apps/studio/src/pages/home/releases/release/tracks/BasicTrackDetails.tsx index aadc9469..5471870c 100644 --- a/apps/studio/src/pages/home/releases/release/tracks/BasicTrackDetails.tsx +++ b/apps/studio/src/pages/home/releases/release/tracks/BasicTrackDetails.tsx @@ -54,7 +54,11 @@ const BasicTrackDetails: FunctionComponent = ({ dspPlanSubscribed: isArtistPricePlanSelected = false, } = emptyProfile, } = useGetProfileQuery(); - const { webStudioDisableTrackDistributionAndMinting } = useFlags(); + const { + webStudioAlbumPhaseTwo, + webStudioDisableTrackDistributionAndMinting, + } = useFlags(); + const { data: genres = [] } = useGetGenresQuery(); const { data: moodOptions = [] } = useGetMoodsQuery(); const { data: languages = [] } = useGetLanguagesQuery(); @@ -137,7 +141,7 @@ const BasicTrackDetails: FunctionComponent = ({ return ( - { !isArtistPricePlanSelected && ( + { !webStudioAlbumPhaseTwo && !isArtistPricePlanSelected && ( = ({ const songDetailsRef = useRef(null); const { + // webStudioAlbumPhaseTwo, webStudioDisableTrackDistributionAndMinting, - webStudioDisableDistributionAndSales, + // webStudioDisableDistributionAndSales, } = useFlags(); + const webStudioDisableDistributionAndSales = false; + const webStudioAlbumPhaseTwo = false; + const isDistributionDisabled = webStudioDisableDistributionAndSales || webStudioDisableTrackDistributionAndMinting; @@ -210,7 +214,7 @@ const BasicSongDetails: FunctionComponent = ({ return ( - { !isArtistPricePlanSelected && ( + { !webStudioAlbumPhaseTwo && !isArtistPricePlanSelected && ( = ({ title="DISTRIBUTE & MINT SONG" toggleTooltipText={ tooltipContent } onClick={ () => { - if (!isArtistPricePlanSelected) handlePricingPlanOpen(); + if (!webStudioAlbumPhaseTwo && !isArtistPricePlanSelected) { + handlePricingPlanOpen(); + } } } /> From 44d8c519adb4f5c952dd678e5538d30d9bfc2cad Mon Sep 17 00:00:00 2001 From: ITurres Date: Wed, 25 Feb 2026 13:07:53 -0300 Subject: [PATCH 2/3] fix(studio/uploadSong): remove unnecessary 'webStudioAlbumPhaseTwo' gating in 'BasicSongDetails' --- .../src/pages/home/uploadSong/BasicSongDetails.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/studio/src/pages/home/uploadSong/BasicSongDetails.tsx b/apps/studio/src/pages/home/uploadSong/BasicSongDetails.tsx index a05ca445..78fa1bb1 100644 --- a/apps/studio/src/pages/home/uploadSong/BasicSongDetails.tsx +++ b/apps/studio/src/pages/home/uploadSong/BasicSongDetails.tsx @@ -86,14 +86,10 @@ const BasicSongDetails: FunctionComponent = ({ const songDetailsRef = useRef(null); const { - // webStudioAlbumPhaseTwo, webStudioDisableTrackDistributionAndMinting, - // webStudioDisableDistributionAndSales, + webStudioDisableDistributionAndSales, } = useFlags(); - const webStudioDisableDistributionAndSales = false; - const webStudioAlbumPhaseTwo = false; - const isDistributionDisabled = webStudioDisableDistributionAndSales || webStudioDisableTrackDistributionAndMinting; @@ -214,7 +210,7 @@ const BasicSongDetails: FunctionComponent = ({ return ( - { !webStudioAlbumPhaseTwo && !isArtistPricePlanSelected && ( + { !isArtistPricePlanSelected && ( = ({ title="DISTRIBUTE & MINT SONG" toggleTooltipText={ tooltipContent } onClick={ () => { - if (!webStudioAlbumPhaseTwo && !isArtistPricePlanSelected) { + if (!isArtistPricePlanSelected) { handlePricingPlanOpen(); } } } From e1902d6d0f418615bbb4e9810291c8b7ef4bd9f4 Mon Sep 17 00:00:00 2001 From: ITurres Date: Wed, 25 Feb 2026 13:10:29 -0300 Subject: [PATCH 3/3] refactor(studio/releases): remove pricing dialog wiring from phase-two track details Drop profile query and pricing dialog logic from 'BasicTrackDetails'. Phase-two flow no longer uses the mint toggle or plan gating. --- .../release/tracks/BasicTrackDetails.tsx | 45 +------------------ 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/apps/studio/src/pages/home/releases/release/tracks/BasicTrackDetails.tsx b/apps/studio/src/pages/home/releases/release/tracks/BasicTrackDetails.tsx index 5471870c..e546c5d8 100644 --- a/apps/studio/src/pages/home/releases/release/tracks/BasicTrackDetails.tsx +++ b/apps/studio/src/pages/home/releases/release/tracks/BasicTrackDetails.tsx @@ -1,9 +1,7 @@ -import { FunctionComponent, useEffect, useRef, useState } from "react"; +import { FunctionComponent, useEffect, useRef } from "react"; import { useFormikContext } from "formik"; -import { useFlags } from "launchdarkly-react-client-sdk"; - import { Box, Link, Stack, Typography, useTheme } from "@mui/material"; import { @@ -24,17 +22,13 @@ import { NEWM_STUDIO_FAQ_URL, SONG_DESCRIPTION_MAX_CHARACTER_COUNT, } from "../../../../../common"; -import { DistributionPricingDialog, PlaySong } from "../../../../../components"; +import { PlaySong } from "../../../../../components"; import SelectCoCreators from "../../../../../components/minting/SelectCoCreators"; import { useGetGenresQuery, useGetLanguagesQuery, useGetMoodsQuery, } from "../../../../../modules/content"; -import { - emptyProfile, - useGetProfileQuery, -} from "../../../../../modules/session"; import { Creditor, Featured, Owner } from "../../../../../modules/song"; interface BasicTrackDetailsProps { @@ -49,16 +43,6 @@ const BasicTrackDetails: FunctionComponent = ({ trackId = "", }) => { const theme = useTheme(); - const { - data: { - dspPlanSubscribed: isArtistPricePlanSelected = false, - } = emptyProfile, - } = useGetProfileQuery(); - const { - webStudioAlbumPhaseTwo, - webStudioDisableTrackDistributionAndMinting, - } = useFlags(); - const { data: genres = [] } = useGetGenresQuery(); const { data: moodOptions = [] } = useGetMoodsQuery(); const { data: languages = [] } = useGetLanguagesQuery(); @@ -80,24 +64,6 @@ const BasicTrackDetails: FunctionComponent = ({ initialValues, } = useFormikContext(); - // DSP pricing plan mint song toggling - const [isPricingPlansOpen, setIsPricingPlansOpen] = useState(false); - const handlePricingPlanCancel = () => { - setIsPricingPlansOpen(false); - setFieldValue("isMinting", false); - }; - const handlePricingPlanConfirm = () => { - setIsPricingPlansOpen(false); - setFieldValue("isMinting", true); - }; - - // Monitor feature flag changes, particularly seen for pricing plan acceptance - useEffect(() => { - if (webStudioDisableTrackDistributionAndMinting) { - setFieldValue("isMinting", false); - } - }, [webStudioDisableTrackDistributionAndMinting, setFieldValue]); - const hasCoverArtChanged = values.coverArtUrl !== initialValues.coverArtUrl; const handleChangeOwners = (owners: ReadonlyArray) => { @@ -141,13 +107,6 @@ const BasicTrackDetails: FunctionComponent = ({ return ( - { !webStudioAlbumPhaseTwo && !isArtistPricePlanSelected && ( - - ) }