diff --git a/src/components/subscription/sheets/DeleteSubscriptionSheet.tsx b/src/components/subscription/sheets/DeleteSubscriptionSheet.tsx new file mode 100644 index 0000000..b00c46f --- /dev/null +++ b/src/components/subscription/sheets/DeleteSubscriptionSheet.tsx @@ -0,0 +1,127 @@ +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { subscriptionApi } from '../../../api/subscription'; +import { usePlatform } from '../../../platform'; +import { useDestructiveConfirm } from '../../../platform/hooks/useNativeDialog'; + +// ────────────────────────────────────────────────────────────────── +// Delete-subscription sheet. Telegram path goes through the native +// destructive dialog and skips the inline expand; the web path expands +// an inline confirm panel with two buttons. +// +// Self-owns deleteLoading; parent only supplies the id, theme colour +// hints, open-state, and the onDeleted callback (used for navigate + +// invalidate after the API resolves). +// ────────────────────────────────────────────────────────────────── + +export interface DeleteSubscriptionSheetProps { + subscriptionId: number; + open: boolean; + onOpen: () => void; + onClose: () => void; + onDeleted: () => void; + /** color/background tokens already resolved from glassTheme */ + textSecondary: string; +} + +export function DeleteSubscriptionSheet({ + subscriptionId, + open, + onOpen, + onClose, + onDeleted, + textSecondary, +}: DeleteSubscriptionSheetProps) { + const { t } = useTranslation(); + const { platform } = usePlatform(); + const destructiveConfirm = useDestructiveConfirm(); + const [deleteLoading, setDeleteLoading] = useState(false); + + const performDelete = async () => { + setDeleteLoading(true); + try { + await subscriptionApi.deleteSubscription(subscriptionId); + onDeleted(); + } catch { + setDeleteLoading(false); + onClose(); + } + }; + + const handleTriggerClick = async () => { + if (platform === 'telegram') { + const confirmed = await destructiveConfirm( + t( + 'subscription.deleteWarning', + 'Подписка будет удалена безвозвратно. Все данные, устройства и настройки будут потеряны.', + ), + t('subscription.confirmDelete', 'Да, удалить'), + t('subscription.deleteTitle', 'Удалить подписку?'), + ); + if (!confirmed) return; + await performDelete(); + } else { + onOpen(); + } + }; + + if (!open) { + return ( + + ); + } + + return ( +
+
+ {t('subscription.deleteTitle', 'Удалить подписку?')} +
+
+ {t( + 'subscription.deleteWarning', + 'Подписка будет удалена безвозвратно. Все данные, устройства и настройки будут потеряны. Это действие нельзя отменить.', + )} +
+
+ + +
+
+ ); +} diff --git a/src/pages/Subscription.tsx b/src/pages/Subscription.tsx index d43eb7e..743f80d 100644 --- a/src/pages/Subscription.tsx +++ b/src/pages/Subscription.tsx @@ -6,7 +6,6 @@ import { subscriptionApi } from '../api/subscription'; import { DEVICE_ALIAS_MAX_LENGTH } from '../constants/devices'; import { WebBackButton } from '../components/WebBackButton'; import { useDestructiveConfirm } from '../platform/hooks/useNativeDialog'; -import { usePlatform } from '../platform'; import TrafficProgressBar from '../components/dashboard/TrafficProgressBar'; import { HoverBorderGradient } from '../components/ui/hover-border-gradient'; import { useTrafficZone } from '../hooks/useTrafficZone'; @@ -31,6 +30,7 @@ import { DeviceTopupSheet } from '../components/subscription/sheets/DeviceTopupS import { DeviceReductionSheet } from '../components/subscription/sheets/DeviceReductionSheet'; import { TrafficTopupSheet } from '../components/subscription/sheets/TrafficTopupSheet'; import { ServerManagementSheet } from '../components/subscription/sheets/ServerManagementSheet'; +import { DeleteSubscriptionSheet } from '../components/subscription/sheets/DeleteSubscriptionSheet'; /** Isolated countdown so 1s interval doesn't re-render the whole page */ const CountdownTimer = memo(function CountdownTimer({ @@ -195,8 +195,6 @@ export default function Subscription() { const haptic = useHaptic(); const [copied, setCopied] = useState(false); const [showDeleteSheet, setShowDeleteSheet] = useState(false); - const [deleteLoading, setDeleteLoading] = useState(false); - const { platform } = usePlatform(); const destructiveConfirm = useDestructiveConfirm(); // Helper to format price from kopeks @@ -1340,93 +1338,17 @@ export default function Subscription() { !subscription.is_trial && !subscription.is_limited && (
- {!showDeleteSheet ? ( - - ) : ( -
-
- {t('subscription.deleteTitle', 'Удалить подписку?')} -
-
- {t( - 'subscription.deleteWarning', - 'Подписка будет удалена безвозвратно. Все данные, устройства и настройки будут потеряны. Это действие нельзя отменить.', - )} -
-
- - -
-
- )} + setShowDeleteSheet(true)} + onClose={() => setShowDeleteSheet(false)} + textSecondary={g.textSecondary} + onDeleted={() => { + queryClient.invalidateQueries({ queryKey: ['subscriptions-list'] }); + navigate('/subscriptions', { replace: true }); + }} + />
)}