Skip to content

feat(banner): bring back the license banner, asking regular users to buy one - #47

Merged
datlechin merged 1 commit into
mainfrom
feat/support-banner
Oct 5, 2026
Merged

datlechin merged 1 commit into
mainfrom
feat/support-banner

Conversation

@datlechin

Copy link
Copy Markdown
Member

Why it was gone

The rebuild changed config/banner.php from enabled = true to off by default. Production's .env has never set BANNER_ENABLED, so the banner disappeared without anyone switching it off. The live HTML has no has-banner on any page. The rebuild also changed its copy from a support ask ("Buy a license") to an informational line ("See pricing").

What it does now

On by default, so it no longer depends on the server's .env. Its copy sells the license and names what the money pays for:

Desktop (≥1024px) Phone
EN Use TablePro every day? A license adds the paid features and funds the next release. Get a license → Get a license, fund TablePro →
VI Bạn dùng TablePro hằng ngày? License thêm tính năng trả phí và nuôi bản phát hành tiếp theo. Mua license → Mua license ủng hộ TablePro →

From research on support asks (Sidekiq, Porzio, Beekeeper Studio, Obsidian) and announcement bars (NN/g, GOV.UK, NextAfter, Wikimedia CentralNotice):

  • Sell first, fund second. It never pleads. "Need your help", "donate" and "struggling" stay banned. "ủng hộ" is now allowed in Vietnamese.
  • Not on /pricing or /vi/pricing, the page it leads to. App\Support\Banner is one rule for the Inertia prop and the pre-paint has-banner class.
  • Scrolls away. It sits above the sticky header instead of sticking with it. scroll-padding-top is back to the header's 5rem.
  • Dismissal with an end date. Closing it snoozes that message for 30 days. "Have a license? Hide this" (from 1280px) hides every message for a year, and TableProApp/license's thank-you page will do the same after a purchase. The record {version, until} is settled before first paint. lib/banner.ts holds the rule, and tests/js/banner.test.ts runs the head script against the same cases. The bare version string older releases stored now hides nothing, and version 3 shows the new copy to everyone.
  • Measured. license_banner_view, license_banner_click (version) and license_banner_dismiss (version, reason) go to GA4 under Consent Mode. Register version and reason as event-scoped custom dimensions in GA4 to see them in reports.
  • The privacy policy (EN and VI) describes the record's two durations. docs/architecture.md, sitemap §B.5 and design-system §5.3.17 record the decision.

Tests

  • TopBannerTest:
    • on by default, off on pricing in both languages;
    • the pre-paint script reads the record and its end date;
    • not sticky;
    • one-line limits, including the new licensed link;
    • the copy names the license, what it adds and what it funds;
    • no pleading.
  • PublicContractsTest registers the three events. tests/js/banner.test.ts covers 10 storage cases in both the lib and the head script.
  • Full suite with SSR: 1427 passed, 1 skipped. npm run test:js: 185/185. Typecheck, build and Pint pass.
  • Headless Chrome with SSR:
    • all three parts show at 1440/1280px, the sentence and link at 1024px, the short link at 390px, and nothing overflows;
    • after scrolling 1200px the banner is off screen and the header sits at top 0;
    • /pricing and /vi/pricing have no banner;
    • X writes version 3 for 30 days, and on reload the class is already gone at DOMContentLoaded (no flash);
    • "Have a license?" writes * for 365 days.

Companion: the TableProApp/license PR that hides the banner after a purchase.

…buy one

The banner went missing when the rebuild made it off by default and
production had never set BANNER_ENABLED. It is back on by default, with
copy that sells the license and names what it pays for: "Use TablePro
every day? A license adds the paid features and funds the next release."
(in English and Vietnamese), linking to Pricing.

Following what research on support asks and announcement bars found:
- off the Pricing page it leads to, in both languages (App\Support\Banner,
  one rule for the prop and the pre-paint class);
- above the sticky header, scrolling away with the page;
- closing it snoozes that message for 30 days; "Have a license? Hide this"
  (from 1280px) hides every message for a year, and so will the account
  app's thank-you page after a purchase;
- license_banner_view, _click and _dismiss go to Google Analytics, under
  the reader's consent choice.

The dismissal record is {version, until}; the head script mirrors
lib/banner.ts and tests/js/banner.test.ts runs it against the same cases.
The privacy policy describes the record's two durations.
@datlechin
datlechin merged commit 9c99fc0 into main Oct 5, 2026
4 checks passed
@datlechin
datlechin deleted the feat/support-banner branch October 5, 2026 13:17
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