Skip to content

Commit

Permalink
fix(app): naïve loading state for tc open lid during lw cal (#4616)
Browse files Browse the repository at this point in the history
  • Loading branch information
b-cooper authored Dec 16, 2019
1 parent e2848f8 commit c4a4cdf
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 8 deletions.
27 changes: 20 additions & 7 deletions app/src/components/PrepareModules/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
// @flow
import * as React from 'react'
import { useDispatch } from 'react-redux'
import some from 'lodash/some'
import { PrimaryButton, AlertModal, Icon } from '@opentrons/components'
import {
useTimeout,
PrimaryButton,
AlertModal,
Icon,
} from '@opentrons/components'

import { sendModuleCommand } from '../../modules'
import DeckMap from '../DeckMap'
Expand All @@ -12,24 +16,33 @@ import { Portal } from '../portal'
import type { Dispatch } from '../../types'
import type { AttachedModule } from '../../modules/types'

const LID_OPEN_DELAY_MS = 30 * 1000
type Props = {| robotName: string, modules: Array<AttachedModule> |}

export function PrepareModules(props: Props) {
const { modules, robotName } = props
const dispatch = useDispatch<Dispatch>()
const [isHandling, setIsHandling] = React.useState(false)

// NOTE: this is the smarter implementation of isHandling that
// relies on the TC reporting its 'in_between' status while the lid m
// motor is moving, which currently doesn't happen because of a FW limitation
// const isHandling = some(
// modules,
// mod => mod.name === 'thermocycler' && mod.data?.lid === 'in_between'
// )

useTimeout(() => setIsHandling(false), isHandling ? LID_OPEN_DELAY_MS : null)

const handleOpenLidClick = () => {
modules
.filter(mod => mod.name === 'thermocycler')
.forEach(mod =>
dispatch(sendModuleCommand(robotName, mod.serial, 'open'))
)
setIsHandling(true)
}

const isHandling = some(
modules,
mod => mod.name === 'thermocycler' && mod.data?.lid === 'in_between'
)
return (
<div className={styles.page_content_dark}>
<div className={styles.deck_map_wrapper}>
Expand All @@ -47,7 +60,7 @@ export function PrepareModules(props: Props) {
<PrimaryButton
className={styles.open_lid_button}
onClick={handleOpenLidClick}
// disabled={isHandling} TODO: uncomment when optical latches report 'closed'
disabled={isHandling}
>
{isHandling ? (
<>
Expand Down
2 changes: 1 addition & 1 deletion components/src/hooks/__tests__/useInterval.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as React from 'react'
import { mount } from 'enzyme'
import { useInterval } from '..'

describe('usePrevious hook', () => {
describe('useInterval hook', () => {
const callback = jest.fn()

beforeEach(() => {
Expand Down
51 changes: 51 additions & 0 deletions components/src/hooks/__tests__/useTimeout.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// @flow
import * as React from 'react'
import { mount } from 'enzyme'
import { useTimeout } from '..'

describe('useTimeouthook', () => {
const callback = jest.fn()

beforeEach(() => {
jest.useFakeTimers()
})

afterEach(() => {
jest.resetAllMocks()
jest.clearAllTimers()
jest.useRealTimers()
})

const TestUseTimeout = (props: { delay: number | null }) => {
useTimeout(callback, props.delay)
return <span />
}

test('delay `null` results in no calls', () => {
mount(<TestUseTimeout delay={null} />)
jest.runTimersToTime(10000)

expect(callback).toHaveBeenCalledTimes(0)
})

test('delay sets a timeout', () => {
mount(<TestUseTimeout delay={2} />)
jest.runTimersToTime(3)

expect(callback).toHaveBeenCalledTimes(1)
})

test('re-rendering with delay={null} clears the interval', () => {
const wrapper = mount(<TestUseTimeout delay={4} />)

jest.runTimersToTime(2)
wrapper.setProps({ delay: null })

expect(callback).toHaveBeenCalledTimes(0)

wrapper.setProps({ delay: 4 })
jest.runTimersToTime(6)

expect(callback).toHaveBeenCalledTimes(1)
})
})
1 change: 1 addition & 0 deletions components/src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@

export * from './usePrevious'
export * from './useInterval'
export * from './useTimeout'
29 changes: 29 additions & 0 deletions components/src/hooks/useTimeout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @flow
import { useEffect, useRef } from 'react'

/**
* React hook to call a function after a delay; adapted from: useInterval
*
* @template T (type of the input value)
* @param {() => mixed} callback (function to call after timeout)
* @param {number | null} delay (timeout delay, or null to disable the timeout)
* @returns {void}
*/
export function useTimeout(callback: () => mixed, delay: number | null): void {
const savedCallback = useRef()

// remember the latest callback
useEffect(() => {
savedCallback.current = callback
}, [callback])

// set up the timeout
useEffect(() => {
const currentCallback = () =>
savedCallback.current && savedCallback.current()
if (delay !== null) {
const id = setTimeout(currentCallback, delay)
return () => clearTimeout(id)
}
}, [delay])
}

0 comments on commit c4a4cdf

Please sign in to comment.