Skip to content

Conversation

@Ur-imazing
Copy link
Contributor

@Ur-imazing Ur-imazing commented Jan 13, 2026

Summary by CodeRabbit

  • Refactor

    • Simplified list and template rendering by removing intermediate providers so item cards render directly.
  • New Features

    • Toolbar and menu actions now accept journey / journeyId props enabling direct prop-driven links and actions (analytics, responses, create/use/duplicate/copy flows).
    • Added extra journey fixture variants for template scenarios.
  • Tests

    • Expanded and parameterized tests to cover both prop-driven and context-driven flows across duplication, copy-to-team, template actions, toolbar items and dialogs.

✏️ Tip: You can customize this high-level summary in your review settings.

@Ur-imazing Ur-imazing requested a review from jianwei1 January 13, 2026 03:52
@Ur-imazing Ur-imazing self-assigned this Jan 13, 2026
@Ur-imazing Ur-imazing added effort: 2 priority: soon type: chore updating folder structure, initializing projects etc; no production code change on stage labels Jan 13, 2026
@linear
Copy link

linear bot commented Jan 13, 2026

@stage-branch-merger
Copy link

I see you added the "on stage" label, I'll get this merged to the stage branch!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 13, 2026

Walkthrough

Removed per-item JourneyProvider wrappers; components now accept explicit journey or journeyId props and propagate them through JourneyCard menus, toolbar items, copy/duplicate dialogs, template actions, and tests; added template fixtures and parameterized tests.

Changes

