feat: silent email rate limit — no count/cooldown shown to users

This commit is contained in:
BizzleBot
2026-03-04 22:34:57 +00:00
parent 7433ec8d9e
commit e37b838718
+8 -12
View File
@@ -254,7 +254,7 @@ export default function Timesheet() {
try { try {
const res = await api.post(`/timesheets/${timesheetId}/email`); const res = await api.post(`/timesheets/${timesheetId}/email`);
setEmailStatus(s => ({ ...s, count: res.data.count, allowed: res.data.remaining > 0, cooldownMs: 30 * 60 * 1000 })); setEmailStatus(s => ({ ...s, count: res.data.count, allowed: res.data.remaining > 0, cooldownMs: 30 * 60 * 1000 }));
setEmailResult({ ok: true, msg: `Sent! (${res.data.count}/${res.data.max} sends used for this week)` }); setEmailResult({ ok: true, msg: 'Sent to Office!' });
setEmailConfirm(false); setEmailConfirm(false);
} catch (err) { } catch (err) {
setEmailResult({ ok: false, msg: err.response?.data?.error || 'Failed to send email' }); setEmailResult({ ok: false, msg: err.response?.data?.error || 'Failed to send email' });
@@ -388,19 +388,15 @@ export default function Timesheet() {
<div className="flex-1 rounded-xl border border-emerald-200 dark:border-emerald-500/30 bg-emerald-50 dark:bg-emerald-500/5 p-3 space-y-2"> <div className="flex-1 rounded-xl border border-emerald-200 dark:border-emerald-500/30 bg-emerald-50 dark:bg-emerald-500/5 p-3 space-y-2">
<p className="text-xs text-emerald-700 dark:text-emerald-400 font-medium text-center"> <p className="text-xs text-emerald-700 dark:text-emerald-400 font-medium text-center">
Send to Office@CoastalContractingFL.com? Send to Office@CoastalContractingFL.com?
{emailStatus && (
<span className="block text-emerald-600/70 dark:text-emerald-500/70 mt-0.5">
{emailStatus.count}/{emailStatus.max} sends used this week
{emailStatus.cooldownMs > 0 ? ` · available in ${Math.ceil(emailStatus.cooldownMs / 60000)}m` : ''}
</span>
)}
</p> </p>
{emailStatus && !emailStatus.allowed ? ( {emailStatus && !emailStatus.allowed ? (
<p className="text-xs text-red-500 text-center"> <div className="flex gap-2">
{emailStatus.count >= emailStatus.max <button disabled className="flex-1 py-1.5 rounded-lg bg-emerald-500 text-white text-xs font-semibold opacity-40 flex items-center justify-center gap-1">
? `Max ${emailStatus.max} sends reached for this timesheet` <Mail size={12} />
: `Please wait ${Math.ceil(emailStatus.cooldownMs / 60000)} min before sending again`} Send
</p> </button>
<button onClick={() => { setEmailConfirm(false); setEmailResult(null); }} className="flex-1 py-1.5 rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 text-xs font-semibold">Cancel</button>
</div>
) : ( ) : (
<div className="flex gap-2"> <div className="flex gap-2">
<button <button