[FEAT] Replace "Contact Us" email with meeting booking form(Cal)#66
Conversation
|
@Manishhhsys is attempting to deploy a commit to the idan lodzki's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughReplaced the Navbar Contact CTA with a Cal.com booking CTA, added Cal.com initialization and UI config in the Navbar, added section-highlight and scroll-blur behaviors, removed Changes
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
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.
Actionable comments posted: 4
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (2)
components/Navbar.tsx(4 hunks)package.json(2 hunks)
🔇 Additional comments (5)
package.json (3)
22-22: Clarify @tailwindcss/typography status: summary vs. code mismatch.The AI summary states that
@tailwindcss/typographywas "removed from devDependencies," but line 22 shows it still present. Please clarify whether this dependency is being removed, retained, or modified. If removed, verify that no components depend on typography utilities.
22-22: No action required—@tailwindcss/typography is retained.The package is not being removed; it remains in the dependency list. The codebase uses prose utilities from this package across three pages (terms.tsx, privacy.tsx, blog/[id].tsx), and all dependencies are satisfied by keeping the package.
12-12: @calcom/embed-react@1.5.3 verified as compatible and secure.@calcom/embed-react v1.5.3 is generally compatible with Next.js 14.2.30 and has no known direct security vulnerabilities. The package has peer dependencies pinned to React 18.2, which is compatible with Next.js 14.x. No action required.
components/Navbar.tsx (2)
1-8: LGTM! New imports are appropriate.The added imports (useEffect, Plus, getCalApi, Image) are all utilized in the implementation and are appropriate for the Cal.com booking integration.
87-87: No action needed—the logo image path is valid.The hardcoded path
/images/logo.pngcorrectly references the existing file atpublic/images/logo.png. The image will load without issues.Likely an incorrect or invalid review comment.
components/Navbar.tsx
Outdated
| useEffect(() => { | ||
| (async function () { | ||
| const cal = await getCalApi({ "namespace": "30min" }); | ||
| cal("ui", { "hideEventTypeDetails": true, "layout": "month_view" }); | ||
| })(); | ||
| }, []) |
There was a problem hiding this comment.
Fix configuration inconsistency and add error handling.
Two critical issues here:
-
Configuration conflict: Line 37 sets
hideEventTypeDetails: true, but both the desktop (line 83) and mobile (line 128) booking buttons set it tofalse. This inconsistency could cause unexpected behavior in the Cal.com widget. -
Missing error handling: If
getCalApifails, the booking functionality will silently break with no user feedback or fallback.
Apply this diff to resolve both issues:
useEffect(() => {
(async function () {
- const cal = await getCalApi({ "namespace": "30min" });
- cal("ui", { "hideEventTypeDetails": true, "layout": "month_view" });
+ try {
+ const cal = await getCalApi({ "namespace": "30min" });
+ cal("ui", { "hideEventTypeDetails": false, "layout": "month_view" });
+ } catch (error) {
+ console.error("Failed to initialize Cal.com:", error);
+ }
})();
- }, [])
+ }, []);🤖 Prompt for AI Agents
In components/Navbar.tsx around lines 34-39, the Cal.com init lacks error
handling and its hideEventTypeDetails value conflicts with booking buttons; wrap
the async IIFE in a try/catch, await getCalApi inside the try, check the
returned cal before calling it, change hideEventTypeDetails to false to match
desktop/mobile buttons, and in the catch log the error (console.error or
existing logger) and optionally set a local state flag to disable booking
actions or show a user-facing fallback message.
- Add official Slack icon from lucide-react to all community links - Update HeroSection.tsx with 20px Slack icon on CTA button - Update CTASection.tsx with 20px Slack icon on secondary CTA - Update Navbar.tsx with 18px Slack icon on navigation link - Implement proper ARIA attributes (aria-label, aria-hidden) for accessibility - Document icon usage conventions in .github/copilot-instructions.md Enhances visual recognition and professional polish across all Slack community touchpoints. Uses existing lucide-react dependency with zero bundle size increase. All components maintain theme compatibility and responsive behavior. Technical details: - Icon sizes: 20px for buttons, 18px for nav links - Spacing: gap-2 (8px) between icon and text - Accessibility: Screen readers announce 'Join our Slack community' - Theme support: Icons use currentColor for auto light/dark adaptation - Build verified: TypeScript + ESLint pass, production build successful
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
components/Navbar.tsx (1)
48-50: Keep the Cal.com UI config consistent with the button config.
Line 49 initializes Cal withhideEventTypeDetails: true, but Lines 24-27 defineCAL_CONFIGwithhideEventTypeDetails: false. This conflicting pair leads to unpredictable widget behavior. Align both paths on the same value (reusingCAL_CONFIGwould be even better) so the UI state is deterministic.- const cal = await getCalApi({ "namespace": "30min" }); - cal("ui", { "hideEventTypeDetails": true, "layout": "month_view" }); + const cal = await getCalApi({ namespace: "30min" }); + cal("ui", { hideEventTypeDetails: false, layout: "month_view" });
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
components/CTASection.tsx(2 hunks)components/HeroSection.tsx(2 hunks)components/Navbar.tsx(5 hunks)
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
components/Navbar.tsx (1)
54-55: Align Cal UI config with button configWe initialise the Cal UI with
hideEventTypeDetails: true, but every button requestshideEventTypeDetails: false. The conflict makes the embed behave inconsistently. Please keep the init value in sync with the per-button config.- const cal = await getCalApi({ "namespace": "30min" }); - cal("ui", { "hideEventTypeDetails": true, "layout": "month_view" }); + const cal = await getCalApi({ namespace: "30min" }); + cal("ui", { hideEventTypeDetails: false, layout: "month_view" });
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
components/FeatureCard.tsx(2 hunks)components/FeaturesSection.tsx(2 hunks)components/Navbar.tsx(8 hunks)components/PersonCard.tsx(1 hunks)pages/about.tsx(1 hunks)styles/globals.css(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pages/about.tsx (1)
components/PersonCard.tsx (1)
Contributor(3-11)
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
components/Navbar.tsx (2)
23-26: Still not preventing broken booking UI when env var is missing.While environment variable validation was added, the booking buttons (lines 168 and 215) still render with
data-cal-link={undefined}whenNEXT_PUBLIC_CAL_DATA_LINKis not set. Users will see a "Book a Call" button that doesn't work.Past reviews requested conditionally rendering the buttons based on whether
calLinkis present. Consider implementing the suggestedisCalReadypattern from previous feedback.
51-60: Fix configuration inconsistency and guard initialization.Three issues here:
Configuration mismatch: Line 55 sets
hideEventTypeDetails: true, butCAL_CONFIG(line 29) sets it tofalse. Choose one value and use it consistently.Missing guard: The initialization runs even when
calLinkis undefined. Add a check similar to the pattern suggested in previous reviews.Minor syntax: Missing semicolon after the closing bracket on line 60.
Apply this diff to address all issues:
useEffect(() => { + if (!calLink) { + return; + } (async function () { try{ const cal = await getCalApi({ "namespace": "30min" }); - cal("ui", { "hideEventTypeDetails": true, "layout": "month_view" }); + cal("ui", { "hideEventTypeDetails": false, "layout": "month_view" }); }catch(error){ console.error("Failed to initialize Cal.com:", error); } })(); - }, []) + }, [calLink]);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
components/Navbar.tsx(5 hunks)
🔇 Additional comments (4)
components/Navbar.tsx (4)
5-5: LGTM: Imports are correctly added.The new imports (Plus icon, getCalApi, and Image) are properly used within the component for the Cal.com booking integration and UI enhancements.
Also applies to: 9-10
88-112: Duplicate detection - see comment on lines 63-86.These useEffect blocks are duplicated from lines 63-86. Keep these and remove the earlier duplicates.
164-177: Desktop booking button implementation looks good.The button uses semantic HTML, includes the extracted
CAL_CONFIG_STRING, and has an engaging hover animation. The accessibility is adequate with a clear label.The issue of rendering when
calLinkis undefined was already flagged in the comment on lines 23-26.
215-217: Mobile booking button correctly uses semantic HTML.Good work using a
buttonelement instead of adiv(as flagged in previous reviews). The implementation is clean and uses the extractedCAL_CONFIG_STRING.The
calLinkundefined issue was already flagged earlier.
| useEffect(() => { | ||
| const sections = document.querySelectorAll("section[id]"); | ||
| const observer = new IntersectionObserver( | ||
| (entries) => { | ||
| entries.forEach((entry) => { | ||
| if (entry.isIntersecting) { | ||
| setActiveSection(entry.target.id); | ||
| } | ||
| }); | ||
| }, | ||
| { rootMargin: "-50% 0px -50% 0px" } | ||
| ); | ||
|
|
||
| sections.forEach((section) => observer.observe(section)); | ||
| return () => sections.forEach((section) => observer.unobserve(section)); | ||
| }, []); | ||
|
|
||
| // Blur effect on scroll | ||
| useEffect(() => { | ||
| const handleScroll = () => setScrolled(window.scrollY > 20); | ||
| handleScroll(); | ||
| window.addEventListener("scroll", handleScroll); | ||
| return () => window.removeEventListener("scroll", handleScroll); | ||
| }, []); |
There was a problem hiding this comment.
Remove duplicate scroll handling logic.
Lines 63-86 are completely duplicated at lines 88-112. This creates two IntersectionObservers and two scroll event listeners doing identical work, causing unnecessary performance overhead and potential race conditions in state updates.
Apply this diff to remove the duplication:
- // Highlight active section on scroll
- useEffect(() => {
- const sections = document.querySelectorAll("section[id]");
- const observer = new IntersectionObserver(
- (entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting) {
- setActiveSection(entry.target.id);
- }
- });
- },
- { rootMargin: "-50% 0px -50% 0px" }
- );
-
- sections.forEach((section) => observer.observe(section));
- return () => sections.forEach((section) => observer.unobserve(section));
- }, []);
-
- // Blur effect on scroll
- useEffect(() => {
- const handleScroll = () => setScrolled(window.scrollY > 20);
- handleScroll();
- window.addEventListener("scroll", handleScroll);
- return () => window.removeEventListener("scroll", handleScroll);
- }, []);
-🤖 Prompt for AI Agents
In components/Navbar.tsx around lines 63-86, the scroll/section-observer logic
is duplicated (again at 88-112); remove the duplicated block so only one
useEffect creates the IntersectionObserver and one useEffect handles the scroll
blur, and ensure both effects correctly add and clean up their respective
observers/listeners (observer.observe/observer.unobserve and
window.addEventListener/removeEventListener) to avoid double observers/listeners
and redundant state updates.
There was a problem hiding this comment.
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)
components/Navbar.tsx (1)
93-117: Remove duplicate useEffect hooks immediately.Lines 93-117 duplicate the useEffect logic from lines 67-91, creating two IntersectionObservers and two scroll event listeners that both update the same state variables (
activeSectionandscrolled). This causes unnecessary performance overhead and potential race conditions.Apply this diff to remove the duplication:
- // Highlight active section on scroll - useEffect(() => { - const sections = document.querySelectorAll("section[id]"); - const observer = new IntersectionObserver( - (entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - setActiveSection(entry.target.id); - } - }); - }, - { rootMargin: "-50% 0px -50% 0px" } - ); - - sections.forEach((section) => observer.observe(section)); - return () => sections.forEach((section) => observer.unobserve(section)); - }, []); - - // Blur effect on scroll - useEffect(() => { - const handleScroll = () => setScrolled(window.scrollY > 20); - handleScroll(); - window.addEventListener("scroll", handleScroll); - return () => window.removeEventListener("scroll", handleScroll); - }, []); -
♻️ Duplicate comments (1)
components/Navbar.tsx (1)
169-182: Conditionally render desktop booking button based on isCalReady.The desktop "Book a Call" button is always rendered, even when
NEXT_PUBLIC_CAL_DATA_LINKis missing. This leaves users with a non-functional CTA. The mobile booking button (lines 223-229) is correctly gated withisCalReady— apply the same pattern here.Apply this diff to conditionally render the desktop booking button:
</Link> {/* Contact Us button */} - <button className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 - duration-200 - flex items-center gap-2 flex-shrink-0 - transition-all group" - data-cal-namespace="30min" data-cal-link={calLink} data-cal-config={CAL_CONFIG_STRING}> - <div className="flex items-center gap-2 group-hover:gap-8 transition-all duration-300 relative"> - <Image src={'/images/logo.png'} width={28} height={28} alt="logo" className="rounded-full bg-white flex-shrink-0"></Image> - <div className="flex items-center gap-0 absolute left-[28px] transform -translate-x-full opacity-0 group-hover:translate-x-0 group-hover:opacity-100 transition-all duration-300"> - <div className="w-5 h-5 rounded-full flex items-center justify-center text-[10px] ml-1 mr-1"><Plus width={20} height={20}></Plus></div> - <div className="w-7 h-7 rounded-full dark:bg-white/10 bg-white/20 flex items-center justify-center text-[10px] ml-1 mr-1">You</div> - </div> - <span className="whitespace-nowrap relative block text-base font-bold ml-0 group-hover:ml-10 transition-all duration-300">Book a Call</span> - </div> - </button> + {isCalReady && ( + <button className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 + duration-200 + flex items-center gap-2 flex-shrink-0 + transition-all group" + data-cal-namespace="30min" data-cal-link={calLink} data-cal-config={CAL_CONFIG_STRING}> + <div className="flex items-center gap-2 group-hover:gap-8 transition-all duration-300 relative"> + <Image src={'/images/logo.png'} width={28} height={28} alt="logo" className="rounded-full bg-white flex-shrink-0"></Image> + <div className="flex items-center gap-0 absolute left-[28px] transform -translate-x-full opacity-0 group-hover:translate-x-0 group-hover:opacity-100 transition-all duration-300"> + <div className="w-5 h-5 rounded-full flex items-center justify-center text-[10px] ml-1 mr-1"><Plus width={20} height={20}></Plus></div> + <div className="w-7 h-7 rounded-full dark:bg-white/10 bg-white/20 flex items-center justify-center text-[10px] ml-1 mr-1">You</div> + </div> + <span className="whitespace-nowrap relative block text-base font-bold ml-0 group-hover:ml-10 transition-all duration-300">Book a Call</span> + </div> + </button> + )} <ThemeToggle />
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
components/Navbar.tsx(5 hunks)
🔇 Additional comments (3)
components/Navbar.tsx (3)
23-35: Environment validation and config extraction look good.The environment variable validation with trimming and readiness checks, along with the extracted
CAL_CONFIGconstant, properly address previous review concerns. The configuration is now centralized and consistently applied.
53-65: Cal.com initialization properly implemented with guards and error handling.The initialization correctly checks
isCalReadybefore proceeding, includes try-catch for graceful failure, and has the proper dependency array. This addresses previous review feedback effectively.
223-229: Mobile booking button properly guarded.The mobile "Book A Call" button is correctly wrapped in the
isCalReadycheck, preventing a non-functional CTA from appearing when the environment variable is missing. This is the correct pattern.
Issue Reference
SEE (#59 )
What Was Changed
Why Was It Changed
To streamline the booking process and reduce friction. The new system allows instant meeting scheduling with real-time availability, eliminating back-and-forth emails and improving user experience.
Screenshots
cursorful-video-1761669353660.1.mp4
Note
In the Env file an new environment needs to be create under this name NEXT_PUBLIC_CAL_DATA_LINK and the value for this env variable is
data-cal-link="manish-test-i3/30minthis value can be found in the cal embed code just setNEXT_PUBLIC_CAL_DATA_LINK=manish-test-i3/30minAdditional Context (Optional)
data-cal-namespace="30min"for 30-minute meeting slotsNEXT_PUBLIC_CAL_DATA_LINKused for booking link configurationSummary by CodeRabbit