Cohort / File(s) Summary
Journey list renderers
apps/journeys-admin/src/components/JourneyList/...
ActivePriorityList/ActivePriorityList.tsx, ArchivedJourneyList/ArchivedJourneyList.tsx, JourneyListContent/JourneyListContent.tsx, TrashedJourneyList/TrashedJourneyList.tsx
Removed per-item JourneyProvider wrappers and JourneyFields casts; render JourneyCard directly and remove unused imports.
Template list renderers
apps/journeys-admin/src/components/TemplateList/...
ActiveTemplateList/ActiveTemplateList.tsx, ArchivedTemplateList/ArchivedTemplateList.tsx, TrashedTemplateList/TrashedTemplateList.tsx
Same removal of per-item JourneyProvider and JourneyFields casts; direct JourneyCard rendering and import cleanup.
Toolbar items
apps/journeys-admin/src/components/Editor/Toolbar/Items/...
AnalyticsItem/*, ResponsesItem/*, Items.tsx
Added journeyId?: string prop to AnalyticsItem and ResponsesItem; replaced useJourney context usage with prop-based journeyId for queries, links, and effects; updated call sites and tests.
Create / template actions & buttons
libs/journeys/ui/src/components/TemplateView/..., apps/journeys-admin/src/components/Editor/Toolbar/Items/CreateTemplateItem/*
CreateJourneyButton/*, CreateTemplateItem/*, TemplateActionButton/*, UseThisTemplateButton/*
Introduced optional `journey?: JourneyFields
JourneyCard menu & copy/duplicate flows
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/..., libs/journeys/ui/src/components/CopyToTeamDialog/...
DefaultMenu.tsx, DuplicateJourneyMenuItem/*, CopyToTeamMenuItem.tsx, CopyToTeamDialog.tsx
Threaded journey prop through menu items and dialogs; updated prop interfaces to accept/propagate journey?: Journey/JourneyFields; updated tests and added prop-driven scenarios.
JourneyCardInfo updates
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardInfo/...
JourneyCardInfo.tsx
Pass journeyId={journey.id} to ResponsesItem and AnalyticsItem to match new signatures.
Journey fixtures / test data
apps/journeys-admin/src/components/JourneyList/journeyListData.ts, libs/.../specs/*
Added nonCustomizableLocalTemplateJourney, nonCustomizableGlobalTemplateJourney, templateJourneyFromTemplate; extended test fixtures.
Tests
multiple *.spec.tsx under apps and libs
Many tests updated/parameterized to pass journey or journeyId props instead of relying on JourneyProvider; large new tests for duplicate/copy flows, dialogs, and menu actions.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant JourneyCard as JourneyCard
  participant DefaultMenu as DefaultMenu
  participant DuplicateItem as DuplicateJourneyMenuItem
  participant CopyDialog as CopyToTeamDialog
  participant API as GraphQL_API

  User->>JourneyCard: open card menu
  JourneyCard->>DefaultMenu: render menu (pass journey prop)
  User->>DefaultMenu: click "Duplicate" / "Copy"
  DefaultMenu->>DuplicateItem: invoke Duplicate action (journey forwarded)
  DuplicateItem->>CopyDialog: open CopyToTeamDialog (journey prop)
  CopyDialog->>API: duplicateJourney mutation (uses journey.id)
  API-->>CopyDialog: mutation result
  CopyDialog-->>User: show success / trigger navigation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • csiyang
  • jianwei1
  • mikeallisonJS
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.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 summarizes the main change: removing JourneyProvider context wrappers from journey cards throughout the codebase, which is the primary refactoring objective.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch urimchae/nes-316-substitute-journey-provider-wrapping-for-individual-journey

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

nx-cloud bot commented Jan 13, 2026

View your CI Pipeline Execution ↗ for commit 4ae5fe8

Command Status Duration Result
nx run journeys-admin-e2e:e2e ✅ Succeeded 31s View ↗
nx run watch-e2e:e2e ✅ Succeeded 21s View ↗
nx run journeys-e2e:e2e ✅ Succeeded 25s View ↗
nx run resources-e2e:e2e ✅ Succeeded 16s View ↗
nx run videos-admin-e2e:e2e ✅ Succeeded 4s View ↗
nx run-many --target=vercel-alias --projects=jo... ✅ Succeeded 2s View ↗
nx run-many --target=upload-sourcemaps --projec... ✅ Succeeded 12s View ↗
nx run-many --target=vercel-alias --projects=re... ✅ Succeeded 2s View ↗
Additional runs (12) ✅ Succeeded ... View ↗

☁️ Nx Cloud last updated this comment at 2026-01-26 22:49:52 UTC

@github-actions github-actions bot temporarily deployed to Preview - journeys-admin January 13, 2026 03:54 Inactive
@github-actions
Copy link
Contributor

github-actions bot commented Jan 13, 2026

The latest updates on your projects.

Name Status Preview Updated (UTC)
journeys-admin ✅ Ready journeys-admin preview Tue Jan 27 11:45:06 NZDT 2026

Copy link
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: 0

🧹 Nitpick comments (7)
apps/journeys-admin/src/components/JourneyList/ArchivedJourneyList/ArchivedJourneyList.tsx (1)

151-155: Redundant key prop on JourneyCard.

The key is already specified on the parent Grid component (line 148). The key on JourneyCard is unnecessary since React only needs the key on the outermost element in the map iteration.

Suggested fix
-                <JourneyCard
-                  key={journey.id}
-                  journey={journey}
-                  refetch={refetch}
-                />
+                <JourneyCard journey={journey} refetch={refetch} />
apps/journeys-admin/src/components/TemplateList/TrashedTemplateList/TrashedTemplateList.tsx (1)

153-157: Redundant key prop on JourneyCard.

The key is already specified on the parent Grid component (line 150). Remove the duplicate key from JourneyCard.

Suggested fix
-                <JourneyCard
-                  key={journey.id}
-                  journey={journey}
-                  refetch={refetch}
-                />
+                <JourneyCard journey={journey} refetch={refetch} />
apps/journeys-admin/src/components/JourneyList/TrashedJourneyList/TrashedJourneyList.tsx (1)

163-167: Redundant key prop on JourneyCard.

The key is already specified on the parent Grid component (line 160). Remove the duplicate key from JourneyCard.

Suggested fix
-                <JourneyCard
-                  key={journey.id}
-                  journey={journey}
-                  refetch={refetch}
-                />
+                <JourneyCard journey={journey} refetch={refetch} />
apps/journeys-admin/src/components/TemplateList/ActiveTemplateList/ActiveTemplateList.tsx (1)

139-143: Redundant key prop on JourneyCard.

The key is already specified on the parent Grid component (line 136). Remove the duplicate key from JourneyCard.

Suggested fix
-                <JourneyCard
-                  key={journey.id}
-                  journey={journey}
-                  refetch={refetch}
-                />
+                <JourneyCard journey={journey} refetch={refetch} />
apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActivePriorityList.tsx (1)

88-93: LGTM with minor nit: redundant key prop.

The variant handling is correct—casting key as JourneyCardVariant works since allActiveJourneys is keyed by JourneyCardVariant enum values. The direct rendering without JourneyProvider simplifies the component hierarchy.

Minor: The key on JourneyCard (line 89) is redundant since Grid (line 87) already has key={journey.id}.

Optional: Remove redundant key
             <JourneyCard
-              key={journey.id}
               journey={journey}
               refetch={refetch}
               variant={key as JourneyCardVariant}
             />
apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx (1)

586-590: Remove duplicate key prop.

The key is already set on the parent Grid element (line 574). The key on JourneyCard is redundant.

Suggested fix
-                    <JourneyCard
-                      key={journey.id}
-                      journey={journey}
-                      refetch={refetch}
-                    />
+                    <JourneyCard journey={journey} refetch={refetch} />
apps/journeys-admin/src/components/TemplateList/ArchivedTemplateList/ArchivedTemplateList.tsx (1)

140-144: Remove duplicate key prop.

Same issue as JourneyListContent.tsx — the key is already on the parent Grid (line 137).

Suggested fix
-                <JourneyCard
-                  key={journey.id}
-                  journey={journey}
-                  refetch={refetch}
-                />
+                <JourneyCard journey={journey} refetch={refetch} />
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ab58543 and 228851d.

📒 Files selected for processing (7)
  • apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActivePriorityList.tsx
  • apps/journeys-admin/src/components/JourneyList/ArchivedJourneyList/ArchivedJourneyList.tsx
  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
  • apps/journeys-admin/src/components/JourneyList/TrashedJourneyList/TrashedJourneyList.tsx
  • apps/journeys-admin/src/components/TemplateList/ActiveTemplateList/ActiveTemplateList.tsx
  • apps/journeys-admin/src/components/TemplateList/ArchivedTemplateList/ArchivedTemplateList.tsx
  • apps/journeys-admin/src/components/TemplateList/TrashedTemplateList/TrashedTemplateList.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/base.mdc)

**/*.{ts,tsx,js,jsx}: Use early returns whenever possible to make the code more readable.
Use descriptive variable and function/const names.
Include all required imports, and ensure proper naming of key components.

