diff --git a/resources/js/admin/mobile/PackageShopPage.tsx b/resources/js/admin/mobile/PackageShopPage.tsx
index c966e4c..9a7fcb8 100644
--- a/resources/js/admin/mobile/PackageShopPage.tsx
+++ b/resources/js/admin/mobile/PackageShopPage.tsx
@@ -11,7 +11,12 @@ import { MobileCard, CTAButton, PillBadge, SkeletonCard } from './components/Pri
import { useAdminTheme } from './theme';
import { getPackages, Package, getTenantPackagesOverview, TenantPackageSummary } from '../api';
import { useQuery } from '@tanstack/react-query';
-import { buildPackageComparisonRows, classifyPackageChange, selectRecommendedPackageId } from './lib/packageShop';
+import {
+ buildPackageComparisonRows,
+ classifyPackageChange,
+ getEnabledPackageFeatures,
+ selectRecommendedPackageId,
+} from './lib/packageShop';
import { usePackageCheckout } from './hooks/usePackageCheckout';
export default function MobilePackageShopPage() {
@@ -229,13 +234,12 @@ function PackageShopCard({
) : null}
{/* Render specific feature if it was requested */}
- {Object.entries(pkg.features || {})
- .filter(([key, val]) => val === true && (!pkg.max_photos || key !== 'photos'))
- .slice(0, 3)
- .map(([key]) => (
-
- ))
- }
+ {getEnabledPackageFeatures(pkg)
+ .filter((key) => !pkg.max_photos || key !== 'photos')
+ .slice(0, 3)
+ .map((key) => (
+
+ ))}
{
const active = {
@@ -65,3 +70,9 @@ describe('buildPackageComparisonRows', () => {
]);
});
});
+
+describe('getEnabledPackageFeatures', () => {
+ it('accepts array payloads', () => {
+ expect(getEnabledPackageFeatures({ features: ['custom_branding', ''] } as any)).toEqual(['custom_branding']);
+ });
+});
diff --git a/resources/js/admin/mobile/lib/packageShop.ts b/resources/js/admin/mobile/lib/packageShop.ts
index fe5e643..84aaabc 100644
--- a/resources/js/admin/mobile/lib/packageShop.ts
+++ b/resources/js/admin/mobile/lib/packageShop.ts
@@ -17,12 +17,30 @@ export type PackageComparisonRow =
featureKey: string;
};
-function collectFeatures(pkg: Package | null): Set {
+function normalizePackageFeatures(pkg: Package | null): string[] {
if (!pkg?.features) {
- return new Set();
+ return [];
}
- return new Set(Object.entries(pkg.features).filter(([, enabled]) => enabled).map(([key]) => key));
+ if (Array.isArray(pkg.features)) {
+ return pkg.features.filter((feature): feature is string => typeof feature === 'string' && feature.trim().length > 0);
+ }
+
+ if (typeof pkg.features === 'object') {
+ return Object.entries(pkg.features)
+ .filter(([, enabled]) => enabled)
+ .map(([key]) => key);
+ }
+
+ return [];
+}
+
+export function getEnabledPackageFeatures(pkg: Package): string[] {
+ return normalizePackageFeatures(pkg);
+}
+
+function collectFeatures(pkg: Package | null): Set {
+ return new Set(normalizePackageFeatures(pkg));
}
function compareLimit(candidate: number | null, active: number | null): number {
@@ -88,7 +106,7 @@ export function selectRecommendedPackageId(
return null;
}
- const candidates = packages.filter((pkg) => pkg.features?.[feature]);
+ const candidates = packages.filter((pkg) => normalizePackageFeatures(pkg).includes(feature));
if (candidates.length === 0) {
return null;
}
@@ -109,8 +127,8 @@ export function buildPackageComparisonRows(packages: Package[]): PackageComparis
const featureKeys = new Set();
packages.forEach((pkg) => {
- Object.entries(pkg.features ?? {}).forEach(([key, enabled]) => {
- if (enabled && key !== 'photos') {
+ normalizePackageFeatures(pkg).forEach((key) => {
+ if (key !== 'photos') {
featureKeys.add(key);
}
});