From e93a00f0fc4b6067fc06ad8b9a90c51d53e841c6 Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Mon, 12 Jan 2026 12:40:18 +0100 Subject: [PATCH] fix: block non-upgrade package selection --- resources/js/admin/mobile/PackageShopPage.tsx | 24 +++++++++---------- .../mobile/__tests__/packageShop.test.ts | 5 ++++ resources/js/admin/mobile/lib/packageShop.ts | 2 +- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/resources/js/admin/mobile/PackageShopPage.tsx b/resources/js/admin/mobile/PackageShopPage.tsx index 68f1e5c..513be5e 100644 --- a/resources/js/admin/mobile/PackageShopPage.tsx +++ b/resources/js/admin/mobile/PackageShopPage.tsx @@ -182,8 +182,8 @@ function PackageShopCard({ const { t } = useTranslation('management'); const statusLabel = getPackageStatusLabel({ t, isActive, owned }); - const isSubdued = Boolean(isDowngrade && !isActive); - const canSelect = canSelectPackage(isDowngrade, isActive); + const isSubdued = Boolean((isDowngrade || !isUpgrade) && !isActive); + const canSelect = canSelectPackage(isUpgrade, isActive); return ( @@ -425,12 +425,12 @@ function PackageShopCompareView({ {entries.map((entry) => { - const canSelect = canSelectPackage(entry.isDowngrade, entry.isActive); + const canSelect = canSelectPackage(entry.isUpgrade, entry.isActive); const label = entry.isActive ? t('shop.manage', 'Manage Plan') - : entry.isDowngrade - ? t('shop.selectDisabled', 'Not available') - : t('shop.select', 'Select'); + : entry.isUpgrade + ? t('shop.select', 'Select') + : t('shop.selectDisabled', 'Not available'); return ( @@ -470,8 +470,8 @@ function getPackageStatusLabel({ return null; } -function canSelectPackage(isDowngrade?: boolean, isActive?: boolean): boolean { - return !isDowngrade || Boolean(isActive); +function canSelectPackage(isUpgrade?: boolean, isActive?: boolean): boolean { + return Boolean(isActive || isUpgrade); } function CheckoutConfirmation({ pkg, onCancel }: { pkg: Package; onCancel: () => void }) { diff --git a/resources/js/admin/mobile/__tests__/packageShop.test.ts b/resources/js/admin/mobile/__tests__/packageShop.test.ts index 27defd0..2f5e7a4 100644 --- a/resources/js/admin/mobile/__tests__/packageShop.test.ts +++ b/resources/js/admin/mobile/__tests__/packageShop.test.ts @@ -29,6 +29,11 @@ describe('classifyPackageChange', () => { const candidate = { ...active, id: 3, max_photos: 50, features: { advanced_analytics: false } } as any; expect(classifyPackageChange(candidate, active)).toEqual({ isUpgrade: false, isDowngrade: true }); }); + + it('treats mixed changes as downgrade', () => { + const candidate = { ...active, id: 4, max_photos: 200, gallery_days: 10, features: { advanced_analytics: false } } as any; + expect(classifyPackageChange(candidate, active)).toEqual({ isUpgrade: false, isDowngrade: true }); + }); }); describe('selectRecommendedPackageId', () => { diff --git a/resources/js/admin/mobile/lib/packageShop.ts b/resources/js/admin/mobile/lib/packageShop.ts index 84aaabc..b07ec7d 100644 --- a/resources/js/admin/mobile/lib/packageShop.ts +++ b/resources/js/admin/mobile/lib/packageShop.ts @@ -86,7 +86,7 @@ export function classifyPackageChange(pkg: Package, active: Package | null): Pac const hasUpgrade = hasFeatureUpgrade || hasLimitUpgrade; const hasDowngrade = hasFeatureDowngrade || hasLimitDowngrade; - if (hasUpgrade) { + if (hasUpgrade && !hasDowngrade) { return { isUpgrade: true, isDowngrade: false }; }