Skip to content

Conversation

@amandollar
Copy link

@amandollar amandollar commented Nov 4, 2025

Problem

Users need a way to dismiss the announcement banner when they don't want to see it anymore.

Solution

Added a cross button in the top-right corner that allows users to close the banner, with state persistence across page refreshes.

Key Changes

  • Added Cross icon component
  • Implemented close button UI in top-right corner
  • Added visibility state management
  • Implemented localStorage persistence for user preference

Testing Done

  • Verified banner stays hidden after refresh when closed
  • Confirmed no content flash occurs
  • Tested in development and production builds
  • Verified SSR compatibility
  • Tested on multiple browsers (Chrome, Firefox, Safari, Edge)
  • Checked mobile responsiveness

Performance Impact

✅ Eliminates layout shift (CLS improvement)
✅ Reduces unnecessary re-renders
✅ Optimizes component mount behavior

Screenshots/Videos

| Before | After |
image

image

Files Changed

  • components/campaigns/AnnouncementHero.tsx

Review Focus

  • State initialization
  • SSR handling
  • Loading states

Relates to #4534

Summary by CodeRabbit

  • New Features
    • Added a close/dismiss control on the announcement banner so users can hide it.
    • Banner visibility preference is persisted and remembered on return visits.
    • Banner waits for initial load and won’t show until ready, preventing flicker.
    • Only the currently active banner is rendered, improving clarity.
    • Existing navigation and auto-rotation behavior remain intact.

@netlify
Copy link

netlify bot commented Nov 4, 2025

Deploy Preview for asyncapi-website ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 34dfaf9
🔍 Latest deploy log https://app.netlify.com/projects/asyncapi-website/deploys/690a48acfdb8a400087cf1f3
😎 Deploy Preview https://deploy-preview-4536--asyncapi-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

Added a dismissible announcement banner to AnnouncementHero: visibility tracked with isLoading/isVisible, initial visibility read client-side from localStorage, persisted on change, rendering gated when hidden or loading, and a Close (Cross) button dismisses the banner. (47 words)

Changes

Cohort / File(s) Change Summary
Announcement Banner Dismiss Feature
components/campaigns/AnnouncementHero.tsx
Imported Cross icon; added isLoading and isVisible state with initial value read from localStorage (client-only); added effects to initialize loading and persist isVisible; computed visibleBanners with empty deps; introduced isActiveBanner per-index rendering (only active banner rendered); render guarded by isLoading, no visible banners, or isVisible false; added Close button to set isVisible=false; minor className literal adjustments.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Component as AnnouncementHero
    participant Storage as localStorage

    User->>Component: mount
    Component->>Storage: read `isVisible` (client-only)
    Storage-->>Component: visibility value (or undefined)
    Component->>Component: set isVisible (default true), set isLoading = false
    alt isLoading = false AND isVisible = true AND visibleBanners exist
        Component->>User: render active banner
    else
        Component-->>User: no banner shown
    end

    User->>Component: click Close (Cross)
    Component->>Component: set isVisible = false
    Component->>Storage: persist `isVisible = false`
    Component->>User: re-render (banner hidden)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Focused changes in a single component.
  • Check: localStorage key and JSON parsing, SSR-safe client-only read, effect dependency correctness, ARIA/keyboard accessibility of close control, and that active-banner rendering preserves rotation/navigation behavior.

Possibly related issues

Possibly related PRs

Suggested labels

ready-to-merge

Suggested reviewers

  • derberg
  • akshatnema
  • sambhavgupta0705
  • anshgoyalevil
  • vishvamsinh28
  • devilkiller-ag
  • Mayaleeeee

Poem

🐰 A banner hopped across my view,
I tapped the Cross — it bid adieu.
localStorage keeps the tale,
one tiny click, the banner’s pale,
Hops and bytes — dismissed anew.

Pre-merge checks and finishing touches

