Skip to content

Scheduled announcement banners#157

Merged
djoufson merged 4 commits into
mainfrom
feature/banners
Jun 7, 2026
Merged

Scheduled announcement banners#157
djoufson merged 4 commits into
mainfrom
feature/banners

Conversation

@djoufson

@djoufson djoufson commented Jun 7, 2026

Copy link
Copy Markdown
Member

Summary

  • New Banner aggregate (MessageEn/Fr, optional TitleEn/Fr + SubtitleEn/Fr, Variant, StartDate/EndDate, optional CTA link, Dismissible, Priority, IsEnabled) with full CRUD through the admin panel.
  • Public site renders all currently-active banners stacked at the top of MainLayout. Two layouts: a rich Microsoft-style headline + subtitle + body + pill CTA when a title is set, and a compact centered single-line layout when it isn't.
  • 5 intent-based variants — Announcement, Advertisement, Promo, Event, Maintenance — each with its own gradient, icon, and contrast-aware text/CTA colors. Advertisement variant gets a subtle shine sweep.
  • Banner stack pins to the top on scroll with the same threshold and slide-in animation as the navbar. A --banner-stack-height CSS custom property is computed at scroll time so the navbar slides in cleanly below the pinned banner instead of overlapping.
  • Banners flagged as dismissible can be closed by visitors; the dismissal is remembered in localStorage (dismissed-banners).
  • Active banners list is cached in memory for 5 minutes and invalidated on any write.

Architecture

  • Domain: app.domain/Models/BannerAggregate/Banner.cs + BannerVariant enum + BannerModel view-model.
  • Business: IBannerService with GetAllAsync (paged), GetAsync, GetActiveAsync, CreateAsync, UpdateAsync, DeleteAsync.
  • Infrastructure: BannerService (validates EndDate > StartDate, manages cache), BannerConfigurations (indexed on IsEnabled, StartDate, EndDate), two EF migrations.
  • API: AdminBannersApi mounted at /api/admin/banners (cookie auth, admin role).
  • Public UI: BannerStack.razor injected at the top of MainLayout.razor + JS dismiss handler in wwwroot/js/app.js.
  • Admin React: route group /admin/banners (index / new / \$id.edit), BannerForm, api/banners.ts, sidebar entry.

Test plan

  • Apply the migration: dotnet ef database update --project src/app.infrastructure --startup-project src/app --context AppDbContext
  • Create a banner in the admin panel without a title — verify compact centered layout renders
  • Create a banner with a title + subtitle (e.g. "AI Skills Fest" / "June 8-12, 2026") — verify rich layout with bold title, uppercase subtitle, solid pill CTA
  • Verify all five variants render with correct gradient, icon, and contrasting text/CTA colors
  • Verify only banners where now ∈ [StartDate, EndDate] and IsEnabled = true appear on the public site
  • Verify Priority (desc) controls stack order
  • Dismiss a dismissible banner — verify it stays hidden on next page load (cleared via localStorage.removeItem('dismissed-banners'))
  • Scroll past the navbar threshold — banner stack and navbar both pin to top; navbar sits directly under the banner with no overlap
  • Scroll back up — both unpin together
  • Switch language to French — banner content swaps to MessageFr / TitleFr / SubtitleFr / LinkLabelFr
  • Verify the cached active-banners list refreshes within 5 min of any create/update/delete

🤖 Generated with Claude Code

djoufson and others added 4 commits June 7, 2026 09:51
Adds nullable TitleEn/Fr and SubtitleEn/Fr columns so banners can render a
rich Microsoft-style layout (bold headline, uppercase subtitle, body message,
solid pill CTA). When the title is empty, the compact centered layout is kept
as a fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The banner stack now sticks to the top of the viewport once the scroll
threshold is reached, mirroring the navbar behavior. The navbar's pinned
position is offset by the banner stack's measured height via a CSS custom
property so the two stack cleanly instead of overlapping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@djoufson djoufson self-assigned this Jun 7, 2026
@djoufson djoufson merged commit 0b1589e into main Jun 7, 2026
1 check passed
@djoufson djoufson deleted the feature/banners branch June 7, 2026 09:21
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.

1 participant