Limit-Status im Upload-Flow anzeigen (Warnbanner + Sperrzustände).
Upload-Fehlercodes auswerten und freundliche Dialoge zeigen.
This commit is contained in:
107
resources/js/guest/lib/limitSummaries.ts
Normal file
107
resources/js/guest/lib/limitSummaries.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import type { EventPackageLimits, LimitUsageSummary } from '../services/eventApi';
|
||||
|
||||
export type LimitTone = 'neutral' | 'warning' | 'danger';
|
||||
|
||||
export type LimitSummaryCard = {
|
||||
id: 'photos' | 'guests';
|
||||
label: string;
|
||||
state: LimitUsageSummary['state'];
|
||||
tone: LimitTone;
|
||||
used: number;
|
||||
limit: number | null;
|
||||
remaining: number | null;
|
||||
progress: number | null;
|
||||
valueLabel: string;
|
||||
description: string;
|
||||
badgeLabel: string;
|
||||
};
|
||||
|
||||
type TranslateFn = (key: string, fallback?: string) => string;
|
||||
|
||||
function resolveTone(state: LimitUsageSummary['state']): LimitTone {
|
||||
if (state === 'limit_reached') {
|
||||
return 'danger';
|
||||
}
|
||||
|
||||
if (state === 'warning') {
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
return 'neutral';
|
||||
}
|
||||
|
||||
function buildCard(
|
||||
id: 'photos' | 'guests',
|
||||
summary: LimitUsageSummary,
|
||||
t: TranslateFn
|
||||
): LimitSummaryCard {
|
||||
const labelKey = id === 'photos' ? 'upload.status.cards.photos.title' : 'upload.status.cards.guests.title';
|
||||
const remainingKey = id === 'photos'
|
||||
? 'upload.status.cards.photos.remaining'
|
||||
: 'upload.status.cards.guests.remaining';
|
||||
const unlimitedKey = id === 'photos'
|
||||
? 'upload.status.cards.photos.unlimited'
|
||||
: 'upload.status.cards.guests.unlimited';
|
||||
|
||||
const tone = resolveTone(summary.state);
|
||||
const progress = typeof summary.limit === 'number' && summary.limit > 0
|
||||
? Math.min(100, Math.round((summary.used / summary.limit) * 100))
|
||||
: null;
|
||||
|
||||
const valueLabel = typeof summary.limit === 'number' && summary.limit > 0
|
||||
? `${summary.used.toLocaleString()} / ${summary.limit.toLocaleString()}`
|
||||
: t('upload.status.badges.unlimited');
|
||||
|
||||
const description = summary.state === 'unlimited'
|
||||
? t(unlimitedKey)
|
||||
: summary.remaining !== null && summary.limit !== null
|
||||
? t(remainingKey)
|
||||
.replace('{remaining}', `${Math.max(0, summary.remaining)}`)
|
||||
.replace('{limit}', `${summary.limit}`)
|
||||
: valueLabel;
|
||||
|
||||
const badgeKey = (() => {
|
||||
switch (summary.state) {
|
||||
case 'limit_reached':
|
||||
return 'upload.status.badges.limit_reached';
|
||||
case 'warning':
|
||||
return 'upload.status.badges.warning';
|
||||
case 'unlimited':
|
||||
return 'upload.status.badges.unlimited';
|
||||
default:
|
||||
return 'upload.status.badges.ok';
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
id,
|
||||
label: t(labelKey),
|
||||
state: summary.state,
|
||||
tone,
|
||||
used: summary.used,
|
||||
limit: summary.limit,
|
||||
remaining: summary.remaining,
|
||||
progress,
|
||||
valueLabel,
|
||||
description,
|
||||
badgeLabel: t(badgeKey),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildLimitSummaries(limits: EventPackageLimits | null | undefined, t: TranslateFn): LimitSummaryCard[] {
|
||||
if (!limits) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const cards: LimitSummaryCard[] = [];
|
||||
|
||||
if (limits.photos) {
|
||||
cards.push(buildCard('photos', limits.photos, t));
|
||||
}
|
||||
|
||||
if (limits.guests) {
|
||||
cards.push(buildCard('guests', limits.guests, t));
|
||||
}
|
||||
|
||||
return cards;
|
||||
}
|
||||
Reference in New Issue
Block a user