Files:

  • apps/journeys-admin/src/components/TemplateList/ArchivedTemplateList/ArchivedTemplateList.tsx
  • apps/journeys-admin/src/components/TemplateList/TrashedTemplateList/TrashedTemplateList.tsx
  • apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActivePriorityList.tsx
  • apps/journeys-admin/src/components/JourneyList/TrashedJourneyList/TrashedJourneyList.tsx
  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
  • apps/journeys-admin/src/components/JourneyList/ArchivedJourneyList/ArchivedJourneyList.tsx
  • apps/journeys-admin/src/components/TemplateList/ActiveTemplateList/ActiveTemplateList.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/base.mdc)

Define a type if possible.

Files:

  • apps/journeys-admin/src/components/TemplateList/ArchivedTemplateList/ArchivedTemplateList.tsx
  • apps/journeys-admin/src/components/TemplateList/TrashedTemplateList/TrashedTemplateList.tsx
  • apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActivePriorityList.tsx
  • apps/journeys-admin/src/components/JourneyList/TrashedJourneyList/TrashedJourneyList.tsx
  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
  • apps/journeys-admin/src/components/JourneyList/ArchivedJourneyList/ArchivedJourneyList.tsx
  • apps/journeys-admin/src/components/TemplateList/ActiveTemplateList/ActiveTemplateList.tsx
apps/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/apps.mdc)

apps/**/*.{js,jsx,ts,tsx}: Always use MUI over HTML elements; avoid using CSS or tags.
Use descriptive variable and function/const names. Also, event functions should be named with a “handle” prefix, like “handleClick” for onClick and “handleKeyDown” for onKeyDown.
Implement accessibility features on elements. For example, a tag should have a tabindex=“0”, aria-label, on:click, and on:keydown, and similar attributes.

Files:

  • apps/journeys-admin/src/components/TemplateList/ArchivedTemplateList/ArchivedTemplateList.tsx
  • apps/journeys-admin/src/components/TemplateList/TrashedTemplateList/TrashedTemplateList.tsx
  • apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActivePriorityList.tsx
  • apps/journeys-admin/src/components/JourneyList/TrashedJourneyList/TrashedJourneyList.tsx
  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
  • apps/journeys-admin/src/components/JourneyList/ArchivedJourneyList/ArchivedJourneyList.tsx
  • apps/journeys-admin/src/components/TemplateList/ActiveTemplateList/ActiveTemplateList.tsx
🧠 Learnings (7)
📚 Learning: 2025-12-19T04:58:24.460Z
Learnt from: CR
Repo: JesusFilm/core PR: 0
File: apps/watch/AGENTS.md:0-0
Timestamp: 2025-12-19T04:58:24.460Z
Learning: Applies to apps/watch/src/**/*.{ts,tsx} : Preserve existing contracts in components like `VideoBlock` which depend on the full provider stack, video.js, and mux metadata so autoplay, subtitles, and analytics remain intact.

