Files
igny8/frontend/src/components/billing/InsufficientCreditsModal.tsx
2026-01-06 21:28:13 +00:00

169 lines
4.9 KiB
TypeScript

/**
* Insufficient Credits Modal
* Shows when user doesn't have enough credits for an operation
* Provides options to upgrade plan or buy credits
*/
import React from 'react';
import { Modal } from '../ui/modal';
import Button from '../ui/button/Button';
import { ZapIcon, TrendingUpIcon, CreditCardIcon } from '../../icons';
import { useNavigate } from 'react-router-dom';
interface InsufficientCreditsModalProps {
isOpen: boolean;
onClose: () => void;
requiredCredits: number;
availableCredits: number;
operationType?: string;
}
export default function InsufficientCreditsModal({
isOpen,
onClose,
requiredCredits,
availableCredits,
operationType = 'this operation',
}: InsufficientCreditsModalProps) {
const navigate = useNavigate();
const shortfall = requiredCredits - availableCredits;
const handleUpgradePlan = () => {
onClose();
navigate('/account/billing/upgrade');
};
const handleBuyCredits = () => {
onClose();
navigate('/account/billing/credits');
};
const handleViewUsage = () => {
onClose();
navigate('/account/usage');
};
return (
<Modal isOpen={isOpen} onClose={onClose} showCloseButton={true}>
<div className="p-6 text-center">
{/* Warning Icon */}
<div className="relative flex items-center justify-center w-20 h-20 mx-auto mb-6">
<div className="absolute inset-0 bg-warning-100 dark:bg-warning-900/30 rounded-full"></div>
<div className="relative bg-warning-500 rounded-full w-14 h-14 flex items-center justify-center">
<ZapIcon className="w-7 h-7 text-white" />
</div>
</div>
{/* Title */}
<h2 className="text-xl font-bold text-gray-900 dark:text-white mb-2">
Insufficient Credits
</h2>
{/* Message */}
<p className="text-gray-600 dark:text-gray-400 mb-6">
You don't have enough credits for {operationType}.
</p>
{/* Credit Stats */}
<div className="bg-gray-50 dark:bg-gray-800 rounded-lg p-4 mb-6">
<div className="grid grid-cols-3 gap-4 text-center">
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-1">Required</div>
<div className="text-lg font-bold text-warning-600 dark:text-warning-400">
{requiredCredits.toLocaleString()}
</div>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-1">Available</div>
<div className="text-lg font-bold text-gray-900 dark:text-white">
{availableCredits.toLocaleString()}
</div>
</div>
<div>
<div className="text-xs text-gray-500 dark:text-gray-400 mb-1">Shortfall</div>
<div className="text-lg font-bold text-error-600 dark:text-error-400">
{shortfall.toLocaleString()}
</div>
</div>
</div>
</div>
{/* Action Buttons */}
<div className="space-y-3">
<Button
variant="primary"
fullWidth
onClick={handleUpgradePlan}
className="flex items-center justify-center gap-2"
>
<TrendingUpIcon className="w-4 h-4" />
Upgrade Plan
</Button>
<Button
variant="outline"
fullWidth
onClick={handleBuyCredits}
className="flex items-center justify-center gap-2"
>
<CreditCardIcon className="w-4 h-4" />
Buy Credits
</Button>
<button
onClick={handleViewUsage}
className="text-sm text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
>
View Usage Details →
</button>
</div>
{/* Cancel Button */}
<div className="mt-4 pt-4 border-t border-gray-200 dark:border-gray-700">
<Button
variant="ghost"
tone="neutral"
onClick={onClose}
>
Cancel
</Button>
</div>
</div>
</Modal>
);
}
/**
* Hook to manage insufficient credits modal state
*/
export function useInsufficientCreditsModal() {
const [isOpen, setIsOpen] = React.useState(false);
const [modalProps, setModalProps] = React.useState({
requiredCredits: 0,
availableCredits: 0,
operationType: 'this operation',
});
const showInsufficientCreditsModal = (props: {
requiredCredits: number;
availableCredits: number;
operationType?: string;
}) => {
setModalProps({
requiredCredits: props.requiredCredits,
availableCredits: props.availableCredits,
operationType: props.operationType || 'this operation',
});
setIsOpen(true);
};
const closeModal = () => setIsOpen(false);
return {
isOpen,
modalProps,
showInsufficientCreditsModal,
closeModal,
};
}