diff --git a/src/pages/Subscription.tsx b/src/pages/Subscription.tsx index a470666..0fab533 100644 --- a/src/pages/Subscription.tsx +++ b/src/pages/Subscription.tsx @@ -131,6 +131,8 @@ export default function Subscription() { // Device/traffic topup state const [showDeviceTopup, setShowDeviceTopup] = useState(false); const [devicesToAdd, setDevicesToAdd] = useState(1); + const [showDeviceReduction, setShowDeviceReduction] = useState(false); + const [targetDeviceLimit, setTargetDeviceLimit] = useState(1); const [showTrafficTopup, setShowTrafficTopup] = useState(false); const [selectedTrafficPackage, setSelectedTrafficPackage] = useState(null); const [showServerManagement, setShowServerManagement] = useState(false); @@ -287,6 +289,7 @@ export default function Subscription() { setShowPurchaseForm(false); setShowTariffPurchase(false); setShowDeviceTopup(false); + setShowDeviceReduction(false); setShowTrafficTopup(false); setShowServerManagement(false); setSwitchTariffId(null); @@ -359,6 +362,36 @@ export default function Subscription() { }, }); + // Device reduction info query + const { data: deviceReductionInfo } = useQuery({ + queryKey: ['device-reduction-info'], + queryFn: subscriptionApi.getDeviceReductionInfo, + enabled: showDeviceReduction && !!subscription, + }); + + // Initialize target device limit when reduction info loads + useEffect(() => { + if (deviceReductionInfo && showDeviceReduction) { + setTargetDeviceLimit( + Math.max( + deviceReductionInfo.min_device_limit, + deviceReductionInfo.current_device_limit - 1, + ), + ); + } + }, [deviceReductionInfo, showDeviceReduction]); + + // Device reduction mutation + const deviceReductionMutation = useMutation({ + mutationFn: () => subscriptionApi.reduceDevices(targetDeviceLimit), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['subscription'] }); + queryClient.invalidateQueries({ queryKey: ['devices'] }); + queryClient.invalidateQueries({ queryKey: ['device-reduction-info'] }); + setShowDeviceReduction(false); + }, + }); + // Traffic packages query const { data: trafficPackages } = useQuery({ queryKey: ['traffic-packages'], @@ -1155,6 +1188,174 @@ export default function Subscription() { )} + {/* Reduce Devices */} +
+ {!showDeviceReduction ? ( + + ) : ( +
+
+

+ {t('subscription.additionalOptions.reduceDevicesTitle')} +

+ +
+ + {deviceReductionInfo?.available === false ? ( +
+ {deviceReductionInfo.reason || + t('subscription.additionalOptions.reduceUnavailable')} +
+ ) : deviceReductionInfo ? ( +
+ {/* Device limit selector */} +
+ +
+
{targetDeviceLimit}
+
+ {t('subscription.additionalOptions.devicesUnit')} +
+
+ +
+ + {/* Info */} +
+
+ {t('subscription.additionalOptions.currentDeviceLimit', { + count: deviceReductionInfo.current_device_limit, + })} +
+
+ {t('subscription.additionalOptions.minDeviceLimit', { + count: deviceReductionInfo.min_device_limit, + })} +
+
+ {t('subscription.additionalOptions.connectedDevices', { + count: deviceReductionInfo.connected_devices_count, + })} +
+
+ + {/* Warning if connected devices block reduction */} + {deviceReductionInfo.connected_devices_count > + deviceReductionInfo.min_device_limit && ( +
+ {t('subscription.additionalOptions.disconnectDevicesFirst', { + count: deviceReductionInfo.connected_devices_count, + })} +
+ )} + + {/* New limit preview */} +
+
+ {t('subscription.additionalOptions.newDeviceLimit', { + count: targetDeviceLimit, + })} +
+
+ + + + {deviceReductionMutation.isError && ( +
+ {getErrorMessage(deviceReductionMutation.error)} +
+ )} +
+ ) : ( +
+ +
+ )} +
+ )} +
+ {/* Buy Traffic */} {subscription.traffic_limit_gb > 0 && (