Skip to content

Refactor home page ads into a single file, add corner video ad#3601

Merged
evanpelle merged 1 commit intov30from
corner-video
Apr 6, 2026
Merged

Refactor home page ads into a single file, add corner video ad#3601
evanpelle merged 1 commit intov30from
corner-video

Conversation

@evanpelle
Copy link
Copy Markdown
Collaborator

@evanpelle evanpelle commented Apr 6, 2026

Description:

image

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Please put your Discord username so you can be contacted if a bug or regression is found:

evan

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 6, 2026

Walkthrough

The PR consolidates two separate ad-handling components (GutterAds and HomeFooterAd) into a single unified HomepagePromos component. The custom element tag in the HTML is updated from <gutter-ads> to <homepage-promos>, and references in Main.ts are updated accordingly. The new implementation handles both gutter and footer ads based on viewport conditions within one file.

Changes

Cohort / File(s) Summary
HTML template update
index.html
Custom element tag changed from <gutter-ads> to <homepage-promos> in the desktop top-level content area.
Component consolidation
src/client/HomepagePromos.ts
New unified file combining gutter and footer ad functionality. Exports FOOTER_AD_MIN_HEIGHT constant and defines HomepagePromos and HomeFooterAd custom elements with Playwire RAMP integration, viewport-based conditions, and lifecycle management.
Component migration
src/client/Main.ts
Updated ad element wiring: removed GutterAds lookup and validation, added HomepagePromos lookup; changed lifecycle cleanup to target "homepage-promos" instead of "gutter-ads"; removed HomeFooterAd import side-effect.
Component removal
src/client/GutterAds.ts, src/client/components/HomeFooterAd.ts
Removed two separate ad component files. GutterAds handled gutter ad rendering and RAMP.que integration; HomeFooterAd managed footer ad display based on viewport rules.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🎪 Two ad helpers danced apart,
Now they waltz as one smart heart—
Gutter, footer, side by side,
In HomepagePromos they reside! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is completely missing substantive content. It contains only unfilled template placeholders and unchecked checklist items with no details about the actual changes. Provide a clear description explaining what the PR does, why these changes were made, and complete the checklist items. Include the Discord username and describe the corner video feature changes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main changes: refactoring homepage ads into a single file and adding a corner video ad feature.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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.

Copy link
Copy Markdown
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

🧹 Nitpick comments (1)
src/client/Main.ts (1)

247-247: Rename gutterAds to homepageAds for clearer intent.

The current name reflects the old component and can confuse future changes.

Proposed refactor
-  private gutterAds: HomepageAds;
+  private homepageAds: HomepageAds;
...
-    const gutterAds = document.querySelector("homepage-ads");
-    if (!(gutterAds instanceof HomepageAds))
+    const homepageAds = document.querySelector("homepage-ads");
+    if (!(homepageAds instanceof HomepageAds))
       throw new Error("Missing homepage-ads");
-    this.gutterAds = gutterAds;
+    this.homepageAds = homepageAds;

