169 lines
4.9 KiB
TypeScript
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,
|
|
};
|
|
}
|