removed all references to credits. now credits are completely replaced by addons.
This commit is contained in:
@@ -362,11 +362,6 @@ export default function EventFormPage() {
|
||||
setShowUpgradeHint(true);
|
||||
break;
|
||||
}
|
||||
case 'event_credits_exhausted': {
|
||||
setError(tErrors('creditsExhausted'));
|
||||
setShowUpgradeHint(true);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const metaErrors = Array.isArray(err.meta?.errors) ? err.meta.errors.filter(Boolean).join('\n') : null;
|
||||
setError(metaErrors || err.message || tErrors('generic'));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { AlertTriangle, CheckCircle2, Loader2, Lock, LogOut, Mail, Moon, ShieldCheck, SunMedium, UserCog } from 'lucide-react';
|
||||
import { AlertTriangle, Loader2, Lock, LogOut, Mail, Moon, ShieldCheck, SunMedium, UserCog } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import AppearanceToggleDropdown from '@/components/appearance-dropdown';
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
getNotificationPreferences,
|
||||
updateNotificationPreferences,
|
||||
NotificationPreferences,
|
||||
NotificationPreferencesMeta,
|
||||
} from '../api';
|
||||
import { getApiErrorMessage } from '../lib/apiError';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -40,7 +39,6 @@ export default function SettingsPage() {
|
||||
const [loadingNotifications, setLoadingNotifications] = React.useState(true);
|
||||
const [savingNotifications, setSavingNotifications] = React.useState(false);
|
||||
const [notificationError, setNotificationError] = React.useState<string | null>(null);
|
||||
const [notificationMeta, setNotificationMeta] = React.useState<NotificationPreferencesMeta | null>(null);
|
||||
|
||||
const heroDescription = t('settings.hero.description', { defaultValue: 'Gestalte das Erlebnis für dein Admin-Team – Darstellung, Benachrichtigungen und Session-Sicherheit.' });
|
||||
const heroSupporting = [
|
||||
@@ -222,7 +220,6 @@ export default function SettingsPage() {
|
||||
<NotificationPreferencesForm
|
||||
preferences={preferences}
|
||||
defaults={defaults}
|
||||
meta={notificationMeta}
|
||||
onChange={(next) => setPreferences(next)}
|
||||
onReset={() => setPreferences(defaults)}
|
||||
onSave={async () => {
|
||||
@@ -236,9 +233,6 @@ export default function SettingsPage() {
|
||||
if (updated.defaults && Object.keys(updated.defaults).length > 0) {
|
||||
setDefaults(updated.defaults);
|
||||
}
|
||||
if (updated.meta) {
|
||||
setNotificationMeta(updated.meta);
|
||||
}
|
||||
setNotificationError(null);
|
||||
} catch (error) {
|
||||
setNotificationError(
|
||||
@@ -255,7 +249,6 @@ export default function SettingsPage() {
|
||||
</SectionCard>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<NotificationMetaCard meta={notificationMeta} loading={loadingNotifications} translate={translateNotification} />
|
||||
<SupportCard />
|
||||
</div>
|
||||
</div>
|
||||
@@ -266,7 +259,6 @@ export default function SettingsPage() {
|
||||
function NotificationPreferencesForm({
|
||||
preferences,
|
||||
defaults,
|
||||
meta,
|
||||
onChange,
|
||||
onReset,
|
||||
onSave,
|
||||
@@ -275,7 +267,6 @@ function NotificationPreferencesForm({
|
||||
}: {
|
||||
preferences: NotificationPreferences;
|
||||
defaults: NotificationPreferences;
|
||||
meta: NotificationPreferencesMeta | null;
|
||||
onChange: (next: NotificationPreferences) => void;
|
||||
onReset: () => void;
|
||||
onSave: () => Promise<void>;
|
||||
@@ -283,22 +274,6 @@ function NotificationPreferencesForm({
|
||||
translate: (key: string, fallback?: string, options?: Record<string, unknown>) => string;
|
||||
}) {
|
||||
const items = React.useMemo(() => buildPreferenceMeta(translate), [translate]);
|
||||
const locale = typeof window !== 'undefined' ? window.navigator.language : 'de-DE';
|
||||
const creditText = React.useMemo(() => {
|
||||
if (!meta) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (meta.credit_warning_sent_at) {
|
||||
const date = formatDateTime(meta.credit_warning_sent_at, locale);
|
||||
|
||||
return translate('settings.notifications.meta.creditLast', 'Letzte Slot-Warnung: {{date}}', {
|
||||
date,
|
||||
});
|
||||
}
|
||||
|
||||
return translate('settings.notifications.meta.creditNever', 'Noch keine Slot-Warnung versendet.');
|
||||
}, [meta, translate, locale]);
|
||||
|
||||
return (
|
||||
<div className="relative space-y-4 pb-16">
|
||||
@@ -332,7 +307,6 @@ function NotificationPreferencesForm({
|
||||
{translate('settings.notifications.hint', 'Du kannst Benachrichtigungen jederzeit wieder aktivieren.')}
|
||||
</span>
|
||||
</div>
|
||||
{creditText ? <p className="text-xs text-slate-500 dark:text-slate-400">{creditText}</p> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -391,11 +365,6 @@ function buildPreferenceMeta(
|
||||
label: translate('settings.notifications.items.packageExpired.label', 'Paket ist abgelaufen'),
|
||||
description: translate('settings.notifications.items.packageExpired.description', 'Benachrichtige mich, wenn das Paket abgelaufen ist.'),
|
||||
},
|
||||
{
|
||||
key: 'credits_low',
|
||||
label: translate('settings.notifications.items.creditsLow.label', 'Event-Slots werden knapp'),
|
||||
description: translate('settings.notifications.items.creditsLow.description', 'Informiert mich bei niedrigen Slot-Schwellen.'),
|
||||
},
|
||||
];
|
||||
|
||||
return map as Array<{ key: keyof NotificationPreferences; label: string; description: string }>;
|
||||
@@ -414,61 +383,6 @@ function NotificationSkeleton() {
|
||||
);
|
||||
}
|
||||
|
||||
function NotificationMetaCard({
|
||||
meta,
|
||||
loading,
|
||||
translate,
|
||||
}: {
|
||||
meta: NotificationPreferencesMeta | null;
|
||||
loading: boolean;
|
||||
translate: (key: string, fallback?: string, options?: Record<string, unknown>) => string;
|
||||
}) {
|
||||
const locale = typeof window !== 'undefined' ? window.navigator.language : 'de-DE';
|
||||
const lastWarning = meta?.credit_warning_sent_at
|
||||
? formatDateTime(meta.credit_warning_sent_at, locale)
|
||||
: translate('settings.notifications.meta.creditNever', 'Noch keine Slot-Warnung versendet.');
|
||||
|
||||
return (
|
||||
<Card className="border border-slate-200 bg-white/90 shadow-sm dark:border-slate-800 dark:bg-slate-900/60">
|
||||
<CardContent className="space-y-4 p-5">
|
||||
<div>
|
||||
<p className="text-xs uppercase tracking-[0.3em] text-slate-500">{translate('settings.notifications.summary.badge', 'Status')}</p>
|
||||
<p className="mt-1 text-base font-semibold text-slate-900 dark:text-white">
|
||||
{translate('settings.notifications.summary.title', 'Benachrichtigungsübersicht')}
|
||||
</p>
|
||||
</div>
|
||||
{loading ? (
|
||||
<div className="space-y-2">
|
||||
<div className="h-3 w-3/4 animate-pulse rounded bg-slate-200" />
|
||||
<div className="h-3 w-1/2 animate-pulse rounded bg-slate-100" />
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3 text-sm text-slate-600 dark:text-slate-300">
|
||||
<div className="flex items-center gap-2 rounded-2xl border border-slate-200/80 bg-white/70 p-3 text-slate-800 dark:border-slate-700 dark:bg-slate-900/40 dark:text-white">
|
||||
<Mail className="h-4 w-4 text-primary" />
|
||||
<div>
|
||||
<p className="text-xs uppercase tracking-[0.2em] text-slate-500 dark:text-slate-300">{translate('settings.notifications.summary.channel', 'E-Mail Kanal')}</p>
|
||||
<p>{translate('settings.notifications.summary.channelCopy', 'Alle Warnungen werden per E-Mail versendet.')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-slate-200/80 bg-amber-50 p-3 text-slate-800">
|
||||
<p className="text-xs uppercase tracking-[0.2em] text-amber-700">{translate('settings.notifications.summary.credits', 'Credits')}</p>
|
||||
<p>{lastWarning}</p>
|
||||
{meta?.credit_warning_threshold ? (
|
||||
<p className="text-xs text-amber-700/80">
|
||||
{translate('settings.notifications.summary.threshold', 'Warnung bei {{count}} verbleibenden Slots', {
|
||||
count: meta.credit_warning_threshold,
|
||||
})}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function SupportCard() {
|
||||
const { t } = useTranslation('management');
|
||||
return (
|
||||
@@ -492,22 +406,3 @@ function SupportCard() {
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function formatDateTime(value: string, locale: string): string {
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return value;
|
||||
}
|
||||
|
||||
try {
|
||||
return new Intl.DateTimeFormat(locale, {
|
||||
day: '2-digit',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
}).format(date);
|
||||
} catch {
|
||||
return date.toISOString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user