diff --git a/src/pages/Subscription.tsx b/src/pages/Subscription.tsx index eaf5a1b..3f5f5cd 100644 --- a/src/pages/Subscription.tsx +++ b/src/pages/Subscription.tsx @@ -89,24 +89,47 @@ export default function Subscription() { // Helper to format price from kopeks const formatPrice = (kopeks: number) => `${formatAmount(kopeks / 100)} ${currencySymbol}`; - // Helper to apply promo discount to a price + // Helper to apply promo discount to a price, stacking with existing promo group discount const applyPromoDiscount = ( priceKopeks: number, - hasExistingDiscount: boolean = false, + existingOriginalPrice?: number | null, ): { price: number; original: number | null; percent: number | null; + isPromoGroup: boolean; } => { - // Only apply promo discount if no existing discount (from promo group) and we have an active promo discount - if (!activeDiscount?.is_active || !activeDiscount.discount_percent || hasExistingDiscount) { - return { price: priceKopeks, original: null, percent: null }; + const hasExisting = (existingOriginalPrice ?? 0) > priceKopeks; + const hasPromo = !!activeDiscount?.is_active && !!activeDiscount.discount_percent; + + if (!hasExisting && !hasPromo) { + return { price: priceKopeks, original: null, percent: null, isPromoGroup: false }; } - const discountedPrice = Math.round(priceKopeks * (1 - activeDiscount.discount_percent / 100)); + + let finalPrice = priceKopeks; + if (hasPromo) { + finalPrice = Math.round(priceKopeks * (1 - activeDiscount!.discount_percent! / 100)); + } + + if (hasExisting) { + // Promo group discount exists — calculate combined percent from deepest original + const combinedPercent = hasPromo + ? Math.round((1 - finalPrice / existingOriginalPrice!) * 100) + : Math.round((1 - priceKopeks / existingOriginalPrice!) * 100); + return { + price: finalPrice, + original: existingOriginalPrice!, + percent: combinedPercent, + isPromoGroup: true, + }; + } + + // Only promo offer discount (no promo group) return { - price: discountedPrice, + price: finalPrice, original: priceKopeks, - percent: activeDiscount.discount_percent, + percent: activeDiscount!.discount_percent!, + isPromoGroup: false, }; }; @@ -2416,41 +2439,34 @@ export default function Subscription() { const dailyPrice = tariff.daily_price_kopeks ?? tariff.price_per_day_kopeks ?? 0; const originalDailyPrice = tariff.original_daily_price_kopeks || 0; - const hasExistingDailyDiscount = originalDailyPrice > dailyPrice; if (dailyPrice > 0) { - // Apply promo discount if no existing discount const promoDaily = applyPromoDiscount( dailyPrice, - hasExistingDailyDiscount, + originalDailyPrice > dailyPrice ? originalDailyPrice : undefined, ); return ( {formatPrice(promoDaily.price)} - {/* Show original price from promo group or promo offer */} - {(hasExistingDailyDiscount || promoDaily.original) && ( - - {formatPrice( - hasExistingDailyDiscount - ? originalDailyPrice - : promoDaily.original!, - )} - - )} + {promoDaily.original && + promoDaily.original > promoDaily.price && ( + + {formatPrice(promoDaily.original)} + + )} {t('subscription.tariff.perDay')} {/* Show discount badge */} - {tariff.daily_discount_percent && - tariff.daily_discount_percent > 0 ? ( - - -{tariff.daily_discount_percent}% + {promoDaily.percent && promoDaily.percent > 0 && ( + + -{promoDaily.percent}% - ) : ( - promoDaily.percent && ( - - -{promoDaily.percent}% - - ) )} ); @@ -2458,14 +2474,9 @@ export default function Subscription() { // Period-based price if (tariff.periods.length > 0) { const firstPeriod = tariff.periods[0]; - const hasExistingDiscount = !!( - firstPeriod?.original_price_kopeks && - firstPeriod.original_price_kopeks > firstPeriod.price_kopeks - ); - // Apply promo discount if no existing discount const promoPeriod = applyPromoDiscount( firstPeriod?.price_kopeks || 0, - hasExistingDiscount, + firstPeriod?.original_price_kopeks, ); return ( @@ -2473,27 +2484,22 @@ export default function Subscription() { {formatPrice(promoPeriod.price)} - {/* Show original price from promo group or promo offer */} - {(hasExistingDiscount || promoPeriod.original) && ( - - {formatPrice( - hasExistingDiscount - ? firstPeriod.original_price_kopeks! - : promoPeriod.original!, - )} - - )} - {/* Show discount badge */} - {hasExistingDiscount && firstPeriod.discount_percent ? ( - - -{firstPeriod.discount_percent}% - - ) : ( - promoPeriod.percent && ( - - -{promoPeriod.percent}% + {promoPeriod.original && + promoPeriod.original > promoPeriod.price && ( + + {formatPrice(promoPeriod.original)} - ) + )} + {promoPeriod.percent && promoPeriod.percent > 0 && ( + + -{promoPeriod.percent}% + )} ); @@ -2702,24 +2708,17 @@ export default function Subscription() { {selectedTariff.periods.length > 0 && !useCustomDays && (
{selectedTariff.periods.map((period) => { - const hasExistingDiscount = !!( - period.original_price_kopeks && - period.original_price_kopeks > period.price_kopeks - ); const promoPeriod = applyPromoDiscount( period.price_kopeks, - hasExistingDiscount, + period.original_price_kopeks, ); - const displayDiscount = hasExistingDiscount - ? period.discount_percent - : promoPeriod.percent; - const displayOriginal = hasExistingDiscount - ? period.original_price_kopeks - : promoPeriod.original; + const displayDiscount = promoPeriod.percent; + const displayOriginal = promoPeriod.original; const displayPrice = promoPeriod.price; - const displayPerMonth = hasExistingDiscount - ? period.price_per_month_kopeks - : Math.round(promoPeriod.price / (period.days / 30)); + const displayPerMonth = + displayPrice !== period.price_kopeks + ? Math.round(displayPrice / Math.max(1, period.days / 30)) + : period.price_per_month_kopeks; return (
) : ( @@ -3035,16 +3049,12 @@ export default function Subscription() {
{formatPrice(promoPeriod.price)} - {(hasExistingPeriodDiscount || - promoPeriod.original) && ( - - {formatPrice( - hasExistingPeriodDiscount - ? selectedTariffPeriod.original_price_kopeks! - : promoPeriod.original!, - )} - - )} + {promoPeriod.original && + promoPeriod.original > promoPeriod.price && ( + + {formatPrice(promoPeriod.original)} + + )}
)} @@ -3177,19 +3187,10 @@ export default function Subscription() { {currentStep === 'period' && classicOptions && (
{classicOptions.periods.map((period) => { - const hasExistingDiscount = !!( - period.discount_percent && period.discount_percent > 0 - ); const promoPeriod = applyPromoDiscount( period.price_kopeks, - hasExistingDiscount, + period.original_price_kopeks, ); - const displayDiscount = hasExistingDiscount - ? period.discount_percent - : promoPeriod.percent; - const displayOriginal = hasExistingDiscount - ? period.original_price_kopeks - : promoPeriod.original; return (
@@ -3249,12 +3250,9 @@ export default function Subscription() { {currentStep === 'traffic' && selectedPeriod?.traffic.options && (
{selectedPeriod.traffic.options.map((option) => { - const hasExistingDiscount = !!( - option.discount_percent && option.discount_percent > 0 - ); const promoTraffic = applyPromoDiscount( option.price_kopeks, - hasExistingDiscount, + option.original_price_kopeks, ); return ( @@ -3268,41 +3266,24 @@ export default function Subscription() { : '' } ${!option.is_available ? 'cursor-not-allowed opacity-50' : ''}`} > - {(() => { - const trafficDisplayDiscount = hasExistingDiscount - ? option.discount_percent - : promoTraffic.percent; - const trafficDisplayOriginal = hasExistingDiscount - ? option.original_price_kopeks - : promoTraffic.original; - return ( - <> - {trafficDisplayDiscount && trafficDisplayDiscount > 0 && ( -
- -{trafficDisplayDiscount}% -
- )} -
- {option.label} -
-
- - {formatPrice(promoTraffic.price)} - - {trafficDisplayOriginal && - trafficDisplayOriginal > promoTraffic.price && ( - - {formatPrice(trafficDisplayOriginal)} - - )} -
- - ); - })()} + {promoTraffic.percent && promoTraffic.percent > 0 && ( +
+ -{promoTraffic.percent}% +
+ )} +
{option.label}
+
+ {formatPrice(promoTraffic.price)} + {promoTraffic.original && promoTraffic.original > promoTraffic.price && ( + + {formatPrice(promoTraffic.original)} + + )} +
); })} @@ -3322,12 +3303,9 @@ export default function Subscription() { return true; }) .map((server) => { - const hasExistingDiscount = !!( - server.discount_percent && server.discount_percent > 0 - ); const promoServer = applyPromoDiscount( server.price_kopeks, - hasExistingDiscount, + server.original_price_kopeks, ); return ( @@ -3343,20 +3321,15 @@ export default function Subscription() { : 'cursor-not-allowed border-dark-800/30 bg-dark-900/30 opacity-50' }`} > - {(() => { - const serverDisplayDiscount = hasExistingDiscount - ? server.discount_percent - : promoServer.percent; - return serverDisplayDiscount && serverDisplayDiscount > 0 ? ( -
- -{serverDisplayDiscount}% -
- ) : null; - })()} + {promoServer.percent && promoServer.percent > 0 ? ( +
+ -{promoServer.percent}% +
+ ) : null}
- {(() => { - const serverOriginal = hasExistingDiscount - ? server.original_price_kopeks - : promoServer.original; - return serverOriginal && serverOriginal > promoServer.price ? ( - - {formatPrice(serverOriginal)} - - ) : null; - })()} + {promoServer.original && + promoServer.original > promoServer.price ? ( + + {formatPrice(promoServer.original)} + + ) : null}
@@ -3448,28 +3417,26 @@ export default function Subscription() { ) : preview ? (
{/* Active promo discount banner */} - {activeDiscount?.is_active && - activeDiscount.discount_percent && - !preview.original_price_kopeks && ( -
- - - - - {t('promo.discountApplied')} -{activeDiscount.discount_percent}% - -
- )} + {activeDiscount?.is_active && activeDiscount.discount_percent && ( +
+ + + + + {t('promo.discountApplied')} -{activeDiscount.discount_percent}% + +
+ )} {preview.breakdown.map((item, idx) => (
@@ -3479,16 +3446,10 @@ export default function Subscription() { ))} {(() => { - // Apply promo discount if not already applied by server - const hasServerDiscount = !!preview.original_price_kopeks; const promoTotal = applyPromoDiscount( preview.total_price_kopeks, - hasServerDiscount, + preview.original_price_kopeks, ); - const displayTotal = promoTotal.price; - const displayOriginal = hasServerDiscount - ? preview.original_price_kopeks - : promoTotal.original; return (
@@ -3497,11 +3458,11 @@ export default function Subscription() {
- {formatPrice(displayTotal)} + {formatPrice(promoTotal.price)}
- {displayOriginal && ( + {promoTotal.original && promoTotal.original > promoTotal.price && (
- {formatPrice(displayOriginal)} + {formatPrice(promoTotal.original)}
)}