Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(app): create multiSlideout and plug into ChooseRobotSlideout #14649

Merged
merged 4 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading