feat: subscription packs
This commit is contained in:
@@ -76,6 +76,9 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
|
|||||||
typeof plan?.coinsPerMonth === 'number' && Number.isFinite(plan.coinsPerMonth)
|
typeof plan?.coinsPerMonth === 'number' && Number.isFinite(plan.coinsPerMonth)
|
||||||
? Math.round(plan.coinsPerMonth)
|
? Math.round(plan.coinsPerMonth)
|
||||||
: null
|
: null
|
||||||
|
const details = planKey ? PLAN_DETAILS[planKey] : null
|
||||||
|
const isPopular = details?.popular
|
||||||
|
|
||||||
const planBadgeKey = planKey
|
const planBadgeKey = planKey
|
||||||
const planBadgeSource = planBadgeKey && subBadges[planBadgeKey] ? subBadges[planBadgeKey] : null
|
const planBadgeSource = planBadgeKey && subBadges[planBadgeKey] ? subBadges[planBadgeKey] : null
|
||||||
const handleSelect = React.useCallback(() => {
|
const handleSelect = React.useCallback(() => {
|
||||||
@@ -92,6 +95,7 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
|
|||||||
selected && styles.cardWrapperSelected,
|
selected && styles.cardWrapperSelected,
|
||||||
pressed && styles.cardWrapperPressed,
|
pressed && styles.cardWrapperPressed,
|
||||||
plan?.active === false && styles.cardWrapperInactive,
|
plan?.active === false && styles.cardWrapperInactive,
|
||||||
|
isPopular && styles.cardWrapperPopular,
|
||||||
]}
|
]}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityState={{ selected, disabled: plan?.active === false }}
|
accessibilityState={{ selected, disabled: plan?.active === false }}
|
||||||
@@ -105,6 +109,7 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
|
|||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|
||||||
<View style={styles.cardHeader}>
|
<View style={styles.cardHeader}>
|
||||||
<View style={styles.titleRow}>
|
<View style={styles.titleRow}>
|
||||||
<Text style={styles.planName}>{planName}</Text>
|
<Text style={styles.planName}>{planName}</Text>
|
||||||
@@ -127,7 +132,10 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
|
|||||||
{intervalLabel ? <Text style={styles.period}>{intervalLabel}</Text> : null}
|
{intervalLabel ? <Text style={styles.period}>{intervalLabel}</Text> : null}
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
{coinsPerMonth !== null ? (
|
|
||||||
|
{details?.creditsLabel ? (
|
||||||
|
<Text style={styles.coinsPromoText}>{details.creditsLabel}</Text>
|
||||||
|
) : coinsPerMonth !== null ? (
|
||||||
<View style={styles.coinsPerMonthRow}>
|
<View style={styles.coinsPerMonthRow}>
|
||||||
<CreditAmount
|
<CreditAmount
|
||||||
value={coinsPerMonth}
|
value={coinsPerMonth}
|
||||||
@@ -143,9 +151,33 @@ function SubscriptionCard({ plan, selected, onSelect, isAnnual }) {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<View style={styles.cardBenefits}>
|
<View style={styles.cardBenefits}>
|
||||||
<Text style={styles.cardBenefitsItem}>• Eligible au concours mensuel chanson/Vidéo</Text>
|
<Text style={styles.benefitsTitle}>Privilège Membre :</Text>
|
||||||
<Text style={styles.cardBenefitsItem}>• Crédits gratuits tous les mois</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>
|
</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>
|
</View>
|
||||||
</BlurView>
|
</BlurView>
|
||||||
{isAnnual ? (
|
{isAnnual ? (
|
||||||
@@ -208,6 +240,36 @@ const PLAN_DISPLAY_NAME_BY_KEY = {
|
|||||||
premium: 'Play Backer Gold',
|
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) => {
|
const getPlanKeyForBadge = (plan) => {
|
||||||
if (!plan || typeof plan !== 'object') {
|
if (!plan || typeof plan !== 'object') {
|
||||||
return null
|
return null
|
||||||
@@ -621,7 +683,7 @@ export default function Subscriptions() {
|
|||||||
<Page
|
<Page
|
||||||
headerType="NAVIGATE"
|
headerType="NAVIGATE"
|
||||||
title="Abonnements"
|
title="Abonnements"
|
||||||
scrollEnabled={false}
|
scrollEnabled={isWeb}
|
||||||
width={isWeb ? 960 : undefined}
|
width={isWeb ? 960 : undefined}
|
||||||
containerStyle={styles.page}
|
containerStyle={styles.page}
|
||||||
contentContainerStyle={[styles.pageContent, isMobile && styles.pageContentMobile]}
|
contentContainerStyle={[styles.pageContent, isMobile && styles.pageContentMobile]}
|
||||||
@@ -821,14 +883,47 @@ const styles = StyleSheet.create({
|
|||||||
marginTop: 12,
|
marginTop: 12,
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
borderTopColor: 'rgba(255, 255, 255, 0.1)',
|
borderTopColor: 'rgba(255, 255, 255, 0.1)',
|
||||||
paddingTop: 8,
|
paddingTop: 12,
|
||||||
gap: 4,
|
gap: 6,
|
||||||
},
|
},
|
||||||
cardBenefitsItem: {
|
cardBenefitsItem: {
|
||||||
fontFamily: FONT_FAMILY.InterMedium,
|
fontFamily: FONT_FAMILY.InterMedium,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: 'rgba(255, 255, 255, 0.7)',
|
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: {
|
balanceContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -1032,6 +1127,10 @@ const styles = StyleSheet.create({
|
|||||||
shadowRadius: 20,
|
shadowRadius: 20,
|
||||||
elevation: 8,
|
elevation: 8,
|
||||||
},
|
},
|
||||||
|
cardWrapperPopular: {
|
||||||
|
borderColor: Palette.primary, // Highlight border for popular
|
||||||
|
backgroundColor: 'rgba(112, 35, 247, 0.1)', // Slight tint
|
||||||
|
},
|
||||||
cardWrapperPressed: {
|
cardWrapperPressed: {
|
||||||
transform: [{ scale: 0.98 }],
|
transform: [{ scale: 0.98 }],
|
||||||
},
|
},
|
||||||
@@ -1123,6 +1222,20 @@ const styles = StyleSheet.create({
|
|||||||
color: Palette.primary,
|
color: Palette.primary,
|
||||||
textTransform: 'uppercase',
|
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: {
|
inlineLoader: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user