minors fixes

This commit is contained in:
Thomas Demirdjian
2025-12-09 09:47:26 +01:00
parent 9c2087c574
commit 3f799af419
8 changed files with 155 additions and 164 deletions
+2 -1
View File
@@ -6,7 +6,8 @@
"firebase-debug.log", "firebase-debug.log",
"firebase-debug.*.log" "firebase-debug.*.log"
], ],
"predeploy": [] "predeploy": [],
"source": "functions"
}, },
"emulators": { "emulators": {
"functions": { "functions": {
-31
View File
@@ -7358,30 +7358,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/winston": {
"version": "3.18.3",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.18.3.tgz",
"integrity": "sha512-NoBZauFNNWENgsnC9YpgyYwOVrl2m58PpQ8lNHjV3kosGs7KJ7Npk9pCUE+WJlawVSe8mykWDKWFSVfs3QO9ww==",
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@colors/colors": "^1.6.0",
"@dabh/diagnostics": "^2.0.8",
"async": "^3.2.3",
"is-stream": "^2.0.0",
"logform": "^2.7.0",
"one-time": "^1.0.0",
"readable-stream": "^3.4.0",
"safe-stable-stringify": "^2.3.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.9.0"
},
"engines": {
"node": ">= 12.0.0"
}
},
"node_modules/winston-transport": { "node_modules/winston-transport": {
"version": "4.9.0", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
@@ -7397,13 +7373,6 @@
"node": ">= 12.0.0" "node": ">= 12.0.0"
} }
}, },
"node_modules/winston/node_modules/async": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
"license": "MIT",
"optional": true
},
"node_modules/word-wrap": { "node_modules/word-wrap": {
"version": "1.2.5", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+4 -4
View File
@@ -50,12 +50,12 @@ if (!firebase?.apps?.filter(({ name_ }) => name_ === "[DEFAULT]").length) {
persistence: getReactNativePersistence(AsyncStorage), persistence: getReactNativePersistence(AsyncStorage),
}); });
if (__DEV__) { // if (__DEV__) {
firebase.functions().useEmulator("localhost", 5001); // firebase.functions().useEmulator("localhost", 5001);
} // configureFunctionsEmulator(defaultFunctions, "us-central1");
// }
const defaultFunctions = firebase.functions(); const defaultFunctions = firebase.functions();
functionsInstances["us-central1"] = defaultFunctions; functionsInstances["us-central1"] = defaultFunctions;
configureFunctionsEmulator(defaultFunctions, "us-central1");
console.log("Firebase init"); console.log("Firebase init");
} }
+16 -33
View File
@@ -60,10 +60,10 @@ const HitParade = () => {
[topSongs] [topSongs]
); );
const [playbacksCol1, playbacksCol2] = useMemo(() => { const playbackList = useMemo(
const arr = Array.isArray(topPlaybacks) ? topPlaybacks : []; () => (Array.isArray(topPlaybacks) ? topPlaybacks : []),
return [arr.slice(0, 5), arr.slice(5)]; [topPlaybacks]
}, [topPlaybacks]); );
const resolvePlaybackThumbnail = useCallback((project) => { const resolvePlaybackThumbnail = useCallback((project) => {
const candidates = [ const candidates = [
@@ -110,7 +110,7 @@ const HitParade = () => {
gap: 10, gap: 10,
paddingBottom: responsiveHeight(20), paddingBottom: responsiveHeight(20),
}} }}
data={Array.isArray(topPlaybacks) ? topPlaybacks : []} data={playbackList}
keyExtractor={(item) => item.id} keyExtractor={(item) => item.id}
renderItem={({ item, index }) => ( renderItem={({ item, index }) => (
<PlaybacksCard <PlaybacksCard
@@ -146,34 +146,17 @@ const HitParade = () => {
); );
const renderPlaybackColumns = () => ( const renderPlaybackColumns = () => (
<View style={{ flexDirection: "row", gap: 10, alignItems: "flex-start" }}> <View style={{ gap: 10 }}>
<View style={{ flex: 1, gap: 10 }}> {playbackList.map((item, idx) => (
{playbacksCol1.map((item, idx) => ( <PlaybacksCard
<PlaybacksCard key={item.id}
key={item.id} rank={idx + 1}
rank={idx + 1} title={item?.title || "Sans titre"}
title={item?.title || "Sans titre"} artist={item?.userName}
artist={item?.userName} thumbnailUrl={resolvePlaybackThumbnail(item)}
thumbnailUrl={resolvePlaybackThumbnail(item)} onPress={() => navigate(Routes.Playbacks, { projectId: item.id })}
onPress={() => navigate(Routes.Playbacks, { projectId: item.id })} />
/> ))}
))}
</View>
{playbacksCol2.length > 0 && (
<View style={{ flex: 1, gap: 10 }}>
{playbacksCol2.map((item, idx) => (
<PlaybacksCard
key={item.id}
rank={5 + idx + 1}
title={item?.title || "Sans titre"}
artist={item?.userName}
thumbnailUrl={resolvePlaybackThumbnail(item)}
onPress={() => navigate(Routes.Playbacks, { projectId: item.id })}
/>
))}
</View>
)}
</View> </View>
); );
+4 -3
View File
@@ -12,11 +12,10 @@ import {
import { background, icons } from "../assets"; import { background, icons } from "../assets";
import FullscreenIntroVideo from "../components/FullscreenIntroVideo"; import FullscreenIntroVideo from "../components/FullscreenIntroVideo";
import GradientButton from "../components/GradientButton"; import GradientButton from "../components/GradientButton";
import { LinearGradient } from "../components/LinearGradient/LinearGradient";
import { videosRef } from "../config/firebase"; import { videosRef } from "../config/firebase";
import useDataFromRef from "../hooks/useDataFromRef"; import useDataFromRef from "../hooks/useDataFromRef";
import Page from "../layouts/Page"; import Page from "../layouts/Page";
import { Routes } from "../navigation/Routes"; import { Routes } from "../navigation";
import { useUser } from "../providers/UserDataProvider"; 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";
@@ -154,7 +153,9 @@ export default function LandingPage() {
title="Présentation de Musicland" title="Présentation de Musicland"
onPress={() => onPress={() =>
setVideoUrl( setVideoUrl(
Platform.OS === "web" ? video?.landingWeb : video?.landing Platform.OS === "web"
? video?.landingWeb
: video?.landing,
) )
} }
containerStyle={styles.actionButton} containerStyle={styles.actionButton}
@@ -14,6 +14,7 @@ import { background } from "../../assets";
import FullscreenIntroVideo from "../../components/FullscreenIntroVideo"; import FullscreenIntroVideo from "../../components/FullscreenIntroVideo";
import BorderGradientButton from "../../components/BorderGradientButton"; import BorderGradientButton from "../../components/BorderGradientButton";
import MusicLandHeader from "../../components/MusicLandHeader"; import MusicLandHeader from "../../components/MusicLandHeader";
import AppCheckbox from "../../components/AppCheckbox";
import firebase, { import firebase, {
projectsRef, projectsRef,
serverTimestamp, serverTimestamp,
@@ -143,6 +144,7 @@ const PlaybackDownload = ({ route }) => {
project?.playbackUrl || null, project?.playbackUrl || null,
); );
const [isPublishing, setIsPublishing] = useState(false); const [isPublishing, setIsPublishing] = useState(false);
const [hasAcceptedPublication, setHasAcceptedPublication] = useState(true);
const hasShownAfterPlaybackRef = useRef(false); const hasShownAfterPlaybackRef = useRef(false);
const { data: video } = useDataFromRef({ const { data: video } = useDataFromRef({
@@ -284,6 +286,13 @@ const PlaybackDownload = ({ route }) => {
const handlePublish = async () => { const handlePublish = async () => {
if (isPublishing) return; if (isPublishing) return;
if (!hasAcceptedPublication) {
setTooltip({
type: "error",
text: "Confirme la diffusion sur Musicland et YouTube avant de publier",
});
return;
}
if (!project?.id) { if (!project?.id) {
if (action === "playback") { if (action === "playback") {
setTooltip({ setTooltip({
@@ -429,6 +438,19 @@ const PlaybackDownload = ({ route }) => {
<ClubAdvantagesCard style={styles.clubCardSpacing} /> <ClubAdvantagesCard style={styles.clubCardSpacing} />
<View style={styles.publishConsentContainer}>
<AppCheckbox
selected={hasAcceptedPublication}
onPress={() =>
setHasAcceptedPublication((prevState) => !prevState)
}
label="J'accepte la diffusion de mon playback sur Musicland et YouTube."
/>
<Text style={styles.publishConsentDescription}>
Cette confirmation est requise avant de lancer la publication.
</Text>
</View>
<BorderGradientButton <BorderGradientButton
title={continueLabel} title={continueLabel}
onPress={() => { onPress={() => {
@@ -438,6 +460,7 @@ const PlaybackDownload = ({ route }) => {
setShowConfirmModal(true); setShowConfirmModal(true);
} }
}} }}
disabled={isPublishing || !hasAcceptedPublication}
containerStyle={styles.continueButton} containerStyle={styles.continueButton}
/> />
</ScrollView> </ScrollView>
@@ -491,6 +514,16 @@ const styles = StyleSheet.create({
clubCardSpacing: { clubCardSpacing: {
marginTop: 10, marginTop: 10,
}, },
publishConsentContainer: {
gap: 6,
marginTop: 2,
},
publishConsentDescription: {
fontFamily: FONT_FAMILY.InterRegular,
fontSize: 13,
color: Palette.white,
opacity: 0.8,
},
continueButton: { continueButton: {
marginTop: 10, marginTop: 10,
}, },
+46 -3
View File
@@ -1,8 +1,9 @@
import { useRoute } from "@react-navigation/native"; import { useRoute } from "@react-navigation/native";
import React, { useCallback, useMemo, useState } from "react"; import React, { useCallback, useMemo, useState } from "react";
import { Linking, Text, View } from "react-native"; import { Linking, StyleSheet, Text, View } from "react-native";
import useMinuit from "react-native-minuit/src/hooks/useMinuit.js"; import useMinuit from "react-native-minuit/src/hooks/useMinuit.js";
import { background } from "../../assets"; import { background } from "../../assets";
import AppCheckbox from "../../components/AppCheckbox";
import BorderGradientButton from "../../components/BorderGradientButton"; import BorderGradientButton from "../../components/BorderGradientButton";
import GradientButton from "../../components/GradientButton"; import GradientButton from "../../components/GradientButton";
import MusicLandHeader from "../../components/MusicLandHeader"; import MusicLandHeader from "../../components/MusicLandHeader";
@@ -37,6 +38,7 @@ const PublishYoutube = () => {
const projectId = project?.id || routeProjectId || null; const projectId = project?.id || routeProjectId || null;
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const [hasAcceptedPublication, setHasAcceptedPublication] = useState(true);
const youtubeUrl = project?.youtubeUrl ?? null; const youtubeUrl = project?.youtubeUrl ?? null;
const youtubeStatus = project?.youtubeStatus ?? null; const youtubeStatus = project?.youtubeStatus ?? null;
const youtubeError = project?.youtubeError ?? null; const youtubeError = project?.youtubeError ?? null;
@@ -50,7 +52,11 @@ const PublishYoutube = () => {
[youtubeStatus] [youtubeStatus]
); );
const publishDisabled = const publishDisabled =
saving || isPublishing || !playbackReady || !projectId; saving ||
isPublishing ||
!playbackReady ||
!projectId ||
!hasAcceptedPublication;
const publishButtonLabel = isPublishing const publishButtonLabel = isPublishing
? "Publication en cours..." ? "Publication en cours..."
: hasYoutubePublication : hasYoutubePublication
@@ -128,6 +134,13 @@ const PublishYoutube = () => {
}, [playbackReady, projectId, setTooltip]); }, [playbackReady, projectId, setTooltip]);
const handleConfirmPublish = useCallback(() => { const handleConfirmPublish = useCallback(() => {
if (!hasAcceptedPublication) {
setTooltip?.({
type: "error",
text: "Confirme la diffusion sur Musicland et YouTube avant de publier",
});
return;
}
if (publishDisabled) { if (publishDisabled) {
return; return;
} }
@@ -144,7 +157,13 @@ const PublishYoutube = () => {
onPress: handleMarkPublished, onPress: handleMarkPublished,
}, },
]); ]);
}, [handleMarkPublished, hasYoutubePublication, publishDisabled]); }, [
handleMarkPublished,
hasAcceptedPublication,
hasYoutubePublication,
publishDisabled,
setTooltip,
]);
const handleResetPublication = useCallback(async () => { const handleResetPublication = useCallback(async () => {
if (!projectId) { if (!projectId) {
@@ -246,6 +265,18 @@ const PublishYoutube = () => {
)} )}
</View> </View>
<View style={{ gap: 14 }}> <View style={{ gap: 14 }}>
<View style={styles.consentContainer}>
<AppCheckbox
selected={hasAcceptedPublication}
onPress={() =>
setHasAcceptedPublication((prevState) => !prevState)
}
label="J'accepte la diffusion de mon contenu sur Musicland et YouTube."
/>
<Text style={styles.consentDescription}>
Cette confirmation est requise avant toute mise en ligne.
</Text>
</View>
<GradientButton <GradientButton
title={publishButtonLabel} title={publishButtonLabel}
onPress={handleConfirmPublish} onPress={handleConfirmPublish}
@@ -272,4 +303,16 @@ const PublishYoutube = () => {
); );
}; };
const styles = StyleSheet.create({
consentContainer: {
gap: 6,
},
consentDescription: {
fontSize: 13,
fontFamily: FONT_FAMILY.InterRegular,
color: Palette.white,
opacity: 0.8,
},
});
export default PublishYoutube; export default PublishYoutube;
+50 -89
View File
@@ -70,9 +70,13 @@ const getIntervalLabel = (recurring) => {
}; };
function SubscriptionCard({ plan, selected, onSelect }) { function SubscriptionCard({ plan, selected, onSelect }) {
const planKey = getPlanKeyForBadge(plan);
const planName = const planName =
plan?.product?.name || plan?.nickname || plan?.priceId || "Abonnement"; (planKey && PLAN_DISPLAY_NAME_BY_KEY[planKey]) ||
const planDescription = plan?.product?.description || ""; plan?.product?.name ||
plan?.nickname ||
plan?.priceId ||
"Abonnement";
const formattedPrice = formatCurrency(plan?.unitAmount, plan?.currency); const formattedPrice = formatCurrency(plan?.unitAmount, plan?.currency);
const intervalLabel = getIntervalLabel(plan?.recurring); const intervalLabel = getIntervalLabel(plan?.recurring);
const coinsPerMonth = const coinsPerMonth =
@@ -80,21 +84,10 @@ function SubscriptionCard({ plan, selected, onSelect }) {
Number.isFinite(plan.coinsPerMonth) Number.isFinite(plan.coinsPerMonth)
? Math.round(plan.coinsPerMonth) ? Math.round(plan.coinsPerMonth)
: null; : null;
const songsPerMonth = const planBadgeKey = planKey;
coinsPerMonth !== null
? Math.floor(coinsPerMonth / CREDITS_PER_MUSIC)
: null;
const songsPerMonthLabel =
songsPerMonth === null
? null
: songsPerMonth >= 1
? `${songsPerMonth} ${
songsPerMonth > 1 ? "musiques" : "musique"
} / mois`
: "Moins d'une musique / mois";
const planBadgeKey = getPlanKeyForBadge(plan);
const planBadgeSource = const planBadgeSource =
planBadgeKey && subBadges[planBadgeKey] ? subBadges[planBadgeKey] : null; planBadgeKey && subBadges[planBadgeKey] ? subBadges[planBadgeKey] : null;
const planFeatures = SUBSCRIPTION_FEATURES;
const handleSelect = React.useCallback(() => { const handleSelect = React.useCallback(() => {
if (typeof onSelect === "function" && plan?.priceId) { if (typeof onSelect === "function" && plan?.priceId) {
onSelect(plan.priceId); onSelect(plan.priceId);
@@ -138,14 +131,16 @@ function SubscriptionCard({ plan, selected, onSelect }) {
) : null} ) : null}
</View> </View>
{formattedPrice ? ( {formattedPrice || coinsPerMonth !== null ? (
<View style={styles.priceBlock}> <View style={styles.priceBlock}>
<View style={styles.priceRow}> {formattedPrice ? (
<Text style={styles.priceValue}>{formattedPrice}</Text> <View style={styles.priceRow}>
{intervalLabel ? ( <Text style={styles.priceValue}>{formattedPrice}</Text>
<Text style={styles.period}>{intervalLabel}</Text> {intervalLabel ? (
) : null} <Text style={styles.period}>{intervalLabel}</Text>
</View> ) : null}
</View>
) : null}
{coinsPerMonth !== null ? ( {coinsPerMonth !== null ? (
<View style={styles.coinsPerMonthRow}> <View style={styles.coinsPerMonthRow}>
<CreditAmount <CreditAmount
@@ -153,19 +148,22 @@ function SubscriptionCard({ plan, selected, onSelect }) {
showPlus showPlus
textStyle={styles.coinsPerMonth} textStyle={styles.coinsPerMonth}
iconSize={16} iconSize={16}
accessibilityLabel={`+${coinsPerMonth} pièces par mois`} accessibilityLabel={`+${coinsPerMonth} crédits par mois`}
/> />
<Text style={styles.coinsPerMonthSuffix}>/ mois</Text> <Text style={styles.coinsPerMonthSuffix}>/ mois</Text>
</View> </View>
) : null} ) : null}
{songsPerMonthLabel ? (
<Text style={styles.songsPerMonth}>{songsPerMonthLabel}</Text>
) : null}
</View> </View>
) : null} ) : null}
{planDescription ? ( {planFeatures?.length ? (
<Text style={styles.description}>{planDescription}</Text> <View style={styles.features}>
{planFeatures.map((feature) => (
<Text key={feature} style={styles.featureText}>
{feature}
</Text>
))}
</View>
) : null} ) : null}
</View> </View>
</BlurView> </BlurView>
@@ -174,11 +172,6 @@ function SubscriptionCard({ plan, selected, onSelect }) {
} }
const PRICE_PRIORITY_BY_PERIOD = { const PRICE_PRIORITY_BY_PERIOD = {
monthly: [
"price_1SPgitCzf2o5bDRdbnhLFx6f", // Starter
"price_1SPgjCCzf2o5bDRdr08Xzp8u", // Pro
"price_1SPgjaCzf2o5bDRdd9Xo2u26", // Premium
],
annual: [ annual: [
"price_1SPgkDCzf2o5bDRdNGLVNeQ3", // Starter "price_1SPgkDCzf2o5bDRdNGLVNeQ3", // Starter
"price_1SPgkXCzf2o5bDRdejBVxEBY", // Pro "price_1SPgkXCzf2o5bDRdejBVxEBY", // Pro
@@ -187,16 +180,9 @@ const PRICE_PRIORITY_BY_PERIOD = {
}; };
const PACK_PRICE_ID_BY_PERIOD = { const PACK_PRICE_ID_BY_PERIOD = {
monthly: {
starter: "price_1SPgitCzf2o5bDRdbnhLFx6f",
pro: "price_1SPgjCCzf2o5bDRdr08Xzp8u",
prop: "price_1SPgjCCzf2o5bDRdr08Xzp8u",
premium: "price_1SPgjaCzf2o5bDRdd9Xo2u26",
},
annual: { annual: {
starter: "price_1SPgkDCzf2o5bDRdNGLVNeQ3", starter: "price_1SPgkDCzf2o5bDRdNGLVNeQ3",
pro: "price_1SPgkXCzf2o5bDRdejBVxEBY", pro: "price_1SPgkXCzf2o5bDRdejBVxEBY",
prop: "price_1SPgkXCzf2o5bDRdejBVxEBY",
premium: "price_1SPgkqCzf2o5bDRdIcUwTDrm", premium: "price_1SPgkqCzf2o5bDRdIcUwTDrm",
}, },
}; };
@@ -208,7 +194,7 @@ Object.values(PACK_PRICE_ID_BY_PERIOD).forEach((mapping) => {
if (!priceId) { if (!priceId) {
return; return;
} }
PRICE_ID_TO_PLAN_KEY[priceId] = planKey === "prop" ? "pro" : planKey; PRICE_ID_TO_PLAN_KEY[priceId] = planKey;
}); });
}); });
@@ -216,10 +202,22 @@ const PLAN_FALLBACK_ORDER = ["starter", "pro", "premium"];
const PLAN_SYNONYMS = { const PLAN_SYNONYMS = {
starter: ["starter"], starter: ["starter"],
pro: ["pro", "prop"], pro: ["pro"],
premium: ["premium"], premium: ["premium"],
}; };
const PLAN_DISPLAY_NAME_BY_KEY = {
starter: "Play Backer Blue",
pro: "Play Backer Silver",
premium: "Play Backer Gold",
};
const SUBSCRIPTION_FEATURES = [
"*Eligible au Hit parade Vidéo",
"Privilège Membre : Récompense doublée",
"Eligible au hit parade Artiste trimestriel et annuel",
];
const getPlanKeyForBadge = (plan) => { const getPlanKeyForBadge = (plan) => {
if (!plan || typeof plan !== "object") { if (!plan || typeof plan !== "object") {
return null; return null;
@@ -296,7 +294,6 @@ const PAGE_BACKGROUND_COLOR = "#303438";
const SUBSCRIPTION_DISCLAIMER = const SUBSCRIPTION_DISCLAIMER =
"Résiliable en un clic à tout moment. Les prix sont indiqués TTC. Contacte-nous pour des besoins spécifiques (facturation annuelle, volume, offres éducation)."; "Résiliable en un clic à tout moment. Les prix sont indiqués TTC. Contacte-nous pour des besoins spécifiques (facturation annuelle, volume, offres éducation).";
const CARD_MIN_HEIGHT = isWeb ? 320 : 240; const CARD_MIN_HEIGHT = isWeb ? 320 : 240;
const CREDITS_PER_MUSIC = 8;
export default function Subscriptions() { export default function Subscriptions() {
const route = useRoute(); const route = useRoute();
@@ -456,8 +453,6 @@ export default function Subscriptions() {
); );
}, [combinedErrorMessage]); }, [combinedErrorMessage]);
const renderSegmentedControl = React.useCallback(() => null, []);
const renderMobilePlanItem = React.useCallback( const renderMobilePlanItem = React.useCallback(
({ item }) => ( ({ item }) => (
<View style={styles.mobileCard}> <View style={styles.mobileCard}>
@@ -502,10 +497,9 @@ export default function Subscriptions() {
return ( return (
<View style={styles.mobileStickyHeader}> <View style={styles.mobileStickyHeader}>
{renderHeaderSection()} {renderHeaderSection()}
{renderSegmentedControl()}
</View> </View>
); );
}, [renderHeaderSection, renderSegmentedControl]); }, [renderHeaderSection]);
const renderMobileBottomActions = React.useCallback(() => { const renderMobileBottomActions = React.useCallback(() => {
return ( return (
@@ -606,8 +600,6 @@ export default function Subscriptions() {
</Text> </Text>
) : null} ) : null}
{renderSegmentedControl()}
<View style={[styles.packs, isWeb && styles.packsWeb]}> <View style={[styles.packs, isWeb && styles.packsWeb]}>
{currentPlans.map((plan) => ( {currentPlans.map((plan) => (
<SubscriptionCard <SubscriptionCard
@@ -768,32 +760,6 @@ const styles = StyleSheet.create({
alignItems: "stretch", alignItems: "stretch",
justifyContent: "center", justifyContent: "center",
}, },
segmentedControl: {
flexDirection: "row",
alignSelf: "center",
justifyContent: "center",
padding: 4,
borderRadius: 999,
backgroundColor: "rgba(255, 255, 255, 0.08)",
marginTop: isWeb ? 12 : 8,
marginBottom: isWeb ? 8 : 4,
},
segmentButton: {
paddingVertical: 8,
paddingHorizontal: 18,
borderRadius: 999,
},
segmentButtonActive: {
backgroundColor: "rgba(255, 255, 255, 0.18)",
},
segmentLabel: {
fontFamily: FONT_FAMILY.InterMedium,
fontSize: 14,
color: "rgba(255, 255, 255, 0.7)",
},
segmentLabelActive: {
color: Palette.white,
},
actions: { actions: {
width: "100%", width: "100%",
alignItems: "center", alignItems: "center",
@@ -888,10 +854,15 @@ const styles = StyleSheet.create({
fontSize: 13, fontSize: 13,
color: Palette.primary, color: Palette.primary,
}, },
songsPerMonth: { features: {
fontFamily: FONT_FAMILY.InterRegular, marginTop: isWeb ? 12 : 8,
fontSize: 12, gap: 6,
color: "rgba(255, 255, 255, 0.75)", },
featureText: {
fontFamily: FONT_FAMILY.InterMedium,
fontSize: 13,
lineHeight: 18,
color: "rgba(255, 255, 255, 0.85)",
}, },
priceValue: { priceValue: {
fontFamily: FONT_FAMILY.InterBold, fontFamily: FONT_FAMILY.InterBold,
@@ -903,12 +874,6 @@ const styles = StyleSheet.create({
fontSize: 14, fontSize: 14,
color: "rgba(255, 255, 255, 0.7)", color: "rgba(255, 255, 255, 0.7)",
}, },
description: {
fontFamily: FONT_FAMILY.InterRegular,
fontSize: 14,
lineHeight: 22,
color: Palette.white,
},
badge: { badge: {
alignSelf: "flex-start", alignSelf: "flex-start",
paddingHorizontal: 12, paddingHorizontal: 12,
@@ -939,10 +904,6 @@ const styles = StyleSheet.create({
backgroundColor: PAGE_BACKGROUND_COLOR, backgroundColor: PAGE_BACKGROUND_COLOR,
alignItems: "center", alignItems: "center",
}, },
segmentedControlMobile: {
alignSelf: "center",
marginBottom: 0,
},
mobileList: { mobileList: {
flex: 1, flex: 1,
width: "100%", width: "100%",