Skip to content

refactor: extract ShareDialog in ShareItem component#6801

Closed
thomastayler wants to merge 14 commits into
mainfrom
tommytayler/prj-1569-refactor-share-dialog
Closed

refactor: extract ShareDialog in ShareItem component#6801
thomastayler wants to merge 14 commits into
mainfrom
tommytayler/prj-1569-refactor-share-dialog

Conversation

@thomastayler
Copy link
Copy Markdown
Contributor

@thomastayler thomastayler commented Jun 9, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a unified Share Modal with tabs for link editing, QR code display, and embed code preview, optimized for mobile and desktop.
    • Added journey link editing with validation, copy functionality, and custom domain support.
    • Added embed code preview with copy feature and terms of agreement notice.
    • Added QR code tab showing scan counts and sharing options.
    • Enhanced tooltips with light styling and configurable touch delay.
    • Added new "ImageFocus" icon to the icon library.
  • Refactor

    • Consolidated multiple share dialogs into a single Share Modal component for streamlined sharing.
    • Updated ShareItem component to use the new Share Modal.
  • Bug Fixes

    • Improved handling and display of custom domain URLs and journey metadata in sharing interfaces.
  • Tests

    • Added comprehensive tests for the Share Modal and its tabs.
    • Removed tests for deprecated share dialogs.
  • Chores

    • Updated exports and storybook configurations to reflect new components and remove deprecated ones.
    • Updated icon story listing to include new icon.

@thomastayler thomastayler self-assigned this Jun 9, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 9, 2025

## Walkthrough

A new unified `ShareModal` component is introduced to replace the previous dialog-based sharing UI in the journeys-admin app. This change removes separate dialog components for editing URLs, embedding, and QR codes, consolidating their functionality into tabbed subcomponents within the modal. Associated tests, stories, and exports for the old dialogs are deleted or refactored accordingly.

## Changes