✅ 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 mentions adding a dismissable/close button to a promotional banner, which directly aligns with the main change in the PR: adding visibility state management and a close button to AnnouncementHero component.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@asyncapi-bot
Copy link
Contributor

asyncapi-bot commented Nov 4, 2025

⚡️ Lighthouse report for the changes in this PR:

Category Score
🔴 Performance 14
🟢 Accessibility 98
🟢 Best practices 92
🟢 SEO 100
🔴 PWA 33

Lighthouse ran on https://deploy-preview-4536--asyncapi-website.netlify.app/

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

Caution

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

⚠️ Outside diff range comments (2)
components/campaigns/AnnouncementHero.tsx (2)

103-124: Variable shadowing detected: local isVisible shadows state variable.

Line 105 declares a local isVisible constant that shadows the component's state variable of the same name. This causes linting errors and makes the code confusing.

Rename the local variable to avoid shadowing:

             {visibleBanners.map((banner, index) => {
               // Only render the active banner
-              const isVisible = index === activeIndex;
+              const isActive = index === activeIndex;

-              if (!isVisible) return null;
+              if (!isActive) return null;

               return (
                 <Banner
                   key={index}
                   title={banner.title}
                   dateLocation={banner.dateLocation}
                   cfaText={banner.cfaText}
                   eventName={banner.eventName}
                   cfpDeadline={banner.cfpDeadline}
                   link={banner.link}
                   city={banner.city}
-                  activeBanner={isVisible}
+                  activeBanner={isActive}
                   className={className}
                   small={small}
                 />
               );
             })}

1-150: Address pipeline linting and formatting failures.

The GitHub Actions pipeline reports multiple ESLint and Prettier violations including no-shadow (addressed in separate comment), prettier/prettier, comma-dangle, jsx-quotes, and others.

Run the following to auto-fix most formatting issues:

npm run format
# or
npm run lint:fix

Then commit the formatting changes.

🧹 Nitpick comments (1)
components/campaigns/AnnouncementHero.tsx (1)

46-49: Consider removing unnecessary dependency from useMemo.

The banners import is a static constant, so including it in the dependency array is unnecessary. The filter will only need to recompute based on time changes (for shouldShowBanner), which aren't tracked here anyway.

You can simplify to:

   const visibleBanners = useMemo(
     () => banners.filter((banner) => shouldShowBanner(banner.cfpDeadline)),
-    [banners],
+    [],
   );

Note: This won't trigger on time changes, so if you need dynamic updates based on deadline expiry, consider adding a timer or removing memoization entirely.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4bdd8b and c546030.

📒 Files selected for processing (2)
  • components/campaigns/AnnouncementHero.tsx (4 hunks)
  • next-env.d.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-01-18T08:44:43.614Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3423
File: tests/index.test.js:2-7
Timestamp: 2025-01-18T08:44:43.614Z
Learning: In the AsyncAPI website project, JavaScript test files must include the .ts extension when importing TypeScript files (e.g., `require('../scripts/build-rss.ts')`). This is enforced by the project's configuration which uses `moduleResolution: "bundler"` in tsconfig.json and TypeScript-aware ESLint plugins. The .ts extensions are required even though the files are imported using CommonJS require statements.

Applied to files:

  • next-env.d.ts
📚 Learning: 2025-04-20T16:05:16.482Z
Learnt from: anshgoyalevil
Repo: asyncapi/website PR: 3950
File: scripts/utils/check-locales.ts:122-129
Timestamp: 2025-04-20T16:05:16.482Z
Learning: In the AsyncAPI website project, Next.js throws errors at runtime when locale files are missing, making additional validation for missing files unnecessary in the check-locales script.

Applied to files:

  • next-env.d.ts
📚 Learning: 2024-10-11T10:46:58.882Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/Avatar.tsx:35-44
Timestamp: 2024-10-11T10:46:58.882Z
Learning: In Next.js, when avoiding nested `<a>` tags due to hydration issues, use accessible non-link elements like `<button>` or `<span>` with appropriate roles, `tabIndex`, and event handlers to maintain accessibility and SEO.

