From 4df675fd6940b4d0f7e229b9f6a8cc5e4c6a7cb7 Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 15 Jan 2026 14:15:52 +0100 Subject: [PATCH] feat: add packs to subscriptions --- src/screens/HitParade/components/SongCard.js | 6 +- src/screens/Subscriptions.js | 172 +++++++++++++++++-- 2 files changed, 160 insertions(+), 18 deletions(-) diff --git a/src/screens/HitParade/components/SongCard.js b/src/screens/HitParade/components/SongCard.js index 797a6e7..0e2ffdd 100644 --- a/src/screens/HitParade/components/SongCard.js +++ b/src/screens/HitParade/components/SongCard.js @@ -49,9 +49,9 @@ const SongCard = ({ ...Style.containerRow, }} tint="dark" - // experimentalBlurMethod={ - // Platform.OS !== "ios" ? "dimezisBlurView" : "none" - // } + // experimentalBlurMethod={ + // Platform.OS !== "ios" ? "dimezisBlurView" : "none" + // } > { if (typeof amount !== 'number') { @@ -139,6 +141,11 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) { ) : null} ) : null} + + + • Eligible au concours mensuel chanson/Vidéo + • Crédits gratuits tous les mois + {isAnnual ? ( @@ -278,7 +285,15 @@ export default function Subscriptions() { const initialSubscriptionPack = initialPack && initialPack !== 'packs' ? initialPack : null - const { subscriptions, isCatalogLoading, catalogError, createSubscriptionCheckout } = useStripe() + const { + subscriptions, + coinPacks, + isCatalogLoading, + catalogError, + createSubscriptionCheckout, + createCoinPackCheckout, + } = useStripe() + const { currentUserData } = useUserData() const [selectedPeriodKey, setSelectedPeriodKey] = React.useState('annual') const [selectedPriceId, setSelectedPriceId] = React.useState(null) const [processingPriceId, setProcessingPriceId] = React.useState(null) @@ -315,6 +330,7 @@ export default function Subscriptions() { ) if (!periodEntries.length) { + // Don't reset selectedPeriodKey here so it behaves more stably setSelectedPriceId(null) return } @@ -323,10 +339,11 @@ export default function Subscriptions() { let matchedPriceId = null let matchedPeriodKey = selectedPeriodKey - let nextPeriodKey = - periodEntries.find(([periodKey]) => periodKey === selectedPeriodKey)?.[0] || - periodEntries[0]?.[0] || - 'annual' + let nextPeriodKey = selectedPeriodKey + // Only force switch if current selected period is empty and another is not + if ((normalizedPlansByPeriod[selectedPeriodKey]?.length || 0) === 0) { + nextPeriodKey = periodEntries[0]?.[0] || 'annual' + } if (shouldApplyPack) { const desired = initialSubscriptionPack.trim().toLowerCase() @@ -447,17 +464,35 @@ export default function Subscriptions() { [selectedPeriodKey] ) + const handleBuyCredits = React.useCallback( + async (pack) => { + const targetId = pack?.productId + if (!targetId) return + setProcessingPriceId(targetId) + setErrorMessage(null) + try { + await createCoinPackCheckout(targetId) + } catch (error) { + console.error('[Subscriptions] coin checkout error', error) + setErrorMessage( + error?.message || + 'Une erreur est survenue lors de la création de la session Stripe pour les crédits.' + ) + } finally { + setProcessingPriceId(null) + } + }, + [createCoinPackCheckout] + ) + const renderHeaderSection = React.useCallback(() => { return ( <> Rejoignez le club MusicLand - - Privilège Membre : - - - Eligible au concours mensuel chanson/Vidéo - - Crédits gratuits tous les mois - + + Votre solde actuel : + {combinedErrorMessage ? {combinedErrorMessage} : null} @@ -639,6 +674,45 @@ export default function Subscriptions() { ))} + {coinPacks && coinPacks.length > 0 ? ( + + Recharger vos crédits + + {coinPacks.map((pack) => { + // Attempt to find amount in commonly used Stripe fields + const rawAmount = pack.unitAmount ?? pack.amount ?? pack.price ?? 0 + const price = formatCurrency(rawAmount, pack.currency) + // Assuming pack structure: { id, name, unitAmount/amount, currency, metadata: { coins: 100 } } + const coins = Number(pack.metadata?.coins || 0) + return ( + + + {pack.name} + + + handleBuyCredits(pack)} + disabled={Boolean(processingPriceId)} + style={styles.creditButton} + textStyle={styles.creditButtonText} + gradientStyle={{ paddingVertical: 8, paddingHorizontal: 16 }} + /> + + ) + })} + + + ) : null} + {isLoadingPlans && currentPlanCount > 0 ? ( @@ -742,11 +816,79 @@ const styles = StyleSheet.create({ benefitsList: { gap: 2, }, - benefitsItem: { + + cardBenefits: { + marginTop: 12, + borderTopWidth: 1, + borderTopColor: 'rgba(255, 255, 255, 0.1)', + paddingTop: 8, + gap: 4, + }, + cardBenefitsItem: { fontFamily: FONT_FAMILY.InterMedium, - fontSize: 13, - color: 'rgba(255, 255, 255, 0.85)', + fontSize: 12, + color: 'rgba(255, 255, 255, 0.7)', + }, + balanceContainer: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: 'rgba(255, 255, 255, 0.08)', + paddingHorizontal: 16, + paddingVertical: 8, + borderRadius: 20, + gap: 10, + marginTop: 8, + }, + balanceLabel: { + fontFamily: FONT_FAMILY.InterMedium, + fontSize: 14, + color: Palette.white, + }, + creditsSection: { + width: '100%', + marginTop: 40, + gap: 16, + alignItems: 'center', + }, + sectionTitle: { + fontFamily: FONT_FAMILY.InterBold, + fontSize: 20, + color: Palette.white, + }, + creditsGrid: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: 16, + justifyContent: 'center', + }, + creditCard: { + backgroundColor: 'rgba(255, 255, 255, 0.05)', + borderRadius: 16, + padding: 16, + alignItems: 'center', + justifyContent: 'space-between', + width: isWeb ? 200 : '45%', + gap: 12, + borderWidth: 1, + borderColor: 'rgba(255, 255, 255, 0.1)', + }, + creditName: { + fontFamily: FONT_FAMILY.InterSemiBold, + fontSize: 14, + color: Palette.white, textAlign: 'center', + marginBottom: 4, + }, + creditAmountText: { + fontSize: 20, + }, + creditButton: { + width: '100%', + height: 36, + minHeight: 36, + }, + creditButtonText: { + fontSize: 13, }, webBackContainer: { alignSelf: 'flex-start',