| File(s)                                                                                                     | Change Summary                                                                                                                        |
|-------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
| .../ShareModal/ShareModal.tsx, .../ShareModal/tabs/LinkTab/LinkTab.tsx, .../EmbedTab/EmbedTab.tsx, ...      | Added new `ShareModal` component and tab subcomponents (`LinkTab`, `EmbedTab`, `QrCodeTab`, `EmbedCardPreview`) for unified sharing.  |
| .../ShareModal/ShareModal.spec.tsx                                                                          | Added test suite for `ShareModal` covering modal visibility, tab behavior, and user interactions.                                     |
| .../ShareModal/index.ts, .../tabs/LinkTab/index.ts, .../tabs/EmbedTab/index.ts, .../tabs/QrCodeTab/index.ts | Added re-exports for new sharing components and tabs.                                                                                 |
| .../Toolbar/Items/ShareItem/ShareItem.tsx, .../ShareItem.spec.tsx                                           | Refactored `ShareItem` to use `ShareModal`; updated and simplified tests for new sharing flow.                                        |
| .../Toolbar/Items/ShareItem/SlugDialog/*, .../EmbedJourneyDialog/*, .../QrCodeDialog/*                      | Deleted old dialog components, their stories, tests, and index exports.                                                               |
| .../ShareModal/tabs/QrCodeTab/QrCodeTab.tsx, .../ScanCount/ScanCount.tsx                                    | Refactored QR code dialog into tab panel; updated layout and structure, minor logging added.                                          |
| .../useJourneyForShareLazyQuery/useJourneyForShareLazyQuery.ts                                              | Extended sharing query to include journey title, description, and primary image block details.                                        |
| .../Tooltip/Tooltip.tsx                                                                                     | Added `light` and `leaveTouchDelay` props for tooltip styling and behavior.                                                           |
| .../icons/Icon.tsx, .../icons/ImageFocus.tsx, .../icons/icon.stories.tsx                                    | Added new `ImageFocus` icon to the icon system and stories.                                                                           |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant ShareItem
    participant ShareModal
    participant LinkTab
    participant QrCodeTab
    participant EmbedTab

    User->>ShareItem: Click Share button
    ShareItem->>ShareModal: Open modal (open=true, journey, hostname)
    ShareModal->>User: Show tabbed UI (Link, QR, Embed)
    User->>ShareModal: Switch tab (Link/QR/Embed)
    ShareModal->>LinkTab: Render LinkTab (if selected)
    ShareModal->>QrCodeTab: Render QrCodeTab (if selected)
    ShareModal->>EmbedTab: Render EmbedTab (if selected)
    User->>ShareModal: Click Close
    ShareModal->>ShareItem: onClose()

Possibly related PRs

  • feat: add share menu item #6357: Refactors ShareItem to accept a journey prop and adjust dialog state handling, overlapping with this PR's refactor of sharing UI in the same component.

Suggested reviewers

  • csiyang
  • levi-zustiak

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> npm warn EBADENGINE Unsupported engine {
> npm warn EBADENGINE   package: 'i18next-parser@9.3.0',
> npm warn EBADENGINE   required: { node: '^18.0.0 || ^20.0.0 || ^22.0.0', npm: '>=6', yarn: '>=1' },
> npm warn EBADENGINE   current: { node: 'v24.1.0', npm: '11.3.0' }
> npm warn EBADENGINE }
> npm warn EBADENGINE Unsupported engine {
> npm warn EBADENGINE   package: 'next-firebase-auth-edge@1.9.1',
> npm warn EBADENGINE   required: {
> npm warn EBADENGINE     node: '>=16.0.0 <24.0.0',
> npm warn EBADENGINE     npm: '>=8.0.0 <12.0.0',
> npm warn EBADENGINE     yarn: '>=1.22.0 <2.0.0'
> npm warn EBADENGINE   },
> npm warn EBADENGINE   current: { node: 'v24.1.0', npm: '11.3.0' }
> npm warn EBADENGINE }
> npm error Exit handler never called!
> npm error This is an error with npm itself. Please report this error at:
> npm error   <https://github.com/npm/cli/issues>
> npm error A complete log of this run can be found in: /.npm/_logs/2025-06-09T02_58_06_406Z-debug-0.log
> 
> 
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between b2113f7d0b0d540fb6d709801947957759a7f01f and d86076cba86a9534c7f63759aefb4553a7ab094f.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `apps/journeys-admin/src/components/Editor/ShareModal/tabs/LinkTab/LinkTab.tsx` (1 hunks)

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* apps/journeys-admin/src/components/Editor/ShareModal/tabs/LinkTab/LinkTab.tsx

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (14)</summary>

* GitHub Check: Deploy Preview and Test (arclight, 6801/merge, pull_request, 22)
* GitHub Check: Deploy Preview and Test (watch, 6801/merge, pull_request, 22)
* GitHub Check: Deploy Preview and Test (journeys, 6801/merge, pull_request, 22)
* GitHub Check: Deploy Preview and Test (docs, 6801/merge, pull_request, 22)
* GitHub Check: Deploy Preview and Test (journeys-admin, 6801/merge, pull_request, 22)
* GitHub Check: Deploy Preview and Test (short-links, 6801/merge, pull_request, 22)
* GitHub Check: Deploy Preview and Test (videos-admin, 6801/merge, pull_request, 22)
* GitHub Check: visual-test (22)
* GitHub Check: test (22, 1/3)
* GitHub Check: test (22, 2/3)
* GitHub Check: test (22, 3/3)
* GitHub Check: build (22)
* GitHub Check: lint (22)
* GitHub Check: Analyze (javascript)

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

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.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=JesusFilm/core&utm_content=6801):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 9, 2025

Warnings
⚠️ ❗ Big PR (2901 changes)

(change count - 2901): 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 d86076c

@github-actions github-actions Bot temporarily deployed to Preview - videos-admin June 9, 2025 01:36 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - docs June 9, 2025 01:36 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - short-links June 9, 2025 01:36 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys June 9, 2025 01:36 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - watch June 9, 2025 01:36 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys-admin June 9, 2025 01:36 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - arclight June 9, 2025 01:36 Inactive
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 9, 2025

The latest updates on your projects.

Name Status Preview Updated (UTC)
docs ✅ Ready docs preview Mon Jun 9 14:57:46 NZST 2025

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 9, 2025

The latest updates on your projects.

Name Status Preview Updated (UTC)
arclight ✅ Ready arclight preview Mon Jun 9 14:58:28 NZST 2025

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 9, 2025

The latest updates on your projects.

Name Status Preview Updated (UTC)
short-links ✅ Ready short-links preview Mon Jun 9 14:58:14 NZST 2025

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 9, 2025

The latest updates on your projects.

Name Status Preview Updated (UTC)
journeys ✅ Ready journeys preview Mon Jun 9 14:58:40 NZST 2025

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 9, 2025

The latest updates on your projects.

Name Status Preview Updated (UTC)
videos-admin ✅ Ready videos-admin preview Mon Jun 9 14:59:13 NZST 2025

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 9, 2025

The latest updates on your projects.

Name Status Preview Updated (UTC)
watch ✅ Ready watch preview Mon Jun 9 14:59:00 NZST 2025

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 9, 2025

The latest updates on your projects.

Name Status Preview Updated (UTC)
journeys-admin ✅ Ready journeys-admin preview Mon Jun 9 14:59:42 NZST 2025

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: 6

🧹 Nitpick comments (9)
apps/journeys-admin/src/components/Editor/ShareModal/ShareModal.spec.tsx (1)

95-95: Replace delete operator with undefined assignment for better performance.

The delete operator can impact performance and has side effects on the original object.

-    delete process.env.NEXT_PUBLIC_JOURNEYS_URL
+    process.env.NEXT_PUBLIC_JOURNEYS_URL = undefined
🧰 Tools
🪛 Biome (1.9.4)

[error] 95-95: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

apps/journeys-admin/src/components/Editor/ShareModal/tabs/QrCodeTab/QrCodeTab.tsx (1)

144-144: Consider making TabPanel value configurable.

The hardcoded value "1" makes the component less flexible and could cause issues if tab ordering changes. Consider accepting the tab value as a prop or using a more descriptive constant.

-interface QrCodeTabProps {
+interface QrCodeTabProps {
+  value?: string
  journey?: JourneyFromContext | JourneyFromLazyQuery
}

-export function QrCodeTab({ journey }: QrCodeTabProps): ReactElement {
+export function QrCodeTab({ value = "qr-code", journey }: QrCodeTabProps): ReactElement {

-    <TabPanel value="1" sx={{ padding: 0 }}>
+    <TabPanel value={value} sx={{ padding: 0 }}>
apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedTab.tsx (1)

60-60: Consider making TabPanel value configurable.

Similar to QrCodeTab, the hardcoded value "2" should be made configurable for better maintainability and flexibility.

 interface EmbedTabProps {
+  value?: string
   journey?: JourneyFromContext | JourneyFromLazyQuery
 }

-export function EmbedTab({ journey }: EmbedTabProps): ReactElement {
+export function EmbedTab({ value = "embed", journey }: EmbedTabProps): ReactElement {

-    <TabPanel value="2" sx={{ padding: 0, pb: 3 }}>
+    <TabPanel value={value} sx={{ padding: 0, pb: 3 }}>
apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedCardPreview/EmbedCardPreview.tsx (1)

18-18: Remove unnecessary styled component.

The StyledIframe component is defined but provides no styling. You can use a regular iframe element directly.

-const StyledIframe = styled('iframe')(() => ({}))

-            <StyledIframe
+            <iframe
               src={iframeSrc}
               loading="lazy"
               onLoad={handleIframeLoad}
               onError={handleIframeError}
apps/journeys-admin/src/components/Editor/ShareModal/tabs/LinkTab/LinkTab.tsx (5)

64-64: Remove unnecessary await on setValues

The setValues function from Formik is synchronous, so the await is not needed here.

-      await setValues({ slug: response?.data?.journeyUpdate.slug })
+      setValues({ slug: response?.data?.journeyUpdate.slug })

145-148: Remove redundant empty string fallback

The src prop is already checked for null in the conditional, so the fallback to empty string is unnecessary.

               {journey?.primaryImageBlock?.src != null ? (
                 <Image
-                  src={journey?.primaryImageBlock?.src ?? ''}
+                  src={journey.primaryImageBlock.src}
                   alt="Journey Image"

307-314: Remove empty Box element

This Box element is empty and serves no purpose. Consider removing it to keep the code clean.

-        <Box
-          sx={{
-            display: 'flex',
-            alignItems: 'center',
-            justifyContent: 'flex-end'
-          }}
-        ></Box>

318-424: Consider extracting helper components for better performance

The helper components are recreated on each render. While not critical given their size, you could improve performance by moving them outside the main component or memoizing them with React.memo.

If you decide to refactor, you would need to pass the required dependencies as props instead of relying on closure variables.


147-148: Improve image alt text for better accessibility

Consider using a more descriptive alt text that includes the journey title for better accessibility.

                   src={journey.primaryImageBlock.src}
-                  alt="Journey Image"
+                  alt={journey?.title ? `${journey.title} cover image` : 'Journey cover image'}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f3d0ce and 918b28d.

⛔ Files ignored due to path filters (2)
  • apps/journeys-admin/__generated__/GetJourneyForSharing.ts is excluded by !**/__generated__/**
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (30)
  • apps/journeys-admin/src/components/Editor/ShareModal/ShareModal.spec.tsx (1 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/ShareModal.tsx (1 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/index.ts (1 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedCardPreview/EmbedCardPreview.tsx (1 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedTab.tsx (1 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/index.ts (1 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/tabs/LinkTab/LinkTab.tsx (1 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/tabs/LinkTab/index.ts (1 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/tabs/QrCodeTab/QrCodeTab.tsx (3 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/tabs/QrCodeTab/ScanCount/ScanCount.tsx (3 hunks)
  • apps/journeys-admin/src/components/Editor/ShareModal/tabs/QrCodeTab/index.ts (1 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/EmbedCardPreview/EmbedCardPreview.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/EmbedJourneyDialog.spec.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/EmbedJourneyDialog.stories.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/EmbedJourneyDialog.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/index.ts (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/QrCodeDialog/QrCodeDialog.spec.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/QrCodeDialog/QrCodeDialog.stories.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/QrCodeDialog/index.ts (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.spec.tsx (10 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx (5 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/SlugDialog/SlugDialog.spec.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/SlugDialog/SlugDialog.stories.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/SlugDialog/SlugDialog.tsx (0 hunks)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/SlugDialog/index.ts (0 hunks)
  • apps/journeys-admin/src/components/Tooltip/Tooltip.tsx (2 hunks)
  • apps/journeys-admin/src/libs/useJourneyForShareLazyQuery/useJourneyForShareLazyQuery.ts (2 hunks)
  • libs/shared/ui/src/components/icons/Icon.tsx (3 hunks)
  • libs/shared/ui/src/components/icons/ImageFocus.tsx (1 hunks)
  • libs/shared/ui/src/components/icons/icon.stories.tsx (1 hunks)
💤 Files with no reviewable changes (12)
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/index.ts
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/SlugDialog/index.ts
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/QrCodeDialog/index.ts
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/EmbedJourneyDialog.stories.tsx
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/SlugDialog/SlugDialog.stories.tsx
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/EmbedJourneyDialog.tsx
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/EmbedJourneyDialog.spec.tsx
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/SlugDialog/SlugDialog.spec.tsx
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/QrCodeDialog/QrCodeDialog.stories.tsx
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/SlugDialog/SlugDialog.tsx
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/QrCodeDialog/QrCodeDialog.spec.tsx
  • apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/EmbedJourneyDialog/EmbedCardPreview/EmbedCardPreview.tsx
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedTab.tsx (2)
apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/index.ts (1)
  • EmbedTab (1-1)
apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedCardPreview/EmbedCardPreview.tsx (1)
  • EmbedCardPreview (24-206)
apps/journeys-admin/src/components/Editor/ShareModal/tabs/LinkTab/LinkTab.tsx (4)
apps/journeys-admin/src/components/Editor/ShareModal/tabs/LinkTab/index.ts (1)
  • LinkTab (1-1)
apis/api-journeys/src/app/modules/journey/journey.resolver.ts (1)
  • journeyUpdate (735-838)
libs/journeys/ui/src/components/TextField/TextField.tsx (1)
  • TextField (41-76)
apps/journeys-admin/src/components/Tooltip/Tooltip.tsx (1)
  • Tooltip (46-95)
🪛 Biome (1.9.4)
apps/journeys-admin/src/components/Editor/ShareModal/ShareModal.spec.tsx

[error] 95-95: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Deploy Preview and Test (watch, 6801/merge, pull_request, 22)
  • GitHub Check: Deploy Preview and Test (journeys-admin, 6801/merge, pull_request, 22)
  • GitHub Check: test (22, 3/3)
  • GitHub Check: test (22, 1/3)
  • GitHub Check: test (22, 2/3)
  • GitHub Check: build (22)
🔇 Additional comments (31)
libs/shared/ui/src/components/icons/icon.stories.tsx (1)

114-114: Add new 'ImageFocus' icon to storybook.
The new icon name is now included in the Storybook preview list, matching the updated icon set.

apps/journeys-admin/src/components/Editor/ShareModal/index.ts (1)

1-1: Re-export ShareModal for centralized import.
This barrel file now exposes the new ShareModal component, aligning with the consolidated sharing UI.

libs/shared/ui/src/components/icons/Icon.tsx (3)

106-106: Import new ImageFocus icon component.
Placed correctly between Image3 and ImageX in alphabetical order.


321-321: Update IconName union with 'ImageFocus'.
Ensures the type system recognizes the new icon.


540-540: Include ImageFocus in iconComponents mapping.
Maps the union entry to the imported React component.

apps/journeys-admin/src/components/Editor/ShareModal/tabs/QrCodeTab/index.ts (1)

1-1: Re-export QrCodeTab for tab integration.
Exposes the QR code sharing tab for use in the unified ShareModal.

apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/index.ts (1)

1-1: Re-export EmbedTab for tab integration.
Makes the embed-sharing tab available to the ShareModal.

apps/journeys-admin/src/components/Editor/ShareModal/tabs/LinkTab/index.ts (1)

1-1: LGTM!

Clean barrel export following standard patterns.

libs/shared/ui/src/components/icons/ImageFocus.tsx (1)

3-10: LGTM!

Well-structured SVG icon component following Material-UI patterns. The SVG path data looks valid and the component is properly exported.

apps/journeys-admin/src/libs/useJourneyForShareLazyQuery/useJourneyForShareLazyQuery.ts (1)

13-14: Good enhancement for sharing functionality.

Adding title and description fields will improve the sharing experience by providing rich metadata.

apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx (5)

4-4: LGTM: Clean consolidation of imports.

The refactoring successfully consolidates multiple dialog imports into a single ShareModal import, simplifying the component's dependencies.

Also applies to: 12-12


46-46: Well-designed state consolidation.

The single showShareModal state variable effectively replaces the need for multiple dialog state variables, significantly simplifying state management.


48-52: Simplified event handler looks good.

The handleShowMenu function is now cleaner without needing to manage anchor elements for multiple dialogs.


63-65: Good encapsulation of route logic.

The new handleRouteChange function properly encapsulates the route management logic, making it reusable if needed.


76-84:

Details

❓ Verification inconclusive

Verify that ShareModal handles all previous dialog functionality.

The ShareModal integration looks clean, but please ensure that all functionality from the previous separate dialogs (SlugDialog, EmbedJourneyDialog, QrCodeDialog) is preserved in the new tabbed interface.


🏁 Script executed:

#!/bin/bash
# Description: Verify that removed dialog components are no longer referenced in the codebase
# Expected: No remaining imports or usages of the old dialog components

# Search for any remaining references to the old dialog components
echo "Checking for remaining references to old dialog components..."

echo -e "\n=== SlugDialog references ==="
rg -l "SlugDialog" --type tsx --type ts || echo "No SlugDialog references found"

echo -e "\n=== EmbedJourneyDialog references ==="
rg -l "EmbedJourneyDialog" --type tsx --type ts || echo "No EmbedJourneyDialog references found"

echo -e "\n=== QrCodeDialog references ==="
rg -l "QrCodeDialog" --type tsx --type ts || echo "No QrCodeDialog references found"

echo -e "\n=== Verification complete ==="

Length of output: 899


#!/bin/bash
# Locate the ShareModal component file
echo "Locating ShareModal.tsx..."
FILE=$(rg --files --glob '*ShareModal.tsx' | head -n1)
if [[ -z "$FILE" ]]; then
  echo "ShareModal.tsx not found"
  exit 1
fi
echo "Found file: $FILE"

# Search for tab implementation and each functionality
echo -e "\n=== 'Tab' occurrences in ShareModal ==="
rg -n "Tab" "$FILE" || echo "No 'Tab' patterns found"

echo -e "\n=== 'slug' or 'Slug' in ShareModal ==="
rg -n "slug" "$FILE" || echo "No lowercase 'slug' found"
rg -n "Slug" "$FILE" || echo "No uppercase 'Slug' found"

echo -e "\n=== 'embed' or 'Embed' in ShareModal ==="
rg -n "embed" "$FILE" || echo "No lowercase 'embed' found"
rg -n "Embed" "$FILE" || echo "No uppercase 'Embed' found"

echo -e "\n=== 'qr' or 'Qr' in ShareModal ==="
rg -n "qr" "$FILE" || echo "No lowercase 'qr' found"
rg -n "QR" "$FILE" || echo "No uppercase 'QR' found"

echo -e "\n=== 'QRCode' in ShareModal ==="
rg -n "QRCode" "$FILE" || echo "No 'QRCode' found"

echo -e "\n=== Verification complete ==="

#!/bin/bash
# Locate the ShareModal component file
echo "Locating ShareModal component file..."
FILE=$(rg --files --glob '*ShareModal*.tsx' | head -n1)
if [[ -z "$FILE" ]]; then
  FILE=$(find . -type f -iname '*ShareModal*.tsx' | head -n1)
fi
if [[ -z "$FILE" ]]; then
  echo "Error: ShareModal component file not found"
  exit 1
fi
echo "Found: $FILE"

# Check for tab implementation (common Tab, Tabs, TabList, TabPanel patterns)
echo -e "\n=== Tab-related patterns ==="
rg -nE 'Tab(List|Panel)?s?\b' "$FILE" || echo "No tab patterns found"

# Verify presence of slug functionality
echo -e "\n=== slug / Slug ==="
rg -nE '\bslug\b|\bSlug\b' "$FILE" || echo "No slug references found"

# Verify presence of embed functionality
echo -e "\n=== embed / Embed ==="
rg -nE '\bembed\b|\bEmbed\b' "$FILE" || echo "No embed references found"

# Verify presence of QR code functionality
echo -e "\n=== qr / QR / QRCode ==="
rg -nE '\bqr\b|\bQR\b|\bQRCode\b' "$FILE" || echo "No QR code references found"

echo -e "\nVerification complete."

Verify ShareModal preserves slug, embed & QR functionality
Please ensure the new tabbed ShareModal (lines 76–84) fully replaces the previous SlugDialog, EmbedJourneyDialog, and QrCodeDialog features:

  • Confirm there are three tabs (Slug, Embed, QR) and each renders the correct UI.
  • Validate each tab’s output matches the old dialogs (exporting a slug, generating embed code, producing a QR code).
  • Remove any leftover imports or code referencing the old dialogs.
apps/journeys-admin/src/components/Editor/ShareModal/ShareModal.spec.tsx (1)

1-173: Excellent test coverage for the new ShareModal component.

The test suite comprehensively covers all key functionality including:

  • Modal rendering and visibility states
  • Loading behavior with null journey data
  • URL construction with different domain configurations
  • User interaction callbacks
  • Clipboard copy functionality

This provides good confidence that the ShareModal properly replaces the previous dialog components.

🧰 Tools
🪛 Biome (1.9.4)

[error] 95-95: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

apps/journeys-admin/src/components/Tooltip/Tooltip.tsx (2)

42-43: Well-designed prop additions for enhanced customization.

The new light and leaveTouchDelay props provide valuable customization options while maintaining backward compatibility through optional typing and sensible defaults.


64-78: Clean implementation of light theme styling.

The conditional light theme styling provides a polished alternative appearance with proper attention to:

  • Color contrast (white background with primary text)
  • Visual hierarchy (border and shadow effects)
  • Consistency (matching arrow styling with shadow)

This enhancement will be valuable for the new ShareModal components that likely need varied tooltip styles.

apps/journeys-admin/src/components/Editor/ShareModal/ShareModal.tsx (5)

28-33: Well-designed component interface.

The props interface is clean and properly typed, providing exactly what's needed for the sharing functionality without unnecessary complexity.


54-59: Good responsive design pattern implementation.

The use of useMediaQuery to switch between Dialog and SwipeableDrawer provides an excellent responsive user experience that follows Material-UI best practices.


63-71: Proper loading state handling.

The loading spinner provides good user feedback when journey data is not yet available, preventing confusion and maintaining a professional experience.


74-84: Excellent tab organization and component separation.

The tabbed interface cleanly organizes the three sharing options (Link, QR Code, Embed) with appropriate icons and delegates functionality to dedicated tab components, promoting good separation of concerns.


108-153: Well-implemented mobile drawer with proper accessibility.

The SwipeableDrawer implementation includes:

  • Required onOpen handler for accessibility compliance
  • Proper styling with rounded corners and responsive padding
  • Clean header with title and close button
  • Good minimum height for usability

The mobile experience will be intuitive and accessible.

apps/journeys-admin/src/components/Editor/ShareModal/tabs/QrCodeTab/QrCodeTab.tsx (1)

162-190: LGTM! Excellent responsive layout implementation.

The responsive layout design is well-implemented with proper breakpoints, flexible spacing, and appropriate alignment adjustments for different screen sizes. The component structure is clean and maintainable.

apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedTab.tsx (2)

63-103: LGTM! Excellent responsive design with mobile-first approach.

The responsive implementation using conditional rendering for desktop vs mobile (accordion) is well-executed. The accordion provides a clean way to hide the preview on smaller screens while maintaining accessibility.


155-166: Good security practices with external link.

The external link to terms of agreement properly includes rel="noopener" and target="_blank" for security and user experience.

apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedCardPreview/EmbedCardPreview.tsx (2)

36-39: LGTM! Good use of memoization.

Properly memoizing the iframe src prevents unnecessary re-renders and improves performance. The dependency array is correct.


123-183: LGTM! Excellent loading and error state handling.

The component properly manages loading and error states with appropriate visual feedback. The opacity transition for the iframe provides a smooth user experience.

apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.spec.tsx (3)

58-88: LGTM! Enhanced mock data aligns with GraphQL changes.

The addition of title, description, and primaryImageBlock to the journey mock properly reflects the expanded GraphQL query fields mentioned in the AI summary.


142-167: LGTM! Clear test structure for modal opening behavior.

The test properly verifies that the ShareModal opens when the Share button is clicked, with appropriate assertions for dialog presence.


169-293: LGTM! Navigation tests properly verify router integration.

The tests for edit URL, embed journey, and QR code navigation properly verify that the correct router.push calls are made with the expected query parameters.

Comment on lines +51 to +57
const handleCopyCode = async (): Promise<void> => {
await navigator.clipboard.writeText(iframeLink ?? '')
enqueueSnackbar(t('Code Copied'), {
variant: 'success',
preventDuplicate: true
})
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for clipboard operations.

The clipboard write operation should include error handling in case the operation fails (e.g., in insecure contexts or when permissions are denied).

 const handleCopyCode = async (): Promise<void> => {
-  await navigator.clipboard.writeText(iframeLink ?? '')
-  enqueueSnackbar(t('Code Copied'), {
-    variant: 'success',
-    preventDuplicate: true
-  })
+  try {
+    await navigator.clipboard.writeText(iframeLink ?? '')
+    enqueueSnackbar(t('Code Copied'), {
+      variant: 'success',
+      preventDuplicate: true
+    })
+  } catch (error) {
+    enqueueSnackbar(t('Failed to copy code'), {
+      variant: 'error',
+      preventDuplicate: true
+    })
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleCopyCode = async (): Promise<void> => {
await navigator.clipboard.writeText(iframeLink ?? '')
enqueueSnackbar(t('Code Copied'), {
variant: 'success',
preventDuplicate: true
})
}
const handleCopyCode = async (): Promise<void> => {
try {
await navigator.clipboard.writeText(iframeLink ?? '')
enqueueSnackbar(t('Code Copied'), {
variant: 'success',
preventDuplicate: true
})
} catch (error) {
enqueueSnackbar(t('Failed to copy code'), {
variant: 'error',
preventDuplicate: true
})
}
}
🤖 Prompt for AI Agents
In
apps/journeys-admin/src/components/Editor/ShareModal/tabs/EmbedTab/EmbedTab.tsx
between lines 51 and 57, the clipboard write operation lacks error handling.
Wrap the navigator.clipboard.writeText call in a try-catch block to catch any
errors during the copy operation. In the catch block, use enqueueSnackbar to
display an error message indicating the copy failed, ensuring the user is
informed if the clipboard operation does not succeed.

Comment on lines +375 to 398
mockedUseRouter.mockReturnValue({
query: { param: null },
push,
events: { on }
} as unknown as NextRouter)

render(
<SnackbarProvider>
<MockedProvider mocks={[journeyForSharingMock]}>
<JourneyProvider
value={{ journey: defaultJourney, variant: 'admin' }}
>
<ShareItem variant="button" journey={defaultJourney} />
</JourneyProvider>
</MockedProvider>
</SnackbarProvider>
)

fireEvent.click(screen.getByRole('button', { name: 'Share' }))
expect(screen.getByRole('dialog')).toBeInTheDocument()

expect(screen.getByRole('dialog')).toBeInTheDocument()
})
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Complete the test implementation for closing dialog.

The test case for closing the ShareDialog when clicking outside is incomplete. It opens the dialog but doesn't actually test the closing behavior.

   it('should close ShareDialog when clicking outside', () => {
     mockedUseRouter.mockReturnValue({
       query: { param: null },
       push,
       events: { on }
     } as unknown as NextRouter)

     render(
       <SnackbarProvider>
         <MockedProvider mocks={[journeyForSharingMock]}>
           <JourneyProvider
             value={{ journey: defaultJourney, variant: 'admin' }}
           >
             <ShareItem variant="button" journey={defaultJourney} />
           </JourneyProvider>
         </MockedProvider>
       </SnackbarProvider>
     )

     fireEvent.click(screen.getByRole('button', { name: 'Share' }))
     expect(screen.getByRole('dialog')).toBeInTheDocument()

-    expect(screen.getByRole('dialog')).toBeInTheDocument()
+    // Click outside the dialog (on the backdrop)
+    fireEvent.click(document.body)
+    
+    expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
   })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should close ShareDialog when clicking outside', () => {
mockedUseRouter.mockReturnValue({
query: { param: null },
push,
events: { on }
} as unknown as NextRouter)
render(
<SnackbarProvider>
<MockedProvider mocks={[journeyForSharingMock]}>
<JourneyProvider
value={{ journey: defaultJourney, variant: 'admin' }}
>
<ShareItem variant="button" journey={defaultJourney} />
</JourneyProvider>
</MockedProvider>
</SnackbarProvider>
)
fireEvent.click(screen.getByRole('button', { name: 'Share' }))
expect(screen.getByRole('dialog')).toBeInTheDocument()
expect(screen.getByRole('dialog')).toBeInTheDocument()
})
it('should close ShareDialog when clicking outside', () => {
mockedUseRouter.mockReturnValue({
query: { param: null },
push,
events: { on }
} as unknown as NextRouter)
render(
<SnackbarProvider>
<MockedProvider mocks={[journeyForSharingMock]}>
<JourneyProvider
value={{ journey: defaultJourney, variant: 'admin' }}
>
<ShareItem variant="button" journey={defaultJourney} />
</JourneyProvider>
</MockedProvider>
</SnackbarProvider>
)
fireEvent.click(screen.getByRole('button', { name: 'Share' }))
expect(screen.getByRole('dialog')).toBeInTheDocument()
// Click outside the dialog (on the backdrop)
fireEvent.click(document.body)
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
})
🤖 Prompt for AI Agents
In
apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.spec.tsx
around lines 375 to 398, the test opens the ShareDialog but does not verify that
it closes when clicking outside. To fix this, simulate a click event outside the
dialog after it opens and then assert that the dialog is no longer present in
the document, confirming it has closed properly.

@github-actions github-actions Bot temporarily deployed to Preview - arclight June 9, 2025 02:11 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys-admin June 9, 2025 02:11 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - docs June 9, 2025 02:11 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - watch June 9, 2025 02:11 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys June 9, 2025 02:11 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - videos-admin June 9, 2025 02:11 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - short-links June 9, 2025 02:11 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - videos-admin June 9, 2025 02:56 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - short-links June 9, 2025 02:56 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys-admin June 9, 2025 02:56 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - docs June 9, 2025 02:56 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - watch June 9, 2025 02:56 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - arclight June 9, 2025 02:56 Inactive
@github-actions github-actions Bot temporarily deployed to Preview - journeys June 9, 2025 02:56 Inactive
@github-actions
Copy link
Copy Markdown
Contributor

This pull request has been marked stale due to {daysBeforePrStale} days without activity. It will be closed in {daysBeforePrClose} days unless updated.

@github-actions
Copy link
Copy Markdown
Contributor

This pull request has been marked stale due to 28 days without activity. It will be closed in 14 days unless updated.

@github-actions github-actions Bot added the stale label Aug 22, 2025
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Sep 6, 2025

This pull request was automatically closed after remaining stale for 14 days.

@github-actions github-actions Bot closed this Sep 6, 2025
@github-actions github-actions Bot deleted the tommytayler/prj-1569-refactor-share-dialog branch September 15, 2025 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant