Skip to content

Commit

Permalink
feat(protocol-designer): add announcement toast (#16562)
Browse files Browse the repository at this point in the history
* feat(protocol-designer): add announcement toast
  • Loading branch information
koji authored Oct 23, 2024
1 parent 33554cb commit 57de055
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 54 deletions.
2 changes: 1 addition & 1 deletion components/src/atoms/Toast/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ export function Toast(props: ToastProps): JSX.Element {
) : null}
<Flex alignItems={ALIGN_CENTER}>
<LegacyStyledText css={TEXT_STYLE}>{message}</LegacyStyledText>
{linkText ? (
{linkText != null ? (
<Link
role="button"
onClick={() => {
Expand Down
2 changes: 0 additions & 2 deletions protocol-designer/src/ProtocolRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
Kitchen,
FileUploadMessagesModal,
LabwareUploadModal,
AnnouncementModal,
} from './organisms'

import type { RouteProps } from './types'
Expand Down Expand Up @@ -63,7 +62,6 @@ export function ProtocolRoutes(): JSX.Element {
<NavigationBar />
<Kitchen>
<Box width="100%">
<AnnouncementModal />
<LabwareUploadModal />
<FileUploadMessagesModal />
<Routes>
Expand Down
2 changes: 2 additions & 0 deletions protocol-designer/src/assets/localization/en/shared.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"labware_detail": "Labware detail",
"labware_name_conflict": "Duplicate labware name",
"labware": "Labware",
"learn_more": "Learn more about the recent changes in the {{version}} release.",
"left_right": "Left+Right",
"left": "Left",
"liquid": "Liquid",
Expand Down Expand Up @@ -118,6 +119,7 @@
"temperaturemoduletype": "Temperature Module",
"thermocyclermoduletype": "Thermocycler Module",
"trashBin": "Trash Bin",
"updated_protocol_designer": "We've updated Protocol Designer!",
"user_settings": "User settings",
"uses_standard_namespace": "Opentrons verified labware",
"version": "Version {{version}}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ export const useAnnouncements = (): Announcement[] => {
),
},
{
announcementKey: 'redesign9.0',
announcementKey: 'redesign8.2',
image: <Flex />,
heading: t('announcements.redesign.body1'),
message: (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const AnnouncementModal = (
justifyContent={JUSTIFY_CENTER}
gridGap={SPACING.spacing12}
>
{image && image}
{image != null && image}
{message}
</Flex>
</Modal>
Expand Down
20 changes: 20 additions & 0 deletions protocol-designer/src/pages/Landing/__tests__/Landing.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ import { renderWithProviders } from '../../../__testing-utils__'
import { loadProtocolFile } from '../../../load-file/actions'
import { getFileMetadata } from '../../../file-data/selectors'
import { toggleNewProtocolModal } from '../../../navigation/actions'
import { useKitchen } from '../../../organisms/Kitchen/hooks'
import { useAnnouncements } from '../../../organisms/AnnouncementModal/announcements'
import { Landing } from '../index'

vi.mock('../../../load-file/actions')
vi.mock('../../../file-data/selectors')
vi.mock('../../../navigation/actions')
vi.mock('../../../organisms/AnnouncementModal/announcements')
vi.mock('../../../organisms/Kitchen/hooks')

const mockMakeSnackbar = vi.fn()
const mockEatToast = vi.fn()
const mockBakeToast = vi.fn()

const render = () => {
return renderWithProviders(
Expand All @@ -27,7 +35,14 @@ describe('Landing', () => {
beforeEach(() => {
vi.mocked(getFileMetadata).mockReturnValue({})
vi.mocked(loadProtocolFile).mockReturnValue(vi.fn())
vi.mocked(useAnnouncements).mockReturnValue({} as any)
vi.mocked(useKitchen).mockReturnValue({
makeSnackbar: mockMakeSnackbar,
bakeToast: mockBakeToast,
eatToast: mockEatToast,
})
})

it('renders the landing page image and text', () => {
render()
screen.getByLabelText('welcome image')
Expand All @@ -40,4 +55,9 @@ describe('Landing', () => {
screen.getByText('Edit existing protocol')
screen.getByRole('img', { name: 'welcome image' })
})

it('render toast when there is an announcement', () => {
render()
expect(mockBakeToast).toHaveBeenCalled()
})
})
147 changes: 98 additions & 49 deletions protocol-designer/src/pages/Landing/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react'
import { useEffect, useState } from 'react'
import { NavLink, useNavigate } from 'react-router-dom'
import styled from 'styled-components'
import { useDispatch, useSelector } from 'react-redux'
Expand All @@ -9,16 +9,21 @@ import {
CURSOR_POINTER,
DIRECTION_COLUMN,
Flex,
INFO_TOAST,
JUSTIFY_CENTER,
LargeButton,
SPACING,
StyledText,
TYPOGRAPHY,
} from '@opentrons/components'
import { BUTTON_LINK_STYLE } from '../../atoms'
import { AnnouncementModal } from '../../organisms'
import { actions as loadFileActions } from '../../load-file'
import { getFileMetadata } from '../../file-data/selectors'
import { toggleNewProtocolModal } from '../../navigation/actions'
import { useKitchen } from '../../organisms/Kitchen/hooks'
import { useAnnouncements } from '../../organisms/AnnouncementModal/announcements'
import { getLocalStorageItem, localStorageAnnouncementKey } from '../../persist'
import welcomeImage from '../../assets/images/welcome_page.png'

import type { ThunkDispatch } from '../../types'
Expand All @@ -28,8 +33,42 @@ export function Landing(): JSX.Element {
const dispatch: ThunkDispatch<any> = useDispatch()
const metadata = useSelector(getFileMetadata)
const navigate = useNavigate()
const [showAnnouncementModal, setShowAnnouncementModal] = useState<boolean>(
false
)
const { bakeToast, eatToast } = useKitchen()
const announcements = useAnnouncements()
const lastAnnouncement = announcements[announcements.length - 1]
const announcementKey = lastAnnouncement
? lastAnnouncement.announcementKey
: null
const showGateModal =
process.env.NODE_ENV === 'production' || process.env.OT_PD_SHOW_GATE
const userHasNotSeenAnnouncement =
getLocalStorageItem(localStorageAnnouncementKey) !== announcementKey &&
!showGateModal

useEffect(() => {
if (userHasNotSeenAnnouncement) {
const toastId = bakeToast(
t('learn_more', { version: process.env.OT_PD_VERSION }) as string,
INFO_TOAST,
{
heading: t('updated_protocol_designer'),
closeButton: true,
linkText: t('view_release_notes'),
onLinkClick: () => {
eatToast(toastId)
setShowAnnouncementModal(true)
},
disableTimeout: true,
justifyContent: JUSTIFY_CENTER,
}
)
}
}, [userHasNotSeenAnnouncement])

React.useEffect(() => {
useEffect(() => {
if (metadata?.created != null) {
console.warn('protocol already exists, navigating to overview')
navigate('/overview')
Expand All @@ -43,57 +82,67 @@ export function Landing(): JSX.Element {
}

return (
<Flex
backgroundColor={COLORS.grey20}
flexDirection={DIRECTION_COLUMN}
alignItems={ALIGN_CENTER}
justifyContent={JUSTIFY_CENTER}
height="calc(100vh - 3.5rem)"
width="100%"
gridGap={SPACING.spacing32}
>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing16}>
<img
src={welcomeImage}
height="132px"
width="548px"
aria-label="welcome image"
<>
{showAnnouncementModal ? (
<AnnouncementModal
isViewReleaseNotes={showAnnouncementModal}
onClose={() => {
setShowAnnouncementModal(false)
}}
/>
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={SPACING.spacing8}
alignItems={ALIGN_CENTER}
>
<StyledText desktopStyle="headingLargeBold">
{t('welcome')}
</StyledText>
<StyledText
desktopStyle="headingSmallRegular"
color={COLORS.grey60}
maxWidth="34.25rem"
textAlign={TYPOGRAPHY.textAlignCenter}
) : null}
<Flex
backgroundColor={COLORS.grey20}
flexDirection={DIRECTION_COLUMN}
alignItems={ALIGN_CENTER}
justifyContent={JUSTIFY_CENTER}
height="calc(100vh - 3.5rem)"
width="100%"
gridGap={SPACING.spacing32}
>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing16}>
<img
src={welcomeImage}
height="132px"
width="548px"
aria-label="welcome image"
/>
<Flex
flexDirection={DIRECTION_COLUMN}
gridGap={SPACING.spacing8}
alignItems={ALIGN_CENTER}
>
{t('no-code-required')}
</StyledText>
<StyledText desktopStyle="headingLargeBold">
{t('welcome')}
</StyledText>
<StyledText
desktopStyle="headingSmallRegular"
color={COLORS.grey60}
maxWidth="34.25rem"
textAlign={TYPOGRAPHY.textAlignCenter}
>
{t('no-code-required')}
</StyledText>
</Flex>
</Flex>
<StyledNavLink to={'/createNew'}>
<LargeButton
onClick={() => {
dispatch(toggleNewProtocolModal(true))
}}
buttonText={<ButtonText>{t('create_a_protocol')}</ButtonText>}
/>
</StyledNavLink>
<StyledLabel>
<Flex css={BUTTON_LINK_STYLE}>
<StyledText desktopStyle="bodyLargeRegular">
{t('edit_existing')}
</StyledText>
</Flex>
<input type="file" onChange={loadFile}></input>
</StyledLabel>
</Flex>
<StyledNavLink to={'/createNew'}>
<LargeButton
onClick={() => {
dispatch(toggleNewProtocolModal(true))
}}
buttonText={<ButtonText>{t('create_a_protocol')}</ButtonText>}
/>
</StyledNavLink>
<StyledLabel>
<Flex css={BUTTON_LINK_STYLE}>
<StyledText desktopStyle="bodyLargeRegular">
{t('edit_existing')}
</StyledText>
</Flex>
<input type="file" onChange={loadFile}></input>
</StyledLabel>
</Flex>
</>
)
}

Expand Down

0 comments on commit 57de055

Please sign in to comment.