Improve package usage visibility
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type { TenantPackageSummary } from '../api';
|
||||
|
||||
export type PackageUsageMetricKey = 'events' | 'guests' | 'photos';
|
||||
export type PackageUsageMetricKey = 'events' | 'guests' | 'photos' | 'gallery';
|
||||
|
||||
export type PackageUsageMetric = {
|
||||
key: PackageUsageMetricKey;
|
||||
@@ -9,6 +9,8 @@ export type PackageUsageMetric = {
|
||||
remaining: number | null;
|
||||
};
|
||||
|
||||
export type PackageUsageState = 'ok' | 'warning' | 'danger';
|
||||
|
||||
const toNumber = (value: unknown): number | null => {
|
||||
if (typeof value === 'number' && Number.isFinite(value)) {
|
||||
return value;
|
||||
@@ -48,25 +50,56 @@ const deriveUsedFromRemaining = (limit: number | null, remaining: number | null)
|
||||
return Math.max(limit - remaining, 0);
|
||||
};
|
||||
|
||||
const deriveRemainingFromUsed = (limit: number | null, used: number | null): number | null => {
|
||||
if (limit === null || used === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Math.max(limit - used, 0);
|
||||
};
|
||||
|
||||
const normalizeCount = (value: number | null, precision: 'round' | 'floor' = 'round'): number | null => {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const safe = Number.isFinite(value) ? value : null;
|
||||
if (safe === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Math.max(0, precision === 'floor' ? Math.floor(safe) : Math.round(safe));
|
||||
};
|
||||
|
||||
export const buildPackageUsageMetrics = (pkg: TenantPackageSummary): PackageUsageMetric[] => {
|
||||
const limits = pkg.package_limits ?? {};
|
||||
|
||||
const eventLimit = resolveLimitValue(limits, 'max_events_per_year');
|
||||
const eventRemaining = resolveUsageValue(pkg.remaining_events);
|
||||
const eventUsed = resolveUsageValue(pkg.used_events) ?? deriveUsedFromRemaining(eventLimit, eventRemaining);
|
||||
const resolvedEventRemaining = eventRemaining ?? deriveRemainingFromUsed(eventLimit, eventUsed);
|
||||
|
||||
const guestLimit = resolveLimitValue(limits, 'max_guests');
|
||||
const guestRemaining = resolveUsageValue(limits['remaining_guests']);
|
||||
const guestUsed = resolveUsageValue(limits['used_guests']) ?? deriveUsedFromRemaining(guestLimit, guestRemaining);
|
||||
const resolvedGuestRemaining = guestRemaining ?? deriveRemainingFromUsed(guestLimit, guestUsed);
|
||||
|
||||
const photoLimit = resolveLimitValue(limits, 'max_photos');
|
||||
const photoRemaining = resolveUsageValue(limits['remaining_photos']);
|
||||
const photoUsed = resolveUsageValue(limits['used_photos']) ?? deriveUsedFromRemaining(photoLimit, photoRemaining);
|
||||
const resolvedPhotoRemaining = photoRemaining ?? deriveRemainingFromUsed(photoLimit, photoUsed);
|
||||
|
||||
const galleryLimit = resolveLimitValue(limits, 'gallery_days');
|
||||
const galleryRemaining = resolveUsageValue(limits['remaining_gallery_days']);
|
||||
const galleryUsed = resolveUsageValue(limits['used_gallery_days']) ?? deriveUsedFromRemaining(galleryLimit, galleryRemaining);
|
||||
const resolvedGalleryRemaining = normalizeCount(galleryRemaining ?? deriveRemainingFromUsed(galleryLimit, galleryUsed));
|
||||
const resolvedGalleryUsed = normalizeCount(galleryUsed);
|
||||
|
||||
return [
|
||||
{ key: 'events', limit: eventLimit, used: eventUsed, remaining: eventRemaining },
|
||||
{ key: 'guests', limit: guestLimit, used: guestUsed, remaining: guestRemaining },
|
||||
{ key: 'photos', limit: photoLimit, used: photoUsed, remaining: photoRemaining },
|
||||
{ key: 'events', limit: eventLimit, used: eventUsed, remaining: resolvedEventRemaining },
|
||||
{ key: 'guests', limit: guestLimit, used: guestUsed, remaining: resolvedGuestRemaining },
|
||||
{ key: 'photos', limit: photoLimit, used: photoUsed, remaining: resolvedPhotoRemaining },
|
||||
{ key: 'gallery', limit: galleryLimit, used: resolvedGalleryUsed, remaining: resolvedGalleryRemaining },
|
||||
].filter((metric) => metric.limit !== null);
|
||||
};
|
||||
|
||||
@@ -81,3 +114,28 @@ export const usagePercent = (metric: PackageUsageMetric): number => {
|
||||
|
||||
return Math.min(100, Math.max(0, Math.round((metric.used / metric.limit) * 100)));
|
||||
};
|
||||
|
||||
export const getUsageState = (metric: PackageUsageMetric): PackageUsageState => {
|
||||
if (!metric.limit || metric.limit <= 0) {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
if (metric.remaining !== null && metric.remaining <= 0) {
|
||||
return 'danger';
|
||||
}
|
||||
|
||||
if (metric.used === null) {
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
const percent = usagePercent(metric);
|
||||
if (percent >= 95) {
|
||||
return 'danger';
|
||||
}
|
||||
|
||||
if (percent >= 80) {
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
return 'ok';
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user