/** * QuotaOverageModal Component * * Modal that appears on login/masquerade when the tenant has exceeded quotas. * Shows warning about grace period and what will happen when it expires. * Uses sessionStorage to only show once per session. */ import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { AlertTriangle, X, Clock, Archive, ChevronRight, Users, Layers, Briefcase, Mail, Zap, } from 'lucide-react'; import { QuotaOverage } from '../api/auth'; interface QuotaOverageModalProps { overages: QuotaOverage[]; onDismiss: () => void; } const QUOTA_ICONS: Record = { 'MAX_ADDITIONAL_USERS': , 'MAX_RESOURCES': , 'MAX_SERVICES': , 'MAX_EMAIL_TEMPLATES': , 'MAX_AUTOMATED_TASKS': , }; const SESSION_STORAGE_KEY = 'quota_overage_modal_dismissed'; const QuotaOverageModal: React.FC = ({ overages, onDismiss }) => { const { t } = useTranslation(); const [isVisible, setIsVisible] = useState(false); useEffect(() => { // Check if already dismissed this session const dismissed = sessionStorage.getItem(SESSION_STORAGE_KEY); if (!dismissed && overages && overages.length > 0) { setIsVisible(true); } }, [overages]); const handleDismiss = () => { sessionStorage.setItem(SESSION_STORAGE_KEY, 'true'); setIsVisible(false); onDismiss(); }; if (!isVisible || !overages || overages.length === 0) { return null; } // Find the most urgent overage (least days remaining) const mostUrgent = overages.reduce((prev, curr) => curr.days_remaining < prev.days_remaining ? curr : prev ); const isCritical = mostUrgent.days_remaining <= 1; const isUrgent = mostUrgent.days_remaining <= 7; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString(undefined, { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', }); }; return (
{/* Header */}

{isCritical ? t('quota.modal.titleCritical', 'Action Required Immediately!') : isUrgent ? t('quota.modal.titleUrgent', 'Action Required Soon') : t('quota.modal.title', 'Quota Exceeded') }

{mostUrgent.days_remaining <= 0 ? t('quota.modal.subtitleExpired', 'Grace period has expired') : mostUrgent.days_remaining === 1 ? t('quota.modal.subtitleOneDay', '1 day remaining') : t('quota.modal.subtitle', '{{days}} days remaining', { days: mostUrgent.days_remaining }) }

{/* Body */}
{/* Main message */}

{t('quota.modal.gracePeriodEnds', 'Grace period ends on {{date}}', { date: formatDate(mostUrgent.grace_period_ends_at) })}

{t('quota.modal.explanation', 'Your account has exceeded its plan limits. Please remove or archive excess items before the grace period ends, or they will be automatically archived.' )}

{/* Overage list */}

{t('quota.modal.overagesTitle', 'Items Over Quota')}

{overages.map((overage) => (
{QUOTA_ICONS[overage.quota_type] || }

{overage.display_name}

{t('quota.modal.usageInfo', '{{current}} used / {{limit}} allowed', { current: overage.current_usage, limit: overage.allowed_limit })}

+{overage.overage_amount}

{t('quota.modal.overLimit', 'over limit')}

))}
{/* What happens section */}

{t('quota.modal.whatHappens', 'What happens if I don\'t take action?')}

{t('quota.modal.autoArchiveExplanation', 'After the grace period ends, the oldest items over your limit will be automatically archived. Archived items remain in your account but cannot be used until you upgrade or remove other items.' )}

{/* Footer */}
{t('quota.modal.manageButton', 'Manage Quota')}
); }; export default QuotaOverageModal; /** * Clear the session storage dismissal flag * Call this when user logs out or masquerade changes */ export const resetQuotaOverageModalDismissal = () => { sessionStorage.removeItem(SESSION_STORAGE_KEY); };