Applied to files:

  • apps/journeys-admin/src/components/TemplateList/ArchivedTemplateList/ArchivedTemplateList.tsx
  • apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActivePriorityList.tsx
  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
  • apps/journeys-admin/src/components/JourneyList/ArchivedJourneyList/ArchivedJourneyList.tsx
  • apps/journeys-admin/src/components/TemplateList/ActiveTemplateList/ActiveTemplateList.tsx
📚 Learning: 2025-11-11T23:22:02.196Z
Learnt from: mikeallisonJS
Repo: JesusFilm/core PR: 8156
File: apis/api-journeys-modern/src/lib/google/googleAuth.ts:0-0
Timestamp: 2025-11-11T23:22:02.196Z
Learning: In apis/api-journeys-modern, use the validated `env` object from `../../env` instead of accessing `process.env` directly for environment variables that are defined in env.ts (e.g., GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, INTEGRATION_ACCESS_KEY_ENCRYPTION_SECRET). This eliminates the need for runtime validation checks since Zod validates them at application startup.

Applied to files:

  • apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActivePriorityList.tsx
  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
📚 Learning: 2025-04-29T04:56:45.588Z
Learnt from: Ur-imazing
Repo: JesusFilm/core PR: 6382
File: apps/journeys-admin/src/components/JourneyList/ArchivedJourneyList/ArchivedJourneyList.spec.tsx:149-150
Timestamp: 2025-04-29T04:56:45.588Z
Learning: The trailing "00" characters in journey card text content assertions are intentional in the JourneyList component tests.

Applied to files:

  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
📚 Learning: 2025-09-16T04:10:28.624Z
Learnt from: jaco-brink
Repo: JesusFilm/core PR: 7679
File: apis/api-gateway/schema.graphql:0-0
Timestamp: 2025-09-16T04:10:28.624Z
Learning: In PR #7679 (showAssistant field), the showAssistant field was intentionally excluded from JourneyUpdateInput because it will be controlled through direct database operations rather than through GraphQL mutations, keeping it out of the public API surface while still being queryable.

Applied to files:

  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
📚 Learning: 2025-12-19T04:58:24.460Z
Learnt from: CR
Repo: JesusFilm/core PR: 0
File: apps/watch/AGENTS.md:0-0
Timestamp: 2025-12-19T04:58:24.460Z
Learning: Applies to apps/watch/src/**/*.tsx : Use optional props with sensible defaults, include className prop for extensibility, and use ReactNode for children and content slots. Name interfaces with component name prefix (e.g., `ComponentNameProps`).

Applied to files:

  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
