added watermark settings tab on the branding page and added more package details to the billing page, added a new guest notifications page
This commit is contained in:
@@ -44,7 +44,8 @@ export default function MobileBillingPage() {
|
||||
setAddons(addonHistory.data ?? []);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
setError(getApiErrorMessage(err, t('billing.errors.load', 'Konnte Abrechnung nicht laden.')));
|
||||
const message = getApiErrorMessage(err, t('billing.errors.load', 'Konnte Abrechnung nicht laden.'));
|
||||
setError(message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -206,18 +207,71 @@ function PackageCard({ pkg, label }: { pkg: TenantPackageSummary; label?: string
|
||||
{expires}
|
||||
</Text>
|
||||
) : null}
|
||||
<XStack space="$2" marginTop="$2">
|
||||
<XStack space="$2" marginTop="$2" flexWrap="wrap">
|
||||
<PillBadge tone="muted">
|
||||
{t('mobileBilling.remainingEvents', '{{count}} events', { count: remaining })}
|
||||
</PillBadge>
|
||||
{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'))}
|
||||
</XStack>
|
||||
<YStack space="$1.5" marginTop="$2">
|
||||
<FeatureList pkg={pkg} />
|
||||
</YStack>
|
||||
</MobileCard>
|
||||
);
|
||||
}
|
||||
|
||||
function renderFeatureBadge(pkg: TenantPackageSummary, t: any, key: string, label: string) {
|
||||
const value = (pkg.package_limits as any)?.[key] ?? (pkg as any)[key];
|
||||
if (value === undefined || value === null) return null;
|
||||
const enabled = value !== false;
|
||||
return <PillBadge tone={enabled ? 'success' : 'muted'}>{enabled ? label : `${label} off`}</PillBadge>;
|
||||
}
|
||||
|
||||
function FeatureList({ pkg }: { pkg: TenantPackageSummary }) {
|
||||
const { t } = useTranslation('management');
|
||||
const limits = pkg.package_limits ?? {};
|
||||
const features = (pkg as any).features as string[] | undefined;
|
||||
|
||||
const rows: Array<{ label: string; value: string }> = [];
|
||||
|
||||
if (limits.max_photos !== undefined && limits.max_photos !== null) {
|
||||
rows.push({ label: t('billing.features.maxPhotos', 'Max photos'), value: String(limits.max_photos) });
|
||||
}
|
||||
if (limits.max_guests !== undefined && limits.max_guests !== null) {
|
||||
rows.push({ label: t('billing.features.maxGuests', 'Max guests'), value: String(limits.max_guests) });
|
||||
}
|
||||
if (limits.gallery_days !== undefined && limits.gallery_days !== null) {
|
||||
rows.push({ label: t('billing.features.galleryDays', 'Gallery days'), value: String(limits.gallery_days) });
|
||||
}
|
||||
if (limits.max_tasks !== undefined && limits.max_tasks !== null) {
|
||||
rows.push({ label: t('billing.features.maxTasks', 'Max tasks'), value: String(limits.max_tasks) });
|
||||
}
|
||||
if (Array.isArray(features) && features.length) {
|
||||
rows.push({ label: t('billing.features.featureList', 'Included features'), value: features.join(', ') });
|
||||
}
|
||||
|
||||
if (!rows.length) return null;
|
||||
|
||||
return (
|
||||
<YStack space="$1">
|
||||
{rows.map((row) => (
|
||||
<XStack key={row.label} alignItems="center" justifyContent="space-between">
|
||||
<Text fontSize="$xs" color="#6b7280">
|
||||
{row.label}
|
||||
</Text>
|
||||
<Text fontSize="$xs" color="#0f172a" fontWeight="700">
|
||||
{row.value}
|
||||
</Text>
|
||||
</XStack>
|
||||
))}
|
||||
</YStack>
|
||||
);
|
||||
}
|
||||
|
||||
function formatAmount(value: number | null | undefined, currency: string | null | undefined): string {
|
||||
if (value === null || value === undefined) {
|
||||
return '—';
|
||||
|
||||
Reference in New Issue
Block a user