Skip to content

refactor: template customisation screens design#8785

Merged
csiyang merged 10 commits intomainfrom
siyangcao/nes-1375-update-minor-design-details-for-screens
Feb 27, 2026
Merged

refactor: template customisation screens design#8785
csiyang merged 10 commits intomainfrom
siyangcao/nes-1375-update-minor-design-details-for-screens

Conversation

@csiyang
Copy link
Copy Markdown
Contributor

@csiyang csiyang commented Feb 26, 2026

Summary by CodeRabbit

  • New Features

    • Template preview of the first step and a new "Go To Projects Dashboard" navigation button; streamlined "Preview" action.
  • Improvements

    • Responsive next-button sizing on very small screens; revamped social preview card with image upload, updated headings/subtitles, and tightened layout/spacing.
  • Bug Fixes

    • Minor copy fixes for external-link messaging and wording consistency (US spelling alignment).
  • Tests

    • Updated tests to reflect new UI copy, preview behavior, and navigation flows.

@csiyang csiyang self-assigned this Feb 26, 2026
@linear
Copy link
Copy Markdown

linear Bot commented Feb 26, 2026

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 26, 2026

Walkthrough

UI and copy updates across TemplateCustomization multi-step screens: responsive Next button width, Cards/TemplateCard preview replacing SocialImage, Card-based social preview UI, Done screen copy/navigation changes, LanguageScreen prop addition, localized string updates, and corresponding test adjustments.

Changes

Cohort / File(s) Summary
Button Styling
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/CustomizeFlowNextButton/CustomizeFlowNextButton.tsx
Next button width changed from fixed BUTTON_NEXT_STEP_WIDTH to responsive { xs: '100%', sm: BUTTON_NEXT_STEP_WIDTH }.
Done / Preview
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx
Replaces legacy image/SEO blocks with TemplateCardPreviewItem from transformed journey steps; updates heading/copy, replaces Continue Editing with "Go To Projects Dashboard" button, and adjusts button variants/icons and layout.
Language Screen
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx
Replaces SocialImage with CardsPreview/cards preview driven by transformer; adds handleScreenNavigation prop; copy and responsive layout tweaks; journey title wrapped in quotes.
Social Screen (copy/layout)
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx
Heading changed to "Final Details"; subtitle copy updated for desktop and mobile; simplified padding from responsive px to fixed py.
Social Image Card
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx
Refactored from Stack to MUI Card (CardHeader/CardMedia/CardContent/CardActions); introduced media dimension constants and loading skeleton/UI; preserved image upload and loading logic; adjusted testids.
Links & Text Screens (copy-only)
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx, apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx
Minor copy edits and typo fixes (e.g., "customise" → "customize"); no behavioral changes.
Localization
libs/locales/en/apps-journeys-admin.json, libs/locales/en/journeys-ui.json
Updated/renamed locale keys to match new UI copy (e.g., "It's Ready!" → "Ready to Share!", added social/share entries, capitalization and phrasing changes).
Tests
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx, apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx
Adapted tests to new copy and preview components: removed image-centric assertions, added TemplateCard/CardsSwiperSlide checks, and updated navigation assertions for Projects Dashboard.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • jianwei1
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: refactoring template customization screens design across multiple UI components, layouts, and copy updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch siyangcao/nes-1375-update-minor-design-details-for-screens

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Feb 26, 2026

View your CI Pipeline Execution ↗ for commit 450ed60

Command Status Duration Result
nx affected --target=subgraph-check --base=feeb... ✅ Succeeded 4s View ↗
nx affected --target=extract-translations --bas... ✅ Succeeded 3s View ↗
nx affected --target=lint --base=feeb7a90cc986a... ✅ Succeeded 6s View ↗
nx affected --target=type-check --base=feeb7a90... ✅ Succeeded 6s View ↗
nx run-many --target=codegen --all --parallel=3 ✅ Succeeded 2s View ↗
nx run-many --target=prisma-generate --all --pa... ✅ Succeeded 5s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-27 00:27:24 UTC

@github-actions github-actions Bot requested a deployment to Preview - journeys-admin February 26, 2026 03:38 Pending
@github-actions github-actions Bot temporarily deployed to Preview - videos-admin February 26, 2026 03:42 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - resources February 26, 2026 03:42 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - watch-modern February 26, 2026 03:42 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys February 26, 2026 03:42 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys-admin February 26, 2026 03:42 Inactive
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx (1)

