import * as React from 'react'; import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Box, Button, Heading, HStack, Portal, Spacer, Tag, TagLabel, TagLeftIcon, Tooltip, useBreakpoint, useColorModeValue, useDisclosure, useToast, } from '@chakra-ui/react'; import axios from 'axios'; import { Heart, HeartBreak, LockSimple, LockSimpleOpen, WifiHigh, WifiSlash } from 'phosphor-react'; import { useTranslation } from 'react-i18next'; import Masonry from 'react-masonry-css'; import { useNavigate } from 'react-router-dom'; import DeviceDetails from './Details'; import DeviceLogsCard from './LogsCard'; import DeviceNotes from './Notes'; import RadiusClientsCard from './RadiusClients'; import RestrictionsCard from './RestrictionsCard'; import DeviceStatisticsCard from './StatisticsCard'; import DeviceSummary from './Summary'; import WifiAnalysisCard from './WifiAnalysis'; import { DeleteButton } from 'components/Buttons/DeleteButton'; import DeviceActionDropdown from 'components/Buttons/DeviceActionDropdown'; import { RefreshButton } from 'components/Buttons/RefreshButton'; import { Card } from 'components/Containers/Card'; import { CardHeader } from 'components/Containers/Card/CardHeader'; import GlobalSearchBar from 'components/GlobalSearchBar'; import FormattedDate from 'components/InformationDisplays/FormattedDate'; import { ConfigureModal } from 'components/Modals/ConfigureModal'; import { EventQueueModal } from 'components/Modals/EventQueueModal'; import FactoryResetModal from 'components/Modals/FactoryResetModal'; import { FirmwareUpgradeModal } from 'components/Modals/FirmwareUpgradeModal'; import { RebootModal } from 'components/Modals/RebootModal'; import { useScriptModal } from 'components/Modals/ScriptModal/useScriptModal'; import { TelemetryModal } from 'components/Modals/TelemetryModal'; import { TraceModal } from 'components/Modals/TraceModal'; import { WifiScanModal } from 'components/Modals/WifiScanModal'; import { useDeleteDevice, useGetDevice, useGetDeviceHealthChecks, useGetDeviceStatus } from 'hooks/Network/Devices'; type Props = { serialNumber: string; }; const DevicePageWrapper = ({ serialNumber }: Props) => { const { t } = useTranslation(); const toast = useToast(); const breakpoint = useBreakpoint(); const cancelRef = React.useRef(null); const navigate = useNavigate(); const { mutateAsync: deleteDevice, isLoading: isDeleting } = useDeleteDevice({ serialNumber, }); const getDevice = useGetDevice({ serialNumber }); const getStatus = useGetDeviceStatus({ serialNumber }); const getHealth = useGetDeviceHealthChecks({ serialNumber, limit: 1 }); const { isOpen: isDeleteOpen, onOpen: onDeleteOpen, onClose: onDeleteClose } = useDisclosure(); const scanModalProps = useDisclosure(); const resetModalProps = useDisclosure(); const eventQueueProps = useDisclosure(); const configureModalProps = useDisclosure(); const upgradeModalProps = useDisclosure(); const telemetryModalProps = useDisclosure(); const traceModalProps = useDisclosure(); const rebootModalProps = useDisclosure(); const scriptModal = useScriptModal(); // Sticky-top styles const isCompact = breakpoint === 'base' || breakpoint === 'sm' || breakpoint === 'md'; const boxShadow = useColorModeValue('0px 7px 23px rgba(0, 0, 0, 0.05)', 'none'); const handleDeleteClick = () => deleteDevice(serialNumber, { onSuccess: () => { toast({ id: `delete-device-success-${serialNumber}`, title: t('common.success'), status: 'success', duration: 5000, isClosable: true, position: 'top-right', }); navigate('/devices'); }, onError: (e) => { if (axios.isAxiosError(e)) { toast({ id: `delete-device-error-${serialNumber}`, title: t('common.error'), description: e.response?.data?.ErrorDescription, status: 'error', duration: 5000, isClosable: true, position: 'top-right', }); } }, }); const connectedTag = React.useMemo(() => { if (!getStatus.data) return null; return ( {getStatus?.data?.connected ? t('common.connected') : t('common.disconnected')} ); }, [getStatus.data]); const healthTag = React.useMemo(() => { if (!getStatus.data || !getStatus.data.connected || !getHealth.data || getHealth.data?.values?.length === 0) return null; let color = 'red'; let sanity: number | undefined; if (getHealth.data?.values?.[0]) { const { sanity: sanityValue } = getHealth.data.values[0]; sanity = sanityValue; if (sanityValue === 100) color = 'green'; else if (sanityValue > 80) color = 'yellow'; } return ( ) : ( '' ) } > {sanity ? `${sanity}%` : t('common.unknown')} ); }, [getStatus.data, getHealth.data]); const restrictedTag = React.useMemo(() => { if (!getDevice.data || !getDevice.data.restrictedDevice) return null; if (getDevice.data.restrictionDetails?.developer) return ( {t('devices.restricted')} {isCompact ? '' : '(Dev Mode)'} ); return ( {t('devices.restricted')} ); }, [getDevice.data, isCompact]); const refresh = () => { getDevice.refetch(); getStatus.refetch(); getHealth.refetch(); }; return ( <> {isCompact ? ( {serialNumber} {connectedTag} {healthTag} {restrictedTag} {getDevice?.data && ( )} ) : ( {serialNumber} {connectedTag} {healthTag} {restrictedTag} {getDevice?.data && ( )} )} {t('crud.delete')} {serialNumber} {t('crud.delete_confirm', { obj: t('devices.one') })} {scriptModal.modal} {getDevice.data && getDevice.data?.hasRADIUSSessions > 0 ? ( ) : null} ); }; export default DevicePageWrapper;