fix: handle array package features
This commit is contained in:
@@ -11,7 +11,12 @@ import { MobileCard, CTAButton, PillBadge, SkeletonCard } from './components/Pri
|
|||||||
import { useAdminTheme } from './theme';
|
import { useAdminTheme } from './theme';
|
||||||
import { getPackages, Package, getTenantPackagesOverview, TenantPackageSummary } from '../api';
|
import { getPackages, Package, getTenantPackagesOverview, TenantPackageSummary } from '../api';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
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';
|
import { usePackageCheckout } from './hooks/usePackageCheckout';
|
||||||
|
|
||||||
export default function MobilePackageShopPage() {
|
export default function MobilePackageShopPage() {
|
||||||
@@ -229,13 +234,12 @@ function PackageShopCard({
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{/* Render specific feature if it was requested */}
|
{/* Render specific feature if it was requested */}
|
||||||
{Object.entries(pkg.features || {})
|
{getEnabledPackageFeatures(pkg)
|
||||||
.filter(([key, val]) => val === true && (!pkg.max_photos || key !== 'photos'))
|
.filter((key) => !pkg.max_photos || key !== 'photos')
|
||||||
.slice(0, 3)
|
.slice(0, 3)
|
||||||
.map(([key]) => (
|
.map((key) => (
|
||||||
<FeatureRow key={key} label={t(`shop.features.${key}`, key)} />
|
<FeatureRow key={key} label={t(`shop.features.${key}`, key)} />
|
||||||
))
|
))}
|
||||||
}
|
|
||||||
</YStack>
|
</YStack>
|
||||||
|
|
||||||
<CTAButton
|
<CTAButton
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
import { buildPackageComparisonRows, classifyPackageChange, selectRecommendedPackageId } from '../lib/packageShop';
|
import {
|
||||||
|
buildPackageComparisonRows,
|
||||||
|
classifyPackageChange,
|
||||||
|
getEnabledPackageFeatures,
|
||||||
|
selectRecommendedPackageId,
|
||||||
|
} from '../lib/packageShop';
|
||||||
|
|
||||||
describe('classifyPackageChange', () => {
|
describe('classifyPackageChange', () => {
|
||||||
const active = {
|
const active = {
|
||||||
@@ -65,3 +70,9 @@ describe('buildPackageComparisonRows', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getEnabledPackageFeatures', () => {
|
||||||
|
it('accepts array payloads', () => {
|
||||||
|
expect(getEnabledPackageFeatures({ features: ['custom_branding', ''] } as any)).toEqual(['custom_branding']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -17,12 +17,30 @@ export type PackageComparisonRow =
|
|||||||
featureKey: string;
|
featureKey: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function collectFeatures(pkg: Package | null): Set<string> {
|
function normalizePackageFeatures(pkg: Package | null): string[] {
|
||||||
if (!pkg?.features) {
|
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<string> {
|
||||||
|
return new Set(normalizePackageFeatures(pkg));
|
||||||
}
|
}
|
||||||
|
|
||||||
function compareLimit(candidate: number | null, active: number | null): number {
|
function compareLimit(candidate: number | null, active: number | null): number {
|
||||||
@@ -88,7 +106,7 @@ export function selectRecommendedPackageId(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const candidates = packages.filter((pkg) => pkg.features?.[feature]);
|
const candidates = packages.filter((pkg) => normalizePackageFeatures(pkg).includes(feature));
|
||||||
if (candidates.length === 0) {
|
if (candidates.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -109,8 +127,8 @@ export function buildPackageComparisonRows(packages: Package[]): PackageComparis
|
|||||||
|
|
||||||
const featureKeys = new Set<string>();
|
const featureKeys = new Set<string>();
|
||||||
packages.forEach((pkg) => {
|
packages.forEach((pkg) => {
|
||||||
Object.entries(pkg.features ?? {}).forEach(([key, enabled]) => {
|
normalizePackageFeatures(pkg).forEach((key) => {
|
||||||
if (enabled && key !== 'photos') {
|
if (key !== 'photos') {
|
||||||
featureKeys.add(key);
|
featureKeys.add(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user