Clarify watermark features across packages

This commit is contained in:
Codex Agent
2026-01-20 13:10:49 +01:00
parent 620dfa415a
commit 1ce0fad720
13 changed files with 157 additions and 29 deletions

View File

@@ -41,11 +41,26 @@ function normalizePackageFeatures(pkg: Package | null): string[] {
}
export function getEnabledPackageFeatures(pkg: Package): string[] {
return normalizePackageFeatures(pkg);
const features = normalizePackageFeatures(pkg);
const watermarkFeature = resolvePackageWatermarkFeatureKey(pkg, features);
if (watermarkFeature) {
const cleaned = features.filter(
(feature) => !['watermark', 'watermark_allowed', 'no_watermark', 'watermark_base', 'watermark_custom'].includes(feature)
);
cleaned.push(watermarkFeature);
return Array.from(new Set(cleaned));
}
return features;
}
function collectFeatures(pkg: Package | null): Set<string> {
return new Set(normalizePackageFeatures(pkg));
if (!pkg) {
return new Set();
}
return new Set(getEnabledPackageFeatures(pkg));
}
function compareLimit(candidate: number | null, active: number | null): number {
@@ -119,9 +134,12 @@ export function selectRecommendedPackageId(
return null;
}
const candidates = feature === 'watermark_allowed'
? packages.filter((pkg) => pkg.watermark_allowed === true)
: packages.filter((pkg) => normalizePackageFeatures(pkg).includes(feature));
const candidates =
feature === 'watermark_allowed'
? packages.filter((pkg) => pkg.watermark_allowed === true)
: feature?.startsWith('watermark')
? packages.filter((pkg) => resolvePackageWatermarkFeatureKey(pkg, normalizePackageFeatures(pkg)) === feature)
: packages.filter((pkg) => normalizePackageFeatures(pkg).includes(feature));
if (candidates.length === 0) {
return null;
}
@@ -151,7 +169,7 @@ export function buildPackageComparisonRows(packages: Package[]): PackageComparis
const featureKeys = new Set<string>();
packages.forEach((pkg) => {
normalizePackageFeatures(pkg).forEach((key) => {
getEnabledPackageFeatures(pkg).forEach((key) => {
if (key !== 'photos') {
featureKeys.add(key);
}
@@ -168,3 +186,23 @@ export function buildPackageComparisonRows(packages: Package[]): PackageComparis
return [...limitRows, ...featureRows];
}
function resolvePackageWatermarkFeatureKey(pkg: Package, features: string[]): string | null {
if (pkg.type === 'reseller') {
return null;
}
if (pkg.watermark_allowed === false) {
return 'watermark_base';
}
if (features.includes('no_watermark')) {
return 'no_watermark';
}
if (pkg.watermark_allowed === true) {
return 'watermark_custom';
}
return null;
}

View File

@@ -44,7 +44,9 @@ describe('packageSummary helpers', () => {
watermark_allowed: false,
} as any);
expect(result).toEqual(expect.arrayContaining(['custom_branding', 'reseller_dashboard', 'branding_allowed']));
expect(result).toEqual(
expect.arrayContaining(['custom_branding', 'reseller_dashboard', 'branding_allowed', 'watermark_base'])
);
});
it('returns labeled limit entries', () => {

View File

@@ -80,6 +80,18 @@ const FEATURE_LABELS: Record<string, { key: string; fallback: string }> = {
key: 'mobileDashboard.packageSummary.feature.watermark_allowed',
fallback: 'Watermarks',
},
watermark_base: {
key: 'mobileDashboard.packageSummary.feature.watermark_base',
fallback: 'Fotospiel watermark',
},
no_watermark: {
key: 'mobileDashboard.packageSummary.feature.no_watermark',
fallback: 'Remove Fotospiel watermark',
},
watermark_custom: {
key: 'mobileDashboard.packageSummary.feature.watermark_custom',
fallback: 'Custom watermark',
},
};
const LIMIT_LABELS: Array<{ key: string; labelKey: string; fallback: string }> = [
@@ -241,13 +253,38 @@ export function collectPackageFeatures(pkg: TenantPackageSummary): string[] {
features.add('branding_allowed');
}
if (pkg.package_type !== 'reseller' && pkg.watermark_allowed) {
features.add('watermark_allowed');
const watermarkFeature = resolveTenantWatermarkFeatureKey(pkg);
if (watermarkFeature) {
['watermark_allowed', 'watermark', 'no_watermark', 'watermark_base', 'watermark_custom'].forEach((key) =>
features.delete(key)
);
features.add(watermarkFeature);
}
return Array.from(features);
}
export function resolveTenantWatermarkFeatureKey(pkg: TenantPackageSummary): string | null {
if (pkg.package_type === 'reseller') {
return null;
}
if (pkg.watermark_allowed === false) {
return 'watermark_base';
}
const features = Array.isArray(pkg.features) ? pkg.features : [];
if (features.includes('no_watermark')) {
return 'no_watermark';
}
if (pkg.watermark_allowed === true) {
return 'watermark_custom';
}
return null;
}
export function formatEventUsage(used: number | null, limit: number | null, t: Translate): string | null {
if (limit === null || used === null) {
return null;