mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
feat: auto-close modals when success notification appears
- Add closeOthersSignal to success notification store - Create useCloseOnSuccessNotification hook for modals to subscribe - Update TopUpModal to auto-close on success events - Update InsufficientBalancePrompt to auto-close on success events - Update Subscription page to close all modals/forms on success events This ensures that when a WebSocket event indicates successful payment or subscription purchase, all related modals close automatically, providing clear feedback to users.
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { balanceApi } from '../api/balance';
|
||||
import { useCurrency } from '../hooks/useCurrency';
|
||||
import { useCloseOnSuccessNotification } from '../store/successNotification';
|
||||
import TopUpModal from './TopUpModal';
|
||||
import type { PaymentMethod } from '../types';
|
||||
|
||||
@@ -28,6 +29,13 @@ export default function InsufficientBalancePrompt({
|
||||
const [showMethodSelect, setShowMethodSelect] = useState(false);
|
||||
const [selectedMethod, setSelectedMethod] = useState<PaymentMethod | null>(null);
|
||||
|
||||
// Auto-close modals when success notification appears
|
||||
const handleCloseAll = useCallback(() => {
|
||||
setShowMethodSelect(false);
|
||||
setSelectedMethod(null);
|
||||
}, []);
|
||||
useCloseOnSuccessNotification(handleCloseAll);
|
||||
|
||||
const { data: paymentMethods } = useQuery({
|
||||
queryKey: ['payment-methods'],
|
||||
queryFn: balanceApi.getPaymentMethods,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { balanceApi } from '../api/balance';
|
||||
import { useCurrency } from '../hooks/useCurrency';
|
||||
import { useTelegramWebApp } from '../hooks/useTelegramWebApp';
|
||||
import { checkRateLimit, getRateLimitResetTime, RATE_LIMIT_KEYS } from '../utils/rateLimit';
|
||||
import { useCloseOnSuccessNotification } from '../store/successNotification';
|
||||
import type { PaymentMethod } from '../types';
|
||||
import BentoCard from './ui/BentoCard';
|
||||
|
||||
@@ -144,6 +145,9 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top
|
||||
onClose();
|
||||
}, [onClose]);
|
||||
|
||||
// Auto-close when success notification appears (e.g., balance topped up via WebSocket)
|
||||
useCloseOnSuccessNotification(handleClose);
|
||||
|
||||
// Keyboard: Escape to close (PC)
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useMemo, useRef } from 'react';
|
||||
import { useState, useEffect, useMemo, useRef, useCallback } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
@@ -15,6 +15,7 @@ import type {
|
||||
import ConnectionModal from '../components/ConnectionModal';
|
||||
import InsufficientBalancePrompt from '../components/InsufficientBalancePrompt';
|
||||
import { useCurrency } from '../hooks/useCurrency';
|
||||
import { useCloseOnSuccessNotification } from '../store/successNotification';
|
||||
import i18n from '../i18n';
|
||||
|
||||
// Helper to extract error message from axios/api errors
|
||||
@@ -279,6 +280,21 @@ export default function Subscription() {
|
||||
|
||||
// Tariff switch preview
|
||||
const [switchTariffId, setSwitchTariffId] = useState<number | null>(null);
|
||||
|
||||
// Auto-close all modals/forms when success notification appears (e.g., subscription purchased via WebSocket)
|
||||
const handleCloseAllModals = useCallback(() => {
|
||||
setShowConnectionModal(false);
|
||||
setShowPurchaseForm(false);
|
||||
setShowTariffPurchase(false);
|
||||
setShowDeviceTopup(false);
|
||||
setShowTrafficTopup(false);
|
||||
setShowServerManagement(false);
|
||||
setSwitchTariffId(null);
|
||||
setSelectedTariff(null);
|
||||
setSelectedTariffPeriod(null);
|
||||
}, []);
|
||||
useCloseOnSuccessNotification(handleCloseAllModals);
|
||||
|
||||
const { data: switchPreview, isLoading: switchPreviewLoading } = useQuery({
|
||||
queryKey: ['tariff-switch-preview', switchTariffId],
|
||||
queryFn: () => subscriptionApi.previewTariffSwitch(switchTariffId!),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useEffect } from 'react';
|
||||
import { create } from 'zustand';
|
||||
|
||||
export type SuccessNotificationType =
|
||||
@@ -25,6 +26,8 @@ export interface SuccessNotificationData {
|
||||
interface SuccessNotificationState {
|
||||
isOpen: boolean;
|
||||
data: SuccessNotificationData | null;
|
||||
/** Signal that increments when other modals should close */
|
||||
closeOthersSignal: number;
|
||||
|
||||
show: (data: SuccessNotificationData) => void;
|
||||
hide: () => void;
|
||||
@@ -33,7 +36,30 @@ interface SuccessNotificationState {
|
||||
export const useSuccessNotification = create<SuccessNotificationState>((set) => ({
|
||||
isOpen: false,
|
||||
data: null,
|
||||
closeOthersSignal: 0,
|
||||
|
||||
show: (data) => set({ isOpen: true, data }),
|
||||
show: (data) =>
|
||||
set((state) => ({
|
||||
isOpen: true,
|
||||
data,
|
||||
// Increment signal to tell other modals to close
|
||||
closeOthersSignal: state.closeOthersSignal + 1,
|
||||
})),
|
||||
hide: () => set({ isOpen: false, data: null }),
|
||||
}));
|
||||
|
||||
/**
|
||||
* Hook that calls onClose when a success notification appears.
|
||||
* Use this in modals that should auto-close on success events.
|
||||
*/
|
||||
export function useCloseOnSuccessNotification(onClose: () => void) {
|
||||
const closeOthersSignal = useSuccessNotification((state) => state.closeOthersSignal);
|
||||
|
||||
useEffect(() => {
|
||||
// Skip the initial render (signal = 0)
|
||||
if (closeOthersSignal > 0) {
|
||||
onClose();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [closeOthersSignal]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user