Applied to files:

  • components/campaigns/AnnouncementHero.tsx
🧬 Code graph analysis (1)
components/campaigns/AnnouncementHero.tsx (2)
components/campaigns/banners.ts (2)
  • banners (18-46)
  • shouldShowBanner (6-16)
components/icons/Cross.tsx (1)
  • Cross (8-22)
🪛 GitHub Actions: PR testing - if Node project
components/campaigns/AnnouncementHero.tsx

[error] 1-105: Linting/formatting errors detected in AnnouncementHero.tsx: multiple prettier/prettier, comma-dangle, newline-after-var, padding-line-between-statements, jsx-quotes, no-shadow, and related ESLint/Prettier issues.

⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Redirect rules - asyncapi-website
  • GitHub Check: Header rules - asyncapi-website
  • GitHub Check: Pages changed - asyncapi-website
  • GitHub Check: Lighthouse CI
🔇 Additional comments (4)
next-env.d.ts (1)

1-6: LGTM! Standard Next.js auto-generated file.

This is the standard Next.js TypeScript declaration file. It's auto-generated and follows Next.js conventions correctly.

components/campaigns/AnnouncementHero.tsx (3)

5-5: LGTM! Cross icon import added for close button.

The import is correctly added to support the new close button functionality.


36-44: Good use of isLoading guard in localStorage persistence.

The isLoading guard correctly prevents writing to localStorage during initial mount, avoiding unnecessary writes.


79-81: Verify that isLoading pattern doesn't cause layout shift.

The component returns null while isLoading is true, then renders after mount. This could cause Cumulative Layout Shift (CLS) when the banner suddenly appears, contrary to the PR's claim that it "eliminates layout shift."

Consider testing the CLS impact in production. If layout shift is occurring, you might need a placeholder or skeleton during the loading state instead of returning null.

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

Caution

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

⚠️ Outside diff range comments (1)
components/campaigns/AnnouncementHero.tsx (1)

103-124: Fix variable shadowing of isVisible.

The local variable isVisible (line 105) shadows the state variable isVisible (line 28), making the code confusing and triggering an ESLint error.

Apply this diff to rename the local variable:

             {visibleBanners.map((banner, index) => {
               // Only render the active banner
-              const isVisible = index === activeIndex;
+              const isActive = index === activeIndex;

-              if (!isVisible) return null;
+              if (!isActive) return null;

               return (
                 <Banner
                   key={index}
                   title={banner.title}
                   dateLocation={banner.dateLocation}
                   cfaText={banner.cfaText}
                   eventName={banner.eventName}
                   cfpDeadline={banner.cfpDeadline}
                   link={banner.link}
                   city={banner.city}
-                  activeBanner={isVisible}
+                  activeBanner={isActive}
                   className={className}
                   small={small}
                 />
               );
             })}
🧹 Nitpick comments (1)
components/campaigns/AnnouncementHero.tsx (1)

30-30: Consider extracting localStorage key to a constant.

The localStorage key 'announcementBannerVisible' is hard-coded in multiple places. Extracting it to a constant improves maintainability.

Add at the top of the file:

const BANNER_VISIBILITY_KEY = 'announcementBannerVisible';

Then use it:

const stored = localStorage.getItem(BANNER_VISIBILITY_KEY);
// ...
localStorage.setItem(BANNER_VISIBILITY_KEY, isVisible.toString());

Also applies to: 42-42

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4bdd8b and b0d6e22.

