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

testing modal management #17132

Draft
wants to merge 2 commits into
base: edge
Choose a base branch
from
Draft
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
31 changes: 17 additions & 14 deletions protocol-designer/src/ProtocolRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
GateModal,
} from './organisms'
import { ProtocolDesignerAppFallback } from './resources/ProtocolDesignerAppFallback'
import { ModalProvider } from './resources/ModalProvider'

import type { RouteProps } from './types'

Expand Down Expand Up @@ -72,20 +73,22 @@ export function ProtocolRoutes(): JSX.Element {
FallbackComponent={ProtocolDesignerAppFallback}
onReset={handleReset}
>
<NavigationBar />
<Kitchen>
<Box width="100%">
{showGateModal ? <GateModal /> : null}
<LabwareUploadModal />
<FileUploadMessagesModal />
<Routes>
{allRoutes.map(({ Component, path }: RouteProps) => {
return <Route key={path} path={path} element={<Component />} />
})}
<Route path="*" element={<Navigate to={landingPage.path} />} />
</Routes>
</Box>
</Kitchen>
<ModalProvider>
<NavigationBar />
<Kitchen>
<Box width="100%">
{showGateModal ? <GateModal /> : null}
<LabwareUploadModal />
<FileUploadMessagesModal />
<Routes>
{allRoutes.map(({ Component, path }: RouteProps) => {
return <Route key={path} path={path} element={<Component />} />
})}
<Route path="*" element={<Navigate to={landingPage.path} />} />
</Routes>
</Box>
</Kitchen>
</ModalProvider>
</ErrorBoundary>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,16 @@ interface MaterialsListModalProps {
fixtures: FixtureInList[]
labware: LabwareOnDeck[]
liquids: OrderedLiquids
setShowMaterialsListModal: (showMaterialsListModal: boolean) => void
onClose: () => void
}

export function MaterialsListModal({
hardware,
fixtures,
labware,
liquids,
setShowMaterialsListModal,
// setShowMaterialsListModal,
onClose,
}: MaterialsListModalProps): JSX.Element {
const { t } = useTranslation(['protocol_overview', 'shared'])
const robotType = useSelector(getRobotType)
Expand All @@ -71,7 +72,7 @@ export function MaterialsListModal({
const tCSlot = robotType === FLEX_ROBOT_TYPE ? 'A1, B1' : '7,8,10,11'

const handleClose = (): void => {
setShowMaterialsListModal(false)
onClose()
}

return createPortal(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ interface InstrumentsInfoProps {
robotType: RobotType
pipettesOnDeck: PipetteOnDeck[]
additionalEquipment: AdditionalEquipmentEntities
setShowEditInstrumentsModal: (showEditInstrumentsModal: boolean) => void
handleOpenEditInstrumentsModal: () => void
}

export function InstrumentsInfo({
robotType,
pipettesOnDeck,
additionalEquipment,
setShowEditInstrumentsModal,
handleOpenEditInstrumentsModal,
}: InstrumentsInfoProps): JSX.Element {
const { t } = useTranslation(['protocol_overview', 'shared'])
const leftPipette = pipettesOnDeck.find(pipette => pipette.mount === 'left')
Expand Down Expand Up @@ -84,9 +84,7 @@ export function InstrumentsInfo({
<Flex padding={SPACING.spacing4}>
<Btn
textDecoration={TYPOGRAPHY.textDecorationUnderline}
onClick={() => {
setShowEditInstrumentsModal(true)
}}
onClick={handleOpenEditInstrumentsModal}
css={BUTTON_LINK_STYLE}
>
<StyledText desktopStyle="bodyDefaultRegular">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ type MetadataInfo = Array<{
}>

interface ProtocolMetadataProps {
setShowEditMetadataModal: (showEditMetadataModal: boolean) => void
handleOpenEditMetadataModal: () => void
metaDataInfo: MetadataInfo
}

export function ProtocolMetadata({
setShowEditMetadataModal,
handleOpenEditMetadataModal,
metaDataInfo,
}: ProtocolMetadataProps): JSX.Element {
const { t } = useTranslation('protocol_overview')
Expand All @@ -43,9 +43,7 @@ export function ProtocolMetadata({
<Flex padding={SPACING.spacing4}>
<Btn
textDecoration={TYPOGRAPHY.textDecorationUnderline}
onClick={() => {
setShowEditMetadataModal(true)
}}
onClick={handleOpenEditMetadataModal}
css={BUTTON_LINK_STYLE}
data-testid="ProtocolOverview_MetadataEditButton"
>
Expand Down
14 changes: 6 additions & 8 deletions protocol-designer/src/pages/ProtocolOverview/StartingDeck.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ import type { DeckSlot } from '../../types'

interface StartingDeckProps {
robotType: RobotType
setShowMaterialsListModal: Dispatch<SetStateAction<boolean>>
handleOpenMaterialsListModal: () => void
}

export function StartingDeck({
robotType,
setShowMaterialsListModal,
handleOpenMaterialsListModal,
}: StartingDeckProps): JSX.Element {
const [isOffDeck, setIsOFfDeck] = useState<boolean>(false)

Expand All @@ -41,7 +41,7 @@ export function StartingDeck({
<StartingDeckHeader
isOffDeck={isOffDeck}
setIsOffDeck={setIsOFfDeck}
setShowMaterialsListModal={setShowMaterialsListModal}
handleOpenMaterialsListModal={handleOpenMaterialsListModal}
/>
<StartingDeckBody isOffDeck={isOffDeck} robotType={robotType} />
</Flex>
Expand All @@ -51,11 +51,11 @@ export function StartingDeck({
interface StartingDeckHeaderProps {
isOffDeck: boolean
setIsOffDeck: Dispatch<SetStateAction<boolean>>
setShowMaterialsListModal: Dispatch<SetStateAction<boolean>>
handleOpenMaterialsListModal: () => void
}

function StartingDeckHeader(props: StartingDeckHeaderProps): JSX.Element {
const { isOffDeck, setIsOffDeck, setShowMaterialsListModal } = props
const { isOffDeck, setIsOffDeck, handleOpenMaterialsListModal } = props
const { t } = useTranslation(['protocol_overview', 'starting_deck_state'])
const onDeckString = t('starting_deck_state:onDeck')
const offDeckString = t('starting_deck_state:offDeck')
Expand All @@ -69,9 +69,7 @@ function StartingDeckHeader(props: StartingDeckHeaderProps): JSX.Element {
<Btn
data-testid="Materials_list"
textDecoration={TYPOGRAPHY.textDecorationUnderline}
onClick={() => {
setShowMaterialsListModal(true)
}}
onClick={handleOpenMaterialsListModal}
css={BUTTON_LINK_STYLE}
>
<StyledText desktopStyle="bodyDefaultRegular">
Expand Down
70 changes: 30 additions & 40 deletions protocol-designer/src/pages/ProtocolOverview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
getUnusedStagingAreas,
getUnusedTrash,
} from './utils'
import { useModal } from '../../resources/ModalProvider'

import type { CreateCommand } from '@opentrons/shared-data'
import type { ThunkDispatch } from '../../types'
Expand Down Expand Up @@ -76,13 +77,8 @@ export function ProtocolOverview(): JSX.Element {
'modules',
])
const navigate = useNavigate()
const [
showEditInstrumentsModal,
setShowEditInstrumentsModal,
] = useState<boolean>(false)
const [showEditMetadataModal, setShowEditMetadataModal] = useState<boolean>(
false
)
const { openModal, closeModal } = useModal()

const [showExportWarningModal, setShowExportWarningModal] = useState<boolean>(
false
)
Expand All @@ -93,9 +89,6 @@ export function ProtocolOverview(): JSX.Element {
labwareIngredSelectors.allIngredientGroupFields
)
const dispatch: ThunkDispatch<any> = useDispatch()
const [showMaterialsListModal, setShowMaterialsListModal] = useState<boolean>(
false
)
const fileData = useSelector(fileSelectors.createFile)
const savedStepForms = useSelector(stepFormSelectors.getSavedStepForms)
const additionalEquipment = useSelector(getAdditionalEquipmentEntities)
Expand Down Expand Up @@ -211,36 +204,33 @@ export function ProtocolOverview(): JSX.Element {
},
})

const handleOpenEditMetadataModal = (): void => {
openModal(<EditProtocolMetadataModal onClose={closeModal} />)
}

const handleOpenEditInstrumentsModal = (): void => {
openModal(<EditInstrumentsModal onClose={closeModal} />)
}

const handleOpenMaterialsListModal = (): void => {
openModal(
<MaterialsListModal
hardware={Object.values(modulesOnDeck)}
fixtures={
robotType === OT2_ROBOT_TYPE
? Object.values(additionalEquipmentOnDeck)
: []
}
labware={Object.values(labwaresOnDeck)}
liquids={liquidsOnDeck}
onClose={closeModal}
/>
)
}

return (
<Fragment>
{showEditMetadataModal ? (
<EditProtocolMetadataModal
onClose={() => {
setShowEditMetadataModal(false)
}}
/>
) : null}
{showEditInstrumentsModal ? (
<EditInstrumentsModal
onClose={() => {
setShowEditInstrumentsModal(false)
}}
/>
) : null}
{exportWarningModal}
{showMaterialsListModal ? (
<MaterialsListModal
hardware={Object.values(modulesOnDeck)}
fixtures={
robotType === OT2_ROBOT_TYPE
? Object.values(additionalEquipmentOnDeck)
: []
}
labware={Object.values(labwaresOnDeck)}
liquids={liquidsOnDeck}
setShowMaterialsListModal={setShowMaterialsListModal}
/>
) : null}
<Flex
flexDirection={DIRECTION_COLUMN}
padding={`${SPACING.spacing60} ${SPACING.spacing80}`}
Expand Down Expand Up @@ -302,13 +292,13 @@ export function ProtocolOverview(): JSX.Element {
>
<ProtocolMetadata
metaDataInfo={metaDataInfo}
setShowEditMetadataModal={setShowEditMetadataModal}
handleOpenEditMetadataModal={handleOpenEditMetadataModal}
/>
<InstrumentsInfo
robotType={robotType}
pipettesOnDeck={pipettesOnDeck}
additionalEquipment={additionalEquipment}
setShowEditInstrumentsModal={setShowEditInstrumentsModal}
handleOpenEditInstrumentsModal={handleOpenEditInstrumentsModal}
/>
<LiquidDefinitions
allIngredientGroupFields={allIngredientGroupFields}
Expand All @@ -322,7 +312,7 @@ export function ProtocolOverview(): JSX.Element {
>
<StartingDeck
robotType={robotType}
setShowMaterialsListModal={setShowMaterialsListModal}
handleOpenMaterialsListModal={handleOpenMaterialsListModal}
/>
</Flex>
</Flex>
Expand Down
43 changes: 43 additions & 0 deletions protocol-designer/src/resources/ModalProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { createContext, useContext } from 'react'
import { useModalManager } from './useModalManager'
import type { ReactNode } from 'react'

interface ModalProviderProps {
children: ReactNode
}

// Create a context with inferred types
const ModalContext = createContext<ReturnType<typeof useModalManager> | null>(
null
)

export const ModalProvider: React.FC<ModalProviderProps> = ({ children }) => {
const modalManager = useModalManager()

return (
<ModalContext.Provider value={modalManager}>
{children}
{modalManager.isOpen && (
<div className="modal-overlay" onClick={modalManager.closeModal}>
<div
className="modal-content"
onClick={e => {
e.stopPropagation()
}}
>
{modalManager.modalContent}
</div>
</div>
)}
</ModalContext.Provider>
)
}

// Hook to access modal context
export const useModal = (): ReturnType<typeof useModalManager> => {
const context = useContext(ModalContext)
if (!context) {
throw new Error('useModal must be used within a ModalProvider')
}
return context
}
28 changes: 28 additions & 0 deletions protocol-designer/src/resources/useModalManager.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useState, useCallback } from 'react'
import type { ReactNode } from 'react'

// Define the shape of the modal manager
interface UseModalManagerReturn {
isOpen: boolean
modalContent: ReactNode | null
openModal: (content: ReactNode) => void
closeModal: () => void
}

// Custom hook for managing modal state
export const useModalManager = (): UseModalManagerReturn => {
const [isOpen, setIsOpen] = useState(false)
const [modalContent, setModalContent] = useState<ReactNode | null>(null)

const openModal = useCallback((content: ReactNode) => {
setModalContent(content)
setIsOpen(true)
}, [])

const closeModal = useCallback(() => {
setModalContent(null)
setIsOpen(false)
}, [])

return { isOpen, modalContent, openModal, closeModal }
}
Loading