Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e25ddf6
refactor: extract ScreenWrapper for shared screen layout
edmonday Mar 2, 2026
e381512
fix: lint issues
autofix-ci[bot] Mar 2, 2026
c294844
refactor: remove unused headerSx prop from multiple screens
edmonday Mar 2, 2026
aed4750
fix: lint issues
autofix-ci[bot] Mar 2, 2026
2d84add
feat: add email notification toggle to DoneScreen
edmonday Mar 2, 2026
7ef0dd6
fix: lint issues
autofix-ci[bot] Mar 2, 2026
141e92f
style: ui changes for email
edmonday Mar 4, 2026
1666191
style: spacing
edmonday Mar 4, 2026
8be8428
fix: styling and carousel
edmonday Mar 6, 2026
21f7f0b
fix: remove border
edmonday Mar 6, 2026
c11ccd3
fix: add test
edmonday Mar 6, 2026
a1d4265
test: fix tests
edmonday Mar 6, 2026
d531206
Merge branch 'main' into edmondshen/nes-1364-media-screen-styling-cha…
edmonday Mar 6, 2026
84c9135
fix: tests
edmonday Mar 6, 2026
66a87cc
fix: lint
edmonday Mar 6, 2026
942e44c
Merge branch 'edmondshen/nes-1364-media-screen-styling-changes' into …
edmonday Mar 6, 2026
f3b8f24
fix: lint issues
autofix-ci[bot] Mar 6, 2026
863f28d
fix: add back the switch
edmonday Mar 8, 2026
dba14e6
fix: remove validateOnSubmit from LinksScreen
edmonday Mar 8, 2026
e52ca65
Merge branch 'edmondshen/nes-1364-media-screen-styling-changes' into …
edmonday Mar 8, 2026
95329da
fix: add response section
edmonday Mar 8, 2026
3dd9423
Merge branch 'main' into edmondshen/nes-1364-media-screen-styling-cha…
edmonday Mar 8, 2026
a8c3270
fix: resolved comments
edmonday Mar 8, 2026
65a82d2
fix: lint issues
autofix-ci[bot] Mar 8, 2026
40da71c
fix: add guest flow flag on button
edmonday Mar 8, 2026
ed64382
Merge branch 'edmondshen/nes-1364-media-screen-styling-changes' into …
edmonday Mar 9, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ describe('NotificationSwitch', () => {
)
})

it('renders without Tooltip when name is not provided', async () => {
render(
<SnackbarProvider>
<MockedProvider>
<NotificationSwitch journeyId="journeyId" />
</MockedProvider>
</SnackbarProvider>
)

fireEvent.mouseOver(screen.getByRole('checkbox'))
await waitFor(() =>
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()
)
})

