Skip to content

Commit

Permalink
feat(app): create multiSlideout and plug into ChooseRobotSlideout (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
jerader authored Mar 13, 2024
1 parent 3b58363 commit d5095bb
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 177 deletions.
3 changes: 3 additions & 0 deletions app/src/assets/localization/en/shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
"before_you_begin": "Before you begin",
"browse": "browse",
"cancel": "cancel",
"change_robot": "Change robot",
"clear_data": "clear data",
"close_robot_door": "Close the robot door before starting the run.",
"close": "close",
"computer_in_app_is_controlling_robot": "A computer with the Opentrons App is currently controlling this robot.",
"confirm_placement": "Confirm placement",
"confirm_position": "Confirm position",
"confirm_terminate": "This will immediately stop the activity begun on a computer. You, or another user, may lose progress or see an error in the Opentrons App.",
"confirm_values": "Confirm values",
"confirm": "Confirm",
"continue_activity": "Continue activity",
"continue_to_param": "Continue to parameters",
"continue": "continue",
"delete": "Delete",
"did_pipette_pick_up_tip": "Did pipette pick up tip successfully?",
Expand Down
52 changes: 52 additions & 0 deletions app/src/atoms/Slideout/MultiSlideout.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import * as React from 'react'
import { TYPOGRAPHY, PrimaryBtn, COLORS } from '@opentrons/components'
import { MultiSlideout } from './MultiSlideout'
import { StyledText } from '../text'

import type { Story, Meta } from '@storybook/react'

export default {
title: 'App/Atoms/MultiSlideout',
component: MultiSlideout,
argTypes: { onClick: { action: 'clicked' } },
} as Meta

const Template: Story<React.ComponentProps<typeof MultiSlideout>> = args => {
const [firstPage, setFirstPage] = React.useState<boolean>(false)

const togglePage = (): void => {
setFirstPage(prevState => !prevState)
}

const children = (
<>
<StyledText as="p">
{firstPage ? 'first page body' : 'second page body'}
</StyledText>

<PrimaryBtn
marginTop="28rem"
onClick={togglePage}
backgroundColor={COLORS.blue50}
textTransform={TYPOGRAPHY.textTransformNone}
>
<StyledText as="p">
{firstPage ? 'Go to Second Page' : 'Go to First Page'}
</StyledText>
</PrimaryBtn>
</>
)

return (
<MultiSlideout {...args} currentStep={firstPage ? 1 : 2}>
{children}
</MultiSlideout>
)
}

export const Primary = Template.bind({})
Primary.args = {
title: 'This is the slideout title with the max width',
isExpanded: 'true',
maxSteps: 2,
}
37 changes: 37 additions & 0 deletions app/src/atoms/Slideout/MultiSlideout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react'
import { Slideout } from './index'

interface MultiSlideoutProps {
title: string | React.ReactElement
children: React.ReactNode
onCloseClick: () => void
currentStep: number
maxSteps: number
// isExpanded is for collapse and expand animation
isExpanded?: boolean
footer?: React.ReactNode
}

export const MultiSlideout = (props: MultiSlideoutProps): JSX.Element => {
const {
isExpanded,
title,
onCloseClick,
children,
footer,
maxSteps,
currentStep,
} = props

return (
<Slideout
title={title}
isExpanded={isExpanded}
footer={footer}
onCloseClick={onCloseClick}
multiSlideoutSpecs={{ currentStep, maxSteps }}
>
{children}
</Slideout>
)
}
32 changes: 29 additions & 3 deletions app/src/atoms/Slideout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ import {

import { Divider } from '../structure'
import { StyledText } from '../text'
import { useTranslation } from 'react-i18next'

export interface MultiSlideoutSpecs {
currentStep: number
maxSteps: number
}
export interface SlideoutProps {
title: string | React.ReactElement
children: React.ReactNode
onCloseClick: () => unknown
onCloseClick: () => void
// isExpanded is for collapse and expand animation
isExpanded?: boolean
footer?: React.ReactNode
multiSlideoutSpecs?: MultiSlideoutSpecs
}

const SHARED_STYLE = css`
Expand Down Expand Up @@ -108,10 +114,17 @@ const CLOSE_ICON_STYLE = css`
`

export const Slideout = (props: SlideoutProps): JSX.Element => {
const { isExpanded, title, onCloseClick, children, footer } = props
const {
isExpanded,
title,
onCloseClick,
children,
footer,
multiSlideoutSpecs,
} = props
const { t } = useTranslation('shared')
const slideOutRef = React.useRef<HTMLDivElement>(null)
const [isReachedBottom, setIsReachedBottom] = React.useState<boolean>(false)

const hasBeenExpanded = React.useRef<boolean>(isExpanded ?? false)
const handleScroll = (): void => {
if (slideOutRef.current == null) return
Expand Down Expand Up @@ -166,6 +179,19 @@ export const Slideout = (props: SlideoutProps): JSX.Element => {
flexDirection={DIRECTION_COLUMN}
justifyContent={JUSTIFY_SPACE_BETWEEN}
>
{multiSlideoutSpecs === undefined ? null : (
<StyledText
as="p"
color={COLORS.grey60}
alignItems={ALIGN_CENTER}
paddingX={SPACING.spacing16}
>
{t('step', {
current: multiSlideoutSpecs.currentStep,
max: multiSlideoutSpecs.maxSteps,
})}
</StyledText>
)}
{typeof title === 'string' ? (
<Flex
flexDirection={DIRECTION_ROW}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
mockReachableRobot,
mockUnreachableRobot,
} from '../../../redux/discovery/__fixtures__'
import { useFeatureFlag } from '../../../redux/config'
import { getNetworkInterfaces } from '../../../redux/networking'
import { ChooseRobotSlideout } from '..'
import { useNotifyService } from '../../../resources/useNotifyService'
Expand All @@ -26,7 +27,7 @@ vi.mock('../../../redux/discovery')
vi.mock('../../../redux/robot-update')
vi.mock('../../../redux/networking')
vi.mock('../../../resources/useNotifyService')

vi.mock('../../../redux/config')
const render = (props: React.ComponentProps<typeof ChooseRobotSlideout>) => {
return renderWithProviders(
<StaticRouter>
Expand All @@ -42,6 +43,7 @@ const mockSetSelectedRobot = vi.fn()

describe('ChooseRobotSlideout', () => {
beforeEach(() => {
vi.mocked(useFeatureFlag).mockReturnValue(true)
vi.mocked(getConnectableRobots).mockReturnValue([mockConnectableRobot])
vi.mocked(getUnreachableRobots).mockReturnValue([mockUnreachableRobot])
vi.mocked(getReachableRobots).mockReturnValue([mockReachableRobot])
Expand Down Expand Up @@ -127,6 +129,32 @@ describe('ChooseRobotSlideout', () => {
expect(vi.mocked(startDiscovery)).toHaveBeenCalled()
expect(dispatch).toHaveBeenCalledWith({ type: 'mockStartDiscovery' })
})
it('renders the multi slideout page 1', () => {
render({
onCloseClick: vi.fn(),
isExpanded: true,
isSelectedRobotOnDifferentSoftwareVersion: false,
selectedRobot: null,
setSelectedRobot: mockSetSelectedRobot,
title: 'choose robot slideout title',
robotType: 'OT-2 Standard',
multiSlideout: { currentPage: 1 },
})
screen.getByText('Step 1 / 2')
})
it('renders the multi slideout page 2', () => {
render({
onCloseClick: vi.fn(),
isExpanded: true,
isSelectedRobotOnDifferentSoftwareVersion: false,
selectedRobot: null,
setSelectedRobot: mockSetSelectedRobot,
title: 'choose robot slideout title',
robotType: 'OT-2 Standard',
multiSlideout: { currentPage: 2 },
})
screen.getByText('Step 2 / 2')
})
it('defaults to first available robot and allows an available robot to be selected', () => {
vi.mocked(getConnectableRobots).mockReturnValue([
{ ...mockConnectableRobot, name: 'otherRobot', ip: 'otherIp' },
Expand Down
Loading

0 comments on commit d5095bb

Please sign in to comment.