diff --git a/app/src/assets/localization/en/labware_position_check.json b/app/src/assets/localization/en/labware_position_check.json index be73b09f6b9..58fe6550ddd 100644 --- a/app/src/assets/localization/en/labware_position_check.json +++ b/app/src/assets/localization/en/labware_position_check.json @@ -11,6 +11,7 @@ "check_labware_in_slot_title": "Check Labware {{labware_display_name}} in slot {{slot}}", "check_remaining_labware_with_primary_pipette_section": "Check remaining labware with {{primary_mount}} Pipette and tip", "clear_all_slots": "Clear all deck slots of labware, leaving modules in place", + "clear_all_slots_odd": "Clear all deck slots of labware", "cli_ssh": "Command Line Interface (SSH)", "close_and_apply_offset_data": "Close and apply labware offset data", "confirm_pick_up_tip_modal_title": "Did the pipette pick up a tip successfully?", diff --git a/app/src/organisms/LabwarePositionCheck/CheckItem.tsx b/app/src/organisms/LabwarePositionCheck/CheckItem.tsx index 7cfb76e79d0..aaed13ca607 100644 --- a/app/src/organisms/LabwarePositionCheck/CheckItem.tsx +++ b/app/src/organisms/LabwarePositionCheck/CheckItem.tsx @@ -454,7 +454,10 @@ export const CheckItem = (props: CheckItemProps): JSX.Element | null => { })} body={ } labwareDef={labwareDef} diff --git a/app/src/organisms/LabwarePositionCheck/ExitConfirmation.tsx b/app/src/organisms/LabwarePositionCheck/ExitConfirmation.tsx index 5bdb7911af7..23f498392d9 100644 --- a/app/src/organisms/LabwarePositionCheck/ExitConfirmation.tsx +++ b/app/src/organisms/LabwarePositionCheck/ExitConfirmation.tsx @@ -16,15 +16,13 @@ import { RESPONSIVENESS, SecondaryButton, JUSTIFY_FLEX_END, + TEXT_ALIGN_CENTER, } from '@opentrons/components' import { StyledText } from '../../atoms/text' -import { NeedHelpLink } from '../CalibrationPanels' import { useSelector } from 'react-redux' import { getIsOnDevice } from '../../redux/config' import { SmallButton } from '../../atoms/buttons' -const LPC_HELP_LINK_URL = - 'https://support.opentrons.com/s/article/How-Labware-Offsets-work-on-the-OT-2' interface ExitConfirmationProps { onGoBack: () => void onConfirmExit: () => void @@ -45,12 +43,28 @@ export const ExitConfirmation = (props: ExitConfirmationProps): JSX.Element => { flexDirection={DIRECTION_COLUMN} justifyContent={JUSTIFY_CENTER} alignItems={ALIGN_CENTER} + paddingX={SPACING.spacing32} > - {t('exit_screen_title')} - - {t('exit_screen_subtitle')} - + {isOnDevice ? ( + <> + + {t('exit_screen_title')} + + + + {t('exit_screen_subtitle')} + + + + ) : ( + <> + {t('exit_screen_title')} + + {t('exit_screen_subtitle')} + + + )} {isOnDevice ? ( { justifyContent={JUSTIFY_SPACE_BETWEEN} alignItems={ALIGN_CENTER} > - {t('shared:go_back')} @@ -97,8 +110,23 @@ export const ExitConfirmation = (props: ExitConfirmationProps): JSX.Element => { const ConfirmationHeader = styled.h1` margin-top: ${SPACING.spacing24}; - ${TYPOGRAPHY.h1Default} + ${TYPOGRAPHY.level3HeaderSemiBold} @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { ${TYPOGRAPHY.level4HeaderSemiBold} } ` + +const ConfirmationHeaderODD = styled.h1` + margin-top: ${SPACING.spacing24}; + ${TYPOGRAPHY.level3HeaderBold} + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + ${TYPOGRAPHY.level4HeaderSemiBold} + } +` +const ConfirmationBodyODD = styled.h1` + ${TYPOGRAPHY.level4HeaderRegular} + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + ${TYPOGRAPHY.level4HeaderRegular} + } + color: ${COLORS.darkBlack70}; +` diff --git a/app/src/organisms/LabwarePositionCheck/LabwarePositionCheckComponent.tsx b/app/src/organisms/LabwarePositionCheck/LabwarePositionCheckComponent.tsx index 4a96d8bc2e3..95f9fc02c5e 100644 --- a/app/src/organisms/LabwarePositionCheck/LabwarePositionCheckComponent.tsx +++ b/app/src/organisms/LabwarePositionCheck/LabwarePositionCheckComponent.tsx @@ -261,6 +261,8 @@ export const LabwarePositionCheckComponent = ( const currentStep = LPCSteps?.[currentStepIndex] if (currentStep == null) return null + const protocolHasModules = protocolData.modules.length > 0 + const handleJog = ( axis: Axis, dir: Sign, @@ -357,7 +359,14 @@ export const LabwarePositionCheckComponent = ( } else if (currentStep.section === 'DETACH_PROBE') { modalContent = } else if (currentStep.section === 'PICK_UP_TIP') { - modalContent = + modalContent = ( + + ) } else if (currentStep.section === 'RETURN_TIP') { modalContent = ( { const { t, i18n } = useTranslation(['labware_position_check', 'shared']) @@ -67,6 +69,8 @@ export const PickUpTip = (props: PickUpTipProps): JSX.Element | null => { setFatalError, adapterId, robotType, + protocolHasModules, + currentStepIndex, } = props const [showTipConfirmation, setShowTipConfirmation] = React.useState(false) const isOnDevice = useSelector(getIsOnDevice) @@ -87,7 +91,10 @@ export const PickUpTip = (props: PickUpTipProps): JSX.Element | null => { ) const labwareDisplayName = getLabwareDisplayName(labwareDef) const instructions = [ - t('clear_all_slots'), + ...(protocolHasModules && currentStepIndex === 1 + ? [t('place_modules')] + : []), + isOnDevice ? t('clear_all_slots_odd') : t('clear_all_slots'), { adapterId, } = props + const isOnDevice = useSelector(getIsOnDevice) + const labwareDef = getLabwareDef(labwareId, protocolData) if (labwareDef == null) return null @@ -60,7 +64,7 @@ export const ReturnTip = (props: ReturnTipProps): JSX.Element | null => { const labwareDisplayName = getLabwareDisplayName(labwareDef) const instructions = [ - t('clear_all_slots'), + isOnDevice ? t('clear_all_slots_odd') : t('clear_all_slots'), - + { existingOffsets: mockExistingOffsets, isRobotMoving: false, robotType: FLEX_ROBOT_TYPE, + protocolHasModules: false, + currentStepIndex: 1, } mockUseProtocolMetaData.mockReturnValue({ robotType: 'OT-3 Standard' }) }) @@ -69,16 +71,46 @@ describe('PickUpTip', () => { jest.resetAllMocks() resetAllWhenMocks() }) - it('renders correct copy when preparing space', () => { + it('renders correct copy when preparing space on desktop if protocol has modules', () => { + props.protocolHasModules = true const { getByText, getByRole } = render(props) getByRole('heading', { name: 'Prepare tip rack in Slot D1' }) + getByText('Place modules on deck') getByText('Clear all deck slots of labware, leaving modules in place') getByText( matchTextWithSpans('Place a full Mock TipRack Definition into Slot D1') ) - getByRole('link', { name: 'Need help?' }) getByRole('button', { name: 'Confirm placement' }) }) + it('renders correct copy when preparing space on touchscreen if protocol has modules', () => { + mockGetIsOnDevice.mockReturnValue(true) + props.protocolHasModules = true + const { getByText, getByRole } = render(props) + getByRole('heading', { name: 'Prepare tip rack in Slot D1' }) + getByText('Place modules on deck') + getByText('Clear all deck slots of labware') + getByText( + matchTextWithSpans('Place a full Mock TipRack Definition into Slot D1') + ) + }) + it('renders correct copy when preparing space on desktop if protocol has no modules', () => { + const { getByText, getByRole } = render(props) + getByRole('heading', { name: 'Prepare tip rack in Slot D1' }) + getByText('Clear all deck slots of labware, leaving modules in place') + getByText( + matchTextWithSpans('Place a full Mock TipRack Definition into Slot D1') + ) + getByRole('button', { name: 'Confirm placement' }) + }) + it('renders correct copy when preparing space on touchscreen if protocol has no modules', () => { + mockGetIsOnDevice.mockReturnValue(true) + const { getByText, getByRole } = render(props) + getByRole('heading', { name: 'Prepare tip rack in Slot D1' }) + getByText('Clear all deck slots of labware') + getByText( + matchTextWithSpans('Place a full Mock TipRack Definition into Slot D1') + ) + }) it('renders correct copy when confirming position on desktop', () => { const { getByText, getByRole } = render({ ...props, diff --git a/app/src/organisms/LabwarePositionCheck/__tests__/ReturnTip.test.tsx b/app/src/organisms/LabwarePositionCheck/__tests__/ReturnTip.test.tsx index 465609db8c4..037d171579a 100644 --- a/app/src/organisms/LabwarePositionCheck/__tests__/ReturnTip.test.tsx +++ b/app/src/organisms/LabwarePositionCheck/__tests__/ReturnTip.test.tsx @@ -7,12 +7,17 @@ import { ReturnTip } from '../ReturnTip' import { SECTIONS } from '../constants' import { mockCompletedAnalysis } from '../__fixtures__' import { useProtocolMetadata } from '../../Devices/hooks' +import { getIsOnDevice } from '../../../redux/config' jest.mock('../../Devices/hooks') +jest.mock('../../../redux/config') const mockUseProtocolMetaData = useProtocolMetadata as jest.MockedFunction< typeof useProtocolMetadata > +const mockGetIsOnDevice = getIsOnDevice as jest.MockedFunction< + typeof getIsOnDevice +> const matchTextWithSpans: (text: string) => MatcherFunction = ( text: string @@ -37,6 +42,7 @@ describe('ReturnTip', () => { beforeEach(() => { mockChainRunCommands = jest.fn().mockImplementation(() => Promise.resolve()) + mockGetIsOnDevice.mockReturnValue(false) props = { section: SECTIONS.RETURN_TIP, pipetteId: mockCompletedAnalysis.pipettes[0].id, @@ -55,7 +61,7 @@ describe('ReturnTip', () => { afterEach(() => { jest.restoreAllMocks() }) - it('renders correct copy', () => { + it('renders correct copy on desktop', () => { const { getByText, getByRole } = render(props) getByRole('heading', { name: 'Return tip rack to Slot D1' }) getByText('Clear all deck slots of labware, leaving modules in place') @@ -66,6 +72,17 @@ describe('ReturnTip', () => { ) getByRole('link', { name: 'Need help?' }) }) + it('renders correct copy on device', () => { + mockGetIsOnDevice.mockReturnValue(true) + const { getByText, getByRole } = render(props) + getByRole('heading', { name: 'Return tip rack to Slot D1' }) + getByText('Clear all deck slots of labware') + getByText( + matchTextWithSpans( + 'Place the Mock TipRack Definition that you used before back into Slot D1. The pipette will return tips to their original location in the rack.' + ) + ) + }) it('executes correct chained commands when CTA is clicked', async () => { const { getByRole } = render(props) await getByRole('button', { name: 'Confirm placement' }).click()