it('does not update event email notifications when disabled', async () => {
render(
<SnackbarProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,22 @@ export function NotificationSwitch({
}
}

const switchElement = (
<Box>
<Switch
inputProps={{ 'aria-checked': checked }}
checked={checked}
onChange={handleChange}
disabled={loading || disabled}
/>
</Box>
)

if (name == null) return switchElement

return (
<Tooltip title={t('Only {{ name }} can change this', { name })}>
<Box>
<Switch
inputProps={{ 'aria-checked': checked }}
checked={checked}
onChange={handleChange}
disabled={loading || disabled}
/>
</Box>
{switchElement}
</Tooltip>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import CircularProgress from '@mui/material/CircularProgress'
import Stack from '@mui/material/Stack'
import { SxProps, Theme } from '@mui/material/styles'
import dynamic from 'next/dynamic'
import { useRouter } from 'next/router'
import { useTranslation } from 'next-i18next'
Expand Down Expand Up @@ -51,6 +52,7 @@ interface ShareItemProps {
handleKeepMounted?: () => void
buttonVariant?: 'icon' | 'default'
setHasOpenDialog?: (hasOpenDialog: boolean) => void
buttonProps?: ComponentProps<typeof Button>
}

/**
Expand All @@ -70,7 +72,8 @@ export function ShareItem({
handleCloseMenu,
handleKeepMounted,
buttonVariant = 'icon',
setHasOpenDialog
setHasOpenDialog,
buttonProps
}: ShareItemProps): ReactElement {
const { t } = useTranslation('apps-journeys-admin')
const { enqueueSnackbar } = useSnackbar()
Expand Down Expand Up @@ -124,7 +127,7 @@ export function ShareItem({
variant={variant}
label={t('Share')}
onClick={handleShowMenu}
ButtonProps={{ variant: 'contained' }}
ButtonProps={{ variant: 'contained', ...buttonProps }}
icon={buttonVariant === 'icon' ? <ShareIcon /> : undefined}
/>
<Dialog
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,9 @@ jest.mock('./Screens', () => ({
</button>
</div>
),
DoneScreen: ({
handleScreenNavigation
}: {
handleScreenNavigation: (screen: string) => void
}) => (
DoneScreen: () => (
<div data-testid="done-screen">
<h2>Done Screen</h2>
<button
onClick={() => handleScreenNavigation('language')}
data-testid="done-screen-go-to-language"
>
Go to language
</button>
</div>
)
}))
Expand Down Expand Up @@ -784,90 +774,6 @@ describe('MultiStepForm', () => {
})
})

describe('Edit Manually button', () => {
it('should hide edit manually button when on the language screen', () => {
const journey = {
id: 'test-journey-id'
} as unknown as Journey

setRouterQuery({ journeyId: 'test-journey-id' })

render(
<FlagsProvider flags={defaultFlags}>
<SnackbarProvider>
<JourneyProvider value={{ journey }}>
<MultiStepForm />
</JourneyProvider>
</SnackbarProvider>
</FlagsProvider>
)

const editButton = screen.getByText('Edit Manually')
expect(editButton).toHaveStyle('visibility: hidden')
})

it('should show edit manually button when on any screen after the first screen', () => {
const journey = {
id: 'test-journey-id'
} as unknown as Journey

setRouterQuery({ journeyId: 'test-journey-id' })

const { rerender } = render(
<FlagsProvider flags={defaultFlags}>
<SnackbarProvider>
<JourneyProvider value={{ journey: journey }}>
<MultiStepForm />
</JourneyProvider>
</SnackbarProvider>
</FlagsProvider>
)

const editButton = screen.getByText('Edit Manually')
expect(editButton).toHaveStyle('visibility: hidden')

fireEvent.click(screen.getByTestId('language-next'))
setRouterQuery({ journeyId: 'test-journey-id', screen: 'social' })
rerender(
<FlagsProvider flags={defaultFlags}>
<SnackbarProvider>
<JourneyProvider value={{ journey: journey }}>
<MultiStepForm />
</JourneyProvider>
</SnackbarProvider>
</FlagsProvider>
)
const editButtonAfterRerender = screen.getByText('Edit Manually')
expect(editButtonAfterRerender).toHaveStyle('visibility: visible')
expect(editButtonAfterRerender).toHaveAttribute(
'href',
'/journeys/test-journey-id'
)
})

it('should disable edit manually button if journey is not found', () => {
const journey = {
id: null
} as unknown as Journey

setRouterQuery({ journeyId: 'test-journey-id' })

render(
<FlagsProvider flags={defaultFlags}>
<SnackbarProvider>
<JourneyProvider value={{ journey }}>
<MultiStepForm />
</JourneyProvider>
</SnackbarProvider>
</FlagsProvider>
)
expect(screen.getByText('Edit Manually')).toHaveAttribute(
'aria-disabled',
'true'
)
})
})

describe('progress stepper', () => {
it('should not render progress stepper when journey has no customization capabilities', async () => {
const journeyWithNoCapabilities = {
Expand Down Expand Up @@ -1171,55 +1077,6 @@ describe('MultiStepForm', () => {
})
})

it('should call router.replace with correct URL when handleScreenNavigation is called', () => {
const journeyWithAllCapabilities = {
...journey,
journeyCustomizationDescription: 'Hello {{ firstName: John }}!',
journeyCustomizationFields: [
{
id: '1',
key: 'firstName',
value: 'John',
__typename: 'JourneyCustomizationField'
}
],
blocks: [
{
__typename: 'ButtonBlock',
id: '1',
label: 'Test Button',
action: {
__typename: 'LinkAction',
url: 'https://wa.me/123',
customizable: true,
parentStepId: null
}
}
]
} as unknown as Journey

const journeyId = journeyWithAllCapabilities.id
setRouterQuery({ journeyId, screen: 'done' })

render(
<FlagsProvider flags={defaultFlags}>
<SnackbarProvider>
<JourneyProvider value={{ journey: journeyWithAllCapabilities }}>
<MultiStepForm />
</JourneyProvider>
</SnackbarProvider>
</FlagsProvider>
)

expect(screen.getByTestId('done-screen')).toBeInTheDocument()
fireEvent.click(screen.getByTestId('done-screen-go-to-language'))

expect(mockReplace).toHaveBeenCalledTimes(1)
expect(mockReplace).toHaveBeenCalledWith(
`/templates/${journeyId}/customize?screen=language`
)
})

it('should call router.replace with override journey id and next screen when handleNext(overrideJourneyId) is called', () => {
const journeyWithAllCapabilities = {
...journey,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import Container from '@mui/material/Container'
import Stack from '@mui/material/Stack'
import NextLink from 'next/link'
import { useRouter } from 'next/router'
import { useUser } from 'next-firebase-auth'
import { useTranslation } from 'next-i18next'
import { ReactElement, useMemo } from 'react'

import { useJourney } from '@core/journeys/ui/JourneyProvider'
import { useFlags } from '@core/shared/ui/FlagsProvider'
import Edit3 from '@core/shared/ui/icons/Edit3'

import {
CUSTOMIZE_SCREEN_QUERY_KEY,
Expand Down Expand Up @@ -38,42 +35,21 @@ export const MULTI_STEP_FORM_MIN_HEIGHT = 900

function renderScreen(
screen: CustomizationScreen,
handleNext: (overrideJourneyId?: string) => void,
handleScreenNavigation: (screen: CustomizationScreen) => void
handleNext: (overrideJourneyId?: string) => void
): ReactElement {
switch (screen) {
case 'language':
return (
<LanguageScreen
handleNext={handleNext}
handleScreenNavigation={handleScreenNavigation}
/>
)
return <LanguageScreen handleNext={handleNext} />
case 'text':
return (
<TextScreen
handleNext={handleNext}
handleScreenNavigation={handleScreenNavigation}
/>
)
return <TextScreen handleNext={handleNext} />
case 'links':
return (
<LinksScreen
handleNext={handleNext}
handleScreenNavigation={handleScreenNavigation}
/>
)
return <LinksScreen handleNext={handleNext} />
case 'media':
return <MediaScreen handleNext={handleNext} />
case 'social':
return (
<SocialScreen
handleNext={handleNext}
handleScreenNavigation={handleScreenNavigation}
/>
)
return <SocialScreen handleNext={handleNext} />
case 'done':
return <DoneScreen handleScreenNavigation={handleScreenNavigation} />
return <DoneScreen />
default:
return <></>
}
Expand All @@ -89,7 +65,6 @@ export function MultiStepForm(): ReactElement {
const firebaseUserLoaded = user?.firebaseUser != null
const isAnon = user?.firebaseUser?.isAnonymous ?? false
const journeyId = journey?.id ?? ''
const link = `/journeys/${journeyId}`

const {
screens,
Expand Down Expand Up @@ -130,16 +105,11 @@ export function MultiStepForm(): ReactElement {
)
}

async function handleScreenNavigation(
screen: CustomizationScreen
): Promise<void> {
void router.replace(buildCustomizeUrl(journeyId, screen, undefined))
}

return (
<TemplateVideoUploadProvider>
<Container
maxWidth="sm"
disableGutters
sx={{
width: '100%',
minHeight: { xs: '100%', sm: MULTI_STEP_FORM_MIN_HEIGHT },
Expand All @@ -151,27 +121,7 @@ export function MultiStepForm(): ReactElement {
overflow: 'hidden'
}}
>
<Stack gap={{ xs: 6, sm: 6 }} data-testid="MultiStepForm">
<NextLink href={link} passHref legacyBehavior>
<Button
variant="text"
color="primary"
startIcon={<Edit3 />}
sx={{
alignSelf: 'flex-end',
mr: '4px',
fontWeight: 'bold',
visibility: activeScreen === 'language' ? 'hidden' : 'visible',
'& .MuiButton-startIcon': {
marginRight: 0.3,
marginTop: 1
}
}}
disabled={journey?.id == null}
>
{t('Edit Manually')}
</Button>
</NextLink>
<Stack gap={{ xs: 8, sm: 17 }} data-testid="MultiStepForm">
{(hasEditableText ||
hasCustomizableLinks ||
hasCustomizableMedia) && (
Expand All @@ -182,17 +132,7 @@ export function MultiStepForm(): ReactElement {
/>
</Box>
)}

<Box
sx={{
alignSelf: 'center',
width: '100%',
px: '14px',
py: { xs: '10px', sm: '24px' }
}}
>
{renderScreen(activeScreen, handleNext, handleScreenNavigation)}
</Box>
{renderScreen(activeScreen, handleNext)}
</Stack>
</Container>
</TemplateVideoUploadProvider>
Expand Down
Loading
Loading