72-131: ⚠️ Potential issue | 🔴 Critical

Fix upload error handling to avoid false success + stuck loading state.

Line 76 sets loading to true, but failures outside the inner try/finally path can leave loading active. Also, Line 126 always shows a success snackbar even after errors.

🛠️ Suggested fix
 async function handleImageChange(
   file: File | null | undefined
 ): Promise<void> {
   if (journey == null || file == null) return
   setLoading(true)

-  const { data } = await createCloudflareUploadByFile({})
-  if (data?.createCloudflareUploadByFile?.uploadUrl != null) {
-    const formData = new FormData()
-    formData.append('file', file)
-    try {
-      const response = await (
-        await fetch(data?.createCloudflareUploadByFile?.uploadUrl, {
-          method: 'POST',
-          body: formData as unknown as FormDataType
-        })
-      ).json()
+  try {
+    const { data } = await createCloudflareUploadByFile({})
+    const uploadUrl = data?.createCloudflareUploadByFile?.uploadUrl
+    if (uploadUrl == null) {
+      throw new Error('Missing upload URL')
+    }
+
+    const formData = new FormData()
+    formData.append('file', file)
+    const response = await (
+      await fetch(uploadUrl, {
+        method: 'POST',
+        body: formData as unknown as FormDataType
+      })
+    ).json()
+
+    const imageId = response?.result?.id as string | undefined
+    if (imageId == null) throw new Error('Missing uploaded image id')

-        const src = `https://imagedelivery.net/${
-          process.env.NEXT_PUBLIC_CLOUDFLARE_UPLOAD_KEY ?? ''
-        }/${response.result.id as string}/public`
+    const src = `https://imagedelivery.net/${
+      process.env.NEXT_PUBLIC_CLOUDFLARE_UPLOAD_KEY ?? ''
+    }/${imageId}/public`

-        if (journey?.primaryImageBlock != null) {
-          await journeyImageBlockUpdate({
-            variables: {
-              id: journey.primaryImageBlock.id,
-              journeyId: journey.id,
-              input: { src, alt: 'journey image' }
-            }
-          })
-        } else {
-          const { data: imageData } = await journeyImageBlockCreate({
-            variables: {
-              input: { journeyId: journey.id, src, alt: 'journey image' }
-            }
-          })
-          if (imageData?.imageBlockCreate != null) {
-            await journeyImageBlockAssociationUpdate({
-              variables: {
-                id: journey.id,
-                input: { primaryImageBlockId: imageData.imageBlockCreate.id }
-              }
-            })
-          }
-        }
-      } catch (error) {
-        enqueueSnackbar(
-          t('Failed to update social image, please try again later'),
-          {
-            variant: 'error',
-            preventDuplicate: true
-          }
-        )
-      } finally {
-        setLoading(false)
-        enqueueSnackbar(t('Social image updated'), {
-          variant: 'success',
-          preventDuplicate: true
-        })
+    if (journey.primaryImageBlock != null) {
+      await journeyImageBlockUpdate({
+        variables: {
+          id: journey.primaryImageBlock.id,
+          journeyId: journey.id,
+          input: { src, alt: 'journey image' }
+        }
+      })
+    } else {
+      const { data: imageData } = await journeyImageBlockCreate({
+        variables: {
+          input: { journeyId: journey.id, src, alt: 'journey image' }
+        }
+      })
+      if (imageData?.imageBlockCreate != null) {
+        await journeyImageBlockAssociationUpdate({
+          variables: {
+            id: journey.id,
+            input: { primaryImageBlockId: imageData.imageBlockCreate.id }
+          }
+        })
       }
     }
+
+    enqueueSnackbar(t('Social image updated'), {
+      variant: 'success',
+      preventDuplicate: true
+    })
+  } catch (error) {
+    enqueueSnackbar(t('Failed to update social image, please try again later'), {
+      variant: 'error',
+      preventDuplicate: true
+    })
+  } finally {
+    setLoading(false)
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`
around lines 72 - 131, In handleImageChange: ensure loading is cleared on every
exit and success snackbar is only shown on actual success by expanding the
try/catch/finally scope to cover the entire upload/update flow (including the
createCloudflareUploadByFile call and the branch where uploadUrl is missing);
specifically, keep setLoading(true) at start, wrap the logic from
createCloudflareUploadByFile through
journeyImageBlockAssociationUpdate/journeyImageBlockUpdate in a single try, show
enqueueSnackbar(..., variant: 'success') only inside the successful path after
updates complete, show the error snackbar inside catch, and call
setLoading(false) in the finally so journeyImageBlockCreate,
journeyImageBlockUpdate, journeyImageBlockAssociationUpdate, enqueueSnackbar,
and setLoading are properly referenced and handled.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx`:
- Around line 33-35: The preview rendering assumes steps[0] always exists and
will crash when transformer(...) returns an empty array; in DoneScreen, guard
the preview by checking that the computed steps (const steps = transformer(...))
has length > 0 (or steps[0] is defined) before accessing steps[0]; if empty,
render a safe fallback (null or a placeholder) or skip preview logic so the
component doesn't attempt to read properties on undefined. Update DoneScreen's
render/path that uses steps[0] to early-return or conditional-render based on
steps.length and keep references to transformer, steps, TreeBlock<StepBlock>
intact.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx`:
- Around line 227-229: In LinksScreen (LinksScreen.tsx) update the desktop
helper copy passed to t(...) to remove the duplicated word so the string reads
"This contains buttons linking to external sites. Check them and update the
links below."; locate the t(...) call inside the component's render/return and
replace the duplicated "contains contains" with a single "contains" (ensure any
corresponding i18n key/update is made if the text is sourced from translation
files).

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`:
- Around line 215-236: The IconButton wrapping the file input is icon-only and
lacks an accessible name; add an aria-label (e.g., aria-label="Upload social
image" or similar) to the IconButton so screen readers announce the control, and
also add a matching aria-label or aria-describedby on StyledInput (which
currently uses data-testid="SocialScreenSocialImageInput") to ensure the file
input is accessible; keep the onChange handler handleImageChange as-is and
ensure the label text clearly describes the action.

---

Outside diff comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`:
- Around line 72-131: In handleImageChange: ensure loading is cleared on every
exit and success snackbar is only shown on actual success by expanding the
try/catch/finally scope to cover the entire upload/update flow (including the
createCloudflareUploadByFile call and the branch where uploadUrl is missing);
specifically, keep setLoading(true) at start, wrap the logic from
createCloudflareUploadByFile through
journeyImageBlockAssociationUpdate/journeyImageBlockUpdate in a single try, show
enqueueSnackbar(..., variant: 'success') only inside the successful path after
updates complete, show the error snackbar inside catch, and call
setLoading(false) in the finally so journeyImageBlockCreate,
journeyImageBlockUpdate, journeyImageBlockAssociationUpdate, enqueueSnackbar,
and setLoading are properly referenced and handled.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between feeb7a9 and 9b39c75.

📒 Files selected for processing (7)
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/CustomizeFlowNextButton/CustomizeFlowNextButton.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 26, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
watch-modern ✅ Ready watch-modern preview Fri Feb 27 13:21:49 NZDT 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 26, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
player ✅ Ready player preview Fri Feb 27 13:21:50 NZDT 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 26, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
videos-admin ✅ Ready videos-admin preview Fri Feb 27 13:22:31 NZDT 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 26, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
journeys ✅ Ready journeys preview Fri Feb 27 13:22:05 NZDT 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 26, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
watch ✅ Ready watch preview Fri Feb 27 13:22:58 NZDT 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 26, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
resources ✅ Ready resources preview Fri Feb 27 13:22:49 NZDT 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 26, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
journeys-admin ✅ Ready journeys-admin preview Fri Feb 27 13:23:38 NZDT 2026

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx (1)

75-130: ⚠️ Potential issue | 🟠 Major

Fix upload state and snackbar flow in handleImageChange.

Line [75] sets loading true, but loading is reset only inside the inner finally (Line [124]). If upload URL is missing (or the initial mutation throws), loading can get stuck. Also, success is always shown in Line [125], even after failure.

Suggested fix
   async function handleImageChange(
     file: File | null | undefined
   ): Promise<void> {
     if (journey == null || file == null) return
     setLoading(true)
-
-    const { data } = await createCloudflareUploadByFile({})
-    if (data?.createCloudflareUploadByFile?.uploadUrl != null) {
+    try {
+      const { data } = await createCloudflareUploadByFile({})
+      const uploadUrl = data?.createCloudflareUploadByFile?.uploadUrl
+      if (uploadUrl == null) throw new Error('No upload URL')
+
       const formData = new FormData()
       formData.append('file', file)
-      try {
-        const response = await (
-          await fetch(data?.createCloudflareUploadByFile?.uploadUrl, {
-            method: 'POST',
-            body: formData as unknown as FormDataType
-          })
-        ).json()
-        const src = `https://imagedelivery.net/${
-          process.env.NEXT_PUBLIC_CLOUDFLARE_UPLOAD_KEY ?? ''
-        }/${response.result.id as string}/public`
+      const response = await (
+        await fetch(uploadUrl, {
+          method: 'POST',
+          body: formData as unknown as FormDataType
+        })
+      ).json()
+      const src = `https://imagedelivery.net/${
+        process.env.NEXT_PUBLIC_CLOUDFLARE_UPLOAD_KEY ?? ''
+      }/${response.result.id as string}/public`
@@
-      } catch (error) {
-        enqueueSnackbar(
-          t('Failed to update social image, please try again later'),
-          {
-            variant: 'error',
-            preventDuplicate: true
-          }
-        )
-      } finally {
-        setLoading(false)
-        enqueueSnackbar(t('Social image updated'), {
-          variant: 'success',
-          preventDuplicate: true
-        })
-      }
-    }
+      enqueueSnackbar(t('Social image updated'), {
+        variant: 'success',
+        preventDuplicate: true
+      })
+    } catch (error) {
+      enqueueSnackbar(t('Failed to update social image, please try again later'), {
+        variant: 'error',
+        preventDuplicate: true
+      })
+    } finally {
+      setLoading(false)
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`
around lines 75 - 130, The upload flow sets setLoading(true) but only resets it
in the inner finally and always shows a success snackbar; wrap the entire
upload+mutations in a top-level try/catch/finally so setLoading(false) always
runs and move the success enqueueSnackbar into the success path (after all
awaits succeed). Specifically, in the handler around
createCloudflareUploadByFile, create a top-level try { const {data} = await
createCloudflareUploadByFile(...); if
(!data?.createCloudflareUploadByFile?.uploadUrl) throw new Error('Missing
uploadUrl'); /* perform fetch and await
journeyImageBlockUpdate/journeyImageBlockCreate/journeyImageBlockAssociationUpdate
as now */ enqueueSnackbar(t('Social image updated'),
{variant:'success',preventDuplicate:true}); } catch (error) {
enqueueSnackbar(t('Failed to update social image, please try again later'),
{variant:'error',preventDuplicate:true}); } finally { setLoading(false); } This
ensures createCloudflareUploadByFile, fetch response, and GraphQL mutations
(journeyImageBlockUpdate, journeyImageBlockCreate,
journeyImageBlockAssociationUpdate) errors are handled, loading is cleared on
every path, and success is only shown when all steps complete.
♻️ Duplicate comments (2)
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx (1)

33-35: ⚠️ Potential issue | 🟠 Major

Guard preview rendering when no steps are returned.

Line [84] still passes steps[0] directly. If transformer(...) returns an empty array, preview rendering can fail at runtime.

Suggested fix
   const steps = transformer(journey?.blocks ?? []) as Array<
     TreeBlock<StepBlock>
   >
+  const previewStep = steps[0]
@@
-      <TemplateCardPreviewItem step={steps[0]} variant="preview" />
+      {previewStep != null && (
+        <TemplateCardPreviewItem step={previewStep} variant="preview" />
+      )}

Also applies to: 84-84

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx`
around lines 33 - 35, The preview rendering in DoneScreen uses steps[0] directly
which will crash if transformer(journey?.blocks ?? []) returns an empty array;
update the DoneScreen component to guard access to steps by checking
steps.length (or using a null/undefined fallback) before passing steps[0] into
the preview renderer so you only pass a valid StepBlock or undefined/null when
no steps exist, and adjust the preview component call accordingly to handle the
empty case.
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx (1)

214-234: ⚠️ Potential issue | 🟠 Major

Add accessible labels to the upload icon button and file input.

Line [214] is an icon-only upload control without an accessible name, and the hidden input at Line [229] also needs one for assistive tech clarity.

Suggested fix
             <IconButton
               component="label"
+              aria-label={t('Upload social image')}
               sx={{
@@
               <StyledInput
                 onChange={(event) => handleImageChange(event.target.files?.[0])}
                 data-testid="SocialScreenSocialImageInput"
                 type="file"
                 accept="image/*"
+                aria-label={t('Upload social image')}
               />

As per coding guidelines: "Implement accessibility features on elements. For example, a tag should have a tabindex=“0”, aria-label, on:click, and on:keydown, and similar attributes."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`
around lines 214 - 234, The upload control lacks accessible names: add an
accessible label to the IconButton (the label wrapper) and to the hidden file
input so assistive tech can identify the control. Update the IconButton
(component="label") to include an aria-label (e.g., "Upload social image") and
keyboard focusability if needed, and update StyledInput to include either an id
and aria-labelledby pointing to that label or an aria-label attribute itself
(keep data-testid and the onChange handler handleImageChange unchanged); ensure
the input remains type="file" and accept="image/*" but now has an accessible
name for screen readers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx`:
- Around line 100-103: The anchor created in DoneScreen (the JSX element using
props href/component/target/startIcon) sets target="_blank" without rel,
creating reverse-tabnabbing risk; update the element to include rel="noopener
noreferrer" whenever href != null (i.e., when target is '_blank') so the
rendered anchor uses rel="noopener noreferrer" only for new-tab previews.

In `@libs/locales/en/apps-journeys-admin.json`:
- Line 1014: The localization entry currently contains a duplicated word in the
string value ("This contains contains buttons..."); update the JSON value for
that key so the string reads "This contains buttons linking to external sites.
Check them and update the links below." (locate the offending entry by searching
for the exact text "This contains contains buttons linking to external sites.
Check them and update the links below." and correct the duplicated "contains").

---

Outside diff comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`:
- Around line 75-130: The upload flow sets setLoading(true) but only resets it
in the inner finally and always shows a success snackbar; wrap the entire
upload+mutations in a top-level try/catch/finally so setLoading(false) always
runs and move the success enqueueSnackbar into the success path (after all
awaits succeed). Specifically, in the handler around
createCloudflareUploadByFile, create a top-level try { const {data} = await
createCloudflareUploadByFile(...); if
(!data?.createCloudflareUploadByFile?.uploadUrl) throw new Error('Missing
uploadUrl'); /* perform fetch and await
journeyImageBlockUpdate/journeyImageBlockCreate/journeyImageBlockAssociationUpdate
as now */ enqueueSnackbar(t('Social image updated'),
{variant:'success',preventDuplicate:true}); } catch (error) {
enqueueSnackbar(t('Failed to update social image, please try again later'),
{variant:'error',preventDuplicate:true}); } finally { setLoading(false); } This
ensures createCloudflareUploadByFile, fetch response, and GraphQL mutations
(journeyImageBlockUpdate, journeyImageBlockCreate,
journeyImageBlockAssociationUpdate) errors are handled, loading is cleared on
every path, and success is only shown when all steps complete.

---

Duplicate comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx`:
- Around line 33-35: The preview rendering in DoneScreen uses steps[0] directly
which will crash if transformer(journey?.blocks ?? []) returns an empty array;
update the DoneScreen component to guard access to steps by checking
steps.length (or using a null/undefined fallback) before passing steps[0] into
the preview renderer so you only pass a valid StepBlock or undefined/null when
no steps exist, and adjust the preview component call accordingly to handle the
empty case.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`:
- Around line 214-234: The upload control lacks accessible names: add an
accessible label to the IconButton (the label wrapper) and to the hidden file
input so assistive tech can identify the control. Update the IconButton
(component="label") to include an aria-label (e.g., "Upload social image") and
keyboard focusability if needed, and update StyledInput to include either an id
and aria-labelledby pointing to that label or an aria-label attribute itself
(keep data-testid and the onChange handler handleImageChange unchanged); ensure
the input remains type="file" and accept="image/*" but now has an accessible
name for screen readers.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9b39c75 and 7b5a3f2.

📒 Files selected for processing (5)
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx
  • libs/locales/en/apps-journeys-admin.json
  • libs/locales/en/journeys-ui.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx

Comment thread libs/locales/en/apps-journeys-admin.json Outdated
@csiyang csiyang requested a review from thomastayler February 26, 2026 04:08
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 26, 2026

Warnings
⚠️ ❗ Big PR (682 changes)

(change count - 682): Pull Request size seems relatively large. If Pull Request contains multiple changes, split each into separate PR will helps faster, easier review.

Generated by 🚫 dangerJS against 450ed60

@github-actions github-actions Bot temporarily deployed to Preview - resources February 26, 2026 04:08 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys-admin February 26, 2026 04:08 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - videos-admin February 26, 2026 04:08 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys February 26, 2026 04:08 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - watch-modern February 26, 2026 04:08 Inactive
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx (1)

102-105: ⚠️ Potential issue | 🟠 Major

Add rel when using target="_blank" on the preview CTA.

Line [104] opens a new tab, but there is no rel="noopener noreferrer". This leaves a reverse-tabnabbing vector.

🔒 Suggested fix
             href={href}
             component={href != null ? 'a' : 'button'}
             target={href != null ? '_blank' : undefined}
+            rel={href != null ? 'noopener noreferrer' : undefined}
             startIcon={<Play3Icon />}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx`
around lines 102 - 105, The anchor rendered in DoneScreen (the element with
props href, component, target and startIcon and using Play3Icon) opens a new tab
without a rel attribute; add a rel prop when href != null/target is '_blank'
(e.g., rel="noopener noreferrer") to prevent reverse-tabnabbing. Update the JSX
that sets href/component/target to include rel={href != null ? 'noopener
noreferrer' : undefined} (or equivalent conditional) so the link only gets rel
when rendered as an external anchor.
🧹 Nitpick comments (1)
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx (1)

389-420: Desktop test mixes desktop and mobile assertions.

The test name says “desktop”, but Line [419] asserts mobile-specific copy too. This weakens responsive regression coverage and makes intent ambiguous.

🧪 Suggested cleanup
-  it('renders all required components correctly for desktop', async () => {
+  it('renders all required components correctly', async () => {
@@
-    expect(
-      screen.getByText("A few quick edits and it's ready to share!")
-    ).toBeInTheDocument()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx`
around lines 389 - 420, The desktop test 'renders all required components
correctly for desktop' in LanguageScreen.spec.tsx mixes desktop and mobile
assertions—remove the mobile-specific expectation that checks the string "A few
quick edits and it's ready to share!" from this test; instead create a separate
mobile-focused test that renders LanguageScreen in a mobile context (e.g., set
the viewport or pass the mobile prop/context) and asserts that mobile copy.
Update the existing desktop test to only assert desktop-only text like "Let's
Get Started!" and "A few quick edits and your template will be ready to share."
and ensure the new mobile test targets the mobile string to keep responsive
coverage clear.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@libs/locales/en/apps-journeys-admin.json`:
- Line 1037: The locale key "your.nextsteps.is" appears to be a typo and should
match the existing default-domain key "your.nextstep.is"; update the new JSON
entry to use "your.nextstep.is" (or the intended canonical key) and ensure any
consumers/reference lookups are updated to the corrected key so they resolve
consistently; search for both "your.nextsteps.is" and "your.nextstep.is" and
remove/replace the incorrect variant in the translation file and any code that
references it (e.g., translation lookup calls) to keep keys consistent.

---

Duplicate comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx`:
- Around line 102-105: The anchor rendered in DoneScreen (the element with props
href, component, target and startIcon and using Play3Icon) opens a new tab
without a rel attribute; add a rel prop when href != null/target is '_blank'
(e.g., rel="noopener noreferrer") to prevent reverse-tabnabbing. Update the JSX
that sets href/component/target to include rel={href != null ? 'noopener
noreferrer' : undefined} (or equivalent conditional) so the link only gets rel
when rendered as an external anchor.

---

Nitpick comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx`:
- Around line 389-420: The desktop test 'renders all required components
correctly for desktop' in LanguageScreen.spec.tsx mixes desktop and mobile
assertions—remove the mobile-specific expectation that checks the string "A few
quick edits and it's ready to share!" from this test; instead create a separate
mobile-focused test that renders LanguageScreen in a mobile context (e.g., set
the viewport or pass the mobile prop/context) and asserts that mobile copy.
Update the existing desktop test to only assert desktop-only text like "Let's
Get Started!" and "A few quick edits and your template will be ready to share."
and ensure the new mobile test targets the mobile string to keep responsive
coverage clear.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7b5a3f2 and 203a239.

📒 Files selected for processing (7)
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.spec.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/DoneScreen/DoneScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx
  • libs/locales/en/apps-journeys-admin.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx

Comment thread libs/locales/en/apps-journeys-admin.json Outdated
thomastayler
thomastayler previously approved these changes Feb 27, 2026
@github-actions github-actions Bot temporarily deployed to Preview - resources February 27, 2026 00:19 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - videos-admin February 27, 2026 00:19 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys February 27, 2026 00:19 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - watch-modern February 27, 2026 00:19 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys-admin February 27, 2026 00:19 Inactive
@csiyang csiyang enabled auto-merge February 27, 2026 00:19
@csiyang csiyang added this pull request to the merge queue Feb 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx (1)

245-258: Remove redundant loading check in the loading branch.

The inner loading && is unnecessary because this block is already gated by loading.

Suggested cleanup
-            {loading && (
-              <CircularProgress
-                data-testid="SocialScreenSocialImageCircularProgress"
-                size={30}
-                sx={{
-                  position: 'absolute',
-                  top: 0,
-                  right: 0,
-                  bottom: 0,
-                  left: 0,
-                  margin: 'auto'
-                }}
-              />
-            )}
+            <CircularProgress
+              data-testid="SocialScreenSocialImageCircularProgress"
+              size={30}
+              sx={{
+                position: 'absolute',
+                top: 0,
+                right: 0,
+                bottom: 0,
+                left: 0,
+                margin: 'auto'
+              }}
+            />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`
around lines 245 - 258, The JSX currently nests a redundant conditional
(`loading &&`) inside a parent block already guarded by `loading`; in the
SocialScreenSocialImage component remove the inner `loading &&` check so the
CircularProgress (the element with data-testid
"SocialScreenSocialImageCircularProgress") is rendered directly inside the outer
loading branch; ensure you only leave the single outer conditional that renders
CircularProgress to avoid the duplicate guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx`:
- Line 210: The current JSX expression `{`'${journey?.title ?? ''}'`}` renders
literal empty quotes when journey?.title is falsy; update the LanguageScreen JSX
to conditionally render the quoted title only when journey?.title is non-empty
(e.g., check `journey?.title` before rendering) so that the UI does not show
`''` — locate the template that uses `journey?.title` (the expression currently
producing `'{journey?.title ?? ''}'`) and wrap it in a conditional (or render an
alternative) to avoid outputting empty quoted text.

In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`:
- Line 212: The hardcoded aria-label "Edit social image" in the
SocialScreenSocialImage component must be localized; replace the literal string
with a value obtained from your app's i18n helper (e.g., using
useTranslation().t or intl.formatMessage) and pass that localized string to the
edit button's aria-label prop (reference: SocialScreenSocialImage component and
the edit button element with aria-label). Add a corresponding translation key
(e.g., "socialScreen.editSocialImage" or "editSocialImage") to your locale files
and use that key when calling the translation function so the aria-label is
translated for all languages.

---

Nitpick comments:
In
`@apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx`:
- Around line 245-258: The JSX currently nests a redundant conditional (`loading
&&`) inside a parent block already guarded by `loading`; in the
SocialScreenSocialImage component remove the inner `loading &&` check so the
CircularProgress (the element with data-testid
"SocialScreenSocialImageCircularProgress") is rendered directly inside the outer
loading branch; ensure you only leave the single outer conditional that renders
CircularProgress to avoid the duplicate guard.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 203a239 and 450ed60.

📒 Files selected for processing (7)
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreenSocialImage/SocialScreenSocialImage.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx
  • libs/locales/en/apps-journeys-admin.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/TextScreen/TextScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/SocialScreen/SocialScreen.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.spec.tsx
  • apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LinksScreen/LinksScreen.tsx

Merged via the queue into main with commit e26cb6f Feb 27, 2026
35 checks passed
@csiyang csiyang deleted the siyangcao/nes-1375-update-minor-design-details-for-screens branch February 27, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants