From e25ddf6cfad960040e84adb68bbae2f97d424b99 Mon Sep 17 00:00:00 2001 From: edmonday Date: Mon, 2 Mar 2026 04:04:07 +0000 Subject: [PATCH 01/21] refactor: extract ScreenWrapper for shared screen layout Create ScreenWrapper component with responsive title/subtitle and migrate all 6 customization screens to use it. Fixes MediaScreen using wrong Typography variants and broken color prop. Refs: NES-1364 Co-Authored-By: Claude Opus 4.6 --- .../Screens/DoneScreen/DoneScreen.tsx | 48 +---- .../Screens/LanguageScreen/LanguageScreen.tsx | 188 ++++++++---------- .../Screens/LinksScreen/LinksScreen.tsx | 57 ++---- .../Screens/MediaScreen/MediaScreen.tsx | 50 +++-- .../Screens/ScreenWrapper/ScreenWrapper.tsx | 65 ++++++ .../Screens/ScreenWrapper/index.ts | 1 + .../Screens/SocialScreen/SocialScreen.tsx | 80 +++----- .../Screens/TextScreen/TextScreen.tsx | 160 ++++++--------- 8 files changed, 290 insertions(+), 359 deletions(-) create mode 100644 apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx create mode 100644 apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/index.ts diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index 9fc51812375..9c94fbfbcd3 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -16,6 +16,7 @@ import Play3Icon from '@core/shared/ui/icons/Play3' import { ShareItem } from '../../../../Editor/Toolbar/Items/ShareItem' import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' +import { ScreenWrapper } from '../ScreenWrapper' interface DoneScreenProps { handleScreenNavigation?: (screen: CustomizationScreen) => void @@ -40,48 +41,12 @@ export function DoneScreen({ return ( - - {t('Ready to Share!')} - - - {t('Ready to Share!')} - - - {t('Share your unique link on any platform.')} - - - {t('Share your unique link on any platform.')} - - - {steps.length > 0 && ( + {steps.length > 0 && ( )} @@ -131,6 +96,7 @@ export function DoneScreen({ {t('Go To Projects Dashboard')} + ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx index a1fe586c64c..8eead9c3c37 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx @@ -24,6 +24,7 @@ import { useGetParentTemplateJourneyLanguages } from '../../../../../libs/useGet import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' import { CardsPreview } from '../LinksScreen/CardsPreview' +import { ScreenWrapper } from '../ScreenWrapper' import { JourneyCustomizeTeamSelect } from './JourneyCustomizeTeamSelect' @@ -168,116 +169,97 @@ export function LanguageScreen({ return ( - - - {t("Let's Get Started!")} - - - {t('Get Started')} - - - {t('A few quick edits and your template will be ready to share.')} - + - {t("A few quick edits and it's ready to share!")} + {`'${journey?.title ?? ''}'`} - - - {`'${journey?.title ?? ''}'`} - - - {steps.length > 0 && } + {steps.length > 0 && } - - {({ handleSubmit, setFieldValue, values }) => ( -
- - - - {t('Select a language')} - - - {t('Select a language')} - - ({ - id: language?.id, - name: language?.name, - slug: language?.slug - }))} - onChange={(value) => setFieldValue('languageSelect', value)} - /> - {isSignedIn && ( - <> - - {t('Select a team')} - + + {({ handleSubmit, setFieldValue, values }) => ( + + + + + {t('Select a language')} + + + {t('Select a language')} + + ({ + id: language?.id, + name: language?.name, + slug: language?.slug + }))} + onChange={(value) => + setFieldValue('languageSelect', value) + } + /> + {isSignedIn && ( + <> + + {t('Select a team')} + - - {t('Select a team')} - - - - )} - handleSubmit()} - disabled={ - (templateCustomizationGuestFlow && !isSignedIn) || loading - } - ariaLabel={t('Next')} - /> - - - - )} - + + {t('Select a team')} + + + + )} + handleSubmit()} + disabled={ + (templateCustomizationGuestFlow && !isSignedIn) || loading + } + ariaLabel={t('Next')} + /> + +
+ + )} +
+
) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx index ff41feeb824..f128075d367 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx @@ -1,6 +1,5 @@ import { useMutation } from '@apollo/client' import Stack from '@mui/material/Stack' -import Typography from '@mui/material/Typography' import { Formik, FormikHelpers, FormikProvider } from 'formik' import { useTranslation } from 'next-i18next' import { ReactElement, useMemo } from 'react' @@ -28,6 +27,7 @@ import { countries } from '../../../../Editor/Slider/Settings/CanvasDetails/Prop import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { getJourneyLinks } from '../../../utils/getJourneyLinks' import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' +import { ScreenWrapper } from '../ScreenWrapper' import { CardsPreview } from './CardsPreview' import { LinksForm } from './LinksForm' @@ -197,49 +197,18 @@ export function LinksScreen({ width: '100%' }} > - - - {t('Links')} - - - {t('Links')} - - - {t( - 'This content contains buttons linking to external sites. Check them and update the links below.' - )} - - - {t( - 'Buttons here point to external sites. Check and update the links.' - )} - - - + + + >((acc, link) => { diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx index 2ba8f54673e..6998317b976 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx @@ -1,6 +1,4 @@ -import Box from '@mui/material/Box' import Stack from '@mui/material/Stack' -import Typography from '@mui/material/Typography' import { useTranslation } from 'next-i18next' import { ReactElement, useEffect, useState } from 'react' @@ -12,6 +10,7 @@ import { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys import { getJourneyMedia } from '../../../utils/getJourneyMedia' import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' import { useTemplateVideoUpload } from '../../TemplateVideoUploadProvider' +import { ScreenWrapper } from '../ScreenWrapper' import { CardsSection, @@ -83,30 +82,29 @@ export function MediaScreen({ handleNext }: MediaScreenProps): ReactElement { overflow: { xs: 'visible', sm: 'hidden' } }} > - - - {t('Media')} - - - {t('Personalize and manage your media assets')} - - - {showLogo && } - - {showImages && ( - - )} - {showVideos && } - handleNext()} - ariaLabel={t('Next')} - loading={hasActiveUploads} - /> + handleNext()} + ariaLabel={t('Next')} + loading={hasActiveUploads} + /> + } + > + {showLogo && } + + {showImages && ( + + )} + {showVideos && } + ) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx new file mode 100644 index 00000000000..5aab822e4bd --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx @@ -0,0 +1,65 @@ +import Stack from '@mui/material/Stack' +import { SxProps, Theme } from '@mui/material/styles' +import Typography from '@mui/material/Typography' +import { ReactElement, ReactNode } from 'react' + +interface ScreenWrapperProps { + title: string + mobileTitle?: string + subtitle: string + mobileSubtitle?: string + headerSx?: SxProps + footer?: ReactNode + children: ReactNode +} + +export function ScreenWrapper({ + title, + mobileTitle, + subtitle, + mobileSubtitle, + headerSx, + footer, + children +}: ScreenWrapperProps): ReactElement { + return ( + <> + + + {title} + + + {mobileTitle ?? title} + + + {subtitle} + + + {mobileSubtitle ?? subtitle} + + + {children} + {footer} + + ) +} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/index.ts new file mode 100644 index 00000000000..dfa2c06cdb7 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/index.ts @@ -0,0 +1 @@ +export { ScreenWrapper } from './ScreenWrapper' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx index d054a95f5bb..ddf431b6261 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx @@ -1,5 +1,4 @@ import Stack from '@mui/material/Stack' -import Typography from '@mui/material/Typography' import { useTranslation } from 'next-i18next' import { ReactElement } from 'react' @@ -7,6 +6,7 @@ import { DescriptionEdit } from '../../../../Editor/Slider/Settings/SocialDetail import { TitleEdit } from '../../../../Editor/Slider/Settings/SocialDetails/TitleEdit' import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' +import { ScreenWrapper } from '../ScreenWrapper' import { SocialScreenSocialImage } from './SocialScreenSocialImage' @@ -28,56 +28,36 @@ export function SocialScreen({ px: { xs: 5, sm: 20 } }} > - handleNext()} + ariaLabel={t('Done')} + /> + } > - {t('Final Details')} - - - {t('Final Details')} - - - {t('Customize how your invite appears when shared on social media.')} - - - {t('This is how your content will appear when shared on social media.')} - - - - - - - handleNext()} - ariaLabel={t('Done')} - /> + + + + + + ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx index 0c70d8d5e8b..a9256acf9da 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx @@ -1,7 +1,6 @@ import { gql, useMutation } from '@apollo/client' import Box from '@mui/material/Box' import Stack from '@mui/material/Stack' -import Typography from '@mui/material/Typography' import { useTranslation } from 'next-i18next' import { ReactElement, useCallback, useEffect, useState } from 'react' @@ -11,6 +10,7 @@ import { GetJourney_journey_journeyCustomizationFields as JourneyCustomizationFi import { JourneyCustomizationFieldUpdate } from '../../../../../../__generated__/JourneyCustomizationFieldUpdate' import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' +import { ScreenWrapper } from '../ScreenWrapper' export const JOURNEY_CUSTOMIZATION_FIELD_UPDATE = gql` mutation JourneyCustomizationFieldUpdate( @@ -202,101 +202,71 @@ export function TextScreen({ width: '100%' }} > - - - {t('Text')} - - - {t('Text')} - - - {t( - "Fill out the blue fields and we'll customize the content with your information." - )} - - - {t('Fill in the blue fields to customize the content.')} - - - - - {renderEditableText( - journey?.journeyCustomizationDescription ?? '', - replacementItems, - handleValueChange - )} + + } + > + + + {renderEditableText( + journey?.journeyCustomizationDescription ?? '', + replacementItems, + handleValueChange + )} + + - - - + ) } From e381512732d0649ec9bda3aa59bf972db2b8ad70 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 04:08:47 +0000 Subject: [PATCH 02/21] fix: lint issues --- .../Screens/DoneScreen/DoneScreen.tsx | 92 ++++++++++--------- .../Screens/LanguageScreen/LanguageScreen.tsx | 4 +- .../Screens/MediaScreen/MediaScreen.tsx | 5 +- .../Screens/TextScreen/TextScreen.tsx | 4 +- 4 files changed, 54 insertions(+), 51 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index 9c94fbfbcd3..dfed7dbbb01 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -47,55 +47,59 @@ export function DoneScreen({ headerSx={{ pb: { xs: 4, sm: 6 } }} > {steps.length > 0 && ( - - )} + + )} - - - + + - {t('Preview')} - - - + + + + + {t('Go To Projects Dashboard')} + + ) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx index 8eead9c3c37..230a294f4b3 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx @@ -222,9 +222,7 @@ export function LanguageScreen({ name: language?.name, slug: language?.slug }))} - onChange={(value) => - setFieldValue('languageSelect', value) - } + onChange={(value) => setFieldValue('languageSelect', value)} /> {isSignedIn && ( <> diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx index 6998317b976..cfe7e36cc38 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx @@ -101,7 +101,10 @@ export function MediaScreen({ handleNext }: MediaScreenProps): ReactElement { handleStepClick={handleStepClick} /> {showImages && ( - + )} {showVideos && } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx index a9256acf9da..22bdbbe7e3f 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx @@ -207,9 +207,7 @@ export function TextScreen({ subtitle={t( "Fill out the blue fields and we'll customize the content with your information." )} - mobileSubtitle={t( - 'Fill in the blue fields to customize the content.' - )} + mobileSubtitle={t('Fill in the blue fields to customize the content.')} headerSx={{ pb: 4 }} footer={ Date: Mon, 2 Mar 2026 22:16:23 +0000 Subject: [PATCH 03/21] refactor: remove unused headerSx prop from multiple screens Eliminate the headerSx prop from DoneScreen, LanguageScreen, LinksScreen, and ScreenWrapper components to streamline the code. Update TextScreen to maintain consistent mobileSubtitle formatting. --- .../MultiStepForm/Screens/DoneScreen/DoneScreen.tsx | 1 - .../Screens/LanguageScreen/LanguageScreen.tsx | 1 - .../MultiStepForm/Screens/LinksScreen/LinksScreen.tsx | 1 - .../Screens/ScreenWrapper/ScreenWrapper.tsx | 11 ++++------- .../MultiStepForm/Screens/TextScreen/TextScreen.tsx | 5 +++-- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index dfed7dbbb01..6977128cbe9 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -44,7 +44,6 @@ export function DoneScreen({ {steps.length > 0 && ( diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx index 230a294f4b3..59a70befb7d 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx @@ -176,7 +176,6 @@ export function LanguageScreen({ 'A few quick edits and your template will be ready to share.' )} mobileSubtitle={t("A few quick edits and it's ready to share!")} - headerSx={{ pb: { xs: 6, sm: 10 } }} > diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx index 5aab822e4bd..72660e215db 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx @@ -1,5 +1,4 @@ import Stack from '@mui/material/Stack' -import { SxProps, Theme } from '@mui/material/styles' import Typography from '@mui/material/Typography' import { ReactElement, ReactNode } from 'react' @@ -8,7 +7,6 @@ interface ScreenWrapperProps { mobileTitle?: string subtitle: string mobileSubtitle?: string - headerSx?: SxProps footer?: ReactNode children: ReactNode } @@ -18,15 +16,14 @@ export function ScreenWrapper({ mobileTitle, subtitle, mobileSubtitle, - headerSx, footer, children }: ScreenWrapperProps): ReactElement { return ( - <> - + + {children} {footer} - + ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx index 22bdbbe7e3f..a00a99148ce 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx @@ -207,8 +207,9 @@ export function TextScreen({ subtitle={t( "Fill out the blue fields and we'll customize the content with your information." )} - mobileSubtitle={t('Fill in the blue fields to customize the content.')} - headerSx={{ pb: 4 }} + mobileSubtitle={t( + 'Fill in the blue fields to customize the content.' + )} footer={ Date: Mon, 2 Mar 2026 22:22:52 +0000 Subject: [PATCH 04/21] fix: lint issues --- .../MultiStepForm/Screens/TextScreen/TextScreen.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx index a00a99148ce..70a3d93e58d 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx @@ -207,9 +207,7 @@ export function TextScreen({ subtitle={t( "Fill out the blue fields and we'll customize the content with your information." )} - mobileSubtitle={t( - 'Fill in the blue fields to customize the content.' - )} + mobileSubtitle={t('Fill in the blue fields to customize the content.')} footer={ Date: Mon, 2 Mar 2026 22:48:37 +0000 Subject: [PATCH 05/21] feat: add email notification toggle to DoneScreen Refs: NES-1295 Co-Authored-By: Claude Opus 4.6 --- .../NotificationSwitch.spec.tsx | 15 +++++ .../NotificationSwitch/NotificationSwitch.tsx | 22 +++++--- .../Screens/DoneScreen/DoneScreen.spec.tsx | 56 +++++++++++++++++++ .../Screens/DoneScreen/DoneScreen.tsx | 16 ++++++ 4 files changed, 101 insertions(+), 8 deletions(-) diff --git a/apps/journeys-admin/src/components/AccessDialog/NotificationSwitch/NotificationSwitch.spec.tsx b/apps/journeys-admin/src/components/AccessDialog/NotificationSwitch/NotificationSwitch.spec.tsx index 9baa4c9a23f..7cbb5130c32 100644 --- a/apps/journeys-admin/src/components/AccessDialog/NotificationSwitch/NotificationSwitch.spec.tsx +++ b/apps/journeys-admin/src/components/AccessDialog/NotificationSwitch/NotificationSwitch.spec.tsx @@ -55,6 +55,21 @@ describe('NotificationSwitch', () => { ) }) + it('renders without Tooltip when name is not provided', async () => { + render( + + + + + + ) + + fireEvent.mouseOver(screen.getByRole('checkbox')) + await waitFor(() => + expect(screen.queryByRole('tooltip')).not.toBeInTheDocument() + ) + }) + it('does not update event email notifications when disabled', async () => { render( diff --git a/apps/journeys-admin/src/components/AccessDialog/NotificationSwitch/NotificationSwitch.tsx b/apps/journeys-admin/src/components/AccessDialog/NotificationSwitch/NotificationSwitch.tsx index 2196bb9fd4f..103ed3f66fb 100644 --- a/apps/journeys-admin/src/components/AccessDialog/NotificationSwitch/NotificationSwitch.tsx +++ b/apps/journeys-admin/src/components/AccessDialog/NotificationSwitch/NotificationSwitch.tsx @@ -60,16 +60,22 @@ export function NotificationSwitch({ } } + const switchElement = ( + + + + ) + + if (name == null) return switchElement + return ( - - - + {switchElement} ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx index d002acd995b..ca343623a4a 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx @@ -12,6 +12,7 @@ import { } from '../../../../../../__generated__/globalTypes' import { GET_CUSTOM_DOMAINS } from '../../../../../libs/useCustomDomainsQuery/useCustomDomainsQuery' import { GET_JOURNEY_FOR_SHARING } from '../../../../../libs/useJourneyForShareLazyQuery/useJourneyForShareLazyQuery' +import { useJourneyNotifcationUpdateMock } from '../../../../../libs/useJourneyNotificationUpdate/useJourneyNotificationUpdate.mock' import { DoneScreen } from './DoneScreen' @@ -201,6 +202,61 @@ describe('DoneScreen', () => { expect(push).toHaveBeenCalledWith('/') }) + it('renders notification section heading and label', () => { + render( + + + + + + + + ) + + expect( + screen.getByText('Choose where responses go:') + ).toBeInTheDocument() + expect(screen.getByText('Send to my email')).toBeInTheDocument() + }) + + it('renders notification switch unchecked by default', () => { + render( + + + + + + + + ) + + const checkbox = screen.getByRole('checkbox') + expect(checkbox).not.toBeChecked() + }) + + it('fires notification update mutation when switch is toggled', async () => { + const result = jest + .fn() + .mockReturnValueOnce(useJourneyNotifcationUpdateMock.result) + render( + + + + + + + + ) + + fireEvent.click(screen.getByRole('checkbox')) + await waitFor(() => expect(result).toHaveBeenCalled()) + }) + it('opens the share dialog when clicked', async () => { const journeyWithTeam = { ...journey, diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index 6977128cbe9..39d433daf2e 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -14,6 +14,7 @@ import { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys import ArrowRightContained1Icon from '@core/shared/ui/icons/ArrowRightContained1' import Play3Icon from '@core/shared/ui/icons/Play3' +import { NotificationSwitch } from '../../../../AccessDialog/NotificationSwitch' import { ShareItem } from '../../../../Editor/Toolbar/Items/ShareItem' import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { ScreenWrapper } from '../ScreenWrapper' @@ -99,6 +100,21 @@ export function DoneScreen({ {t('Go To Projects Dashboard')} + + + {t('Choose where responses go:')} + + + + {t('Send to my email')} + + + + ) From 7ef0dd656feea06731c58f7ddc3fbc9359287b86 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 22:57:26 +0000 Subject: [PATCH 06/21] fix: lint issues --- .../MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx | 4 +--- .../MultiStepForm/Screens/DoneScreen/DoneScreen.tsx | 4 +--- .../MultiStepForm/Screens/TextScreen/TextScreen.tsx | 4 +--- libs/locales/en/apps-journeys-admin.json | 2 ++ 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx index ca343623a4a..46255259d71 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx @@ -213,9 +213,7 @@ describe('DoneScreen', () => { ) - expect( - screen.getByText('Choose where responses go:') - ).toBeInTheDocument() + expect(screen.getByText('Choose where responses go:')).toBeInTheDocument() expect(screen.getByText('Send to my email')).toBeInTheDocument() }) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index 39d433daf2e..3af35982aa4 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -109,9 +109,7 @@ export function DoneScreen({ justifyContent="space-between" alignItems="center" > - - {t('Send to my email')} - + {t('Send to my email')} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx index a00a99148ce..70a3d93e58d 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx @@ -207,9 +207,7 @@ export function TextScreen({ subtitle={t( "Fill out the blue fields and we'll customize the content with your information." )} - mobileSubtitle={t( - 'Fill in the blue fields to customize the content.' - )} + mobileSubtitle={t('Fill in the blue fields to customize the content.')} footer={ Date: Wed, 4 Mar 2026 00:44:49 +0000 Subject: [PATCH 07/21] style: ui changes for email --- .../Screens/DoneScreen/DoneScreen.tsx | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index 3af35982aa4..9cc95b7b848 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -90,20 +90,29 @@ export function DoneScreen({ /> - - - + {t('Choose where responses go:')} + + {t('Choose Response Destination:')} + + ) From 16661914cfd8300593239e0ca47495067fc65762 Mon Sep 17 00:00:00 2001 From: edmonday Date: Wed, 4 Mar 2026 02:52:14 +0000 Subject: [PATCH 08/21] style: spacing --- .../MultiStepForm/Screens/DoneScreen/DoneScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index 9cc95b7b848..5ffe264e2f3 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -91,7 +91,7 @@ export function DoneScreen({ Date: Fri, 6 Mar 2026 02:59:43 +0000 Subject: [PATCH 09/21] fix: styling and carousel --- .../Toolbar/Items/ShareItem/ShareItem.tsx | 8 +- .../MultiStepForm/MultiStepForm.tsx | 54 +---- .../Screens/DoneScreen/DoneScreen.tsx | 113 +++++----- .../Screens/LanguageScreen/LanguageScreen.tsx | 105 +++++----- .../LinksScreen/CardsPreview/CardsPreview.tsx | 3 +- .../Screens/LinksScreen/CardsPreview/index.ts | 2 +- .../Screens/LinksScreen/LinksScreen.tsx | 197 ++++++++---------- .../Screens/MediaScreen/MediaScreen.tsx | 18 -- .../Sections/CardsSection/CardsSection.tsx | 11 +- .../Screens/ScreenWrapper/ScreenWrapper.tsx | 13 +- .../Screens/SocialScreen/SocialScreen.tsx | 17 +- .../Screens/TextScreen/TextScreen.tsx | 133 ++++++------ .../TemplateCardPreview.tsx | 22 ++ .../TemplateCardPreview/index.ts | 2 +- .../templateCardPreviewConfig.ts | 16 +- 15 files changed, 331 insertions(+), 383 deletions(-) diff --git a/apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx b/apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx index 861b5b09d0c..b245f05420c 100644 --- a/apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx +++ b/apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx @@ -17,6 +17,7 @@ import { GetJourneyForSharing_journey as JourneyFromLazyQuery } from '../../../. import { JourneyFields as JourneyFromContext } from '../../../../../../__generated__/JourneyFields' import { useCustomDomainsQuery } from '../../../../../libs/useCustomDomainsQuery' import { Item } from '../Item/Item' +import { SxProps, Theme } from '@mui/material/styles' const EmbedJourneyDialog = dynamic( async () => @@ -50,7 +51,9 @@ interface ShareItemProps { handleCloseMenu?: () => void handleKeepMounted?: () => void buttonVariant?: 'icon' | 'default' + buttonSx?: SxProps setHasOpenDialog?: (hasOpenDialog: boolean) => void + buttonProps?: ComponentProps } /** @@ -70,7 +73,8 @@ export function ShareItem({ handleCloseMenu, handleKeepMounted, buttonVariant = 'icon', - setHasOpenDialog + setHasOpenDialog, + buttonProps }: ShareItemProps): ReactElement { const { t } = useTranslation('apps-journeys-admin') const { enqueueSnackbar } = useSnackbar() @@ -124,7 +128,7 @@ export function ShareItem({ variant={variant} label={t('Share')} onClick={handleShowMenu} - ButtonProps={{ variant: 'contained' }} + ButtonProps={{ variant: 'contained', ...buttonProps }} icon={buttonVariant === 'icon' ? : undefined} /> void, - handleScreenNavigation: (screen: CustomizationScreen) => void ): ReactElement { switch (screen) { case 'language': return ( ) case 'text': return ( ) case 'links': return ( ) case 'media': @@ -69,11 +62,10 @@ function renderScreen( return ( ) case 'done': - return + return default: return <> } @@ -128,16 +120,11 @@ export function MultiStepForm(): ReactElement { ) } - async function handleScreenNavigation( - screen: CustomizationScreen - ): Promise { - void router.replace(buildCustomizeUrl(journeyId, screen, undefined)) - } - return ( - - - - + {(hasEditableText || hasCustomizableLinks || hasCustomizableMedia) && ( @@ -180,17 +150,7 @@ export function MultiStepForm(): ReactElement { /> )} - - - {renderScreen(activeScreen, handleNext, handleScreenNavigation)} - + {renderScreen(activeScreen, handleNext)} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index 6977128cbe9..aa4cdc4fbb7 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -1,4 +1,3 @@ -import Box from '@mui/material/Box' import Button from '@mui/material/Button' import Stack from '@mui/material/Stack' import Typography from '@mui/material/Typography' @@ -15,16 +14,9 @@ import ArrowRightContained1Icon from '@core/shared/ui/icons/ArrowRightContained1 import Play3Icon from '@core/shared/ui/icons/Play3' import { ShareItem } from '../../../../Editor/Toolbar/Items/ShareItem' -import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { ScreenWrapper } from '../ScreenWrapper' -interface DoneScreenProps { - handleScreenNavigation?: (screen: CustomizationScreen) => void -} - -export function DoneScreen({ - handleScreenNavigation -}: DoneScreenProps): ReactElement { +export function DoneScreen(): ReactElement { const { t } = useTranslation('apps-journeys-admin') const { journey } = useJourney() const router = useRouter() @@ -40,55 +32,10 @@ export function DoneScreen({ } return ( - - - {steps.length > 0 && ( - - )} - - - - - - - - - + - - + } + > + {steps.length > 0 && ( + + )} + + + + + + ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx index 59a70befb7d..7d870435534 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx @@ -11,8 +11,6 @@ import { object, string } from 'yup' import { TreeBlock } from '@core/journeys/ui/block' import { useJourney } from '@core/journeys/ui/JourneyProvider' import { useTeam } from '@core/journeys/ui/TeamProvider' -import { TemplateCardPreview } from '@core/journeys/ui/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview' -import { TemplateCardPreviewItem } from '@core/journeys/ui/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreviewItem' import { transformer } from '@core/journeys/ui/transformer' import { useJourneyDuplicateMutation } from '@core/journeys/ui/useJourneyDuplicateMutation' import { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys/ui/useJourneyQuery/__generated__/GetJourney' @@ -21,21 +19,19 @@ import { LanguageAutocomplete } from '@core/shared/ui/LanguageAutocomplete' import { useGetChildTemplateJourneyLanguages } from '../../../../../libs/useGetChildTemplateJourneyLanguages' import { useGetParentTemplateJourneyLanguages } from '../../../../../libs/useGetParentTemplateJourneyLanguages' -import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' -import { CardsPreview } from '../LinksScreen/CardsPreview' +import { CardsPreview, EDGE_FADE_PX } from '../LinksScreen/CardsPreview' import { ScreenWrapper } from '../ScreenWrapper' import { JourneyCustomizeTeamSelect } from './JourneyCustomizeTeamSelect' +import Box from '@mui/material/Box' interface LanguageScreenProps { handleNext: (overrideJourneyId?: string) => void - handleScreenNavigation: (screen: CustomizationScreen) => void } export function LanguageScreen({ handleNext, - handleScreenNavigation }: LanguageScreenProps): ReactElement { const { templateCustomizationGuestFlow } = useFlags() const { t } = useTranslation('journeys-ui') @@ -117,8 +113,6 @@ export function LanguageScreen({ const [journeyDuplicate] = useJourneyDuplicateMutation() - const FORM_SM_BREAKPOINT_WIDTH = '390px' - function shouldSkipDuplicate( journey: { template?: boolean | null @@ -168,40 +162,61 @@ export function LanguageScreen({ } return ( - - - - {`'${journey?.title ?? ''}'`} - - - {steps.length > 0 && } - - + {({ handleSubmit: formikHandleSubmit, setFieldValue, values }) => ( + formikHandleSubmit()} + disabled={ + (templateCustomizationGuestFlow && !isSignedIn) || loading + } + ariaLabel={t('Next')} + /> + } > - {({ handleSubmit, setFieldValue, values }) => ( + + + {`'${journey?.title ?? ''}'`} + + + {steps.length > 0 && } +
- + setFieldValue('languageSelect', value)} + onChange={(value) => + setFieldValue('languageSelect', value) + } /> {isSignedIn && ( <> @@ -243,20 +260,12 @@ export function LanguageScreen({ )} - handleSubmit()} - disabled={ - (templateCustomizationGuestFlow && !isSignedIn) || loading - } - ariaLabel={t('Next')} - />
- )} -
-
-
+
+ + )} +
) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/CardsPreview/CardsPreview.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/CardsPreview/CardsPreview.tsx index 0bfa7fac69d..1e9b575e458 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/CardsPreview/CardsPreview.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/CardsPreview/CardsPreview.tsx @@ -51,7 +51,7 @@ const IFRAME_SCALE = CONTAINER_WIDTH / FRAME_WIDTH const CONTAINER_HEIGHT = Math.round(FRAME_HEIGHT * IFRAME_SCALE) // Spacing and offsets -const EDGE_FADE_PX = 16 +export const EDGE_FADE_PX = 40 function CardsPreviewItem({ step }: CardsPreviewItemProps): ReactElement { const { journey } = useJourney() @@ -159,6 +159,7 @@ export function CardsPreview({ steps }: CardsPreviewProps): ReactElement { slidesPerView="auto" spaceBetween={12} slidesOffsetBefore={EDGE_FADE_PX} + slidesOffsetAfter={EDGE_FADE_PX} observer observeParents sx={{ diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/CardsPreview/index.ts b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/CardsPreview/index.ts index 0330eeabf1f..6e5e3f1a2bf 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/CardsPreview/index.ts +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/CardsPreview/index.ts @@ -1 +1 @@ -export { CardsPreview } from './CardsPreview' +export { CardsPreview, EDGE_FADE_PX } from './CardsPreview' diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx index 789e9be4806..654f460dacb 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx @@ -1,5 +1,4 @@ import { useMutation } from '@apollo/client' -import Stack from '@mui/material/Stack' import { Formik, FormikHelpers, FormikProvider } from 'formik' import { useTranslation } from 'next-i18next' import { ReactElement, useMemo } from 'react' @@ -24,7 +23,6 @@ import { useBlockActionLinkUpdateMutation } from '../../../../../libs/useBlockAc import { useBlockActionPhoneUpdateMutation } from '../../../../../libs/useBlockActionPhoneUpdateMutation' import { JOURNEY_CHAT_BUTTON_UPDATE } from '../../../../Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Chat/ChatOption/Details/Details' import { countries } from '../../../../Editor/Slider/Settings/CanvasDetails/Properties/controls/Action/PhoneAction/countriesList' -import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { getJourneyLinks } from '../../../utils/getJourneyLinks' import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' import { ScreenWrapper } from '../ScreenWrapper' @@ -34,13 +32,9 @@ import { LinksForm } from './LinksForm' interface LinksScreenProps { handleNext: (overrideJourneyId?: string) => void - handleScreenNavigation: (screen: CustomizationScreen) => void } -export function LinksScreen({ - handleNext, - handleScreenNavigation -}: LinksScreenProps): ReactElement { +export function LinksScreen({ handleNext }: LinksScreenProps): ReactElement { const { t } = useTranslation('apps-journeys-admin') const { journey } = useJourney() const links = useMemo(() => getJourneyLinks(t, journey), [journey]) @@ -189,105 +183,98 @@ export function LinksScreen({ } return ( - >((acc, link) => { + if (link.linkType === 'phone') { + const block = journey?.blocks?.find((b) => b.id === link.id) + const action = + (block as any)?.action?.__typename === 'PhoneAction' + ? ((block as any).action as JourneyPhoneAction) + : undefined + const country = + action?.countryCode != null + ? countries.find((c) => c.countryCode === action.countryCode) + : undefined + const callingCode = country?.callingCode ?? '+' + const ccDigits = callingCode.replace(/[^\d]/g, '') + const prefix = ccDigits === '' ? '' : `+${ccDigits}` + const local = (action?.phone ?? '').startsWith(prefix) + ? (action?.phone ?? '').slice(prefix.length) + : (action?.phone ?? '').replace(/^\+/, '') + acc[`${link.id}__cc`] = callingCode + acc[`${link.id}__local`] = local + } else { + acc[link.id] = link.url ?? '' + } + return acc + }, {})} + validationSchema={object().shape( + links.reduce>>( + (acc, link) => { + if (link.linkType === 'email') { + acc[link.id] = string().email(t('Enter a valid email')) + } else if (link.linkType === 'phone') { + acc[`${link.id}__cc`] = string().test( + 'valid-cc', + t('Enter a valid calling code'), + (val) => { + if (val == null || val.trim() === '') return false + const normalized = val.startsWith('+') ? val : `+${val}` + return countries.some((c) => c.callingCode === normalized) + } + ) + acc[`${link.id}__local`] = string().test( + 'valid-local', + t('Enter a valid phone number'), + (val) => + val == null || + val.trim() === '' || + /^[0-9\s\-()]+$/.test(val.trim()) + ) + } else { + acc[link.id] = string().url(t('Enter a valid URL')) + } + return acc + }, + {} + ) + )} + validateOnSubmit={false} + onSubmit={handleFormSubmit} + validateOnMount > - - - - >((acc, link) => { - if (link.linkType === 'phone') { - const block = journey?.blocks?.find((b) => b.id === link.id) - const action = - (block as any)?.action?.__typename === 'PhoneAction' - ? ((block as any).action as JourneyPhoneAction) - : undefined - const country = - action?.countryCode != null - ? countries.find((c) => c.countryCode === action.countryCode) - : undefined - const callingCode = country?.callingCode ?? '+' - const ccDigits = callingCode.replace(/[^\d]/g, '') - const prefix = ccDigits === '' ? '' : `+${ccDigits}` - const local = (action?.phone ?? '').startsWith(prefix) - ? (action?.phone ?? '').slice(prefix.length) - : (action?.phone ?? '').replace(/^\+/, '') - acc[`${link.id}__cc`] = callingCode - acc[`${link.id}__local`] = local - } else { - acc[link.id] = link.url ?? '' - } - return acc - }, {})} - validationSchema={object().shape( - links.reduce>>( - (acc, link) => { - if (link.linkType === 'email') { - acc[link.id] = string().email(t('Enter a valid email')) - } else if (link.linkType === 'phone') { - acc[`${link.id}__cc`] = string().test( - 'valid-cc', - t('Enter a valid calling code'), - (val) => { - if (val == null || val.trim() === '') return false - const normalized = val.startsWith('+') ? val : `+${val}` - return countries.some((c) => c.callingCode === normalized) - } - ) - acc[`${link.id}__local`] = string().test( - 'valid-local', - t('Enter a valid phone number'), - (val) => - val == null || - val.trim() === '' || - /^[0-9\s\-()]+$/.test(val.trim()) - ) - } else { - acc[link.id] = string().url(t('Enter a valid URL')) - } - return acc - }, - {} - ) - )} - validateOnSubmit={false} - onSubmit={handleFormSubmit} - validateOnMount - > - {(formik) => ( - + {(formik) => ( + + + } + > + - - - )} - - + + + )} + ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx index cfe7e36cc38..20b0895071f 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx @@ -1,4 +1,3 @@ -import Stack from '@mui/material/Stack' import { useTranslation } from 'next-i18next' import { ReactElement, useEffect, useState } from 'react' @@ -67,21 +66,6 @@ export function MediaScreen({ handleNext }: MediaScreenProps): ReactElement { setSelectedCardBlockId(getCardBlockIdFromStep(step)) } return ( - - } - - ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx index c23b32ec903..220dfe02ce7 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx @@ -7,6 +7,7 @@ import { ReactElement } from 'react' import { TreeBlock } from '@core/journeys/ui/block' import { TemplateCardPreview } from '@core/journeys/ui/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview' import { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys/ui/useJourneyQuery/__generated__/GetJourney' +import { OVERFLOW_PX } from '@core/journeys/ui/TemplateView/TemplatePreviewTabs/TemplateCardPreview/templateCardPreviewConfig' interface CardsSectionProps { customizableSteps: Array> @@ -37,13 +38,19 @@ export function CardsSection({ gap={4} data-testid="CardsSection" sx={{ - width: '100%' + width: '100%', + overflow: 'visible' }} > {t('Cards')} - + - + + void - handleScreenNavigation: (screen: CustomizationScreen) => void } export function SocialScreen({ handleNext, - handleScreenNavigation }: SocialScreenProps): ReactElement { const { t } = useTranslation('apps-journeys-admin') return ( - - ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx index 70a3d93e58d..a0b4df0a992 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx @@ -1,6 +1,5 @@ import { gql, useMutation } from '@apollo/client' import Box from '@mui/material/Box' -import Stack from '@mui/material/Stack' import { useTranslation } from 'next-i18next' import { ReactElement, useCallback, useEffect, useState } from 'react' @@ -8,7 +7,6 @@ import { useJourney } from '@core/journeys/ui/JourneyProvider' import { GetJourney_journey_journeyCustomizationFields as JourneyCustomizationField } from '../../../../../../__generated__/GetJourney' import { JourneyCustomizationFieldUpdate } from '../../../../../../__generated__/JourneyCustomizationFieldUpdate' -import { CustomizationScreen } from '../../../utils/getCustomizeFlowConfig' import { CustomizeFlowNextButton } from '../../CustomizeFlowNextButton' import { ScreenWrapper } from '../ScreenWrapper' @@ -126,12 +124,10 @@ const renderEditableText = ( interface TextScreenProps { handleNext: (overrideJourneyId?: string) => void - handleScreenNavigation: (screen: CustomizationScreen) => void } export function TextScreen({ handleNext, - handleScreenNavigation }: TextScreenProps): ReactElement { const { t } = useTranslation() const { journey } = useJourney() @@ -194,76 +190,67 @@ export function TextScreen({ } return ( - + } > - - } - > - - - {renderEditableText( - journey?.journeyCustomizationDescription ?? '', - replacementItems, - handleValueChange - )} - - + + + {renderEditableText( + journey?.journeyCustomizationDescription ?? '', + replacementItems, + handleValueChange + )} - - + + + ) } diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx index dc383c7599e..b229efbc257 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx @@ -15,6 +15,7 @@ import { GetJourney_journey_blocks_StepBlock as StepBlock } from '../../../../li import { TemplateActionButton } from '../../TemplateViewHeader/TemplateActionButton/TemplateActionButton' import { + type BreakpointSwiperOptions, SELECTED_SCALE, type TemplateCardPreviewVariant, VARIANT_CONFIGS @@ -64,6 +65,16 @@ function TemplateCardPreviewPlaceholder({ const StyledSwiperSlide = styled(SwiperSlide)(() => ({})) const StyledSwiper = styled(Swiper)(() => ({})) +function getSpacerWidth( + cardWidth: number, + bp: BreakpointSwiperOptions +): string { + const selectedWidth = cardWidth * SELECTED_SCALE + const space = bp.spaceBetween ?? 0 + const offset = bp.slidesOffsetBefore ?? 0 + return `calc(100% - ${selectedWidth}px - ${space}px - ${offset}px)` +} + /** * Horizontal carousel of template step cards with optional "more cards" slide. * @@ -165,6 +176,17 @@ export function TemplateCardPreview({ ) })} + {variant === 'media' && ( + + )} {showMoreCardsSlide && steps.length > slidesToRender.length && ( export interface VariantConfig { @@ -31,6 +31,7 @@ export interface VariantConfig { } export const SELECTED_SCALE = 1.07 +export const OVERFLOW_PX = 40 const MEDIA_CARD_HEIGHT = 209 const PREVIEW_CARD_HEIGHT_XS = 295 const PREVIEW_CARD_HEIGHT_SM = 404 @@ -47,8 +48,8 @@ const PREVIEW_VARIANT_CONFIG: VariantConfig = { borderRadius: 4 }, breakpoints: { - xs: { spaceBetween: 12, slidesOffsetAfter: 0 }, - sm: { spaceBetween: 28, slidesOffsetAfter: 0 } + xs: { spaceBetween: 12 }, + sm: { spaceBetween: 28 } }, cardSx: { position: 'relative', @@ -91,8 +92,8 @@ const MEDIA_VARIANT_CONFIG: VariantConfig = { borderRadius: '24px' }, breakpoints: { - xs: { spaceBetween: 12, slidesOffsetAfter: 265 }, - sm: { spaceBetween: 12, slidesOffsetAfter: 260 } + xs: { spaceBetween: 12, slidesOffsetBefore: 0 }, + sm: { spaceBetween: 12, slidesOffsetBefore: OVERFLOW_PX } }, swiperProps: { mousewheel: { forceToAxis: true }, @@ -118,7 +119,8 @@ const MEDIA_VARIANT_CONFIG: VariantConfig = { borderRadius: '12px' }, swiperSx: { - overflow: 'visible', + width: '100%', + overflow: { xs: 'visible', sm: 'hidden' }, zIndex: 2, '& .swiper-wrapper': { alignItems: 'center' From 21f7f0b5a293c7419cd6f5288f25d0ead9c9644a Mon Sep 17 00:00:00 2001 From: edmonday Date: Fri, 6 Mar 2026 03:00:20 +0000 Subject: [PATCH 10/21] fix: remove border --- .../MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx index 660a46485f9..5182ffa0dd3 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx @@ -23,12 +23,12 @@ export function ScreenWrapper({ - + Date: Fri, 6 Mar 2026 03:13:05 +0000 Subject: [PATCH 11/21] fix: add test --- .../MultiStepForm/MultiStepForm.tsx | 1 - .../ScreenWrapper/ScreenWrapper.spec.tsx | 103 ++++++++++++++++++ .../Screens/ScreenWrapper/ScreenWrapper.tsx | 10 ++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.spec.tsx diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx index 06225332216..51e0a1073ad 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx @@ -79,7 +79,6 @@ export function MultiStepForm(): ReactElement { const { customizableMedia, templateCustomizationGuestFlow } = useFlags() const journeyId = journey?.id ?? '' - const link = `/journeys/${journeyId}` const { screens, diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.spec.tsx new file mode 100644 index 00000000000..01da9ac2667 --- /dev/null +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.spec.tsx @@ -0,0 +1,103 @@ +import { render, screen } from '@testing-library/react' + +import { ScreenWrapper } from './ScreenWrapper' + +describe('ScreenWrapper', () => { + it('renders title and subtitle', () => { + render( + +
content
+
+ ) + + expect(screen.getByTestId('ScreenWrapper')).toBeInTheDocument() + expect(screen.getAllByText('Test Title')[0]).toBeInTheDocument() + expect(screen.getAllByText('Test Subtitle')[0]).toBeInTheDocument() + }) + + it('renders children', () => { + render( + +
child content
+
+ ) + + expect(screen.getByTestId('child')).toBeInTheDocument() + }) + + it('renders footer when provided', () => { + render( + footer content} + > +
content
+
+ ) + + expect(screen.getByTestId('footer')).toBeInTheDocument() + }) + + it('does not render footer when not provided', () => { + render( + +
content
+
+ ) + + expect(screen.queryByTestId('footer')).not.toBeInTheDocument() + }) + + it('renders mobileTitle when provided', () => { + render( + +
content
+
+ ) + + expect(screen.getByText('Desktop Title')).toBeInTheDocument() + expect(screen.getByText('Mobile Title')).toBeInTheDocument() + }) + + it('falls back to title when mobileTitle is not provided', () => { + render( + +
content
+
+ ) + + const titleElements = screen.getAllByText('Shared Title') + expect(titleElements).toHaveLength(2) + }) + + it('renders mobileSubtitle when provided', () => { + render( + +
content
+
+ ) + + expect(screen.getByText('Desktop Subtitle')).toBeInTheDocument() + expect(screen.getByText('Mobile Subtitle')).toBeInTheDocument() + }) + + it('falls back to subtitle when mobileSubtitle is not provided', () => { + render( + +
content
+
+ ) + + const subtitleElements = screen.getAllByText('Shared Subtitle') + expect(subtitleElements).toHaveLength(2) + }) +}) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx index 5182ffa0dd3..b8e706ab079 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/ScreenWrapper/ScreenWrapper.tsx @@ -11,6 +11,16 @@ interface ScreenWrapperProps { children: ReactNode } +/** + * Wraps a multi-step form screen with a responsive title, subtitle, and optional footer. + * + * @param title - The heading displayed on desktop viewports. + * @param mobileTitle - Optional heading override for mobile viewports. Falls back to `title`. + * @param subtitle - The subheading displayed on desktop viewports. + * @param mobileSubtitle - Optional subheading override for mobile viewports. Falls back to `subtitle`. + * @param footer - Optional content rendered below the children. + * @param children - The main screen content. + */ export function ScreenWrapper({ title, mobileTitle, From a1d426520ba78844abfbb0f5edd6a1f817659fc4 Mon Sep 17 00:00:00 2001 From: edmonday Date: Fri, 6 Mar 2026 03:23:08 +0000 Subject: [PATCH 12/21] test: fix tests --- .../MultiStepForm/MultiStepForm.spec.tsx | 154 +----------------- .../Screens/DoneScreen/DoneScreen.spec.tsx | 2 +- 2 files changed, 2 insertions(+), 154 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx index 58ddbb74cdf..8cf69ef0c73 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx @@ -131,15 +131,10 @@ jest.mock('./Screens', () => ({ ), - DoneScreen: ({ - handleScreenNavigation - }: { - handleScreenNavigation: (screen: string) => void - }) => ( + DoneScreen: () => (

Done Screen

+
) })) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx index 51e0a1073ad..8c9c371c37c 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.tsx @@ -35,35 +35,19 @@ export const MULTI_STEP_FORM_MIN_HEIGHT = 900 function renderScreen( screen: CustomizationScreen, - handleNext: (overrideJourneyId?: string) => void, + handleNext: (overrideJourneyId?: string) => void ): ReactElement { switch (screen) { case 'language': - return ( - - ) + return case 'text': - return ( - - ) + return case 'links': - return ( - - ) + return case 'media': return case 'social': - return ( - - ) + return case 'done': return default: @@ -135,10 +119,7 @@ export function MultiStepForm(): ReactElement { overflow: 'hidden' }} > - + {(hasEditableText || hasCustomizableLinks || hasCustomizableMedia) && ( diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx index c91b42a9c42..62b54da7a74 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx @@ -162,9 +162,7 @@ describe('LanguageScreen', () => { value={{ journey: nonTemplateJourney, variant: 'customize' }} > - + @@ -199,9 +197,7 @@ describe('LanguageScreen', () => { - + @@ -301,9 +297,7 @@ describe('LanguageScreen', () => { value={{ journey: journeyWithFromTemplateId, variant: 'admin' }} > - + @@ -504,9 +498,7 @@ describe('LanguageScreen', () => { }} > - + @@ -559,9 +551,7 @@ describe('LanguageScreen', () => { - + @@ -619,9 +609,7 @@ describe('LanguageScreen', () => { value={{ journey: journeyWithImage, variant: 'admin' }} > - + @@ -643,9 +631,7 @@ describe('LanguageScreen', () => { - + diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx index ef30671784f..3c391807ded 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx @@ -1,3 +1,4 @@ +import Box from '@mui/material/Box' import FormControl from '@mui/material/FormControl' import Stack from '@mui/material/Stack' import Typography from '@mui/material/Typography' @@ -25,14 +26,13 @@ import { CardsPreview, EDGE_FADE_PX } from '../LinksScreen/CardsPreview' import { ScreenWrapper } from '../ScreenWrapper' import { JourneyCustomizeTeamSelect } from './JourneyCustomizeTeamSelect' -import Box from '@mui/material/Box' interface LanguageScreenProps { handleNext: (overrideJourneyId?: string) => void } export function LanguageScreen({ - handleNext, + handleNext }: LanguageScreenProps): ReactElement { const { templateCustomizationGuestFlow } = useFlags() const { t } = useTranslation('journeys-ui') @@ -251,9 +251,7 @@ export function LanguageScreen({ name: language?.name, slug: language?.slug }))} - onChange={(value) => - setFieldValue('languageSelect', value) - } + onChange={(value) => setFieldValue('languageSelect', value)} /> {isSignedIn && ( <> diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.spec.tsx index 9918d1b53f5..89bb26e4190 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.spec.tsx @@ -132,9 +132,7 @@ describe('LinksScreen', () => { render( - + ) @@ -290,9 +288,7 @@ describe('LinksScreen', () => { - + ) @@ -398,9 +394,7 @@ describe('LinksScreen', () => { - + ) @@ -467,9 +461,7 @@ describe('LinksScreen', () => { variant: 'admin' }} > - + ) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx index 654f460dacb..8f644536670 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx @@ -210,35 +210,32 @@ export function LinksScreen({ handleNext }: LinksScreenProps): ReactElement { return acc }, {})} validationSchema={object().shape( - links.reduce>>( - (acc, link) => { - if (link.linkType === 'email') { - acc[link.id] = string().email(t('Enter a valid email')) - } else if (link.linkType === 'phone') { - acc[`${link.id}__cc`] = string().test( - 'valid-cc', - t('Enter a valid calling code'), - (val) => { - if (val == null || val.trim() === '') return false - const normalized = val.startsWith('+') ? val : `+${val}` - return countries.some((c) => c.callingCode === normalized) - } - ) - acc[`${link.id}__local`] = string().test( - 'valid-local', - t('Enter a valid phone number'), - (val) => - val == null || - val.trim() === '' || - /^[0-9\s\-()]+$/.test(val.trim()) - ) - } else { - acc[link.id] = string().url(t('Enter a valid URL')) - } - return acc - }, - {} - ) + links.reduce>>((acc, link) => { + if (link.linkType === 'email') { + acc[link.id] = string().email(t('Enter a valid email')) + } else if (link.linkType === 'phone') { + acc[`${link.id}__cc`] = string().test( + 'valid-cc', + t('Enter a valid calling code'), + (val) => { + if (val == null || val.trim() === '') return false + const normalized = val.startsWith('+') ? val : `+${val}` + return countries.some((c) => c.callingCode === normalized) + } + ) + acc[`${link.id}__local`] = string().test( + 'valid-local', + t('Enter a valid phone number'), + (val) => + val == null || + val.trim() === '' || + /^[0-9\s\-()]+$/.test(val.trim()) + ) + } else { + acc[link.id] = string().url(t('Enter a valid URL')) + } + return acc + }, {}) )} validateOnSubmit={false} onSubmit={handleFormSubmit} diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx index 20b0895071f..470037d11ba 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/MediaScreen.tsx @@ -66,31 +66,28 @@ export function MediaScreen({ handleNext }: MediaScreenProps): ReactElement { setSelectedCardBlockId(getCardBlockIdFromStep(step)) } return ( - handleNext()} - ariaLabel={t('Next')} - loading={hasActiveUploads} - /> - } - > - {showLogo && } - - {showImages && ( - - )} - {showVideos && } - + handleNext()} + ariaLabel={t('Next')} + loading={hasActiveUploads} + /> + } + > + {showLogo && } + + {showImages && ( + + )} + {showVideos && } + ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx index 220dfe02ce7..dd26d14b5be 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/MediaScreen/Sections/CardsSection/CardsSection.tsx @@ -6,8 +6,8 @@ import { ReactElement } from 'react' import { TreeBlock } from '@core/journeys/ui/block' import { TemplateCardPreview } from '@core/journeys/ui/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview' -import { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys/ui/useJourneyQuery/__generated__/GetJourney' import { OVERFLOW_PX } from '@core/journeys/ui/TemplateView/TemplatePreviewTabs/TemplateCardPreview/templateCardPreviewConfig' +import { GetJourney_journey_blocks_StepBlock as StepBlock } from '@core/journeys/ui/useJourneyQuery/__generated__/GetJourney' interface CardsSectionProps { customizableSteps: Array> diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx index b7da567ff76..e61b47aaa6c 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx @@ -13,38 +13,34 @@ interface SocialScreenProps { handleNext: (overrideJourneyId?: string) => void } -export function SocialScreen({ - handleNext, -}: SocialScreenProps): ReactElement { +export function SocialScreen({ handleNext }: SocialScreenProps): ReactElement { const { t } = useTranslation('apps-journeys-admin') return ( - handleNext()} - ariaLabel={t('Done')} - /> - } + handleNext()} + ariaLabel={t('Done')} + /> + } + > + - - - - - - + + + + + ) } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.spec.tsx index 025a46aec3d..0242ccec144 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.spec.tsx @@ -38,9 +38,7 @@ describe('TextScreen', () => { render( - + ) @@ -54,9 +52,7 @@ describe('TextScreen', () => { render( - + ) @@ -113,9 +109,7 @@ describe('TextScreen', () => { render( - + ) @@ -144,9 +138,7 @@ describe('TextScreen', () => { render( - + ) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx index a0b4df0a992..86860b6274f 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx @@ -126,9 +126,7 @@ interface TextScreenProps { handleNext: (overrideJourneyId?: string) => void } -export function TextScreen({ - handleNext, -}: TextScreenProps): ReactElement { +export function TextScreen({ handleNext }: TextScreenProps): ReactElement { const { t } = useTranslation() const { journey } = useJourney() const [journeyCustomizationFieldUpdate, { loading: isSubmitting }] = diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx index b229efbc257..a2aa3310529 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/TemplateCardPreview.tsx @@ -183,7 +183,7 @@ export function TemplateCardPreview({ width: { xs: getSpacerWidth(cardWidth.xs, config.breakpoints.xs), sm: getSpacerWidth(cardWidth.sm, config.breakpoints.sm) - }, + } }} /> )} diff --git a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/index.ts b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/index.ts index 55aad589956..be44333288c 100644 --- a/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/index.ts +++ b/libs/journeys/ui/src/components/TemplateView/TemplatePreviewTabs/TemplateCardPreview/index.ts @@ -2,4 +2,4 @@ export { TemplateCardPreview } from './TemplateCardPreview' export { TemplateCardPreviewItem, type TemplateCardPreviewItemProps -} from './TemplateCardPreviewItem/TemplateCardPreviewItem' \ No newline at end of file +} from './TemplateCardPreviewItem/TemplateCardPreviewItem' diff --git a/libs/locales/en/apps-journeys-admin.json b/libs/locales/en/apps-journeys-admin.json index 2cdb9f03804..03a813ad353 100644 --- a/libs/locales/en/apps-journeys-admin.json +++ b/libs/locales/en/apps-journeys-admin.json @@ -1003,21 +1003,20 @@ "Link to project": "Link to project", "Feature Video Started": "Feature Video Started", "Feature Video Ended": "Feature Video Ended", - "Edit Manually": "Edit Manually", - "Ready to Share!": "Ready to Share!", + "Ready to share!": "Ready to share!", "Share your unique link on any platform.": "Share your unique link on any platform.", "Go To Projects Dashboard": "Go To Projects Dashboard", "Share!": "Share!", "{{count}} more cards_one": "{{count}} more cards", "{{count}} more cards_other": "{{count}} more cards", "Edit": "Edit", - "Links": "Links", - "This content contains buttons linking to external sites. Check them and update the links below.": "This content contains buttons linking to external sites. Check them and update the links below.", - "Buttons here point to external sites. Check and update the links.": "Buttons here point to external sites. Check and update the links.", "Enter a valid email": "Enter a valid email", "Enter a valid calling code": "Enter a valid calling code", "Enter a valid phone number": "Enter a valid phone number", "Enter a valid URL": "Enter a valid URL", + "Links": "Links", + "This content contains buttons linking to external sites. Check them and update the links below.": "This content contains buttons linking to external sites. Check them and update the links below.", + "Buttons here point to external sites. Check and update the links.": "Buttons here point to external sites. Check and update the links.", "Next": "Next", "Replace the links": "Replace the links", "Media": "Media", @@ -1030,9 +1029,8 @@ "Supports JPG, PNG, and GIF files.": "Supports JPG, PNG, and GIF files.", "Upload a video to see a preview here": "Upload a video to see a preview here", "Max size is 1 GB": "Max size is 1 GB", - "Final Details": "Final Details", - "Customize how your invite appears when shared on social media.": "Customize how your invite appears when shared on social media.", - "This is how your content will appear when shared on social media.": "This is how your content will appear when shared on social media.", + "Social Media": "Social Media", + "This is how your content will look on social media.": "This is how your content will look on social media.", "Failed to update social image, please try again later": "Failed to update social image, please try again later", "Social image updated": "Social image updated", "your.nextstep.is": "your.nextstep.is", diff --git a/libs/locales/en/journeys-ui.json b/libs/locales/en/journeys-ui.json index ef9ce200f88..7aeadf4622f 100644 --- a/libs/locales/en/journeys-ui.json +++ b/libs/locales/en/journeys-ui.json @@ -4,7 +4,7 @@ "Get Started": "Get Started", "A few quick edits and your template will be ready to share.": "A few quick edits and your template will be ready to share.", "A few quick edits and it's ready to share!": "A few quick edits and it's ready to share!", + "Next": "Next", "Select a language": "Select a language", - "Select a team": "Select a team", - "Next": "Next" + "Select a team": "Select a team" } From 863f28db77f7539fe435c7ec3c5610dda049fc8b Mon Sep 17 00:00:00 2001 From: edmonday Date: Sun, 8 Mar 2026 20:06:16 +0000 Subject: [PATCH 16/21] fix: add back the switch --- .../MultiStepForm/Screens/DoneScreen/DoneScreen.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index 40bde723119..b82f314b1c6 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -93,6 +93,7 @@ export function DoneScreen(): ReactElement { } }} /> + ) From dba14e61c0c83e006eaaa57cef114d13087a0e38 Mon Sep 17 00:00:00 2001 From: edmonday Date: Sun, 8 Mar 2026 20:14:24 +0000 Subject: [PATCH 17/21] fix: remove validateOnSubmit from LinksScreen --- .../MultiStepForm/Screens/LinksScreen/LinksScreen.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx index 8f644536670..22fffd3994e 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx @@ -237,7 +237,6 @@ export function LinksScreen({ handleNext }: LinksScreenProps): ReactElement { return acc }, {}) )} - validateOnSubmit={false} onSubmit={handleFormSubmit} validateOnMount > From 95329dac5ee988687e77cb1c921a3a6d0126435b Mon Sep 17 00:00:00 2001 From: edmonday Date: Sun, 8 Mar 2026 20:32:32 +0000 Subject: [PATCH 18/21] fix: add response section --- .../Screens/DoneScreen/DoneScreen.tsx | 88 ++++++++++++------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx index b82f314b1c6..5dbe09264f6 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx @@ -54,46 +54,66 @@ export function DoneScreen(): ReactElement { )} - - } + sx={{ + borderWidth: 2, + borderRadius: 2, height: 48, - borderRadius: 2 - } + width: { xs: '100%', sm: 216 }, + borderColor: 'secondary.light' + }} + > + {t('Preview')} + + + + - + > + + {t('Choose where responses go:')} + + + {t('Send to my email')} + + +
) From a8c32708bfbf4ab831b185700d6edc51dbdaefe9 Mon Sep 17 00:00:00 2001 From: edmonday Date: Sun, 8 Mar 2026 21:15:05 +0000 Subject: [PATCH 19/21] fix: resolved comments --- .../src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx | 1 - .../TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx b/apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx index 7f0ff8d5418..ad300532b35 100644 --- a/apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx +++ b/apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx @@ -51,7 +51,6 @@ interface ShareItemProps { handleCloseMenu?: () => void handleKeepMounted?: () => void buttonVariant?: 'icon' | 'default' - buttonSx?: SxProps setHasOpenDialog?: (hasOpenDialog: boolean) => void buttonProps?: ComponentProps } diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx index 92a7255d4c0..c546f63488d 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/MultiStepForm.spec.tsx @@ -143,7 +143,6 @@ jest.mock('./Screens', () => ({ DoneScreen: () => (

Done Screen

-
) })) From 65a82d21655ec0b8647da10d2b454b37f1a0a1f0 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 8 Mar 2026 21:19:15 +0000 Subject: [PATCH 20/21] fix: lint issues --- .../LanguageScreen/LanguageScreen.spec.tsx | 36 +++++-------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx index d1f3768f149..7bfbdffe96a 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx @@ -225,9 +225,7 @@ describe('LanguageScreen', () => { value={{ journey: nonTemplateJourney, variant: 'customize' }} > - + @@ -271,9 +269,7 @@ describe('LanguageScreen', () => { - + @@ -374,9 +370,7 @@ describe('LanguageScreen', () => { value={{ journey: journeyWithFromTemplateId, variant: 'admin' }} > - + @@ -486,9 +480,7 @@ describe('LanguageScreen', () => { - + @@ -584,9 +576,7 @@ describe('LanguageScreen', () => { - + @@ -774,9 +764,7 @@ describe('LanguageScreen', () => { }} > - + @@ -838,9 +826,7 @@ describe('LanguageScreen', () => { - + @@ -897,9 +883,7 @@ describe('LanguageScreen', () => { value={{ journey: journeyWithImage, variant: 'admin' }} > - + @@ -922,9 +906,7 @@ describe('LanguageScreen', () => { - + From 40da71c38f00e5f245e7370a784b300e9f08f525 Mon Sep 17 00:00:00 2001 From: edmonday Date: Sun, 8 Mar 2026 22:59:20 +0000 Subject: [PATCH 21/21] fix: add guest flow flag on button --- .../MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx index 6b1257259f8..db068ce2b66 100644 --- a/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx +++ b/apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx @@ -310,7 +310,9 @@ export function LanguageScreen({ label={t('Next')} onClick={() => formikHandleSubmit()} disabled={ - (templateCustomizationGuestFlow && !isSignedIn) || loading + templateCustomizationGuestFlow == null || + !templateCustomizationGuestFlow || + loading } ariaLabel={t('Next')} />