📚 Learning: 2025-09-08T22:56:21.606Z
Learnt from: mikeallisonJS
Repo: JesusFilm/core PR: 7498
File: apis/api-journeys-modern/src/schema/action/emailAction/blockUpdateEmailAction.mutation.ts:26-36
Timestamp: 2025-09-08T22:56:21.606Z
Learning: In the action mutations migration (PR #7498), the `journeyId` parameter is intentionally kept in blockUpdate*Action mutations even when unused in the resolver, to maintain API compatibility during the migration from the old "api-journeys" endpoint to the modern "api-journeys-modern" endpoint.

Applied to files:

  • apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx
📚 Learning: 2025-12-19T04:58:24.460Z
Learnt from: CR
Repo: JesusFilm/core PR: 0
File: apps/watch/AGENTS.md:0-0
Timestamp: 2025-12-19T04:58:24.460Z
Learning: Applies to apps/watch/src/**/*.{ts,tsx} : Do not introduce new MUI usage; migrate existing MUI to shadcn/Tailwind. New shadcn work should coexist with core shells/wrappers still using MUI until explicit migration tasks retire them.

Applied to files:

  • apps/journeys-admin/src/components/TemplateList/ActiveTemplateList/ActiveTemplateList.tsx
🧬 Code graph analysis (5)
apps/journeys-admin/src/components/TemplateList/ArchivedTemplateList/ArchivedTemplateList.tsx (1)
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCard.tsx (1)
  • JourneyCard (53-383)
apps/journeys-admin/src/components/TemplateList/TrashedTemplateList/TrashedTemplateList.tsx (1)
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCard.tsx (1)
  • JourneyCard (53-383)
apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActivePriorityList.tsx (2)
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCard.tsx (1)
  • JourneyCard (53-383)
apps/journeys-admin/src/components/JourneyList/ActiveJourneyList/ActivePriorityList/ActiveJourneyListData.ts (1)
  • journey (93-97)
apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx (1)
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCard.tsx (1)
  • JourneyCard (53-383)
apps/journeys-admin/src/components/TemplateList/ActiveTemplateList/ActiveTemplateList.tsx (1)
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCard.tsx (1)
  • JourneyCard (53-383)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Deploy Preview (journeys-admin, 8586/merge, pull_request, 22)
🔇 Additional comments (1)
apps/journeys-admin/src/components/JourneyList/JourneyListContent/JourneyListContent.tsx (1)

19-22: LGTM!

Import cleanup is appropriate — removed unused JourneyProvider, JourneyFields, and narrowed to only the required exports.

@Ur-imazing Ur-imazing removed the request for review from jianwei1 January 19, 2026 01:31
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin January 21, 2026 01:28 Inactive
Copy link
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

🤖 Fix all issues with AI agents
In
`@apps/journeys-admin/src/components/JourneyList/ArchivedJourneyList/ArchivedJourneyList.tsx`:
- Around line 170-174: The JourneyCard in ArchivedJourneyList is given a
redundant key prop; remove the duplicate key={journey.id} from the JourneyCard
component (leave the key on the parent Grid item) so only the Grid retains the
unique key, updating the JSX where JourneyCard is rendered inside
ArchivedJourneyList/Grid.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 22, 2026

Warnings
⚠️ ❗ Big PR (4771 changes)

(change count - 4771): 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 4ae5fe8

@github-actions github-actions bot requested a deployment to Preview - videos-admin January 23, 2026 03:18 Pending
@github-actions github-actions bot requested a deployment to Preview - journeys-admin January 23, 2026 03:18 Pending
@github-actions github-actions bot requested a deployment to Preview - resources January 23, 2026 03:18 Pending
@github-actions github-actions bot temporarily deployed to Preview - resources January 23, 2026 03:21 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys January 23, 2026 03:21 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin January 23, 2026 03:21 Inactive
@github-actions github-actions bot temporarily deployed to Preview - videos-admin January 23, 2026 03:21 Inactive
Copy link
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

🤖 Fix all issues with AI agents
In
`@apps/journeys-admin/src/components/Editor/Toolbar/Items/CreateTemplateItem/CreateTemplateItem.tsx`:
- Around line 66-68: The code in CreateTemplateItem (teamId: globalPublish ?
'jfp-team' : (journeyData.team?.id ?? '')) can pass an empty string when
globalPublish is false and journeyData.team?.id is undefined; update the
CreateTemplateItem handler (the place that builds the mutation payload and calls
the create template mutation) to explicitly validate journeyData.team?.id when
globalPublish is false and either throw or surface a clear error/validation
message instead of sending an empty string, e.g., check if (!globalPublish &&
!journeyData.team?.id) then throw or return with a user-facing error before
calling the mutation so the mutation always receives a valid teamId.

In
`@apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/DuplicateJourneyMenuItem/DuplicateJourneyMenuItem.spec.tsx`:
- Around line 588-602: Remove the leftover debug console.log statements that
print dialogButtons and footerButtons in the DuplicateJourneyMenuItem.spec.tsx
test; specifically delete the console.log(...) calls that reference
dialogButtons.map(...) and footerButtons.map(...), leaving the surrounding test
logic intact (the queries using getByTestId('CopyToTeamDialog'), within(...) and
queryByTestId('dialog-actions')/getAllByRole('button')). Also remove the
identical debug console.log calls elsewhere in the same spec file where
dialogButtons/footerButtons are logged so no debug output remains.
🧹 Nitpick comments (1)
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/DuplicateJourneyMenuItem/DuplicateJourneyMenuItem.spec.tsx (1)

170-256: Consider parameterized tests to reduce duplication.

The "with journey from props" tests largely duplicate their context-based counterparts. You could use describe.each or it.each to parameterize these test cases, reducing code duplication and making it easier to maintain both variants.

♻️ Example approach using describe.each
describe.each([
  {
    name: 'with JourneyProvider context',
    journey: undefined,
    wrapper: (children: React.ReactNode) => (
      <JourneyProvider value={{ journey: contextJourney, variant: 'admin' }}>
        {children}
      </JourneyProvider>
    ),
    journeyId: 'journeyId',
    teamId: 'teamId'
  },
  {
    name: 'with journey prop',
    journey: defaultJourney,
    wrapper: (children: React.ReactNode) => <>{children}</>,
    journeyId: 'journey-id',
    teamId: 'team1.id'
  }
])('$name', ({ journey, wrapper, journeyId, teamId }) => {
  it('should duplicate a journey on menu card click', async () => {
    // Use journeyId, teamId, and journey in mocks and render
  })
  // ... other tests
})

Also applies to: 455-630, 717-780, 895-986

…or-individual-journey' of https://github.com/JesusFilm/core into urimchae/nes-316-substitute-journey-provider-wrapping-for-individual-journey
@github-actions github-actions bot temporarily deployed to Preview - journeys January 23, 2026 03:31 Inactive
@github-actions github-actions bot temporarily deployed to Preview - resources January 23, 2026 03:31 Inactive
@github-actions github-actions bot temporarily deployed to Preview - videos-admin January 23, 2026 03:31 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin January 23, 2026 03:31 Inactive
@blacksmith-sh

This comment has been minimized.

@github-actions github-actions bot temporarily deployed to Preview - videos-admin January 26, 2026 22:40 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys-admin January 26, 2026 22:40 Inactive
@github-actions github-actions bot temporarily deployed to Preview - resources January 26, 2026 22:40 Inactive
@github-actions github-actions bot temporarily deployed to Preview - journeys January 26, 2026 22:40 Inactive
Copy link
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

Caution

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

⚠️ Outside diff range comments (1)
libs/journeys/ui/src/components/TemplateView/CreateJourneyButton/CreateJourneyButton.tsx (1)

313-313: Boolean null-check is always truthy.

openTeamDialog is a boolean state initialized with useState(false). The condition openTeamDialog != null is always true for booleans. This should simply be openTeamDialog to conditionally render the dialog.

Proposed fix
-      {openTeamDialog != null && (
+      {openTeamDialog && (
🤖 Fix all issues with AI agents
In
`@libs/journeys/ui/src/components/TemplateView/CreateJourneyButton/CreateJourneyButton.tsx`:
- Line 334: Remove the redundant double-cast on the journey prop: instead of
passing journey={journeyData as unknown as JourneyFields} pass
journey={journeyData} because journeyData is already typed as JourneyFields |
undefined and CopyToTeamDialog accepts an optional journey?: JourneyFields;
update the JSX where CopyToTeamDialog (or the component receiving the prop) is
called so it uses journey={journeyData} and remove the unnecessary casts to
improve clarity.
🧹 Nitpick comments (1)
apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/DuplicateJourneyMenuItem/DuplicateJourneyMenuItem.spec.tsx (1)

418-445: Fail fast when no primary dialog action is found.

If none of the fallback paths locate a clickable action, the test silently proceeds and later times out. Consider throwing an explicit error to make failures clearer.

♻️ Suggested tweak
       } else {
         // Last resort: click the last button that's not the close button
         const actionButtons = dialogButtons.filter(
           (btn) => !btn.getAttribute('data-testid')?.includes('close')
         )
         if (actionButtons.length > 0) {
           fireEvent.click(actionButtons[actionButtons.length - 1])
+        } else {
+          throw new Error(
+            'Unable to locate a primary action button in CopyToTeamDialog'
+          )
         }
       }
     }

: undefined
}
isTranslating={translationVariables != null}
journey={journeyData as unknown as JourneyFields}
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 26, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find CopyToTeamDialog component and check its props type definition
fd "CopyToTeamDialog" libs/journeys/ui/src --type f | head -20

Repository: JesusFilm/core

Length of output: 280


🏁 Script executed:

#!/bin/bash
# Check the CreateJourneyButton file and find journeyData type and context
cat -n libs/journeys/ui/src/components/TemplateView/CreateJourneyButton/CreateJourneyButton.tsx | sed -n '1,50p'

Repository: JesusFilm/core

Length of output: 2245


🏁 Script executed:

#!/bin/bash
# Look at the DynamicCopyToTeamDialog component (which wraps CopyToTeamDialog)
fd "DynamicCopyToTeamDialog" libs/journeys/ui/src --type f

Repository: JesusFilm/core

Length of output: 40


🏁 Script executed:

#!/bin/bash
# Get the CopyToTeamDialog component and check its props type
cat -n libs/journeys/ui/src/components/CopyToTeamDialog/CopyToTeamDialog.tsx | head -80

Repository: JesusFilm/core

Length of output: 3890


🏁 Script executed:

#!/bin/bash
# Look for journeyData variable definition in CreateJourneyButton around line 334
cat -n libs/journeys/ui/src/components/TemplateView/CreateJourneyButton/CreateJourneyButton.tsx | sed -n '300,360p'

Repository: JesusFilm/core

Length of output: 1486


🏁 Script executed:

#!/bin/bash
# Look for where journeyData comes from in the file
rg "journeyData" libs/journeys/ui/src/components/TemplateView/CreateJourneyButton/CreateJourneyButton.tsx -n -B 2 -A 2

Repository: JesusFilm/core

Length of output: 2374


🏁 Script executed:

#!/bin/bash
# Check useJourney hook return type to confirm journeyFromContext typing
fd "JourneyProvider" libs/journeys/ui/src/libs --type d

Repository: JesusFilm/core

Length of output: 100


🏁 Script executed:

#!/bin/bash
# Search for useJourney hook definition and return type
rg "export.*useJourney|return.*journey" libs/journeys/ui/src/libs/JourneyProvider -n -A 5 | head -40

Repository: JesusFilm/core

Length of output: 1300


🏁 Script executed:

#!/bin/bash
# Get the JourneyProviderContext type definition
cat -n libs/journeys/ui/src/libs/JourneyProvider/JourneyProvider.tsx | head -50

Repository: JesusFilm/core

Length of output: 1106


Remove unnecessary type cast that adds no value.

The cast journeyData as unknown as JourneyFields is redundant. Since journeyData is JourneyFields | undefined and CopyToTeamDialog accepts journey?: JourneyFields (an optional prop), TypeScript allows passing the value without any cast. Remove it to improve code clarity:

-          journey={journeyData as unknown as JourneyFields}
+          journey={journeyData}
🤖 Prompt for AI Agents
In
`@libs/journeys/ui/src/components/TemplateView/CreateJourneyButton/CreateJourneyButton.tsx`
at line 334, Remove the redundant double-cast on the journey prop: instead of
passing journey={journeyData as unknown as JourneyFields} pass
journey={journeyData} because journeyData is already typed as JourneyFields |
undefined and CopyToTeamDialog accepts an optional journey?: JourneyFields;
update the JSX where CopyToTeamDialog (or the component receiving the prop) is
called so it uses journey={journeyData} and remove the unnecessary casts to
improve clarity.

Copy link
Contributor

Choose a reason for hiding this comment

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

remove the redundant typecast

Copy link
Contributor

Choose a reason for hiding this comment

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

@csiyang, great! Thank you for confirming. The double cast pattern as unknown as is typically used as an escape hatch when TypeScript prevents direct conversion between unrelated types, but in this case it's unnecessary since journeyData (typed as JourneyFields | undefined) is already compatible with the optional prop journey?: JourneyFields.


🧠 Learnings used
Learnt from: mikeallisonJS
Repo: JesusFilm/core PR: 7629
File: apis/api-journeys-modern/src/schema/event/utils.ts:43-60
Timestamp: 2025-09-29T23:03:36.840Z
Learning: In the JesusFilm/core repository, do not recommend using Prisma's `upsert` operation for `JourneyVisitor` creation in `apis/api-journeys-modern/src/schema/event/utils.ts` as it is not race condition safe for this use case. The current `findUnique` then `create` pattern is the preferred approach.

Learnt from: mikeallisonJS
Repo: JesusFilm/core PR: 7486
File: apis/api-journeys-modern/schema.graphql:1068-1074
Timestamp: 2025-08-20T21:51:25.797Z
Learning: Before suggesting type changes during API migrations, always verify the existing implementation to ensure consistency is maintained. The migration to api-journeys-modern should preserve the same field types as the original api-journeys schema.

Learnt from: mikeallisonJS
Repo: JesusFilm/core PR: 7486
File: apis/api-journeys-modern/schema.graphql:199-205
Timestamp: 2025-08-20T23:32:18.117Z
Learning: The ChatButton.link field in api-journeys is actually nullable (String), not non-nullable (String!) as previously learned. When migrating GraphQL types from api-journeys to api-journeys-modern, the ChatButton.link field should remain nullable to match the existing api-journeys schema.

Learnt from: mikeallisonJS
Repo: JesusFilm/core PR: 8156
File: apis/api-journeys-modern/src/lib/google/googleAuth.ts:0-0
Timestamp: 2025-11-11T23:22:02.196Z
Learning: In apis/api-journeys-modern, use the validated `env` object from `../../env` instead of accessing `process.env` directly for environment variables that are defined in env.ts (e.g., GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, INTEGRATION_ACCESS_KEY_ENCRYPTION_SECRET). This eliminates the need for runtime validation checks since Zod validates them at application startup.

Learnt from: mikeallisonJS
Repo: JesusFilm/core PR: 7486
File: apis/api-journeys-modern/schema.graphql:1068-1074
Timestamp: 2025-08-20T21:51:25.797Z
Learning: During the refactor to migrate types to modern, maintain consistency with existing api-journeys schema types, including PlausibleStatsAggregateValue.change as Int to match the original implementation.

Learnt from: jaco-brink
Repo: JesusFilm/core PR: 7679
File: apis/api-gateway/schema.graphql:0-0
Timestamp: 2025-09-16T04:10:28.624Z
Learning: In PR `#7679` (showAssistant field), the showAssistant field was intentionally excluded from JourneyUpdateInput because it will be controlled through direct database operations rather than through GraphQL mutations, keeping it out of the public API surface while still being queryable.

Learnt from: mikeallisonJS
Repo: JesusFilm/core PR: 7498
File: apis/api-journeys-modern/src/schema/action/emailAction/blockUpdateEmailAction.mutation.ts:26-36
Timestamp: 2025-09-08T22:56:21.606Z
Learning: In the action mutations migration (PR `#7498`), the `journeyId` parameter is intentionally kept in blockUpdate*Action mutations even when unused in the resolver, to maintain API compatibility during the migration from the old "api-journeys" endpoint to the modern "api-journeys-modern" endpoint.

If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Comment on lines +139 to +148
const result = jest.fn(() => {
return {
data: {
journeyTemplate: {
id: 'templateId',
template: true
}
}
}
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a nit, but you don't really need a return statement here

Suggested change
const result = jest.fn(() => {
return {
data: {
journeyTemplate: {
id: 'templateId',
template: true
}
}
}
})
const result = jest.fn(() => ({
data: {
journeyTemplate: {
id: 'templateId',
template: true
}
}
}))

<TemplateActionButton
variant="menu-item"
handleCloseMenu={handleCloseMenu}
journey={journey as unknown as JourneyFields}
Copy link
Contributor

Choose a reason for hiding this comment

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

This typecast should be unnecessary. Even if it was, its not good practice to type it as unknown since this makes us loose all the proper type checks for and child components.

Suggested change
journey={journey as unknown as JourneyFields}
journey={journey}

setOpen(false)
}}
submitAction={handleDuplicateJourney}
journey={journey as unknown as JourneyFields}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this will cause a type failure. There's often a reason why types mismatch, we shouldn't just ignore it. You should try find out why there are different types here and make, and either update types to use the same one, or just use a subset of the type you need.

I know we already using this typecast, I don't remember why it was done like this, but this is a good opportunity to clean it up if possible.

    Suggested change
  


  
      
        
                journey={journey as unknown as JourneyFields}
      
      
        
                journey={journey}

expect(getByText('Journey Duplicated')).toBeInTheDocument()
})

