mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 12:18:11 +00:00
Throttling configuration from the backoffice added
This commit is contained in:
@@ -34,6 +34,7 @@ export default function PackagesPage() {
|
||||
const [editingId, setEditingId] = useState<string | null>(null);
|
||||
const [viewPackage, setViewPackage] = useState<any>(null);
|
||||
const [activateConfirm, setActivateConfirm] = useState<any>(null);
|
||||
const [deactivateConfirm, setDeactivateConfirm] = useState<any>(null);
|
||||
const [tiersPackage, setTiersPackage] = useState<any>(null);
|
||||
const [editingTier, setEditingTier] = useState<any>(null);
|
||||
const [tierForm, setTierForm] = useState({ seatType: '', label: '', priceMinor: '', availableSeats: '' });
|
||||
@@ -76,6 +77,11 @@ export default function PackagesPage() {
|
||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['packages'] }); setActivateConfirm(null); },
|
||||
});
|
||||
|
||||
const deactivateMutation = useMutation({
|
||||
mutationFn: packagesApi.deactivate,
|
||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['packages'] }); setDeactivateConfirm(null); },
|
||||
});
|
||||
|
||||
const emptyTierForm = { seatType: '', label: '', priceMinor: '', availableSeats: '' };
|
||||
|
||||
const addTierMutation = useMutation({
|
||||
@@ -261,7 +267,12 @@ export default function PackagesPage() {
|
||||
{
|
||||
label: 'Activate', icon: CheckCircle, variant: 'primary' as const,
|
||||
onClick: (p: any) => setActivateConfirm(p),
|
||||
hidden: (p: any) => p.status === 'ACTIVE',
|
||||
show: (p: any) => p.status !== 'ACTIVE',
|
||||
},
|
||||
{
|
||||
label: 'Deactivate', icon: CheckCircle, variant: 'secondary' as const,
|
||||
onClick: (p: any) => setDeactivateConfirm(p),
|
||||
show: (p: any) => p.status === 'ACTIVE',
|
||||
},
|
||||
{
|
||||
label: 'Delete', icon: Trash2, variant: 'danger' as const,
|
||||
@@ -343,6 +354,18 @@ export default function PackagesPage() {
|
||||
isDanger={false}
|
||||
/>
|
||||
|
||||
{/* Deactivate Confirmation */}
|
||||
<ConfirmDialog
|
||||
isOpen={!!deactivateConfirm}
|
||||
onClose={() => setDeactivateConfirm(null)}
|
||||
onConfirm={() => deactivateMutation.mutate(deactivateConfirm.id)}
|
||||
title="Deactivate Package"
|
||||
message={`Deactivate "${deactivateConfirm?.name}"? It will no longer be available for booking.`}
|
||||
confirmText="Deactivate"
|
||||
isDanger={false}
|
||||
isLoading={deactivateMutation.isPending}
|
||||
/>
|
||||
|
||||
{/* Tiers Modal */}
|
||||
<Modal isOpen={!!tiersPackage} onClose={() => { setTiersPackage(null); setEditingTier(null); setTierError(null); }} title={`Price Tiers — ${tiersPackage?.name ?? ''}`} size="lg">
|
||||
{tiersPackage && (
|
||||
|
||||
@@ -10,6 +10,9 @@ export default function SettingsPage() {
|
||||
const [activeTab, setActiveTab] = useState<Tab>('general');
|
||||
const [seatHoldMinutes, setSeatHoldMinutes] = useState('5');
|
||||
const [holdCutoffHours, setHoldCutoffHours] = useState('2');
|
||||
const [throttleAuthLimit, setThrottleAuthLimit] = useState('5');
|
||||
const [throttleStrictLimit, setThrottleStrictLimit] = useState('20');
|
||||
const [throttleDefaultLimit, setThrottleDefaultLimit] = useState('100');
|
||||
const [configLoading, setConfigLoading] = useState(false);
|
||||
const [configSaving, setConfigSaving] = useState(false);
|
||||
const [configMessage, setConfigMessage] = useState('');
|
||||
@@ -21,6 +24,9 @@ export default function SettingsPage() {
|
||||
.then((data) => {
|
||||
if (data?.seat_hold_duration_minutes) setSeatHoldMinutes(data.seat_hold_duration_minutes);
|
||||
if (data?.hold_cutoff_hours_before_departure) setHoldCutoffHours(data.hold_cutoff_hours_before_departure);
|
||||
if (data?.throttle_auth_limit) setThrottleAuthLimit(data.throttle_auth_limit);
|
||||
if (data?.throttle_strict_limit) setThrottleStrictLimit(data.throttle_strict_limit);
|
||||
if (data?.throttle_default_limit) setThrottleDefaultLimit(data.throttle_default_limit);
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => setConfigLoading(false));
|
||||
@@ -33,6 +39,9 @@ export default function SettingsPage() {
|
||||
await systemConfigApi.update({
|
||||
seat_hold_duration_minutes: seatHoldMinutes,
|
||||
hold_cutoff_hours_before_departure: holdCutoffHours,
|
||||
throttle_auth_limit: throttleAuthLimit,
|
||||
throttle_strict_limit: throttleStrictLimit,
|
||||
throttle_default_limit: throttleDefaultLimit,
|
||||
});
|
||||
setConfigMessage('Saved successfully.');
|
||||
} catch {
|
||||
@@ -177,6 +186,41 @@ export default function SettingsPage() {
|
||||
|
||||
{activeTab === 'configurations' && (
|
||||
<div className="card space-y-6">
|
||||
<h3 className="text-lg font-semibold text-foreground">Rate Limiting (requests / minute / IP)</h3>
|
||||
{!configLoading && (
|
||||
<div className="max-w-sm space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="label" htmlFor="throttle-auth">Auth endpoints limit</label>
|
||||
<input
|
||||
id="throttle-auth"
|
||||
type="number" min="1" className="input"
|
||||
value={throttleAuthLimit}
|
||||
onChange={(e) => setThrottleAuthLimit(e.target.value)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">Login, register, OTP. Default: 5.</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="label" htmlFor="throttle-strict">Strict endpoints limit</label>
|
||||
<input
|
||||
id="throttle-strict"
|
||||
type="number" min="1" className="input"
|
||||
value={throttleStrictLimit}
|
||||
onChange={(e) => setThrottleStrictLimit(e.target.value)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">Sensitive operations. Default: 20.</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="label" htmlFor="throttle-default">Default endpoints limit</label>
|
||||
<input
|
||||
id="throttle-default"
|
||||
type="number" min="1" className="input"
|
||||
value={throttleDefaultLimit}
|
||||
onChange={(e) => setThrottleDefaultLimit(e.target.value)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">All other endpoints including search. Default: 100.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<h3 className="text-lg font-semibold text-foreground">Seat Booking</h3>
|
||||
{configLoading ? (
|
||||
<p className="text-sm text-muted-foreground">Loading...</p>
|
||||
|
||||
Reference in New Issue
Block a user