Implement package limit notification system
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { ArrowLeft, Loader2, Save, Sparkles } from 'lucide-react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
TenantEvent,
|
||||
} from '../api';
|
||||
import { isAuthError } from '../auth/tokens';
|
||||
import { isApiError } from '../lib/apiError';
|
||||
import { ADMIN_BILLING_PATH, ADMIN_EVENT_VIEW_PATH, ADMIN_EVENTS_PATH } from '../constants';
|
||||
|
||||
interface EventFormState {
|
||||
@@ -63,6 +65,8 @@ export default function EventFormPage() {
|
||||
const isEdit = Boolean(slugParam);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { t: tCommon } = useTranslation('common', { keyPrefix: 'errors' });
|
||||
|
||||
const [form, setForm] = React.useState<EventFormState>({
|
||||
name: '',
|
||||
slug: '',
|
||||
@@ -76,6 +80,7 @@ export default function EventFormPage() {
|
||||
const slugSuffixRef = React.useRef<string | null>(null);
|
||||
const [saving, setSaving] = React.useState(false);
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
const [showUpgradeHint, setShowUpgradeHint] = React.useState(false);
|
||||
const [readOnlyPackageName, setReadOnlyPackageName] = React.useState<string | null>(null);
|
||||
const [eventPackageMeta, setEventPackageMeta] = React.useState<EventPackageMeta | null>(null);
|
||||
|
||||
@@ -232,6 +237,7 @@ export default function EventFormPage() {
|
||||
|
||||
setSaving(true);
|
||||
setError(null);
|
||||
setShowUpgradeHint(false);
|
||||
|
||||
const status: 'draft' | 'published' | 'archived' = form.isPublished ? 'published' : 'draft';
|
||||
const packageIdForSubmit = form.package_id || activePackage?.package_id || null;
|
||||
@@ -256,14 +262,44 @@ export default function EventFormPage() {
|
||||
const targetSlug = originalSlug ?? slugParam!;
|
||||
const updated = await updateEvent(targetSlug, payload);
|
||||
setOriginalSlug(updated.slug);
|
||||
setShowUpgradeHint(false);
|
||||
setError(null);
|
||||
navigate(ADMIN_EVENT_VIEW_PATH(updated.slug));
|
||||
} else {
|
||||
const { event: created } = await createEvent(payload);
|
||||
setShowUpgradeHint(false);
|
||||
setError(null);
|
||||
navigate(ADMIN_EVENT_VIEW_PATH(created.slug));
|
||||
}
|
||||
} catch (err) {
|
||||
if (!isAuthError(err)) {
|
||||
setError('Speichern fehlgeschlagen. Bitte prüfe deine Eingaben.');
|
||||
if (isApiError(err)) {
|
||||
switch (err.code) {
|
||||
case 'event_limit_exceeded': {
|
||||
const limit = Number(err.meta?.limit ?? 0);
|
||||
const used = Number(err.meta?.used ?? 0);
|
||||
const remaining = Number(err.meta?.remaining ?? Math.max(0, limit - used));
|
||||
const detail = limit > 0
|
||||
? tCommon('eventLimitDetails', { used, limit, remaining })
|
||||
: '';
|
||||
setError(`${tCommon('eventLimit')}${detail ? `\n${detail}` : ''}`);
|
||||
setShowUpgradeHint(true);
|
||||
break;
|
||||
}
|
||||
case 'event_credits_exhausted': {
|
||||
setError(tCommon('creditsExhausted'));
|
||||
setShowUpgradeHint(true);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
setError(err.message || tCommon('generic'));
|
||||
setShowUpgradeHint(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setError(tCommon('generic'));
|
||||
setShowUpgradeHint(false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
setSaving(false);
|
||||
@@ -360,7 +396,18 @@ export default function EventFormPage() {
|
||||
{error && (
|
||||
<Alert variant="destructive">
|
||||
<AlertTitle>Hinweis</AlertTitle>
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
<AlertDescription className="flex flex-col gap-2">
|
||||
{error.split('\n').map((line, index) => (
|
||||
<span key={index}>{line}</span>
|
||||
))}
|
||||
{showUpgradeHint && (
|
||||
<div>
|
||||
<Button size="sm" variant="outline" onClick={() => navigate(ADMIN_BILLING_PATH)}>
|
||||
{tCommon('goToBilling')}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user