diff --git a/functions/src/cover.js b/functions/src/cover.js
index 5c927f1..dbc82eb 100644
--- a/functions/src/cover.js
+++ b/functions/src/cover.js
@@ -42,7 +42,8 @@ const buildBrandSvg = ({ width = 1024, height = 1024, text = BRAND_TEXT } = {})
const rectX = Math.max(0, Math.round(safeWidth - margin - rectWidth))
const rectY = Math.max(0, Math.round(safeHeight - margin - rectHeight))
const textX = rectX + rectWidth / 2
- const textY = rectY + rectHeight / 2
+ const baselineShift = Math.round(fontSize * 0.3)
+ const textY = rectY + rectHeight / 2 + baselineShift
const rectRadius = Math.max(6, Math.round(rectHeight * 0.35))
return Buffer.from(`
@@ -65,7 +66,6 @@ const buildBrandSvg = ({ width = 1024, height = 1024, text = BRAND_TEXT } = {})
x="${textX}"
y="${textY}"
text-anchor="middle"
- dominant-baseline="middle"
font-family="${BRAND_FONT_FAMILY}"
font-size="${fontSize}"
font-style="italic"
diff --git a/src/screens/Profile/ManageSubscription.js b/src/screens/Profile/ManageSubscription.js
index d3a9890..d20ea19 100644
--- a/src/screens/Profile/ManageSubscription.js
+++ b/src/screens/Profile/ManageSubscription.js
@@ -13,7 +13,6 @@ import { FONT_FAMILY } from '../../styles/Fonts'
import { formatDate, toDate } from '../../utils/dateFormatting'
import { Image as ExpoImage } from 'expo-image'
import { isWeb } from '../../hooks/useLayoutType'
-import ClubAdvantagesCard from './components/ClubAdvantagesCard'
const FUNCTIONS_REGION = 'europe-west1'
@@ -654,7 +653,6 @@ const ManageSubscription = ({ navigation }) => {
/>
)}
- {/**/}
)
diff --git a/src/screens/Profile/components/ClubAdvantagesCard.js b/src/screens/Profile/components/ClubAdvantagesCard.js
index 3dbdbc7..28b84b5 100644
--- a/src/screens/Profile/components/ClubAdvantagesCard.js
+++ b/src/screens/Profile/components/ClubAdvantagesCard.js
@@ -1,160 +1,152 @@
import React from 'react'
-import { StyleSheet, Switch, Text, View } from 'react-native'
-import { MaterialCommunityIcons } from '@expo/vector-icons'
-import { Image as ExpoImage } from 'expo-image'
+import { StyleSheet, Text, View } from 'react-native'
import { useNavigation } from '@react-navigation/native'
-import ClubCard from '../../Home/components/ClubCard'
import { gutters, Palette } from '../../../styles'
import { FONT_FAMILY } from '../../../styles/Fonts'
import { Routes } from '../../../navigation/Routes'
import { useUserData } from '../../../providers/UserDataProvider'
-import { icons } from '../../../assets'
+import GradientButton from '../../../components/GradientButton'
+import CreditAmount from '../../../components/CreditAmount'
+import { useStripe } from '../../../providers/StripeProvider'
import { isWeb } from '../../../hooks/useLayoutType'
-const ICON_BASE_ACCENT = '#A96BFF'
+const formatCurrency = (amount, currency = 'eur') => {
+ if (typeof amount !== 'number') {
+ return null
+ }
+ const normalized = amount / 100
+ const upperCurrency =
+ typeof currency === 'string' && currency.trim() ? currency.trim().toUpperCase() : 'EUR'
-const CLUB_ADVANTAGES = [
- {
- title: 'Gagne des crédits avec ton abonnement',
- description: 'Des crédits premium tous les mois pour créer plus.',
- iconType: 'image',
- icon: icons.coin,
- accent: ICON_BASE_ACCENT,
- },
- {
- title: 'Gagne le double de cashprice grace à ton adésion au club',
- description: 'Cashprice doublé pour les membres du Club Musicland.',
- iconType: 'vector',
- iconName: 'chart-line',
- accent: '#F8C24D',
- },
-]
+ if (typeof Intl !== 'undefined' && Intl.NumberFormat) {
+ try {
+ return new Intl.NumberFormat('fr-FR', {
+ style: 'currency',
+ currency: upperCurrency,
+ minimumFractionDigits: 2,
+ }).format(normalized)
+ } catch (_error) {
+ // Ignore
+ }
+ }
+ return `${normalized.toFixed(2)} ${upperCurrency}`
+}
-const ClubAdvantagesCard = ({ style, isDev = false }) => {
+const COIN_PACK_DETAILS = {
+ starter: {
+ label: 'Pack starter',
+ creditsDisplay: '50 Crédits',
+ disclaimer: '*Non-Eligible au concours Chanson/Vidéo',
+ },
+ medium: {
+ label: 'Pack Medium',
+ creditsDisplay: '100 Crédits + 50 offerts',
+ disclaimer: '*Non-Eligible au concours Chanson/Vidéo',
+ },
+ premium: {
+ label: 'Pack Premium',
+ creditsDisplay: '150 Crédits + 100 offerts',
+ disclaimer: '*Non-Eligible au concours Chanson/Vidéo',
+ },
+}
+
+const getCoinPackKey = (pack) => {
+ const name = (pack?.name || '').toLowerCase()
+ if (name.includes('starter')) return 'starter'
+ if (name.includes('medium')) return 'medium'
+ if (name.includes('premium') || name.includes('prenium') || name.includes('creator'))
+ return 'premium'
+ return null
+}
+
+const ClubAdvantagesCard = ({ style }) => {
const navigation = useNavigation()
const { hasActiveSubscription } = useUserData() || {}
- const [useWebLayout, setUseWebLayout] = React.useState(isDev ? isWeb : false)
- const advantages = CLUB_ADVANTAGES
-
- React.useEffect(() => {
- if (!isDev) {
- setUseWebLayout(false)
- }
- }, [isDev])
-
- const title = hasActiveSubscription
- ? 'Tu profites déjà du Club Musicland'
- : 'Rejoins le Club Musicland'
- const subtitle = hasActiveSubscription
- ? 'Grâce à ton abonnement, tu bénéficies de tous ces avantages.'
- : 'Découvre ce que tu gagnes en passant au club premium.'
+ const { coinPacks, createCoinPackCheckout } = useStripe()
+ const [processingPriceId, setProcessingPriceId] = React.useState(null)
+ const [errorMessage, setErrorMessage] = React.useState(null)
const handleOpenPlans = () => {
navigation.navigate(Routes.Payments)
}
+ const handleBuyCredits = async (pack) => {
+ const targetId = pack?.productId
+ if (!targetId) return
+ setProcessingPriceId(targetId)
+ setErrorMessage(null)
+ try {
+ await createCoinPackCheckout(targetId)
+ } catch (error) {
+ setErrorMessage(error?.message || "Erreur lors de l'achat de crédits.")
+ } finally {
+ setProcessingPriceId(null)
+ }
+ }
+
return (
- {/* {isDev ? (
-
-
- Test layout web
-
-
-
- ) : null} */}
-
- {title}
- {subtitle}
+
+ {'Les abonnements et les packs permettent le téléchargement de vos créations'}
+
+ {'Avec un abonnement le téléchargement est gratuit'}
+ {coinPacks && coinPacks.length > 0 ? (
+
+ Recharger vos crédits
+
+ {coinPacks.map((pack) => {
+ const rawAmount = pack.unitAmount ?? pack.amount ?? pack.price ?? 0
+ const price = formatCurrency(rawAmount, pack.currency)
+ const coins = Number(pack.metadata?.coins || 0)
+ const packKey = getCoinPackKey(pack)
+ const details = packKey ? COIN_PACK_DETAILS[packKey] : null
+ const displayName = details?.label || pack.name
+ const creditsText = details?.creditsDisplay
+
+ return (
+
+
+ {displayName}
+ {creditsText ? (
+ {creditsText}
+ ) : (
+
+ )}
+ {details?.disclaimer ? (
+ {details.disclaimer}
+ ) : null}
+
+ handleBuyCredits(pack)}
+ disabled={Boolean(processingPriceId)}
+ style={styles.creditButton}
+ textStyle={styles.creditButtonText}
+ gradientStyle={{ paddingVertical: 8, paddingHorizontal: 16 }}
+ />
+
+ )
+ })}
+
+ {errorMessage ? {errorMessage} : null}
+
+ ) : null}
+
-
-
- {advantages.map((advantage) => {
- const accent = advantage.accent || Palette.white
- const iconType = advantage.iconType || 'image'
-
- return (
-
- {hasActiveSubscription ? (
-
- ) : null}
-
- {iconType === 'vector' ? (
-
- ) : (
-
- )}
-
-
-
- {advantage.title}
-
-
- {advantage.description}
-
-
-
- )
- })}
-
-
-
)
}
@@ -166,7 +158,6 @@ const styles = StyleSheet.create({
borderRadius: 24,
backgroundColor: '#252438',
borderWidth: 1,
- gap: gutters,
borderColor: 'white',
},
cardInactive: {
@@ -179,28 +170,6 @@ const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
- gap: gutters,
- },
- testSwitches: {
- gap: gutters * 0.75,
- // backgroundColor: "rgba(255, 255, 255, 0.08)",
- padding: gutters * 0.9,
- borderRadius: 14,
- borderWidth: 1,
- borderColor: 'rgba(255, 255, 255, 0.12)',
- },
- switchRow: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: gutters * 0.5,
- justifyContent: 'space-between',
- },
- switchLabel: {
- fontFamily: FONT_FAMILY.InterMedium,
- fontSize: 11,
- color: Palette.grayMid,
- textTransform: 'uppercase',
- letterSpacing: 0.6,
},
titleBlock: {
flex: 1,
@@ -211,7 +180,7 @@ const styles = StyleSheet.create({
fontFamily: FONT_FAMILY.InterSemiBold,
fontSize: 18,
color: Palette.white,
- textAlign: 'center',
+ textAlign: "center",
},
subtitle: {
fontFamily: FONT_FAMILY.InterRegular,
@@ -220,96 +189,80 @@ const styles = StyleSheet.create({
lineHeight: 18,
textAlign: 'center',
},
- advantagesList: {
- gap: gutters * 0.75,
- },
- advantagesListWeb: {
- flexDirection: 'row',
- flexWrap: 'wrap',
- justifyContent: 'space-between',
- },
- advantagesListMobile: {
- flexDirection: 'column',
- },
- advantageCard: {
- flexDirection: 'row',
- alignItems: 'flex-start',
- gap: gutters * 0.65,
- backgroundColor: 'rgba(255, 255, 255, 0.08)',
- borderRadius: 16,
- borderWidth: 0,
- padding: gutters,
- shadowColor: '#000',
- shadowOffset: { width: 0, height: 6 },
- shadowOpacity: 0.2,
- shadowRadius: 10,
- elevation: 2,
- },
- advantageCardWeb: {
- flexBasis: '31%',
- maxWidth: '32%',
- minWidth: 200,
- flexGrow: 1,
- flexShrink: 1,
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'flex-start',
- gap: gutters * 0.5,
- position: 'relative',
- },
- advantageCardMobile: {
+ sectionContainer: {
+ gap: 16,
width: '100%',
- position: 'relative',
- },
- advantageIcon: {
- width: 42,
- height: 42,
- borderRadius: 12,
alignItems: 'center',
- justifyContent: 'center',
- borderWidth: 1,
+ borderTopWidth: 1,
+ borderTopColor: 'rgba(255, 255, 255, 0.08)',
+ paddingTop: gutters,
+ marginTop: gutters * 0.6,
},
- advantageIconWeb: {
- alignSelf: 'center',
- marginBottom: gutters * 0.15,
- },
- advantageIconImage: {
- width: 24,
- height: 24,
- },
- advantageContent: {
- flex: 1,
- gap: gutters * 0.2,
- },
- advantageContentWeb: {
- alignItems: 'center',
- gap: gutters * 0.4,
- },
- advantageTitle: {
- fontFamily: FONT_FAMILY.InterSemiBold,
- fontSize: 15,
+ sectionTitle: {
+ fontFamily: FONT_FAMILY.InterBold,
+ fontSize: 20,
color: Palette.white,
- },
- advantageText: {
- fontFamily: FONT_FAMILY.InterRegular,
- fontSize: 13,
- lineHeight: 18,
- color: 'rgba(255, 255, 255, 0.85)',
- },
- advantageTextCenter: {
textAlign: 'center',
},
- advantageCheck: {
- position: 'absolute',
+ creditsGrid: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ gap: 16,
+ justifyContent: 'center',
+ width: '100%',
},
- advantageCheckWeb: {
- top: 10,
- right: 10,
+ creditCard: {
+ backgroundColor: 'rgba(255, 255, 255, 0.05)',
+ borderRadius: 16,
+ padding: 16,
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ width: isWeb ? 220 : '100%',
+ minHeight: 160,
+ gap: 12,
+ borderWidth: 1,
+ borderColor: 'rgba(255, 255, 255, 0.1)',
},
- advantageCheckMobile: {
- top: '50%',
- right: 12,
- transform: [{ translateY: -10 }],
+ creditInfoContainer: {
+ alignItems: 'center',
+ gap: 4,
+ },
+ creditName: {
+ fontFamily: FONT_FAMILY.InterSemiBold,
+ fontSize: 14,
+ color: Palette.white,
+ textAlign: 'center',
+ marginBottom: 4,
+ },
+ creditAmountCustom: {
+ fontFamily: FONT_FAMILY.InterBold,
+ fontSize: 16,
+ color: Palette.white,
+ textAlign: 'center',
+ },
+ creditAmountText: {
+ fontSize: 20,
+ },
+ packDisclaimer: {
+ fontFamily: FONT_FAMILY.InterRegular,
+ fontSize: 10,
+ color: 'rgba(255, 255, 255, 0.6)',
+ fontStyle: 'italic',
+ textAlign: 'center',
+ marginTop: 4,
+ },
+ creditButton: {
+ width: '100%',
+ height: 36,
+ minHeight: 36,
+ },
+ creditButtonText: {
+ fontSize: 13,
+ },
+ errorText: {
+ color: Palette.red,
+ textAlign: 'center',
+ marginTop: 10,
},
})
diff --git a/src/screens/cover/SongDownload.js b/src/screens/cover/SongDownload.js
index 27b14d0..5c5793b 100644
--- a/src/screens/cover/SongDownload.js
+++ b/src/screens/cover/SongDownload.js
@@ -549,22 +549,7 @@ const SongDownload = ({ route }) => {
- {showSubscriptionCta ? (
-
-
- Avec un abonnement, le téléchargement est gratuit.
-
- navigate(Routes.Payments)}
- containerStyle={styles.subscriptionButton}
- />
-
- ) : (
-
- Avec ton abonnement, le téléchargement est gratuit.
-
- )}
+