Fix endcustomer package allocation and event create gating
This commit is contained in:
@@ -90,6 +90,20 @@ function resellerHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
return limitMaxEvents > usedEvents;
|
||||
}
|
||||
|
||||
function endcustomerHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
if (pkg.package_type !== 'endcustomer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const linkedEvents = toNumber(pkg.linked_events_count) ?? 0;
|
||||
|
||||
return linkedEvents < 1;
|
||||
}
|
||||
|
||||
function packageHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
return resellerHasRemainingEvents(pkg) || endcustomerHasRemainingEvents(pkg);
|
||||
}
|
||||
|
||||
// --- TAMAGUI-ALIGNED PRIMITIVES ---
|
||||
|
||||
function DashboardCard({
|
||||
@@ -252,7 +266,7 @@ export default function MobileDashboardPage() {
|
||||
}
|
||||
|
||||
const activePackages = collectActivePackages(packagesOverview ?? null);
|
||||
return activePackages.some((pkg) => resellerHasRemainingEvents(pkg));
|
||||
return activePackages.some((pkg) => packageHasRemainingEvents(pkg));
|
||||
}, [canManageEvents, isSuperAdmin, isMember, packagesLoading, packagesOverview]);
|
||||
|
||||
const locale = i18n.language?.startsWith('en') ? 'en-GB' : 'de-DE';
|
||||
|
||||
@@ -99,7 +99,7 @@ export default function MobileEventsPage() {
|
||||
}
|
||||
|
||||
const activePackages = collectActivePackages(packagesOverview);
|
||||
return activePackages.some((pkg) => resellerHasRemainingEvents(pkg));
|
||||
return activePackages.some((pkg) => packageHasRemainingEvents(pkg));
|
||||
}, [isMember, isSuperAdmin, packagesLoading, packagesOverview]);
|
||||
|
||||
return (
|
||||
@@ -570,6 +570,20 @@ function resellerHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
return limitMaxEvents > usedEvents;
|
||||
}
|
||||
|
||||
function endcustomerHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
if (pkg.package_type !== 'endcustomer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const linkedEvents = toNumber(pkg.linked_events_count) ?? 0;
|
||||
|
||||
return linkedEvents < 1;
|
||||
}
|
||||
|
||||
function packageHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
return resellerHasRemainingEvents(pkg) || endcustomerHasRemainingEvents(pkg);
|
||||
}
|
||||
|
||||
function resolveEventSearchName(name: TenantEvent['name'], t: (key: string) => string): string {
|
||||
if (typeof name === 'string') return name;
|
||||
if (name && typeof name === 'object') {
|
||||
|
||||
@@ -79,6 +79,7 @@ vi.mock('../../api', () => ({
|
||||
purchased_at: null,
|
||||
expires_at: null,
|
||||
package_limits: null,
|
||||
linked_events_count: 0,
|
||||
},
|
||||
],
|
||||
activePackage: {
|
||||
@@ -95,6 +96,7 @@ vi.mock('../../api', () => ({
|
||||
purchased_at: null,
|
||||
expires_at: null,
|
||||
package_limits: null,
|
||||
linked_events_count: 0,
|
||||
},
|
||||
}),
|
||||
}));
|
||||
@@ -295,6 +297,49 @@ describe('MobileEventsPage', () => {
|
||||
expect(await screen.findByText('New event')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the create button for available endcustomer packages', async () => {
|
||||
vi.mocked(api.getTenantPackagesOverview).mockResolvedValueOnce({
|
||||
packages: [
|
||||
{
|
||||
id: 3,
|
||||
package_id: 3,
|
||||
package_name: 'Classic',
|
||||
package_type: 'endcustomer',
|
||||
included_package_slug: null,
|
||||
active: true,
|
||||
used_events: 0,
|
||||
remaining_events: null,
|
||||
price: 120,
|
||||
currency: 'EUR',
|
||||
purchased_at: null,
|
||||
expires_at: null,
|
||||
package_limits: null,
|
||||
linked_events_count: 0,
|
||||
},
|
||||
],
|
||||
activePackage: {
|
||||
id: 3,
|
||||
package_id: 3,
|
||||
package_name: 'Classic',
|
||||
package_type: 'endcustomer',
|
||||
included_package_slug: null,
|
||||
active: true,
|
||||
used_events: 0,
|
||||
remaining_events: null,
|
||||
price: 120,
|
||||
currency: 'EUR',
|
||||
purchased_at: null,
|
||||
expires_at: null,
|
||||
package_limits: null,
|
||||
linked_events_count: 0,
|
||||
},
|
||||
});
|
||||
|
||||
render(<MobileEventsPage />);
|
||||
|
||||
expect(await screen.findByText('New event')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hides the create button when no remaining events are available', async () => {
|
||||
vi.mocked(api.getTenantPackagesOverview).mockResolvedValueOnce({
|
||||
packages: [
|
||||
@@ -336,4 +381,48 @@ describe('MobileEventsPage', () => {
|
||||
expect(await screen.findByText('Demo Event')).toBeInTheDocument();
|
||||
expect(screen.queryByText('New event')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hides the create button for consumed endcustomer packages', async () => {
|
||||
vi.mocked(api.getTenantPackagesOverview).mockResolvedValueOnce({
|
||||
packages: [
|
||||
{
|
||||
id: 4,
|
||||
package_id: 4,
|
||||
package_name: 'Classic',
|
||||
package_type: 'endcustomer',
|
||||
included_package_slug: null,
|
||||
active: true,
|
||||
used_events: 0,
|
||||
remaining_events: null,
|
||||
price: 120,
|
||||
currency: 'EUR',
|
||||
purchased_at: null,
|
||||
expires_at: null,
|
||||
package_limits: null,
|
||||
linked_events_count: 1,
|
||||
},
|
||||
],
|
||||
activePackage: {
|
||||
id: 4,
|
||||
package_id: 4,
|
||||
package_name: 'Classic',
|
||||
package_type: 'endcustomer',
|
||||
included_package_slug: null,
|
||||
active: true,
|
||||
used_events: 0,
|
||||
remaining_events: null,
|
||||
price: 120,
|
||||
currency: 'EUR',
|
||||
purchased_at: null,
|
||||
expires_at: null,
|
||||
package_limits: null,
|
||||
linked_events_count: 1,
|
||||
},
|
||||
});
|
||||
|
||||
render(<MobileEventsPage />);
|
||||
|
||||
expect(await screen.findByText('Demo Event')).toBeInTheDocument();
|
||||
expect(screen.queryByText('New event')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -85,6 +85,20 @@ function resellerHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
return limitMaxEvents > usedEvents;
|
||||
}
|
||||
|
||||
function endcustomerHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
if (pkg.package_type !== 'endcustomer') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const linkedEvents = toNumber(pkg.linked_events_count) ?? 0;
|
||||
|
||||
return linkedEvents < 1;
|
||||
}
|
||||
|
||||
function packageHasRemainingEvents(pkg: TenantPackageSummary): boolean {
|
||||
return resellerHasRemainingEvents(pkg) || endcustomerHasRemainingEvents(pkg);
|
||||
}
|
||||
|
||||
export function MobileShell({ title, subtitle, children, activeTab, onBack, headerActions }: MobileShellProps) {
|
||||
const { events, activeEvent, selectEvent } = useEventContext();
|
||||
const { user } = useAuth();
|
||||
@@ -219,7 +233,7 @@ export function MobileShell({ title, subtitle, children, activeTab, onBack, head
|
||||
}
|
||||
|
||||
const activePackages = collectActivePackages(packagesOverview ?? null);
|
||||
return activePackages.some((pkg) => resellerHasRemainingEvents(pkg));
|
||||
return activePackages.some((pkg) => packageHasRemainingEvents(pkg));
|
||||
}, [isMember, isSuperAdmin, packagesLoading, packagesOverview]);
|
||||
|
||||
// --- CONTEXT PILL ---
|
||||
|
||||
Reference in New Issue
Block a user