Hintergründe zum EventInvitePage Layout Customizer hinzugefügt. Badge und CTA entfernt, Textfelder zu Textareas gemacht. Geschenkgutscheine verbessert, E-Mail-Versand ergänzt + Resend + Confirmationseite mit Code-Copy und Link zur Package-Seite, die den Code als URL-Parameter enthält.
This commit is contained in:
35
resources/js/hooks/useRateLimitHelper.ts
Normal file
35
resources/js/hooks/useRateLimitHelper.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
type RateBucket = 'coupon' | 'voucher';
|
||||
|
||||
export function useRateLimitHelper(bucket: RateBucket) {
|
||||
return useMemo(() => {
|
||||
const key = (code: string) => `${bucket}:${code.toUpperCase()}`;
|
||||
|
||||
return {
|
||||
isLimited: (code: string): boolean => {
|
||||
const item = localStorage.getItem(key(code));
|
||||
if (!item) return false;
|
||||
const parsed = JSON.parse(item) as { attempts: number; ts: number };
|
||||
const ageSeconds = (Date.now() - parsed.ts) / 1000;
|
||||
if (ageSeconds > 300) {
|
||||
localStorage.removeItem(key(code));
|
||||
return false;
|
||||
}
|
||||
return parsed.attempts >= 3;
|
||||
},
|
||||
bump: (code: string): void => {
|
||||
const item = localStorage.getItem(key(code));
|
||||
if (!item) {
|
||||
localStorage.setItem(key(code), JSON.stringify({ attempts: 1, ts: Date.now() }));
|
||||
return;
|
||||
}
|
||||
const parsed = JSON.parse(item) as { attempts: number; ts: number };
|
||||
localStorage.setItem(key(code), JSON.stringify({ attempts: (parsed.attempts || 0) + 1, ts: Date.now() }));
|
||||
},
|
||||
clear: (code: string): void => {
|
||||
localStorage.removeItem(key(code));
|
||||
},
|
||||
};
|
||||
}, [bucket]);
|
||||
}
|
||||
Reference in New Issue
Block a user