feat: subscription packs

This commit is contained in:
2026-01-15 15:03:06 +01:00
parent 4df675fd69
commit 86c3dccf1a
+119 -6
View File
@@ -76,6 +76,9 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
typeof plan?.coinsPerMonth === 'number' && Number.isFinite(plan.coinsPerMonth)
? Math.round(plan.coinsPerMonth)
: null
const details = planKey ? PLAN_DETAILS[planKey] : null
const isPopular = details?.popular
const planBadgeKey = planKey
const planBadgeSource = planBadgeKey && subBadges[planBadgeKey] ? subBadges[planBadgeKey] : null
const handleSelect = React.useCallback(() => {
@@ -92,6 +95,7 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
selected && styles.cardWrapperSelected,
pressed && styles.cardWrapperPressed,
plan?.active === false && styles.cardWrapperInactive,
isPopular && styles.cardWrapperPopular,
]}
accessibilityRole="button"
accessibilityState={{ selected, disabled: plan?.active === false }}
@@ -105,6 +109,7 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
</View>
) : null}
<View style={styles.cardHeader}>
<View style={styles.titleRow}>
<Text style={styles.planName}>{planName}</Text>
@@ -127,7 +132,10 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
{intervalLabel ? <Text style={styles.period}>{intervalLabel}</Text> : null}
</View>
) : null}
{coinsPerMonth !== null ? (
{details?.creditsLabel ? (
<Text style={styles.coinsPromoText}>{details.creditsLabel}</Text>
) : coinsPerMonth !== null ? (
<View style={styles.coinsPerMonthRow}>
<CreditAmount
value={coinsPerMonth}
@@ -143,9 +151,33 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
) : null}
<View style={styles.cardBenefits}>
<Text style={styles.cardBenefitsItem}> Eligible au concours mensuel chanson/Vidéo</Text>
<Text style={styles.cardBenefitsItem}> Crédits gratuits tous les mois</Text>
<Text style={styles.benefitsTitle}>Privilège Membre :</Text>
{details?.privileges?.map((item, index) => (
<View key={index} style={styles.benefitBlock}>
<Text style={[styles.benefitText, item.bold && styles.benefitTextBold]}>
{item.bold ? `${item.text}` : item.text}
</Text>
{item.subItems ? (
<View style={styles.benefitSubList}>
<Text style={styles.benefitSubText}>{item.subItems.join(' - ')}</Text>
</View>
) : null}
</View>
)) || (
<>
<Text style={styles.cardBenefitsItem}>
Eligible au concours mensuel chanson/Vidéo
</Text>
<Text style={styles.cardBenefitsItem}> Crédits gratuits tous les mois</Text>
</>
)}
</View>
{isPopular ? (
<View style={styles.popularBadge}>
<Text style={styles.popularBadgeText}>Le plus populaire !</Text>
</View>
) : null}
</View>
</BlurView>
{isAnnual ? (
@@ -208,6 +240,36 @@ const PLAN_DISPLAY_NAME_BY_KEY = {
premium: 'Play Backer Gold',
}
const PLAN_DETAILS = {
starter: {
creditsLabel: '50 Crédits / Mois',
popular: false,
privileges: [
{ text: 'Eligible au concours mensuel chanson/Vidéo', bold: true },
{ text: 'Catégorie Chanson :', subItems: ['Top 1: 500 €', 'Top 2: 250 €', 'Top 3: 125 €'] },
{ text: 'Catégorie Vidéo :', subItems: ['Top 1: 1000 €', 'Top 2: 500 €', 'Top 3: 250 €'] },
],
},
pro: {
creditsLabel: '100 crédits + 50 offerts / Mois',
popular: true,
privileges: [
{ text: 'Eligible au concours mensuel chanson/Vidéo', bold: true },
{ text: 'Catégorie Chanson :', subItems: ['Top 1: 500 €', 'Top 2: 250 €', 'Top 3: 125 €'] },
{ text: 'Catégorie Vidéo :', subItems: ['Top 1: 1000 €', 'Top 2: 500 €', 'Top 3: 250 €'] },
],
},
premium: {
creditsLabel: '150 Crédits + 100 offerts / Mois',
popular: false,
privileges: [
{ text: 'Eligible au concours mensuel chanson/Vidéo', bold: true },
{ text: 'Catégorie Chanson :', subItems: ['Top 1: 500 €', 'Top 2: 250 €', 'Top 3: 125 €'] },
{ text: 'Catégorie Vidéo :', subItems: ['Top 1: 1000 €', 'Top 2: 500 €', 'Top 3: 250 €'] },
],
},
}
const getPlanKeyForBadge = (plan) => {
if (!plan || typeof plan !== 'object') {
return null
@@ -621,7 +683,7 @@ export default function Subscriptions() {
<Page
headerType="NAVIGATE"
title="Abonnements"
scrollEnabled={false}
scrollEnabled={isWeb}
width={isWeb ? 960 : undefined}
containerStyle={styles.page}
contentContainerStyle={[styles.pageContent, isMobile && styles.pageContentMobile]}
@@ -821,14 +883,47 @@ const styles = StyleSheet.create({
marginTop: 12,
borderTopWidth: 1,
borderTopColor: 'rgba(255, 255, 255, 0.1)',
paddingTop: 8,
gap: 4,
paddingTop: 12,
gap: 6,
},
cardBenefitsItem: {
fontFamily: FONT_FAMILY.InterMedium,
fontSize: 12,
color: 'rgba(255, 255, 255, 0.7)',
},
benefitsTitle: {
fontFamily: FONT_FAMILY.InterSemiBold,
fontSize: 13,
color: Palette.white,
marginBottom: 2,
},
benefitBlock: {
marginBottom: 4,
},
benefitText: {
fontFamily: FONT_FAMILY.InterRegular,
fontSize: 13,
color: 'rgba(255, 255, 255, 0.85)',
},
benefitTextBold: {
fontFamily: FONT_FAMILY.InterSemiBold,
color: Palette.white,
},
benefitSubList: {
marginTop: 2,
paddingLeft: 0,
},
benefitSubText: {
fontFamily: FONT_FAMILY.InterRegular,
fontSize: 12,
color: 'rgba(255, 255, 255, 0.65)',
fontStyle: 'italic',
},
coinsPromoText: {
fontFamily: FONT_FAMILY.InterBold,
fontSize: 15,
color: Palette.primary,
},
balanceContainer: {
flexDirection: 'row',
alignItems: 'center',
@@ -1032,6 +1127,10 @@ const styles = StyleSheet.create({
shadowRadius: 20,
elevation: 8,
},
cardWrapperPopular: {
borderColor: Palette.primary, // Highlight border for popular
backgroundColor: 'rgba(112, 35, 247, 0.1)', // Slight tint
},
cardWrapperPressed: {
transform: [{ scale: 0.98 }],
},
@@ -1123,6 +1222,20 @@ const styles = StyleSheet.create({
color: Palette.primary,
textTransform: 'uppercase',
},
popularBadge: {
alignSelf: 'center',
marginTop: 12,
paddingHorizontal: 12,
paddingVertical: 4,
borderRadius: 999,
backgroundColor: Palette.primary,
},
popularBadgeText: {
fontFamily: FONT_FAMILY.InterBold,
fontSize: 11,
color: Palette.white,
textTransform: 'uppercase',
},
inlineLoader: {
alignItems: 'center',
},