-
Notifications
You must be signed in to change notification settings - Fork 1.1k
improvement: enterprise card #1046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds an Enterprise Art component and EnterpriseCard with imperative Rive controls and hover-triggered animations; integrates EnterpriseCard into the pricing page. Compacts spacing/typography in Commercial and Pro cards, slightly increases CommercialArt height, and updates Pro description text and layout widths. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant EC as EnterpriseCard
participant EA as EnterpriseArt (Rive)
participant Browser
User->>EC: Mouse enter (hover)
EC->>EA: playHoverAnimation()
note right of EA #E8F5E9: triggers "out" animation
User->>EC: Mouse leave
EC->>EA: playDefaultAnimation()
note right of EA #E8F5E9: returns to "idle" animation
User->>EC: Click "Book a Call"
EC->>Browser: window.open(cal.com URL, "_blank")
note over Browser #FFF3E0: opens scheduling page in new tab
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. 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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/components/pages/PricingPage.tsx (1)
51-53: Fix TS: React namespace type not importedUsing React.MouseEvent without importing React types can fail with “Cannot find namespace 'React'”. Add a type‑only import.
Apply this diff:
"use client"; +import type React from "react"; import { faHeart } from "@fortawesome/free-solid-svg-icons";
🧹 Nitpick comments (8)
apps/web/components/pages/HomePage/Pricing/CommercialArt.tsx (1)
41-47: Consider hiding decorative animation from ATs.If this art is purely decorative, add aria-hidden to avoid noise for screen readers.
- <CommercialRive + <CommercialRive + aria-hidden="true" className={clsx( "w-full max-w-[100px] mx-auto h-[90px]", props.className, )} />apps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsx (2)
41-42: Decorative canvas should be hidden from screen readersMark the Rive canvas aria-hidden to avoid noise for assistive tech.
Apply this diff:
- <EnterpriseRive - className={clsx(className, "mx-auto w-full max-w-[200px] h-[120px]")} - /> + <EnterpriseRive + className={clsx(className, "mx-auto w-full max-w-[200px] h-[120px]")} + aria-hidden="true" + />
14-45: Improve devtools name for wrapped forwardRefmemo(forwardRef(...)) can obscure display names in React DevTools. Set displayName explicitly.
export const EnterpriseArt = memo( forwardRef<EnterpriseArtRef, EnterpriseArtProps>(({ className }, ref) => { @@ }), ); + +EnterpriseArt.displayName = "EnterpriseArt";apps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsx (2)
16-41: Avoid recreating static data on each renderMove enterpriseFeatures to module scope (or mark as const) to avoid per‑render allocation.
+const ENTERPRISE_FEATURES = [ + { icon: faShield, label: "SLAs & Priority Support" }, + { icon: faDownload, label: "Loom Video Importer" }, + { icon: faHandshake, label: "Bulk Discounts" }, + { icon: faServer, label: "Self-hosting Support" }, + { icon: faUsers, label: "SAML SSO Login" }, + { icon: faShield, label: "Advanced Security Controls" }, +] as const; export const EnterpriseCard = () => { const enterpriseArtRef = useRef<EnterpriseArtRef>(null); - const enterpriseFeatures = [ - ... - ]; + const enterpriseFeatures = ENTERPRISE_FEATURES;
96-105: Consider semantic link instead of window.open in buttonIf this is always an external navigation, using Button asChild with an improves semantics and preserves middle‑click, etc. Keep noopener/noreferrer.
- <Button - variant="gray" - size="lg" - onClick={handleBookCall} - className="w-full font-medium" - aria-label="Book a Call for Enterprise" - > - Book a Call - </Button> + <Button asChild variant="gray" size="lg" className="w-full font-medium"> + <a + href="https://cal.com/cap.so/15min" + target="_blank" + rel="noopener noreferrer" + aria-label="Book a Call for Enterprise" + > + Book a Call + </a> + </Button>apps/web/components/pages/HomePage/Pricing/ProCard.tsx (2)
202-204: Potential overflow for double‑digit user countw-5 is tight; “10” may clip depending on font metrics. Bump width slightly.
- <span className="w-5 font-medium tabular-nums text-center text-white"> + <span className="w-7 font-medium tabular-nums text-center text-white">
218-238: Switch scaled down — check touch targetscale-75 may drop below comfortable 44×44 px targets on mobile. Consider keeping visual scale but ensuring hit area ≥44 px via padding or wrapper.
apps/web/components/pages/HomePage/Pricing/CommercialCard.tsx (1)
133-135: Same width concern as Pro: two‑digit countsw-5 may clip “10”. Align with Pro suggestion.
- <span className="w-5 font-medium tabular-nums text-center text-gray-12"> + <span className="w-7 font-medium tabular-nums text-center text-gray-12">
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/web/components/pages/HomePage/Pricing/CommercialArt.tsx(1 hunks)apps/web/components/pages/HomePage/Pricing/CommercialCard.tsx(5 hunks)apps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsx(1 hunks)apps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsx(1 hunks)apps/web/components/pages/HomePage/Pricing/ProCard.tsx(3 hunks)apps/web/components/pages/PricingPage.tsx(3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components
Files:
apps/web/components/pages/PricingPage.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialArt.tsxapps/web/components/pages/HomePage/Pricing/ProCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialCard.tsx
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
apps/web/components/pages/PricingPage.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialArt.tsxapps/web/components/pages/HomePage/Pricing/ProCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialCard.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use strict TypeScript and avoid any; leverage shared types from packages
**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by runningpnpm format.
Files:
apps/web/components/pages/PricingPage.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialArt.tsxapps/web/components/pages/HomePage/Pricing/ProCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialCard.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g.,user-menu.tsx).
Use PascalCase for React/Solid components.
Files:
apps/web/components/pages/PricingPage.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialArt.tsxapps/web/components/pages/HomePage/Pricing/ProCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialCard.tsx
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
On the client, always use
useEffectQueryoruseEffectMutationfrom@/lib/EffectRuntime; never callEffectRuntime.run*directly in components.
Files:
apps/web/components/pages/PricingPage.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsxapps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialArt.tsxapps/web/components/pages/HomePage/Pricing/ProCard.tsxapps/web/components/pages/HomePage/Pricing/CommercialCard.tsx
🧬 Code graph analysis (3)
apps/web/components/pages/PricingPage.tsx (1)
apps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsx (1)
EnterpriseCard(13-109)
apps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsx (1)
apps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsx (2)
EnterpriseArtRef(5-8)EnterpriseArt(14-45)
apps/web/components/pages/HomePage/Pricing/CommercialCard.tsx (1)
apps/web/data/homepage-copy.ts (1)
homepageCopy(110-318)
⏰ 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). (3)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Analyze (rust)
🔇 Additional comments (7)
apps/web/components/pages/HomePage/Pricing/CommercialArt.tsx (1)
44-46: LGTM on the height bump — verify responsive alignment
- Heights found: apps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsx:41 → h-[120px]; ProArt.tsx:43 → h-[80px] (ProCard.tsx:117 wrapper md:h-[180px]); CommercialArt.tsx:44 → h-[90px].
- Visually confirm at sm / md / lg that the Pricing grid (apps/web/components/pages/HomePage/Pricing/index.tsx) does not overflow and all art stays vertically centered; adjust CommercialArt or card wrappers to match baseline if misaligned.
apps/web/components/pages/PricingPage.tsx (2)
69-73: Header animation block LGTMClean integration of motion variants and spacing.
107-115: Wider container — verify large breakpointsmax-w-[1400px] may introduce extra whitespace on xl/2xl. Please sanity‑check wrapping/alignment with three cards at 1280–1536px widths.
apps/web/components/pages/HomePage/Pricing/EnterpriseArt.tsx (1)
16-24: Confirm idle animation behaviorautoplay: false with animations: "idle" means no motion until an explicit play(). If you want idle on first paint, either set autoplay: true or call rive.play("idle") once after load.
apps/web/components/pages/HomePage/Pricing/ProCard.tsx (1)
109-110: Card styling tweak LGTMShadow and color adjustments look consistent with the new Enterprise card.
apps/web/components/pages/HomePage/Pricing/CommercialCard.tsx (2)
118-143: Counter control adjustments LGTMSmaller buttons/icons read well against dark background; aria labels intact.
212-224: Button block LGTMVariant/size move into the same section improves hierarchy and spacing.
| // Enterprise features data | ||
| const enterpriseFeatures = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove inline comment (repo rule: no comments in code)
Inline comments are disallowed per repo guidelines.
- // Enterprise features data
const enterpriseFeatures = [📝 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.
| // Enterprise features data | |
| const enterpriseFeatures = [ | |
| const enterpriseFeatures = [ |
🤖 Prompt for AI Agents
In apps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsx around lines 15
to 16, remove the inline comment "// Enterprise features data" and, if needed
for clarity, rename the variable or add a descriptive variable name (e.g.,
enterpriseFeatures) so the code is self-explanatory; ensure no other inline
comments remain in that block to comply with the repo rule banning comments in
code.
| const handleBookCall = () => { | ||
| window.open("https://cal.com/cap.so/15min", "_blank"); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Harden new‑tab open against tabnabbing
Use noopener/noreferrer (or clear opener) when opening external sites.
- const handleBookCall = () => {
- window.open("https://cal.com/cap.so/15min", "_blank");
- };
+ const handleBookCall = () => {
+ const w = window.open(
+ "https://cal.com/cap.so/15min",
+ "_blank",
+ "noopener,noreferrer",
+ );
+ if (w) w.opener = null;
+ };📝 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.
| const handleBookCall = () => { | |
| window.open("https://cal.com/cap.so/15min", "_blank"); | |
| }; | |
| const handleBookCall = () => { | |
| const w = window.open( | |
| "https://cal.com/cap.so/15min", | |
| "_blank", | |
| "noopener,noreferrer", | |
| ); | |
| if (w) w.opener = null; | |
| }; |
🤖 Prompt for AI Agents
In apps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsx around lines 43
to 45, the handler opens an external URL in a new tab without protection against
tabnabbing; update the handler to open the URL with noopener and noreferrer (or
clear window.opener) so the newly opened page cannot access the opener.
Concretely, call window.open with the appropriate features (e.g., include
"noopener,noreferrer") or immediately null out the returned window's opener (if
window.open returns a Window) to harden against tabnabbing and ensure external
links are safe.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this 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 (5)
apps/web/components/pages/HomePage/Pricing/ProCard.tsx (5)
188-215: Tap targets reduced; may fall below 44×44pxThe decrement/increment buttons now have very small hit areas (
p-1with 8px icons). Consider ensuring a minimum 44×44px hit area while keeping visuals compact.Apply this diff to enlarge the hit targets without changing icon size:
- <Button - onClick={decrementUsers} - className="p-1 bg-gray-1 hover:bg-gray-3 min-w-fit h-fit" - aria-label="Decrease user count" - > + <Button + onClick={decrementUsers} + className="bg-gray-1 hover:bg-gray-3 min-w-[44px] min-h-[44px] h-11 w-11 flex items-center justify-center" + aria-label="Decrease user count" + > <FontAwesomeIcon icon={faMinus} className="text-gray-12 size-2" /> </Button> @@ - <Button - onClick={incrementUsers} - className="p-1 bg-gray-1 hover:bg-gray-3 min-w-fit h-fit" - aria-label="Increase user count" - > + <Button + onClick={incrementUsers} + className="bg-gray-1 hover:bg-gray-3 min-w-[44px] min-h-[44px] h-11 w-11 flex items-center justify-center" + aria-label="Increase user count" + > <FontAwesomeIcon icon={faPlus} className="text-gray-12 size-2" /> </Button>
220-241: Make billing labels clickable; verify switch hit sizeWith
scale-75, ensure adequate tap area. Also make “Monthly/Annual” text toggle the switch for better UX by associating labels to the switch id.Apply this diff to associate labels:
- <span - className={clsx( - "text-sm", - !isAnnually ? "text-white" : "text-gray-8", - )} - > - {homepageCopy.pricing.pro.labels.monthly} - </span> + <label + htmlFor="billing-cycle-cap-pro" + className={clsx( + "text-sm cursor-pointer", + !isAnnually ? "text-white" : "text-gray-8", + )} + > + {homepageCopy.pricing.pro.labels.monthly} + </label> @@ - <span - className={clsx( - "text-sm", - isAnnually ? "text-white" : "text-gray-8", - )} - > - {homepageCopy.pricing.pro.labels.annually} - </span> + <label + htmlFor="billing-cycle-cap-pro" + className={clsx( + "text-sm cursor-pointer", + isAnnually ? "text-white" : "text-gray-8", + )} + > + {homepageCopy.pricing.pro.labels.annually} + </label>
251-258: Copy consistency: “in” vs “from”Align with homepage copy (“Everything in Desktop License”).
- <span className="text-gray-4">Everything from Desktop License</span> + <span className="text-gray-4">Everything in Desktop License</span>
266-267: Avoid double “Unlimited”; align with source copyCurrent: “Unlimited cloud storage & unlimited shareable links”. Consider either one “Unlimited” or align with homepage copy (“Unlimited cloud storage & bandwidth”).
- <span className="text-gray-4"> - Unlimited cloud storage & unlimited shareable links - </span> + <span className="text-gray-4"> + Unlimited cloud storage & bandwidth + </span>
276-277: AI features wording: align with homepage copyKeeps terminology consistent across the site.
- <span className="text-gray-4"> - Automatic AI title, transcription, summary, and chapters - </span> + <span className="text-gray-4"> + Auto-generated titles, summaries, clickable chapters, and transcriptions + </span>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/web/components/pages/HomePage/Pricing/CommercialCard.tsx(7 hunks)apps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsx(1 hunks)apps/web/components/pages/HomePage/Pricing/ProCard.tsx(7 hunks)apps/web/data/homepage-copy.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/web/data/homepage-copy.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/web/components/pages/HomePage/Pricing/EnterpriseCard.tsx
- apps/web/components/pages/HomePage/Pricing/CommercialCard.tsx
🧰 Additional context used
📓 Path-based instructions (5)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components
Files:
apps/web/components/pages/HomePage/Pricing/ProCard.tsx
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
apps/web/components/pages/HomePage/Pricing/ProCard.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use strict TypeScript and avoid any; leverage shared types from packages
**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by runningpnpm format.
Files:
apps/web/components/pages/HomePage/Pricing/ProCard.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g.,user-menu.tsx).
Use PascalCase for React/Solid components.
Files:
apps/web/components/pages/HomePage/Pricing/ProCard.tsx
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
On the client, always use
useEffectQueryoruseEffectMutationfrom@/lib/EffectRuntime; never callEffectRuntime.run*directly in components.
Files:
apps/web/components/pages/HomePage/Pricing/ProCard.tsx
🧬 Code graph analysis (1)
apps/web/components/pages/HomePage/Pricing/ProCard.tsx (1)
apps/web/data/homepage-copy.ts (1)
homepageCopy(110-318)
⏰ 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). (4)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (rust)
🔇 Additional comments (3)
apps/web/components/pages/HomePage/Pricing/ProCard.tsx (3)
5-5: Icon import addition looks good
faCreditCardis used below in the feature list.
110-110: Container elevation/visual tweak — OKReduced elevation (shadow-lg) aligns with the tightened layout.
123-123: Description styling update — OKCompact, still readable.
Summary by CodeRabbit
New Features
Style