clear last tickets

This commit is contained in:
Thomas Demirdjian
2025-11-25 14:58:06 +01:00
parent 72852ad92b
commit ee9cc5dccd
31 changed files with 1009 additions and 531 deletions
+69 -57
View File
@@ -45,6 +45,7 @@ const formatCurrency = (amount, currency = "eur") => {
const FALLBACK_BASE_PRICE_PER_COIN = 12; // ~0,12€ par jeton (valeur indicatif pour l'affichage)
const FALLBACK_DISCOUNT_STEPS = [0, 12, 18, 26, 32];
const STATIC_DISCOUNTS = [0, 30, 50];
const computeCoinPackPricing = (packs = []) => {
if (!Array.isArray(packs) || !packs.length) {
@@ -61,9 +62,7 @@ const computeCoinPackPricing = (packs = []) => {
return {
...pack,
hasValidPrice,
pricePerCoin: hasValidPrice
? pack.unitAmount / pack.coinAmount
: null,
pricePerCoin: hasValidPrice ? pack.unitAmount / pack.coinAmount : null,
};
});
@@ -146,8 +145,7 @@ const computeCoinPackPricing = (packs = []) => {
discountPercent,
isBasePack,
isBestValue:
(bestDiscountPack &&
bestDiscountPack.productId === pack.productId) ||
(bestDiscountPack && bestDiscountPack.productId === pack.productId) ||
(!bestDiscountPack && fallbackBestId === pack.productId),
};
@@ -155,7 +153,13 @@ const computeCoinPackPricing = (packs = []) => {
}, {});
};
function CoinPackCard({ pack, selected, pricingDetail, onSelect }) {
function CoinPackCard({
pack,
selected,
pricingDetail,
onSelect,
staticDiscountPercent,
}) {
const handleSelect = React.useCallback(() => {
if (typeof onSelect !== "function" || !pack?.productId) {
return;
@@ -166,11 +170,20 @@ function CoinPackCard({ pack, selected, pricingDetail, onSelect }) {
const formattedPrice = formatCurrency(pack?.unitAmount, pack?.currency);
const perCoinPrice = pricingDetail?.formattedPricePerCoin;
const discountPercent = pricingDetail?.discountPercent;
const discountLabel = pricingDetail?.isBasePack
? "Pack de base (référence)"
: typeof discountPercent === "number"
? `-${discountPercent}% vs pack de base`
: null;
const hasStaticDiscount = typeof staticDiscountPercent === "number";
const effectiveDiscountPercent = hasStaticDiscount
? staticDiscountPercent
: discountPercent;
const isBaseReference = !hasStaticDiscount && pricingDetail?.isBasePack;
const discountLabel = hasStaticDiscount
? staticDiscountPercent > 0
? `-${staticDiscountPercent}%`
: null
: isBaseReference
? "Pack de base (référence)"
: typeof discountPercent === "number"
? `-${discountPercent}% vs pack de base`
: null;
return (
<Pressable
@@ -184,6 +197,11 @@ function CoinPackCard({ pack, selected, pricingDetail, onSelect }) {
accessibilityState={{ selected }}
>
<BlurView intensity={20} tint="dark" style={styles.cardBlur}>
{/*{pricingDetail?.isBestValue ? (*/}
{/* <View style={styles.tagBestValue}>*/}
{/* <Text style={styles.tagBestValueText}>Meilleure offre</Text>*/}
{/* </View>*/}
{/*) : null}*/}
<View style={styles.cardHeader}>
<CreditAmount
value={pack?.coinAmount}
@@ -191,55 +209,39 @@ function CoinPackCard({ pack, selected, pricingDetail, onSelect }) {
textStyle={styles.coinAmount}
iconSize={26}
/>
{pack?.name ? <Text style={styles.packName}>{pack.name}</Text> : null}
{pricingDetail?.isBestValue ? (
<View style={styles.tagBestValue}>
<Text style={styles.tagBestValueText}>Meilleure offre</Text>
{discountLabel ? (
<View
style={{
position: "absolute",
right: 0,
top: -5,
}}
>
<View
style={[
styles.discountBadge,
isBaseReference && styles.discountBadgeBase,
]}
>
<Text style={[styles.discountText]}>{discountLabel}</Text>
</View>
</View>
) : null}
{pack?.name ? <Text style={styles.packName}>{pack.name}</Text> : null}
</View>
<View style={styles.perksList}>
<Text style={styles.perkItem}>
- Diffusion sur mes plates formes de streaming
</Text>
<Text style={styles.perkItem}>
*Eligible au Hit parade Chanson/Video
</Text>
</View>
{pack?.description ? (
<Text style={styles.packDescription}>{pack.description}</Text>
) : null}
<View style={styles.priceBlock}>
{formattedPrice ? (
<Text style={styles.packPrice}>{formattedPrice}</Text>
) : null}
<Text style={styles.pricePerCoin} numberOfLines={1}>
{perCoinPrice
? `${perCoinPrice} / jeton`
: "Valeurs indicatives / jeton"}
</Text>
</View>
{discountLabel ? (
<View style={styles.discountRow}>
<View
style={[
styles.discountBadge,
pricingDetail?.isBestValue && styles.discountBadgeBest,
pricingDetail?.isBasePack && styles.discountBadgeBase,
]}
>
<Text
style={[
styles.discountText,
pricingDetail?.isBestValue && styles.discountTextBest,
]}
>
{discountLabel}
</Text>
</View>
{!pricingDetail?.isBasePack && typeof discountPercent === "number" ? (
<Text style={styles.discountHelper}>
Économie estimée vs pack de base
</Text>
) : (
<Text style={styles.discountHelperMuted}>
Référence prix/jeton
</Text>
)}
</View>
) : null}
</BlurView>
</Pressable>
);
@@ -359,13 +361,14 @@ const CoinPackModal = ({ visible, onClose }) => {
]}
showsVerticalScrollIndicator={false}
>
{coinPacks.map((pack) => (
{coinPacks.map((pack, index) => (
<CoinPackCard
key={pack.productId}
pack={pack}
selected={selectedPackId === pack.productId}
pricingDetail={packPricingById[pack.productId]}
onSelect={setSelectedPackId}
staticDiscountPercent={STATIC_DISCOUNTS[index]}
/>
))}
</ScrollView>
@@ -564,6 +567,16 @@ const styles = StyleSheet.create({
color: "rgba(255, 255, 255, 0.72)",
textAlign: "center",
},
perksList: {
gap: 6,
alignItems: "center",
},
perkItem: {
fontFamily: FONT_FAMILY.InterRegular,
fontSize: 13,
color: "rgba(255, 255, 255, 0.72)",
textAlign: "center",
},
priceBlock: {
gap: 2,
alignItems: "center",
@@ -580,10 +593,6 @@ const styles = StyleSheet.create({
color: "rgba(255, 255, 255, 0.7)",
textAlign: "center",
},
discountRow: {
alignItems: "center",
gap: 6,
},
discountBadge: {
paddingHorizontal: 12,
paddingVertical: 6,
@@ -626,6 +635,9 @@ const styles = StyleSheet.create({
paddingVertical: 4,
borderRadius: 10,
backgroundColor: Palette.transparentGreen,
alignSelf: "center",
position: "absolute",
top: 10,
},
tagBestValueText: {
fontFamily: FONT_FAMILY.InterSemiBold,