Update partner packages, copy, and demo switcher
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-01-15 17:33:36 +01:00
parent 2f93271d94
commit ad829ae509
50 changed files with 1335 additions and 411 deletions

View File

@@ -58,6 +58,12 @@ export default function MobileBillingPage() {
const invoicesRef = React.useRef<HTMLDivElement | null>(null);
const supportEmail = 'support@fotospiel.de';
const back = useBackNavigation(adminPath('/mobile/profile'));
const shopLink = React.useMemo(() => {
const isPartner =
activePackage?.package_type === 'reseller' || packages.some((pkg) => pkg.package_type === 'reseller');
return isPartner ? adminPath('/mobile/billing/shop?type=reseller') : adminPath('/mobile/billing/shop');
}, [activePackage?.package_type, packages]);
const load = React.useCallback(async () => {
setLoading(true);
@@ -281,7 +287,7 @@ export default function MobileBillingPage() {
<XStack space="$2">
<CTAButton
label={t('billing.checkoutFailedRetry', 'Try again')}
onPress={() => navigate(adminPath('/mobile/billing/shop'))}
onPress={() => navigate(shopLink)}
fullWidth={false}
/>
<CTAButton
@@ -316,7 +322,7 @@ export default function MobileBillingPage() {
window.open(checkoutActionUrl, '_blank', 'noopener');
return;
}
navigate(adminPath('/mobile/billing/shop'));
navigate(shopLink);
}}
fullWidth={false}
/>
@@ -385,7 +391,7 @@ export default function MobileBillingPage() {
pkg={activePackage}
label={t('billing.sections.packages.card.statusActive', 'Aktiv')}
isActive
onOpenShop={() => navigate(adminPath('/mobile/billing/shop'))}
onOpenShop={() => navigate(shopLink)}
/>
) : null}
{packages
@@ -501,6 +507,15 @@ function PackageCard({
const { t } = useTranslation('management');
const { border, primary, accentSoft, textStrong, muted } = useAdminTheme();
const limits = (pkg.package_limits ?? null) as Record<string, unknown> | null;
const isPartnerPackage = pkg.package_type === 'reseller';
const includedTierLabel =
pkg.included_package_slug === 'starter'
? t('shop.partner.tiers.starter', 'Starter')
: pkg.included_package_slug === 'standard'
? t('shop.partner.tiers.standard', 'Standard')
: pkg.included_package_slug === 'pro'
? t('shop.partner.tiers.premium', 'Premium')
: pkg.included_package_slug;
const limitMaxEvents = typeof limits?.max_events_per_year === 'number' ? (limits?.max_events_per_year as number) : null;
const remaining = pkg.remaining_events ?? limitMaxEvents ?? 0;
const remainingText =
@@ -520,7 +535,7 @@ function PackageCard({
const limitEntries = getPackageLimitEntries(limits, t, {
remainingEvents: pkg.remaining_events ?? null,
usedEvents: typeof pkg.used_events === 'number' ? pkg.used_events : null,
});
}, { packageType: pkg.package_type });
const featureKeys = collectPackageFeatures(pkg);
const eventUsageText = formatEventUsage(
typeof pkg.used_events === 'number' ? pkg.used_events : null,
@@ -550,8 +565,9 @@ function PackageCard({
{pkg.price !== null && pkg.price !== undefined ? (
<PillBadge tone="muted">{formatAmount(pkg.price, pkg.currency ?? 'EUR')}</PillBadge>
) : null}
{renderFeatureBadge(pkg, t, 'branding_allowed', t('billing.features.branding', 'Branding'))}
{renderFeatureBadge(pkg, t, 'watermark_allowed', t('billing.features.watermark', 'Watermark'))}
{isPartnerPackage && includedTierLabel ? <PillBadge tone="muted">{includedTierLabel}</PillBadge> : null}
{!isPartnerPackage ? renderFeatureBadge(pkg, t, 'branding_allowed', t('billing.features.branding', 'Branding')) : null}
{!isPartnerPackage ? renderFeatureBadge(pkg, t, 'watermark_allowed', t('billing.features.watermark', 'Watermark')) : null}
</XStack>
{eventUsageText ? (
<Text fontSize="$xs" color={muted}>