Also applies to: 307-310

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/Main.ts` at line 247, Rename the private field gutterAds to
homepageAds to reflect the new component name: update the declaration "private
gutterAds: HomepageAds" to "private homepageAds: HomepageAds" and then rename
all references/usages of gutterAds (constructor assignments, methods, event
handlers, and any access at lines around the later usage block) to homepageAds;
ensure imports/types still reference HomepageAds and update any tests or view
bindings that reference the old name so compilation and runtime references are
consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/client/HomepageAds.ts`:
- Around line 61-69: close() currently only destroys gutter ads; update it to
also destroy the corner video and fully reset state so ads can be reloaded: call
the appropriate destroy on the corner_ad_video created in loadCornerAdVideo()
(and/or window.ramp.destroyUnits for its type), set this.corner_ad_video to
null, set this.adLoaded = false so loadGutterAds() can run again, and set
this.isVisible = false to mark the component hidden; keep destroying leftAdType
and rightAdType as before (leftAdType/rightAdType).
- Around line 195-207: Add a guard boolean to prevent duplicate footer ads: add
a class-level flag (e.g., footerAdLoaded or footerAdShown) and in
onUserMeResponse check that flag before setting this.shouldShow and queuing
this.loadAd() via this.updateComplete; if the flag is false, set it true when
you schedule/load the ad so subsequent userMeResponse events do nothing. Use the
same guard pattern as HomeFooterAd and reference onUserMeResponse,
this.updateComplete, this.loadAd, and this.shouldShow when making the change.
- Around line 33-45: The inline document.addEventListener("userMeResponse", ...)
in connectedCallback adds a handler that cannot be removed on disconnect;
extract that listener into a class property (e.g., this._onUserMeResponse) and
use it when adding the event in connectedCallback and removing it in
disconnectedCallback so handlers don't accumulate on reconnects; keep the
handler body calling this.show() and this.loadCornerAdVideo() conditionally on
window.adsEnabled (mirror HomeFooterAd's pattern) and ensure you reference the
same function identity for both addEventListener and removeEventListener.

---

Nitpick comments:
In `@src/client/Main.ts`:
- Line 247: Rename the private field gutterAds to homepageAds to reflect the new
component name: update the declaration "private gutterAds: HomepageAds" to
"private homepageAds: HomepageAds" and then rename all references/usages of
gutterAds (constructor assignments, methods, event handlers, and any access at
lines around the later usage block) to homepageAds; ensure imports/types still
reference HomepageAds and update any tests or view bindings that reference the
old name so compilation and runtime references are consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b09e7a6c-9951-4824-b016-0f56c8585197

📥 Commits

Reviewing files that changed from the base of the PR and between 10d02de and c5906b7.

📒 Files selected for processing (5)
  • index.html
  • src/client/GutterAds.ts
  • src/client/HomepageAds.ts
  • src/client/Main.ts
  • src/client/components/HomeFooterAd.ts
💤 Files with no reviewable changes (2)
  • src/client/components/HomeFooterAd.ts
  • src/client/GutterAds.ts

Comment thread src/client/HomepagePromos.ts Outdated
Comment on lines +33 to +45
connectedCallback() {
super.connectedCallback();
this.onResize();
window.addEventListener("resize", this.onResize);
document.addEventListener("userMeResponse", () => {
if (window.adsEnabled) {
console.log("showing homepage ads");
this.show();
this.loadCornerAdVideo();
} else {
console.log("not showing homepage ads");
}
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and get its size
wc -l src/client/HomepageAds.ts

Repository: openfrontio/OpenFrontIO

Length of output: 96


🏁 Script executed:

# Read the entire file to understand the structure
cat -n src/client/HomepageAds.ts

Repository: openfrontio/OpenFrontIO

Length of output: 8882


Extract userMeResponse handler to a class property so it can be removed in disconnectedCallback.

The current inline callback cannot be removed, so if the component reconnects, new handlers stack on top of old ones. Each reconnect re-runs show() and loadCornerAdVideo(), causing duplicate ad operations. See how HomeFooterAd (line 195) implements this correctly.

Proposed fix
export class HomepageAds extends LitElement {
  `@state`() private isVisible: boolean = false;
  `@state`() private adLoaded: boolean = false;
  `@state`() private hasFooterAd: boolean = false;

  private onResize = () => {
    const isDesktop = window.innerWidth >= 640;
    this.hasFooterAd = isDesktop && window.innerHeight >= FOOTER_AD_MIN_HEIGHT;
  };

+  private onUserMeResponse = () => {
+    if (!window.adsEnabled) return;
+    console.log("showing homepage ads");
+    this.show();
+    this.loadCornerAdVideo();
+  };

   connectedCallback() {
     super.connectedCallback();
     this.onResize();
     window.addEventListener("resize", this.onResize);
-    document.addEventListener("userMeResponse", () => {
-      if (window.adsEnabled) {
-        console.log("showing homepage ads");
-        this.show();
-        this.loadCornerAdVideo();
-      } else {
-        console.log("not showing homepage ads");
-      }
-    });
+    document.addEventListener("userMeResponse", this.onUserMeResponse);
   }

   disconnectedCallback() {
     super.disconnectedCallback();
     window.removeEventListener("resize", this.onResize);
+    document.removeEventListener("userMeResponse", this.onUserMeResponse);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/HomepageAds.ts` around lines 33 - 45, The inline
document.addEventListener("userMeResponse", ...) in connectedCallback adds a
handler that cannot be removed on disconnect; extract that listener into a class
property (e.g., this._onUserMeResponse) and use it when adding the event in
connectedCallback and removing it in disconnectedCallback so handlers don't
accumulate on reconnects; keep the handler body calling this.show() and
this.loadCornerAdVideo() conditionally on window.adsEnabled (mirror
HomeFooterAd's pattern) and ensure you reference the same function identity for
both addEventListener and removeEventListener.

Comment thread src/client/HomepagePromos.ts
Comment on lines +195 to +207
private onUserMeResponse = () => {
const isDesktop = window.innerWidth >= 640;
if (
!window.adsEnabled ||
(isDesktop && window.innerHeight < FOOTER_AD_MIN_HEIGHT)
) {
return;
}
this.shouldShow = true;
this.updateComplete.then(() => {
this.loadAd();
});
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the HomepageAds.ts file to understand the class structure
cat -n src/client/HomepageAds.ts | head -250

Repository: openfrontio/OpenFrontIO

Length of output: 8862


🏁 Script executed:

# Search for userMeResponse binding/registration to understand when it fires
rg "userMeResponse|addEventListener" src/client/HomepageAds.ts -n -A 3

Repository: openfrontio/OpenFrontIO

Length of output: 532


🏁 Script executed:

# Search for spaAddAds calls to see all paths that might load ads
rg "spaAddAds" src/client/HomepageAds.ts -n -B 3 -A 3

Repository: openfrontio/OpenFrontIO

Length of output: 614


Add guard to prevent duplicate footer ad loads on repeated auth events.

The userMeResponse event can fire multiple times while the component is connected. Each fire currently triggers spaAddAds without protection, creating duplicate ad units. The HomepageAds class already has this guard pattern—HomeFooterAd should use the same approach.

Proposed fix
 export class HomeFooterAd extends LitElement {
   `@state`() private shouldShow: boolean = false;
+  private adLoaded = false;

   private onUserMeResponse = () => {
+    if (this.adLoaded) return;
     const isDesktop = window.innerWidth >= 640;
     if (
       !window.adsEnabled ||
       (isDesktop && window.innerHeight < FOOTER_AD_MIN_HEIGHT)
     ) {
       return;
     }
     this.shouldShow = true;
     this.updateComplete.then(() => {
       this.loadAd();
     });
   };

   private loadAd(): void {
+    if (this.adLoaded) return;
     if (!window.ramp) {
       console.warn("Playwire RAMP not available for footer ad");
       return;
     }
     try {
       window.ramp.que.push(() => {
         try {
           window.ramp.spaAddAds([
             { type: FOOTER_AD_TYPE, selectorId: FOOTER_AD_CONTAINER_ID },
           ]);
+          this.adLoaded = true;
           console.log("Footer ad loaded:", FOOTER_AD_TYPE);
         } catch (e) {
           console.error("Failed to add footer ad:", e);
         }
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/HomepageAds.ts` around lines 195 - 207, Add a guard boolean to
prevent duplicate footer ads: add a class-level flag (e.g., footerAdLoaded or
footerAdShown) and in onUserMeResponse check that flag before setting
this.shouldShow and queuing this.loadAd() via this.updateComplete; if the flag
is false, set it true when you schedule/load the ad so subsequent userMeResponse
events do nothing. Use the same guard pattern as HomeFooterAd and reference
onUserMeResponse, this.updateComplete, this.loadAd, and this.shouldShow when
making the change.

@github-project-automation github-project-automation Bot moved this from Triage to Development in OpenFront Release Management Apr 6, 2026
@evanpelle evanpelle changed the title Corner video Refactor home page ads into a single file, add corner video ad Apr 6, 2026
@evanpelle evanpelle added this to the v31 milestone Apr 6, 2026
Copy link
Copy Markdown
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

🧹 Nitpick comments (1)
src/client/HomepagePromos.ts (1)

27-31: Remove unused static styles declaration.

Since createRenderRoot() returns this (disabling shadow DOM), the static styles property is never applied. This is dead code.

Proposed fix
   createRenderRoot() {
     return this;
   }
-
-  static styles = css``;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/HomepagePromos.ts` around lines 27 - 31, Remove the dead static
styles declaration from the HomepagePromos component: since createRenderRoot()
returns this (disabling shadow DOM), the static styles property on the
HomepagePromos class is never applied, so delete the static styles = css``
declaration (or alternatively move the styles into global CSS or apply them
manually in render) and ensure no other code references HomepagePromos.static
styles.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/client/HomepagePromos.ts`:
- Around line 109-134: loadCornerAdVideo lacks the duplicate-load guard used in
loadGutterAds, so repeated userMeResponse events can enqueue multiple
"corner_ad_video" units; add a boolean flag (e.g., adLoadedCorner or reuse
adLoaded with a separate key) checked at the top of loadCornerAdVideo to return
early if already loaded, set that flag to true once
window.ramp.addUnits(...).then(...) succeeds (or immediately after addUnits
resolves), and leave the rest of the existing try/catch logic intact to avoid
enqueuing duplicate corner_ad_video units.

---

Nitpick comments:
In `@src/client/HomepagePromos.ts`:
- Around line 27-31: Remove the dead static styles declaration from the
HomepagePromos component: since createRenderRoot() returns this (disabling
shadow DOM), the static styles property on the HomepagePromos class is never
applied, so delete the static styles = css`` declaration (or alternatively move
the styles into global CSS or apply them manually in render) and ensure no other
code references HomepagePromos.static styles.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fc90a5a0-3274-460e-a317-47e5b1489e2f

📥 Commits

Reviewing files that changed from the base of the PR and between c5906b7 and 783e184.

📒 Files selected for processing (5)
  • index.html
  • src/client/GutterAds.ts
  • src/client/HomepagePromos.ts
  • src/client/Main.ts
  • src/client/components/HomeFooterAd.ts
💤 Files with no reviewable changes (2)
  • src/client/components/HomeFooterAd.ts
  • src/client/GutterAds.ts
✅ Files skipped from review due to trivial changes (1)
  • index.html
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/client/Main.ts

Comment thread src/client/HomepagePromos.ts
@evanpelle evanpelle marked this pull request as ready for review April 6, 2026 22:40
@evanpelle evanpelle merged commit 592dadf into v30 Apr 6, 2026
10 checks passed
@evanpelle evanpelle deleted the corner-video branch April 6, 2026 23:44
@github-project-automation github-project-automation Bot moved this from Development to Complete in OpenFront Release Management Apr 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

1 participant