it('should call refetchTemplateStats when duplicating a journey with fromTemplateId with journey from props', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

This test is not needed, you haven't made any changes to how refetch is running.

)
})

it('should close copy to dialog with journey from props', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not needed, the onClose function has not been changed

}
},
result: jest.fn(() => ({
describe.each([
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good idea, but just a little hard read/ understand.

: undefined
}
isTranslating={translationVariables != null}
journey={journeyData as unknown as JourneyFields}
Copy link
Contributor

Choose a reason for hiding this comment

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

remove the redundant typecast

variant={variant}
signedIn={signedIn}
openTeamDialogOnSignIn={openTeamDialogOnSignIn}
journey={journeyData as unknown as JourneyFields}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
journey={journeyData as unknown as JourneyFields}
journey={journeyData}

<UseThisTemplateButton
variant={variant}
signedIn={signedIn}
journey={journeyData as unknown as JourneyFields}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
journey={journeyData as unknown as JourneyFields}
journey={journeyData}

describe.each([
['context journey', undefined],
['prop journey', { id: 'journeyId' } as unknown as JourneyFields]
])('(%s)', (_, defaultJourney) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Update these so when tests run the titles match the pattern of how our current tests are structured. Double check this for other places you've used this

Suggested change
])('(%s)', (_, defaultJourney) => {
])((%s', (_, defaultJourney) => {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Chore effort: 8 priority: soon type: chore updating folder structure, initializing projects etc; no production code change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants