Skip to content

Conversation

hbjORbj
Copy link
Contributor

@hbjORbj hbjORbj commented Jul 1, 2025

What does this PR do?

This PR does 3 things to team booking pages:
(1) Replace client-side event-data fetching (/api/trpc/public/event -> this uses getPublicEvent under the hood) with server-side fetching
(2) Cache this ^server-side fetching and invalidate it when event-type is updated
(3) Cache the team data fetching (was already a server-side fetch)

Benefit of this is obviously (1) offloading pressures on our server by defending spamming towards /api/trpc/public/event and team data fetching (2) faster page initial load

Code-wise, This PR

  • Adds pageWithCachedData.tsx RSC alongside page.tsx RSC. We render pageWithCachedData if global feature flag for team-booking-page-cache is enabled && experimentalTeamBookingPageCache search param is "true". Otherwise, we render page.tsx as usual.
  • Once we confirm in production that pageWithCachedData is stable, we can get rid of page.tsx, getServerSideProps.tsx and type-view.tsx entirely.

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • N/A - I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

Manual tests

  • In team booking page, you will see that /api/trpc/public/event is no longer used
  • Below is a demo showing that updating event-type invalidates the cache in team booking pages
461833540-19fb3788-c34a-406c-93c0-00a74124ec75.mov
  • If you comment out the logic inside revalidateTeamBookingPage, you will see that cache invalidation doesn't work (this confirms that (1) page uses cached data (2) invalidation logic works)

Automated tests

  • I confirmed that all e2e tests pass with caching enabled (I returned true in isCachedTeamBookingEnabled and waited for e2e tests)
Screenshot 2025-07-09 at 10 24 10 AM

@hbjORbj hbjORbj requested review from a team as code owners July 1, 2025 01:41
@hbjORbj hbjORbj marked this pull request as draft July 1, 2025 01:41
@graphite-app graphite-app bot requested a review from a team July 1, 2025 01:41
Copy link

vercel bot commented Jul 1, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
cal ⬜️ Ignored (Inspect) Visit Preview Jul 15, 2025 11:32pm
cal-eu ⬜️ Ignored (Inspect) Visit Preview Jul 15, 2025 11:32pm

@keithwillcode keithwillcode added core area: core, team members only foundation labels Jul 1, 2025
@hbjORbj hbjORbj changed the title perf: cache event type team booking page perf: cache event-type & team data in team booking pages Jul 1, 2025
@dosubot dosubot bot added booking-page area: booking page, public booking page, booker performance area: performance, page load, slow, slow endpoints, loading screen, unresponsive labels Jul 1, 2025
Copy link

delve-auditor bot commented Jul 1, 2025

No security or compliance issues detected. Reviewed everything up to de6966b.

Security Overview
  • 🔎 Scanned files: 19 changed file(s)
Detected Code Changes
Change Type Relevant files
Enhancement ► actions.ts
    Add revalidation functions for team data cache
► page.tsx
    Add support for cached team booking page
► pageWithCachedData.tsx
    Implement cached team booking page
► queries.ts
    Add data fetching functions for cached team booking
► type-view-cached.tsx
    Add cached team booking view component
Refactor ► getTeamData.ts
    Extract team data fetching logic
► getTeamEventType.ts
    Extract team event type fetching logic
► getPublicEvent.ts
    Refactor public event data processing
Configuration changes ► config.ts
    Add team-booking-page-cache feature flag
► constants.ts
    Add NEXTJS_CACHE_TTL constant

Reply to this PR with @delve-auditor followed by a description of what change you want and we'll auto-submit a change to this PR to implement it.

Copy link

graphite-app bot commented Jul 1, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (07/01/25)

1 reviewer was added to this PR based on Keith Williams's automation.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

cubic found 5 issues across 9 files. Review them in cubic.dev

React with 👍 or 👎 to teach cubic. Tag @cubic-dev-ai to give specific feedback.

@vercel vercel bot temporarily deployed to Preview – api July 1, 2025 02:25 Inactive
@vercel vercel bot temporarily deployed to Preview – api July 1, 2025 02:39 Inactive
@vercel vercel bot temporarily deployed to Preview – api July 1, 2025 02:54 Inactive
@hbjORbj hbjORbj changed the title perf: cache event-type & team data in team booking pages perf: caching + modular design for team booking pages Jul 1, 2025
@vercel vercel bot temporarily deployed to Preview – api July 1, 2025 03:26 Inactive
teamSlug: string;
orgSlug: string | null;
}) {
revalidateTag(`team:${teamSlug}${orgSlug ? `:${orgSlug}` : ""}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

This feels a little odd to me to have the team first and then the org since teams are nested inside of orgs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed!

meetingSlug: string;
orgSlug: string | null;
}) {
revalidateTag(`event-type:${teamSlug}:${meetingSlug}${orgSlug ? `:${orgSlug}` : ""}`);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same thing here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed!

});
}

async function _getTeamEventType(teamSlug: string, meetingSlug: string, orgSlug: string | null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should move these to repositories. Prisma queries shouldn't be directly in the web app like this

Copy link
Contributor Author

@hbjORbj hbjORbj Jul 15, 2025

Choose a reason for hiding this comment

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

I will move it to packages/features/! We use some helpers from packages/features inside so we can't use repositories in packages/lib.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved

  • getTeamEventType to packages/features/eventtypes/lib/getTeamEventType.ts
  • getTeamData to packages/features/ee/teams/lib/getTeamData.ts.

Let me know if that's wrong!

Copy link
Contributor

@keithwillcode keithwillcode left a comment

Choose a reason for hiding this comment

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

Looking solid overall but have a couple requested changes.

@github-actions github-actions bot marked this pull request as draft July 15, 2025 02:04
@vercel vercel bot temporarily deployed to Preview – api July 15, 2025 19:40 Inactive
Copy link
Contributor

coderabbitai bot commented Jul 15, 2025

Walkthrough

This update introduces a comprehensive caching mechanism for team booking pages and event types within a Next.js application. New server-side modules provide functions to fetch, cache, and revalidate team and event type data using Next.js cache APIs, with cache tags constructed from team and organization slugs. Feature flag support is added for conditionally enabling the cached booking page, with fallback to legacy rendering. Several React components and server modules are updated or added to utilize cached data and ensure cache consistency after mutations. Supporting utilities, type exports, and constants for cache TTL are also introduced. Cache revalidation is triggered in relevant mutation success handlers to maintain up-to-date data.

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.

🔧 ESLint

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.

apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

packages/features/ee/organizations/pages/settings/other-team-profile-view.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-playwright".

(The package "eslint-plugin-playwright" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-playwright@latest --save-dev

The plugin "eslint-plugin-playwright" was referenced from the config file in ".eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

  • 16 others
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • 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 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 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 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 for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@hbjORbj hbjORbj requested a review from keithwillcode July 15, 2025 23:33
@hbjORbj hbjORbj marked this pull request as ready for review July 15, 2025 23:45
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

🔭 Outside diff range comments (1)
packages/platform/atoms/booker/BookerWebWrapper.tsx (1)

37-48: Stubbed query object is incomplete – potential runtime breakage

When eventData is provided you manually craft an object that only contains data, isSuccess, isError, and isPending.
BookerComponent (and other hooks) may depend on additional fields returned by useEvent such as refetch, isFetching, etc. Passing an object that doesn’t fully satisfy that shape can lead to undefined-access errors.

-const event = props.eventData
-  ? {
-      data: props.eventData,
-      isSuccess: true,
-      isError: false,
-      isPending: false,
-    }
-  : clientFetchedEvent;
+const event = props.eventData
+  ? {
+      ...clientFetchedEvent,          // preserves refetch, status flags, etc.
+      data: props.eventData,
+      isSuccess: true,
+      isError: false,
+      isPending: false,
+    }
+  : clientFetchedEvent;

Alternatively, keep useEvent enabled and pass initialData to it; that guarantees the returned object is 100 % compatible with the hook’s contract.

♻️ Duplicate comments (10)
packages/lib/constants.ts (1)

231-231: Expose TTL via env-var to avoid hard-coding
Same feedback as in the previous review: consider making the value configurable to accommodate different cache horizons across environments.

-export const NEXTJS_CACHE_TTL = 3600; // 1 hour
+export const NEXTJS_CACHE_TTL = parseInt(process.env.NEXTJS_CACHE_TTL ?? "3600", 10); // 1 hour default
packages/features/ee/teams/pages/team-profile-view.tsx (1)

45-45: Client component importing server-only module will cause build failure.

This violates Next.js architecture - client components cannot import modules that use "use server". Move the cache revalidation behind an API route/server action or perform it in a wrapper server component.

packages/features/ee/teams/pages/team-appearance-view.tsx (1)

21-21: Client component importing server-only module will cause build failure.

This violates Next.js architecture - client components cannot import modules that use "use server". Move the cache revalidation behind an API route/server action or perform it in a wrapper server component.

packages/features/ee/teams/pages/team-settings-view.tsx (1)

24-24: Client component importing server-only module will cause build failure.

This violates Next.js architecture - client components cannot import modules that use "use server". Move the cache revalidation behind an API route/server action or perform it in a wrapper server component.

packages/features/ee/organizations/pages/settings/other-team-profile-view.tsx (1)

34-34: Client component importing server-only module will cause build failure.

This violates Next.js architecture - client components cannot import modules that use "use server". Move the cache revalidation behind an API route/server action or perform it in a wrapper server component.

packages/features/ee/teams/components/RoundRobinSettings.tsx (1)

14-14: Client component importing server-only module will cause build failure.

This violates Next.js architecture - client components cannot import modules that use "use server". Move the cache revalidation behind an API route/server action or perform it in a wrapper server component.

packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx (3)

23-23: Server action import in client component will cause build errors.

This import brings a server-only function into a client component, which will fail at build time with "Server-only module cannot be imported from a Client Component" error.

The cache invalidation should be handled server-side, either by:

  1. Moving the mutation logic to a server action
  2. Calling the cache invalidation through an API route
  3. Using the mutation's onSettled to trigger a separate server action call
-import { revalidateTeamEventTypeCache } from "@calcom/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions";

142-150: Move cache invalidation to server-side logic.

The cache invalidation call in the client component will fail due to server/client boundary violations.


324-332: Move cache invalidation to server-side logic.

Same issue as in the update handler - this client-side cache invalidation call will fail.

packages/features/eventtypes/lib/getPublicEvent.ts (1)

565-853: Remove unused getPublicEventRefactored function

This function is never exported or referenced anywhere in the codebase, creating unnecessary dead code that increases bundle size and maintenance overhead.

🧹 Nitpick comments (4)
packages/platform/atoms/booker/BookerWebWrapper.tsx (1)

29-33: Nit: clarify prop name

eventData represents pre-fetched event information. Using a more explicit name such as initialEventData would communicate intent and avoid confusion with data that might change at runtime.

packages/features/ee/teams/components/RoundRobinSettings.tsx (1)

43-43: Fix typo in comment.

"Rounb robin" should be "Round robin".

-        // Rounb robin reset interval / basis governs host selection logic on the booking page.
+        // Round robin reset interval / basis governs host selection logic on the booking page.
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx (1)

80-81: Consider returning default metadata instead of empty object

When teamData or enrichedEventType is missing, returning an empty object might hurt SEO. Consider returning a default metadata object with appropriate error messaging or 404 status.

Example improvement:

-  if (!teamData) return {}; // should never happen
+  if (!teamData) return {
+    title: "Team Not Found",
+    description: "The requested team could not be found.",
+    robots: { index: false, follow: false }
+  };

Also applies to: 88-89

packages/features/eventtypes/lib/getPublicEvent.ts (1)

246-249: Consider clarifying the hosts return structure

The function returns both subsetOfHosts (always populated) and hosts (conditionally populated based on fetchAllUsers). This dual structure might be confusing. Consider adding a comment explaining why both are needed for backward compatibility.

Add clarifying comment:

   return {
+    // subsetOfHosts: Always returns enriched hosts (limited to 3 unless fetchAllUsers is true)
     subsetOfHosts: enrichedHosts,
+    // hosts: Only populated when fetchAllUsers is true, for backward compatibility
     hosts: fetchAllUsers ? enrichedHosts : undefined,
   };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e6da5c8 and de6966b.

📒 Files selected for processing (19)
  • apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts (1 hunks)
  • apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx (4 hunks)
  • apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx (1 hunks)
  • apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/queries.ts (1 hunks)
  • apps/web/modules/team/type-view-cached.tsx (1 hunks)
  • packages/features/ee/organizations/pages/settings/other-team-profile-view.tsx (2 hunks)
  • packages/features/ee/teams/components/RoundRobinSettings.tsx (2 hunks)
  • packages/features/ee/teams/lib/getTeamData.ts (1 hunks)
  • packages/features/ee/teams/pages/team-appearance-view.tsx (2 hunks)
  • packages/features/ee/teams/pages/team-profile-view.tsx (2 hunks)
  • packages/features/ee/teams/pages/team-settings-view.tsx (2 hunks)
  • packages/features/eventtypes/lib/getPublicEvent.ts (6 hunks)
  • packages/features/eventtypes/lib/getTeamEventType.ts (1 hunks)
  • packages/features/flags/config.ts (1 hunks)
  • packages/features/flags/hooks/index.ts (1 hunks)
  • packages/lib/constants.ts (1 hunks)
  • packages/platform/atoms/booker/BookerWebWrapper.tsx (1 hunks)
  • packages/platform/atoms/booker/index.ts (1 hunks)
  • packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx (3 hunks)
🧰 Additional context used
🧠 Learnings (8)
packages/features/flags/hooks/index.ts (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
packages/platform/atoms/booker/index.ts (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
packages/platform/atoms/booker/BookerWebWrapper.tsx (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
apps/web/modules/team/type-view-cached.tsx (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/queries.ts (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
packages/features/eventtypes/lib/getPublicEvent.ts (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
🧬 Code Graph Analysis (9)
packages/features/ee/teams/pages/team-profile-view.tsx (1)
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts (1)
  • revalidateTeamDataCache (6-14)
packages/features/ee/teams/pages/team-settings-view.tsx (1)
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts (1)
  • revalidateTeamDataCache (6-14)
packages/platform/atoms/booker/BookerWebWrapper.tsx (1)
packages/features/bookings/Booker/types.ts (1)
  • BookerProps (19-107)
packages/features/ee/organizations/pages/settings/other-team-profile-view.tsx (1)
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts (1)
  • revalidateTeamDataCache (6-14)
packages/features/ee/teams/pages/team-appearance-view.tsx (1)
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts (1)
  • revalidateTeamDataCache (6-14)
packages/features/ee/teams/components/RoundRobinSettings.tsx (1)
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts (1)
  • revalidateTeamDataCache (6-14)
packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx (1)
apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts (1)
  • revalidateTeamEventTypeCache (17-27)
packages/features/ee/teams/lib/getTeamData.ts (1)
packages/features/ee/organizations/lib/orgDomains.ts (1)
  • getSlugOrRequestedSlug (160-173)
packages/features/eventtypes/lib/getTeamEventType.ts (2)
packages/features/ee/organizations/lib/orgDomains.ts (1)
  • getSlugOrRequestedSlug (160-173)
packages/features/eventtypes/lib/getPublicEvent.ts (1)
  • getPublicEventSelect (53-156)
⏰ 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). (11)
  • GitHub Check: Tests / E2E Embed Core
  • GitHub Check: Tests / E2E App Store
  • GitHub Check: Tests / E2E Embed React
  • GitHub Check: Tests / E2E API v2
  • GitHub Check: Analyze Build / analyze
  • GitHub Check: Tests / E2E (3/4)
  • GitHub Check: Tests / E2E (4/4)
  • GitHub Check: Tests / E2E (2/4)
  • GitHub Check: Tests / Integration
  • GitHub Check: Tests / E2E (1/4)
  • GitHub Check: Security Check
🔇 Additional comments (15)
packages/features/flags/config.ts (1)

26-26: Flag addition looks good

The new "team-booking-page-cache" key is consistent with existing boolean flags and will automatically be covered by TeamFeatures. No further action needed.

packages/features/flags/hooks/index.ts (1)

25-26: Default flag wired up correctly

initialData now includes "team-booking-page-cache", keeping the runtime flag object in sync with the type definition.

packages/platform/atoms/booker/index.ts (1)

2-2: Nice quality-of-life re-export

Re-exporting the props type from the package root simplifies imports for downstream consumers.

apps/web/modules/team/type-view-cached.tsx (1)

1-19: Clean and well-structured component implementation.

The component follows React best practices with proper type safety, error boundary usage, and clean prop spreading. The type definition correctly makes eventData required while maintaining flexibility for other props.

packages/features/eventtypes/lib/getTeamEventType.ts (1)

6-22: Well-implemented database query with comprehensive field selection.

The function correctly handles flexible slug matching using getSlugOrRequestedSlug and includes proper filtering for both team and organization hierarchies. The use of getPublicEventSelect(false) ensures all necessary public event fields are included for the booking page.

packages/features/ee/teams/lib/getTeamData.ts (1)

15-47: Comprehensive team data selection with proper nesting.

The select statement correctly includes all necessary team and organization fields, with proper nested selection for parent organization data and settings.

apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/actions.ts (1)

1-27: Well-implemented server actions for cache invalidation.

The functions properly use Next.js revalidateTag API with consistent cache tag construction. The parameter structure is clean and the server action directives are correctly applied.

apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/page.tsx (1)

19-25: Feature flag implementation looks good!

The conditional rendering based on the global feature flag and search parameter is implemented correctly. The async handling of searchParams is proper, and the delegation to cached or legacy implementations is clean.

Also applies to: 27-30, 69-72

apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx (2)

44-64: Excellent input validation and error handling!

Good use of Zod schema for parameter validation with slug normalization. The early return with notFound() for invalid params is appropriate.


125-216: Well-structured server component with comprehensive error handling!

The component properly handles:

  • Organization redirects
  • Data validation with 404 responses
  • Reschedule logic with appropriate status checks
  • Internationalization support
  • Multiple duration configuration

The implementation is thorough and follows best practices.

apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/queries.ts (3)

21-26: Proper caching implementation with well-structured cache tags!

The cache tag format team:${orgSlug}:${teamSlug} enables granular cache invalidation. Good use of the centralized TTL constant.


50-53: Efficient parallel data fetching!

Good use of Promise.all to fetch team and event type data concurrently, reducing latency.


132-148: Good fallback mechanism for CRM data!

The dynamic import fallback ensures CRM data is properly resolved even when not provided in query parameters. This maintains backward compatibility.

packages/features/eventtypes/lib/getPublicEvent.ts (2)

53-156: Good modularization of the Prisma select query!

Exporting the select object enables reuse across different queries and maintains consistency in the data structure.


994-1028: Excellent extraction of shared event data processing!

This function successfully consolidates common event data transformations, improving code reusability and maintainability.

Comment on lines +12 to +14
orderBy: {
slug: { sort: "asc", nulls: "last" },
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix orderBy syntax for Prisma.

The orderBy syntax is incorrect. Prisma doesn't support the { sort: "asc", nulls: "last" } format.

Use the correct Prisma syntax:

-    orderBy: {
-      slug: { sort: "asc", nulls: "last" },
-    },
+    orderBy: {
+      slug: "asc",
+    },

If you need null handling, use:

orderBy: [
  { slug: { sort: "asc", nulls: "last" } }
]
🤖 Prompt for AI Agents
In packages/features/ee/teams/lib/getTeamData.ts around lines 12 to 14, the
orderBy syntax is incorrect for Prisma as it does not support the object format
with sort and nulls directly. To fix this, change the orderBy property to be an
array containing an object with slug and its sorting options, like orderBy: [{
slug: { sort: "asc", nulls: "last" } }], ensuring proper Prisma syntax and null
handling.

@keithwillcode keithwillcode merged commit c4eda5f into main Jul 16, 2025
43 checks passed
@keithwillcode keithwillcode deleted the perf/cache-event-type-team-booking-page branch July 16, 2025 00:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
booking-page area: booking page, public booking page, booker bookings area: bookings, availability, timezones, double booking core area: core, team members only foundation performance area: performance, page load, slow, slow endpoints, loading screen, unresponsive ready-for-e2e teams area: teams, round robin, collective, managed event-types
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants