Disallow downgrades in package shop

This commit is contained in:
Codex Agent
2026-01-12 11:45:12 +01:00
parent ad336f5e18
commit 47f6343347
5 changed files with 108 additions and 34 deletions

View File

@@ -13,7 +13,7 @@ import { useAdminTheme } from './theme';
import { getPackages, createTenantPaddleCheckout, Package, getTenantPackagesOverview, TenantPackageSummary } from '../api';
import { getApiErrorMessage } from '../lib/apiError';
import { useQuery } from '@tanstack/react-query';
import { classifyPackageTier, selectRecommendedPackageId } from './lib/packageShop';
import { classifyPackageChange, selectRecommendedPackageId } from './lib/packageShop';
export default function MobilePackageShopPage() {
const { t } = useTranslation('management');
@@ -60,8 +60,7 @@ export default function MobilePackageShopPage() {
const activePackageId = inventory?.activePackage?.package_id ?? null;
const activeCatalogPackage = (catalog ?? []).find((pkg) => pkg.id === activePackageId) ?? null;
const activePrice = activeCatalogPackage?.price ?? null;
const recommendedPackageId = selectRecommendedPackageId(catalog ?? [], recommendedFeature, activePrice);
const recommendedPackageId = selectRecommendedPackageId(catalog ?? [], recommendedFeature, activeCatalogPackage);
// Merge and sort packages
const sortedPackages = [...(catalog || [])].sort((a, b) => {
@@ -101,7 +100,7 @@ export default function MobilePackageShopPage() {
const owned = inventory?.packages?.find(p => p.package_id === pkg.id);
const isActive = inventory?.activePackage?.package_id === pkg.id;
const isRecommended = recommendedPackageId ? pkg.id === recommendedPackageId : false;
const { isUpgrade, isDowngrade } = classifyPackageTier(pkg.price, activePrice);
const { isUpgrade, isDowngrade } = classifyPackageChange(pkg, activeCatalogPackage);
return (
<PackageShopCard
@@ -151,14 +150,15 @@ function PackageShopCard({
: t('shop.status.owned', 'Purchased'))
: null;
const isSubdued = Boolean(isDowngrade && !isActive);
const canSelect = !isDowngrade || isActive;
return (
<MobileCard
onPress={onSelect}
onPress={canSelect ? onSelect : undefined}
borderColor={isRecommended ? primary : (isActive ? '$green8' : border)}
borderWidth={isRecommended || isActive ? 2 : 1}
space="$3"
pressStyle={{ backgroundColor: accentSoft }}
pressStyle={canSelect ? { backgroundColor: accentSoft } : undefined}
backgroundColor={isActive ? '$green1' : undefined}
style={{ opacity: isSubdued ? 0.6 : 1 }}
>
@@ -211,9 +211,16 @@ function PackageShopCard({
</YStack>
<CTAButton
label={isActive ? t('shop.manage', 'Manage Plan') : t('shop.select', 'Select')}
onPress={onSelect}
tone={isActive ? 'ghost' : 'primary'}
label={
isActive
? t('shop.manage', 'Manage Plan')
: isDowngrade
? t('shop.selectDisabled', 'Not available')
: t('shop.select', 'Select')
}
onPress={canSelect ? onSelect : undefined}
tone={isActive || isDowngrade ? 'ghost' : 'primary'}
disabled={!canSelect}
/>
</MobileCard>
);