📒 Files selected for processing (1)
  • components/campaigns/AnnouncementHero.tsx (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-10-11T10:46:58.882Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/Avatar.tsx:35-44
Timestamp: 2024-10-11T10:46:58.882Z
Learning: In Next.js, when avoiding nested `<a>` tags due to hydration issues, use accessible non-link elements like `<button>` or `<span>` with appropriate roles, `tabIndex`, and event handlers to maintain accessibility and SEO.

Applied to files:

  • components/campaigns/AnnouncementHero.tsx
🧬 Code graph analysis (1)
components/campaigns/AnnouncementHero.tsx (3)
components/campaigns/banners.ts (2)
  • banners (18-46)
  • shouldShowBanner (6-16)
components/icons/ArrowLeft.tsx (1)
  • ArrowLeft (7-17)
components/icons/Cross.tsx (1)
  • Cross (8-22)
🪛 GitHub Actions: PR testing - if Node project
components/campaigns/AnnouncementHero.tsx

[error] 22-24: Prettier formatting issue: Replace ⏎··className·=·'',⏎··small·=·false,⏎ with ·className·=·'',·small·=·false·


[error] 24-24: Prettier: Unexpected trailing comma. comma-dangle


[error] 30-30: ESLint: Expected blank line after variable declarations. newline-after-var


[error] 31-31: ESLint: Expected blank line before this statement. padding-line-between-statements


[error] 33-33: ESLint: Expected blank line before this statement. padding-line-between-statements


[error] 46-46: Prettier: Replace ⏎····()·=>·banners.filter((banner)·=>·shouldShowBanner(banner.cfpDeadline)),⏎····[banners],⏎·· with ()·=>·banners.filter((banner)·=>·shouldShowBanner(banner.cfpDeadline)),·[banners]


[warning] 48-48: React Hook: useMemo has an unnecessary dependency: 'banners'.


[error] 48-48: Prettier: Unexpected trailing comma. comma-dangle


[error] 53-53: Prettier: Replace ⏎······prevIndex·===·0·?·numberOfVisibleBanners·-·1·:·prevIndex·-·1,⏎···· with ·(prevIndex·===·0·?·numberOfVisibleBanners·-·1·:·prevIndex·-·1)


[error] 54-54: Prettier: Unexpected trailing comma. comma-dangle


[error] 59-59: Prettier: Replace ⏎······prevIndex·===·numberOfVisibleBanners·-·1·?·0·:·prevIndex·+·1,⏎···· with ·(prevIndex·===·numberOfVisibleBanners·-·1·?·0·:·prevIndex·+·1)


[error] 60-60: Prettier: Unexpected trailing comma. comma-dangle


[error] 69-69: Prettier: Replace ()=>setActiveIndex((index)=> (index+1) % numberOfVisibleBanners),⏎······10000,⏎···· with ()=>setActiveIndex((index)=> (index+1) % numberOfVisibleBanners),·10000


[error] 71-71: Prettier: Unexpected trailing comma. comma-dangle


[error] 84-84: Prettier: Replace "section" padding="" className="text-center" with 'section' padding='' className='text-center'


[error] 84-84: Prettier: Unexpected usage of doublequote. jsx-quotes


[error] 85-85: Prettier: Replace "relative·flex·flex-row·items-center·justify-center·overflow-x-hidden·md:gap-4" with 'relative·flex·flex-row·items-center·justify-center·overflow-x-hidden·md:gap-4'


[error] 85-85: Prettier: Unexpected usage of doublequote. jsx-quotes


[error] 92-92: Prettier: Replace "text-white" with 'text-white'


[error] 92-92: Prettier: Unexpected usage of doublequote. jsx-quotes


[error] 95-95: Prettier: Replace "relative·flex·w-4/5·md:w-5/6·flex-col·items-center·justify-center·gap-2" with 'relative·flex·w-4/5·md:w-5/6·flex-col·items-center·justify-center·gap-2'


[error] 95-95: Prettier: Unexpected usage of doublequote. jsx-quotes


[error] 96-96: Prettier: Replace "relative·flex·min-h-72·w-full·justify-center·overflow-hidden·lg:h-[17rem]·lg:w-[38rem]" with 'relative·flex·min-h-72·w-full·justify-center·overflow-hidden·lg:h-[17rem]·lg:w-[38rem]'


[error] 96-96: Prettier: Unexpected usage of doublequote. jsx-quotes


[error] 98-98: Prettier: Replace "absolute·right-2·top-6·z-20·cursor-pointer·p-2·hover:opacity-70" with 'absolute·right-2·top-6·z-20·cursor-pointer·p-2·hover:opacity-70'


[error] 98-98: Prettier: Unexpected usage of doublequote. jsx-quotes


[error] 105-105: ESLint: No shadowing of variable 'isVisible' in outer scope.


[error] 126-126: Prettier: Replace "m-auto·flex·justify-center" with 'm-auto·flex·justify-center'


[error] 126-126: Prettier: Unexpected usage of doublequote. jsx-quotes


[error] 144-144: Prettier: Replace "text-white" with 'text-white'


[error] 144-144: Prettier: Unexpected usage of doublequote. jsx-quotes

🔇 Additional comments (4)
components/campaigns/AnnouncementHero.tsx (4)

5-5: LGTM!

The Cross icon import is correctly added and used in the close button implementation.


52-66: Navigation logic is correct.

The cycling behavior correctly wraps around at boundaries for both previous and next navigation.


79-81: Conditional rendering logic is correct.

The addition of !isVisible check properly prevents rendering when the banner is dismissed.


22-25: Verify formatting violations in your local environment before proceeding.

The suggested commands could not be fully validated in the sandbox environment. However, examining the file directly shows the code appears properly formatted with:

  • Single quotes used consistently
  • Proper spacing and structure
  • No obvious trailing commas or formatting issues

To confirm whether violations actually exist:

  1. Run npm run lint in your local environment to identify any real violations
  2. If violations are found, run npm run lint:fix (the correct script for this project) to auto-fix them

Note: npm run format does not exist in this project's scripts. Use npm run lint:fix instead.

@codecov
Copy link

codecov bot commented Nov 4, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (b4bdd8b) to head (34dfaf9).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #4536   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           22        22           
  Lines          780       780           
  Branches       144       144           
=========================================
  Hits           780       780           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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 (2)
components/campaigns/AnnouncementHero.tsx (2)

24-57: State management correctly prevents hydration mismatches.

The implementation properly avoids SSR/client hydration issues by:

  • Rendering null during SSR and initial client render (via isLoading)
  • Reading localStorage only after mount in the first effect
  • Persisting changes only after the initial read completes

However, the logic is complex with two interdependent effects. Consider simplifying:

-  const [isLoading, setIsLoading] = useState(true);
-
-  // Start with a stable server-friendly default. Defer reading localStorage until after mount
   const [isVisible, setIsVisible] = useState(true);
+  const [isHydrated, setIsHydrated] = useState(false);

-  // Read persisted preference from localStorage on mount (client-only)
   useEffect(() => {
     try {
       const stored = localStorage.getItem('announcementBannerVisible');
-
-      if (stored == null) {
-        // no persisted preference
-      } else {
-        const val = stored === 'true';
-
-        setIsVisible((prev) => (prev === val ? prev : val));
+      if (stored !== null) {
+        setIsVisible(stored === 'true');
       }
     } catch (e) {
       // ignore localStorage errors
     } finally {
-      setIsLoading(false);
+      setIsHydrated(true);
     }
   }, []);

-  // Persist visibility changes after initial mount to avoid SSR/client divergence
   useEffect(() => {
-    if (!isLoading) {
+    if (isHydrated) {
       try {
         localStorage.setItem('announcementBannerVisible', isVisible.toString());
       } catch (e) {
         // ignore write errors
       }
     }
-  }, [isVisible, isLoading]);
+  }, [isVisible, isHydrated]);

Then update line 82:

-  if (isLoading || numberOfVisibleBanners === 0 || !isVisible) {
+  if (!isHydrated || numberOfVisibleBanners === 0 || !isVisible) {

This is clearer: isHydrated explicitly communicates "client-side initialization complete" rather than the double-negative !isLoading. The conditional setState optimization on line 39 can also be removed since React batches updates efficiently.


99-106: Consider defensive button styling.

The button correctly uses semantic HTML and has proper accessibility attributes. However, it might benefit from explicit style resets to ensure consistent rendering across browsers:

   <button
     type='button'
-    className='absolute right-2 top-6 z-20 p-2 hover:opacity-70'
+    className='absolute right-2 top-6 z-20 border-0 bg-transparent p-2 hover:opacity-70'
     onClick={() => setIsVisible(false)}
     aria-label='Close announcement'
   >

Adding border-0 bg-transparent explicitly removes default button styling, though Tailwind's reset likely already handles this.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ddd87b9 and 34dfaf9.

📒 Files selected for processing (1)
  • components/campaigns/AnnouncementHero.tsx (6 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2024-10-11T11:32:30.226Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/navigation/BlogPostItem.tsx:95-119
Timestamp: 2024-10-11T11:32:30.226Z
Learning: In the `BlogPostItem` component (`components/navigation/BlogPostItem.tsx`), nesting `<a>` tags inside the parent `Link` component leads to hydration issues; therefore, we should avoid nesting `<a>` tags inside `Link` components in this component.

Applied to files:

  • components/campaigns/AnnouncementHero.tsx
📚 Learning: 2024-10-11T07:38:35.745Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/newsroom/FeaturedBlogPost.tsx:90-92
Timestamp: 2024-10-11T07:38:35.745Z
Learning: In Next.js, nested `<a>` tags cause hydration issues due to invalid HTML. To fix this, avoid nesting `<a>` tags by replacing inner `<a>` tags with non-interactive elements like `<span>`, and use click handlers to maintain interactivity if needed.

Applied to files:

  • components/campaigns/AnnouncementHero.tsx
📚 Learning: 2024-10-11T10:46:58.882Z
Learnt from: akshatnema
Repo: asyncapi/website PR: 3262
File: components/Avatar.tsx:35-44
Timestamp: 2024-10-11T10:46:58.882Z
Learning: In Next.js, when avoiding nested `<a>` tags due to hydration issues, use accessible non-link elements like `<button>` or `<span>` with appropriate roles, `tabIndex`, and event handlers to maintain accessibility and SEO.

Applied to files:

  • components/campaigns/AnnouncementHero.tsx
🧬 Code graph analysis (1)
components/campaigns/AnnouncementHero.tsx (2)
components/campaigns/banners.ts (2)
  • banners (18-46)
  • shouldShowBanner (6-16)
components/icons/Cross.tsx (1)
  • Cross (8-22)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test NodeJS PR - windows-latest
🔇 Additional comments (3)
components/campaigns/AnnouncementHero.tsx (3)

59-59: Empty dependency array is correct.

The empty dependency array is appropriate since banners is a static import. Note that this means visibleBanners is computed once on mount, so banners won't disappear mid-session if a deadline passes—only on page refresh. This is acceptable UX for promotional content.


107-128: Banner rendering logic is correct.

The early return pattern efficiently renders only the active banner. Note that activeBanner={isActiveBanner} always passes true since we return null for inactive banners. This is likely intentional—the Banner component may use this prop for animations or transitions.


82-84: Early return correctly prevents hydration issues and flash.

The isLoading check ensures the component renders null during SSR and initial client render, preventing hydration mismatches while the localStorage preference is being read.

@amandollar
Copy link
Author

@asyncapi-bot @antoniogarrote @MikeRalphson @scharrier

Note: The macOS-13 runner is deprecated and causing brownout failures in this PR.
Updating the workflow to use macos-14 should fix this.

@amandollar amandollar changed the title feat: add close button to promotional banner #4534 feat: add dismissable button to promotional(confrence) banner #4534 Nov 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants