Merge pull request #125 from BEDOLAGA-DEV/dev

Dev
This commit is contained in:
Egor
2026-01-31 20:34:17 +03:00
committed by GitHub
3 changed files with 51 additions and 13 deletions

View File

@@ -98,6 +98,11 @@ export const subscriptionApi = {
return response.data; return response.data;
}, },
// Save devices cart for later purchase after top-up
saveDevicesCart: async (devices: number): Promise<void> => {
await apiClient.post('/cabinet/subscription/devices/save-cart', { devices });
},
// Update autopay settings // Update autopay settings
updateAutopay: async ( updateAutopay: async (
enabled: boolean, enabled: boolean,

View File

@@ -16,6 +16,8 @@ interface InsufficientBalancePromptProps {
compact?: boolean; compact?: boolean;
/** Additional className */ /** Additional className */
className?: string; className?: string;
/** Callback to execute before opening top-up modal (e.g., save cart) */
onBeforeTopUp?: () => Promise<void>;
} }
export default function InsufficientBalancePrompt({ export default function InsufficientBalancePrompt({
@@ -23,11 +25,13 @@ export default function InsufficientBalancePrompt({
message, message,
compact = false, compact = false,
className = '', className = '',
onBeforeTopUp,
}: InsufficientBalancePromptProps) { }: InsufficientBalancePromptProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const { formatAmount, currencySymbol } = useCurrency(); const { formatAmount, currencySymbol } = useCurrency();
const [showMethodSelect, setShowMethodSelect] = useState(false); const [showMethodSelect, setShowMethodSelect] = useState(false);
const [selectedMethod, setSelectedMethod] = useState<PaymentMethod | null>(null); const [selectedMethod, setSelectedMethod] = useState<PaymentMethod | null>(null);
const [isPreparingTopUp, setIsPreparingTopUp] = useState(false);
// Auto-close modals when success notification appears // Auto-close modals when success notification appears
const handleCloseAll = useCallback(() => { const handleCloseAll = useCallback(() => {
@@ -50,6 +54,20 @@ export default function InsufficientBalancePrompt({
setShowMethodSelect(false); setShowMethodSelect(false);
}; };
const handleTopUpClick = async () => {
if (onBeforeTopUp) {
setIsPreparingTopUp(true);
try {
await onBeforeTopUp();
} catch {
// Silently ignore errors - still open the modal
} finally {
setIsPreparingTopUp(false);
}
}
setShowMethodSelect(true);
};
if (compact) { if (compact) {
return ( return (
<> <>
@@ -78,10 +96,15 @@ export default function InsufficientBalancePrompt({
</span> </span>
</div> </div>
<button <button
onClick={() => setShowMethodSelect(true)} onClick={handleTopUpClick}
disabled={isPreparingTopUp}
className="btn-primary whitespace-nowrap px-3 py-1.5 text-xs" className="btn-primary whitespace-nowrap px-3 py-1.5 text-xs"
> >
{t('balance.topUp')} {isPreparingTopUp ? (
<span className="h-3 w-3 animate-spin rounded-full border border-white/30 border-t-white" />
) : (
t('balance.topUp')
)}
</button> </button>
</div> </div>
@@ -139,9 +162,14 @@ export default function InsufficientBalancePrompt({
</div> </div>
</div> </div>
<button <button
onClick={() => setShowMethodSelect(true)} onClick={handleTopUpClick}
disabled={isPreparingTopUp}
className="btn-primary mt-4 flex w-full items-center justify-center gap-2 py-2.5" className="btn-primary mt-4 flex w-full items-center justify-center gap-2 py-2.5"
> >
{isPreparingTopUp ? (
<span className="h-4 w-4 animate-spin rounded-full border-2 border-white/30 border-t-white" />
) : (
<>
<svg <svg
className="h-5 w-5" className="h-5 w-5"
fill="none" fill="none"
@@ -152,6 +180,8 @@ export default function InsufficientBalancePrompt({
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" /> <path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg> </svg>
{t('balance.topUpBalance')} {t('balance.topUpBalance')}
</>
)}
</button> </button>
</div> </div>

View File

@@ -1117,6 +1117,9 @@ export default function Subscription() {
devicePriceData.total_price_kopeks - purchaseOptions.balance_kopeks devicePriceData.total_price_kopeks - purchaseOptions.balance_kopeks
} }
compact compact
onBeforeTopUp={async () => {
await subscriptionApi.saveDevicesCart(devicesToAdd);
}}
/> />
)} )}