import * as React from 'react' ; import { useDispatch , useSelector } from 'react-redux' ; import isEmpty from 'lodash/isEmpty' ; import { css } from 'styled-components' ; import { Box , Card , BORDER_SOLID_LIGHT , SPACING_3 , useInterval , } from '@opentrons/components' ; import { fetchModules , getAttachedModules , getModuleControlsDisabled , } from '../../../redux/modules' ; import { getConnectedRobotName } from '../../../redux/robot/selectors' ; import { ModuleItem , NoModulesMessage } from './ModuleItem' ; import type { State , Dispatch } from '../../../redux/types' ; import type { AttachedModule } from '../../../redux/modules/types' ; import { UsbHubItem } from './UsbHubItem' ; const TITLE = 'Connected Modules' ; const POLL_MODULE_INTERVAL_MS = 5000 ; interface ModulesListByPort { [ port ] : AttachedModule [ ] ; } const moduleListWithUSBInfo = ( modulesByPort , controlDisabledReason ) : JSX . Element [ ] => { return Object . keys ( modulesByPort ) . map ( port => modulesByPort [ port ] . length > 1 ? ( < UsbHubItem hub = { port } modules = { modulesByPort [ port ] } controlDisabledReason = { controlDisabledReason } / > ) : ( < ModuleItem usbPort = { port } key = { modulesByPort [ port ] [ 0 ] . serial } module = { modulesByPort [ port ] [ 0 ] } controlDisabledReason = { controlDisabledReason } / > ) ) ; } ; const legacyModuleList = ( modules , controlDisabledReason ) : JSX . Element [ ] => { return modules . map ( mod => ( < ModuleItem key = { mod . serial } module = { mod } controlDisabledReason = { controlDisabledReason } / > ) ) ; } ; interface Props { robotName : string ; } export function AttachedModulesCard ( props ) { const { robotName } = props ; const dispatch = useDispatch < Dispatch > ( ) ; const connectedRobotName = useSelector ( getConnectedRobotName ) ; const modules = useSelector ( ( state ) => getAttachedModules ( state , robotName ) ) ; const controlDisabledReason = useSelector ( ( state ) => getModuleControlsDisabled ( state , robotName ) ) ; const modulesByPort = modules . reduce < { [ port ] : AttachedModule [ ] ; } > ( ( portMap , module ) => { const port = module . usbPort . hub || module . usbPort . port ; if ( port !== null ) { const portContents = portMap [ port ] ?? [ ] ; portMap [ port ] = [ ... portContents , module ] ; } return portMap ; } , { } ) ; const modulesList = isEmpty ( modulesByPort ) ? legacyModuleList ( modules , controlDisabledReason ) : moduleListWithUSBInfo ( modulesByPort , controlDisabledReason ) ; useInterval ( ( ) => dispatch ( fetchModules ( robotName ) ) , connectedRobotName === null ? POLL_MODULE_INTERVAL_MS : null , true ) ; return ( < Card title = { TITLE } > { modules . length === 0 ? ( < NoModulesMessage />) : (modulesList.map((mod, index) => (<Box key={index} paddingX={SPACING_3} paddingY="1.5rem" borderBottom={BORDER_SOLID_LIGHT} css={css ` & : last - child : { border - bottom : 1 px solid transparent ; } `}>
            {mod}
          </Box>)))}
    </Card>);
}
