{"_id":"@andrezhan27/intelis-restaurant-ui","_rev":"6-61b915f39fd41e9e5308d5e8e9e08ce6","name":"@andrezhan27/intelis-restaurant-ui","dist-tags":{"latest":"0.2.2"},"versions":{"0.1.0":{"name":"@andrezhan27/intelis-restaurant-ui","version":"0.1.0","license":"UNLICENSED","_id":"@andrezhan27/intelis-restaurant-ui@0.1.0","maintainers":[{"name":"andrezhan27","email":"andre.zhan27@gmail.com"}],"homepage":"https://github.com/andrezhan27/intelis-components#readme","bugs":{"url":"https://github.com/andrezhan27/intelis-components/issues"},"dist":{"shasum":"85c797d55a324cb41f39ed1c7c9f4a9bd17af06c","tarball":"https://registry.npmjs.org/@andrezhan27/intelis-restaurant-ui/-/intelis-restaurant-ui-0.1.0.tgz","fileCount":48,"integrity":"sha512-EflSJRb8miOdbYEnarYDjlHplumYFhsFDjN+YO7GzFp/70gCGNB2S7xj9aAnl8F8gSnKZDxID4LHJ2mi0ft44w==","signatures":[{"sig":"MEUCIB4nuPJEgBH/L5dkDsWK7iiKnsaF/NZ4sfyT7GmUDTDqAiEA8nJFJj42W0h6LvR+3Tpd6Ak/K9J7lsxaiFYqN1cDmCM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":56579},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./dashboard":{"types":"./dist/dashboard/index.d.ts","import":"./dist/dashboard/index.js","default":"./dist/dashboard/index.js"}},"gitHead":"ae6b9708f7fe792449e48081875553d4cf3e81ac","scripts":{"test":"npm run build && node --test tests/*.test.mjs","build":"tsc -p tsconfig.build.json && cp src/promotion-banner/promotion-banner.module.css dist/promotion-banner/promotion-banner.module.css && cp src/dashboard/promotion-manager.module.css dist/dashboard/promotion-manager.module.css","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"andrezhan27","email":"andre.zhan27@gmail.com"},"repository":{"url":"git+https://github.com/andrezhan27/intelis-components.git","type":"git"},"_npmVersion":"10.9.2","description":"Shared native UI for Intelis restaurant websites and dashboards.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.14.0","dependencies":{"server-only":"0.0.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"next":"16.3.0","react":"19.2.8","typescript":"5.7.3","@types/node":"22.10.0","@types/react":"19.2.2","@supabase/supabase-js":"2.110.0"},"peerDependencies":{"next":">=16.0.0 <17","react":">=19.0.0 <20","@supabase/supabase-js":">=2.50.0 <3"},"peerDependenciesMeta":{"@supabase/supabase-js":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/intelis-restaurant-ui_0.1.0_1787843318316_0.21402791856775494","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@andrezhan27/intelis-restaurant-ui","version":"0.1.1","license":"UNLICENSED","_id":"@andrezhan27/intelis-restaurant-ui@0.1.1","maintainers":[{"name":"andrezhan27","email":"andre.zhan27@gmail.com"}],"homepage":"https://github.com/andrezhan27/intelis-components#readme","bugs":{"url":"https://github.com/andrezhan27/intelis-components/issues"},"dist":{"shasum":"aa50b7af00bb79e24925ffad731d9bc26cb93c89","tarball":"https://registry.npmjs.org/@andrezhan27/intelis-restaurant-ui/-/intelis-restaurant-ui-0.1.1.tgz","fileCount":48,"integrity":"sha512-gBG0EcCDafd53ROMEarAgPykWXS8WR+3RM44U3kZsPj1G2aLUSMNtMKOyrv7mNJfCQsY3EMOoz2l3UokRbBW9A==","signatures":[{"sig":"MEUCIHI37uRh91lIkmOf3slg5XY/8iJF/+BdjrdmAiJT84EkAiEAtkO/DCbdQUjbt+MmHafVoxxdRRHNp4cHngT4ZvSU0Io=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":56542},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./dashboard":{"types":"./dist/dashboard/index.d.ts","import":"./dist/dashboard/index.js","default":"./dist/dashboard/index.js"}},"gitHead":"531a67b14b596b89c6716b9ce705700bce476157","scripts":{"test":"npm run build && node --test tests/*.test.mjs","build":"tsc -p tsconfig.build.json && cp src/promotion-banner/promotion-banner.module.css dist/promotion-banner/promotion-banner.module.css && cp src/dashboard/promotion-manager.module.css dist/dashboard/promotion-manager.module.css","check":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"andrezhan27","email":"andre.zhan27@gmail.com"},"repository":{"url":"git+https://github.com/andrezhan27/intelis-components.git","type":"git"},"_npmVersion":"10.9.2","description":"Shared native UI for Intelis restaurant websites and dashboards.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.14.0","dependencies":{"server-only":"0.0.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"next":"16.3.0","react":"19.2.8","typescript":"5.7.3","@types/node":"22.10.0","@types/react":"19.2.2","@supabase/supabase-js":"2.110.0"},"peerDependencies":{"next":">=16.0.0 <17","react":">=19.0.0 <20","@supabase/supabase-js":">=2.50.0 <3"},"peerDependenciesMeta":{"@supabase/supabase-js":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/intelis-restaurant-ui_0.1.1_1787845587547_0.15995208253614956","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@andrezhan27/intelis-restaurant-ui","version":"0.1.2","license":"UNLICENSED","_id":"@andrezhan27/intelis-restaurant-ui@0.1.2","maintainers":[{"name":"andrezhan27","email":"andre.zhan27@gmail.com"}],"homepage":"https://github.com/andrezhan27/intelis-components#readme","bugs":{"url":"https://github.com/andrezhan27/intelis-components/issues"},"dist":{"shasum":"52f83fb496eef2c40039c26d3a42cb89a9d348fc","tarball":"https://registry.npmjs.org/@andrezhan27/intelis-restaurant-ui/-/intelis-restaurant-ui-0.1.2.tgz","fileCount":56,"integrity":"sha512-Hk6/JFPOQOmq8GJGcpuG3XK/stljwqZnzSmK/W/9QZzKfJZSTRM7cnS0ppy5PPhz1WAPXrpiFzOwbPzJfLeM0A==","signatures":[{"sig":"MEUCIQDJjn7loePmKOF2T9XosBqs9gXgPeIG/l7piQPxs/JsrQIgaNIXG0n6mcSKgEBX7vbrMg9HxQvd3VXyQAfwsfAmZbA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":96317},"type":"module","_from":"file:/tmp/andrezhan27-intelis-restaurant-ui-0.1.2.tgz","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./dashboard":{"types":"./dist/dashboard/index.d.ts","import":"./dist/dashboard/index.js","default":"./dist/dashboard/index.js"}},"scripts":{"test":"npm run build && node --test tests/*.test.mjs","build":"tsc -p tsconfig.build.json && cp src/promotion-banner/promotion-banner.module.css dist/promotion-banner/promotion-banner.module.css && cp src/dashboard/promotion-manager.module.css dist/dashboard/promotion-manager.module.css","check":"tsc -p tsconfig.json --noEmit","preview:banners":"node tests/preview/server.mjs"},"_npmUser":{"name":"andrezhan27","email":"andre.zhan27@gmail.com"},"_resolved":"/tmp/andrezhan27-intelis-restaurant-ui-0.1.2.tgz","_integrity":"sha512-Hk6/JFPOQOmq8GJGcpuG3XK/stljwqZnzSmK/W/9QZzKfJZSTRM7cnS0ppy5PPhz1WAPXrpiFzOwbPzJfLeM0A==","repository":{"url":"git+https://github.com/andrezhan27/intelis-components.git","type":"git"},"_npmVersion":"10.9.2","description":"Shared native UI for Intelis restaurant websites and dashboards.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.14.0","dependencies":{"server-only":"0.0.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"next":"16.3.0","react":"19.2.8","typescript":"5.7.3","@types/node":"22.10.0","@types/react":"19.2.2","@supabase/supabase-js":"2.110.0"},"peerDependencies":{"next":">=16.0.0 <17","react":">=19.0.0 <20","@supabase/supabase-js":">=2.50.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/intelis-restaurant-ui_0.1.2_1788195106088_0.13728039474749565","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@andrezhan27/intelis-restaurant-ui","version":"0.2.0","license":"UNLICENSED","_id":"@andrezhan27/intelis-restaurant-ui@0.2.0","maintainers":[{"name":"andrezhan27","email":"andre.zhan27@gmail.com"}],"homepage":"https://github.com/andrezhan27/intelis-components#readme","bugs":{"url":"https://github.com/andrezhan27/intelis-components/issues"},"dist":{"shasum":"0712da0fe698ae7ba017d948d18255a21def0bc3","tarball":"https://registry.npmjs.org/@andrezhan27/intelis-restaurant-ui/-/intelis-restaurant-ui-0.2.0.tgz","fileCount":63,"integrity":"sha512-f9W7p0lGTWKQ+STY2Ya3fGOJy4pbqRZiKhwqksO/cUazhmHgldus/1VS8fgRUC2BKRpJQtZIr5GDNhffhRHjZA==","signatures":[{"sig":"MEQCIAwAt3bgBDOqWWB3zhCgImgJLZ/3h8TLB4adRjklIA9FAiAykv7QT8axw3KQzP8u6QmeSBawPZz0N3m9uMq3Z+T5cQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":123267},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./dashboard":{"types":"./dist/dashboard/index.d.ts","import":"./dist/dashboard/index.js","default":"./dist/dashboard/index.js"}},"gitHead":"6afa1d8e1f4de8526c25821c757f32bc1d519d9c","scripts":{"test":"npm run build && node --test tests/*.test.mjs","build":"tsc -p tsconfig.build.json && cp src/promotion-banner/promotion-banner.module.css dist/promotion-banner/promotion-banner.module.css && cp src/dashboard/promotion-manager.module.css dist/dashboard/promotion-manager.module.css","check":"tsc -p tsconfig.json --noEmit","preview:banners":"node tests/preview/server.mjs"},"_npmUser":{"name":"andrezhan27","email":"andre.zhan27@gmail.com"},"repository":{"url":"git+https://github.com/andrezhan27/intelis-components.git","type":"git"},"_npmVersion":"11.19.0","description":"Shared native UI for Intelis restaurant websites and dashboards.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.14.0","dependencies":{"server-only":"0.0.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"next":"16.3.0","react":"19.2.8","typescript":"5.7.3","@types/node":"22.10.0","@types/react":"19.2.2","@supabase/supabase-js":"2.110.0"},"peerDependencies":{"next":">=16.0.0 <17","react":">=19.0.0 <20","@supabase/supabase-js":">=2.50.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/intelis-restaurant-ui_0.2.0_1788272274214_0.45916358031493365","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@andrezhan27/intelis-restaurant-ui","version":"0.2.1","license":"UNLICENSED","_id":"@andrezhan27/intelis-restaurant-ui@0.2.1","maintainers":[{"name":"andrezhan27","email":"andre.zhan27@gmail.com"}],"homepage":"https://github.com/andrezhan27/intelis-components#readme","bugs":{"url":"https://github.com/andrezhan27/intelis-components/issues"},"dist":{"shasum":"dcd19df72ebb6e58e625b722f5eebf3ba825a9e8","tarball":"https://registry.npmjs.org/@andrezhan27/intelis-restaurant-ui/-/intelis-restaurant-ui-0.2.1.tgz","fileCount":64,"integrity":"sha512-4DrqVDJCtCr7whM7yblBDUqmjGVGwDF83M722lbR3fcAgYJKigkeF+HSRbwWlguM/lmU/xj+3nHCYfgidsac+g==","signatures":[{"sig":"MEUCIQCMCqMbe7J8qKFkrMQ1K8GfbWEG95yKxXclvP3bUEWzkAIgPjwz9XrsLXqnOC1omp7fxLPDvboK9s/azCUzjgEcor0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":128030},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./dashboard":{"types":"./dist/dashboard/index.d.ts","import":"./dist/dashboard/index.js","default":"./dist/dashboard/index.js"}},"gitHead":"6afa1d8e1f4de8526c25821c757f32bc1d519d9c","scripts":{"test":"npm run build && node --test tests/*.test.mjs","build":"tsc -p tsconfig.build.json && cp src/promotion-banner/promotion-banner.module.css dist/promotion-banner/promotion-banner.module.css && cp src/dashboard/promotion-manager.module.css dist/dashboard/promotion-manager.module.css","check":"tsc -p tsconfig.json --noEmit","preview:banners":"node tests/preview/server.mjs"},"_npmUser":{"name":"andrezhan27","email":"andre.zhan27@gmail.com"},"repository":{"url":"git+https://github.com/andrezhan27/intelis-components.git","type":"git"},"_npmVersion":"11.19.1","description":"Shared native UI for Intelis restaurant websites and dashboards.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"22.14.0","dependencies":{"server-only":"0.0.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"next":"16.3.0","react":"19.2.8","typescript":"5.7.3","@types/node":"22.10.0","@types/react":"19.2.2","@supabase/supabase-js":"2.110.0"},"peerDependencies":{"next":">=16.0.0 <17","react":">=19.0.0 <20","@supabase/supabase-js":">=2.50.0 <3"},"_npmOperationalInternal":{"tmp":"tmp/intelis-restaurant-ui_0.2.1_1788278956926_0.8839853929326189","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"_id":"@andrezhan27/intelis-restaurant-ui@0.2.2","bugs":{"url":"https://github.com/andrezhan27/intelis-components/issues"},"dist":{"shasum":"e1fe7607bdb9e11d2f0789c8da72288e0ce282ec","tarball":"https://registry.npmjs.org/@andrezhan27/intelis-restaurant-ui/-/intelis-restaurant-ui-0.2.2.tgz","fileCount":64,"integrity":"sha512-rzSmdfykDV75gMTzSzpsEM/2ecsUnfAbppQCcppneYHqbeS0RLB9y5qnH/99mGucm9mmrUkIvWX7KZW/8/+HoA==","signatures":[{"sig":"MEYCIQChDOT3cxKcxeY5kGWE9YE1OyBBeAyI7hJKGfCDPQDB/gIhAM3sOq0dJOBBkW3xi4fXrbTK+ZMY7G3JWXOkA/g8kxMk","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCN1pyCDe0rRk4QMrVO/HENJ1+/dOTVmBtY8qiC2nU39QIhANbP+fnSjPnMyrBeWMNVvflraCnl1+BSlSFDuqmY3m7W"}],"unpackedSize":132262},"name":"@andrezhan27/intelis-restaurant-ui","type":"module","_from":"file:/private/tmp/intelis-release-0.2.2/andrezhan27-intelis-restaurant-ui-0.2.2.tgz","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./dashboard":{"types":"./dist/dashboard/index.d.ts","import":"./dist/dashboard/index.js","default":"./dist/dashboard/index.js"}},"license":"UNLICENSED","scripts":{"test":"npm run build && node --test tests/*.test.mjs","build":"tsc -p tsconfig.build.json && cp src/promotion-banner/promotion-banner.module.css dist/promotion-banner/promotion-banner.module.css && cp src/dashboard/promotion-manager.module.css dist/dashboard/promotion-manager.module.css","check":"tsc -p tsconfig.json --noEmit","preview:banners":"node tests/preview/server.mjs"},"version":"0.2.2","_npmUser":{"name":"andrezhan27","email":"andre.zhan27@gmail.com"},"homepage":"https://github.com/andrezhan27/intelis-components#readme","_resolved":"/private/tmp/intelis-release-0.2.2/andrezhan27-intelis-restaurant-ui-0.2.2.tgz","_integrity":"sha512-rzSmdfykDV75gMTzSzpsEM/2ecsUnfAbppQCcppneYHqbeS0RLB9y5qnH/99mGucm9mmrUkIvWX7KZW/8/+HoA==","repository":{"url":"git+https://github.com/andrezhan27/intelis-components.git","type":"git"},"_npmVersion":"10.9.2","description":"Shared native UI for Intelis restaurant websites and dashboards.","directories":{},"maintainers":[{"name":"andrezhan27","email":"andre.zhan27@gmail.com"}],"sideEffects":["**/*.css"],"_nodeVersion":"22.14.0","dependencies":{"server-only":"0.0.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"next":"16.3.0","react":"19.2.8","typescript":"5.7.3","@types/node":"22.10.0","@types/react":"19.2.2","@supabase/supabase-js":"2.110.0"},"peerDependencies":{"next":">=16.0.0 <17","react":">=19.0.0 <20","@supabase/supabase-js":">=2.50.0 <3"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/intelis-restaurant-ui_0.2.2_1789071773969_0.2794409491033225"}}},"time":{"created":"2026-08-27T15:08:38.175Z","modified":"2026-09-10T20:22:54.211Z","0.1.0":"2026-08-27T15:08:38.453Z","0.1.1":"2026-08-27T15:46:27.680Z","0.1.2":"2026-08-31T16:51:46.208Z","0.2.0":"2026-09-01T14:17:54.353Z","0.2.1":"2026-09-01T16:09:17.101Z","0.2.2":"2026-09-10T20:22:54.053Z"},"bugs":{"url":"https://github.com/andrezhan27/intelis-components/issues"},"license":"UNLICENSED","homepage":"https://github.com/andrezhan27/intelis-components#readme","repository":{"url":"git+https://github.com/andrezhan27/intelis-components.git","type":"git"},"description":"Shared native UI for Intelis restaurant websites and dashboards.","maintainers":[{"name":"andrezhan27","email":"andre.zhan27@gmail.com"}],"readme":"# @andrezhan27/intelis-restaurant-ui\n\nShared native React/Next.js UI for Intelis restaurant websites and dashboards.\n\n## Restaurant website\n\nInstall this package and its peers (`react`, `next`, and `@supabase/supabase-js`).\nSupabase is now required for the live banner, not just for the dashboard.\nConfigure `NEXT_PUBLIC_SUPABASE_URL` and\n`NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY` (or the legacy anon key), then add:\n\n```tsx\nimport { PromotionBanner } from \"@andrezhan27/intelis-restaurant-ui\";\n\n<body>\n  <PromotionBanner restaurantId={restaurantId} />\n  <Header />\n  {children}\n</body>\n```\n\nThe server renders an initial snapshot and the browser subscribes to live\nchanges, including when there are initially no promotions. Only a publishable or\nlegacy `anon` key may be passed to the client. Secret/service-role keys are\nrejected.\n\n### Popup flow\n\n- Active means the restaurant is active, the promotion is enabled, its start\n  has arrived (or is unset), and its exclusive end has not arrived (or is unset).\n- The centered popup opens automatically once per restaurant and browser-tab\n  session. Closing with the × button, backdrop, or Escape leaves a compact\n  `See Promotions` / `Ver Promoções` CTA at the top so it can be reopened.\n- Language is selected from the document's `lang` value, then the browser\n  language. Portuguese locales use Portuguese UI labels; all others use English.\n- Desktop shows every active promotion as cards in authoritative database order.\n  Mobile shows one card at a time with previous/next arrows and a position count.\n- On mobile, the popup stays at 65% of the viewport height without scrolling.\n  Equal-width columns show the complete image on the left and offer text on the\n  right, including on narrow phones. Titles use up to three lines; descriptions\n  fit the available space with an ellipsis, reserving room for the CTA and spacing.\n- Promotion CTAs use normal same-tab links. Popup focus is trapped while open,\n  background scrolling is locked, and focus is restored after closing.\n- A single promotion uses a wide image-and-copy treatment inspired by a classic\n  editorial offer modal.\n\n### Live changes and scheduling\n\n`get_restaurant_promotion_state` is a narrow public RPC returning ordered active\npromotion cards, server time, and the next scheduled change. It uses `cache: \"no-store\"`.\nDatabase triggers broadcast invalidations on\n`restaurant-promotions:<restaurantId>` for promotion insert/update/delete and\nrestaurant activation/deactivation. Payloads contain no promotion content\n(Supabase adds a delivery ID). Visitors refetch the authoritative public RPC;\npublic messages cannot inject banner text or links.\n\nChanges appear as soon as the push notification and refresh arrive, subject to\nnormal network latency. Scheduled starts trigger a refresh at the returned\nboundary. Known endings are removed locally at their deadline even if offline.\nReconnect, visibility return, and online events refresh the data. A 30-second\nsafety check catches missed notifications; failed requests retry with backoff\nfrom one to 30 seconds. During an outage, retain the last known unexpired data.\nInstant remote updates cannot be guaranteed while a visitor is offline.\n\nThe RPC's deliberate `SECURITY DEFINER` boundary preserves existing restrictions:\nanonymous users cannot read the admin table, and draft/future/expired content is\nnot returned. RLS for restaurant administrators remains unchanged. Supabase's\n[public executable function advisor](https://supabase.com/docs/guides/database/database-linter?lint=0028_anon_security_definer_function_executable)\nflags this intentional public API (as it does the legacy single-banner API).\nTrigger functions are private and are not executable by anonymous/authenticated\nclients. Public topics disclose change timing, never unpublished row contents.\n\n### Styling\n\nOverride these brand variables to keep a site's own banner colors:\n\n```css\n:root {\n  --promotion-banner-bg: #171717;\n  --promotion-banner-text: #ffffff;\n  --promotion-banner-link: #f1d48a;\n  --promotion-banner-border: transparent;\n}\n```\n\n## Dashboard\n\nThe dashboard entry uses the existing authenticated Supabase client. RLS limits\nreads and writes to owner/manager memberships for the selected restaurant.\nAdministrators can edit the popup title, description, safe root-relative or\nHTTPS image reference, required image alt text, CTA, schedule, variant, and\npriority. `title` is the single source of truth for promotion headings.\n\n```tsx\nimport { PromotionManager } from \"@andrezhan27/intelis-restaurant-ui/dashboard\";\n\n<PromotionManager supabase={supabase} restaurantId={restaurantId} />\n```\n\nSaving updates connected websites through the database trigger; `onSaved` remains\navailable for deployment-specific follow-up work.\n\n## Rollout and verification\n\nApply the existing promotion migrations followed by\n`supabase/migrations/20260901110855_add_promotion_popup_content.sql` and\n`supabase/migrations/20260901152955_remove_legacy_promotion_message.sql` before\nupgrading the UI. The first migration backfills titles from existing messages;\nthe second removes the duplicate table column after all package code switches\nto `title`.\nThe original `get_active_restaurant_promotion` RPC and `fetchActivePromotion`\nexport remain available for older consumers; the RPC derives its legacy\n`message` output from `title`. Websites only gain the popup and live updates\nafter installing a release containing these changes and redeploying.\nThis repository does not deploy those consumer websites automatically.\n\n- `npm test`: build plus data-contract, URL, ordering, urgency, expiry, and key-safety tests.\n- `npm run check`: TypeScript verification.\n- `tests/promotion-database.sql`: database-owner integration test; fixtures and\n  broadcasts roll back. Needs an existing active restaurant.\n- `npm run preview:banners`: local popup fixture at `http://127.0.0.1:3111`.\n  Visit `/mobile` for a portrait poster fixture with single and multiple offers.\n  Uses the actual component and Supabase client against a local mock RPC and\n  Broadcast server. Controls exercise live edits, removals, urgent notices,\n  schedules, and outages without touching restaurant data.\n- `tests/realtime-probe.mjs`: optional real-project public API/Broadcast probe;\n  see its usage comments. Never provide a service-role key.\n","readmeFilename":"README.md"}