From 5855a88dc630924ea3e047ccb9cc85e578532b08 Mon Sep 17 00:00:00 2001
From: c0mrade
Date: Wed, 3 Jun 2026 15:49:58 +0300
Subject: [PATCH] fix(connection): Happ TV quick-connect is Happ-only + matches
config-block styles
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The TV quick-connect block (Подключить TV / Сканировать QR) is a Happ-only
feature (check.happ.su/sendtv), but it rendered for ANY app on a TV platform and
used one-off button styles (solid btn-primary + grey btn-secondary) that clashed
with the outlined-accent buttons that come from the subscription-page config.
- Show TvQuickConnect only for the Happ app (detected by its happ:// deep-link
scheme, name as fallback).
- Extract the config-block button style into a shared blockButtonClass and use it
for the TV buttons too, so they adapt to exactly the same visual language as the
panel-config blocks (no divergent one-off styling).
- Align the code input with the Happ Android TV API doc (5-digit numeric):
placeholder 12345 + inputMode numeric. The send call already matches the spec
(POST check.happ.su/sendtv/{code}, body {"data": base64(subscriptionUrl)}).
---
src/components/connection/InstallationGuide.tsx | 13 +++++++++++--
src/components/connection/TvQuickConnect.tsx | 15 ++++++++++-----
.../connection/blocks/BlockButtons.tsx | 10 ++--------
src/components/connection/blocks/buttonStyles.ts | 16 ++++++++++++++++
4 files changed, 39 insertions(+), 15 deletions(-)
create mode 100644 src/components/connection/blocks/buttonStyles.ts
diff --git a/src/components/connection/InstallationGuide.tsx b/src/components/connection/InstallationGuide.tsx
index 05aa6cc..c04b574 100644
--- a/src/components/connection/InstallationGuide.tsx
+++ b/src/components/connection/InstallationGuide.tsx
@@ -34,6 +34,14 @@ const RENDERERS: Record> = {
minimal: MinimalBlock,
};
+/** TV quick-connect is a Happ-only feature (check.happ.su/sendtv) — show it only
+ * for the Happ app, detected by its happ:// deep-link scheme (name as fallback). */
+function isHappApp(app: RemnawaveAppClient | null): boolean {
+ if (!app) return false;
+ if ((app.deepLink ?? '').toLowerCase().startsWith('happ://')) return true;
+ return app.name.toLowerCase().includes('happ');
+}
+
interface Props {
appConfig: AppConfig;
onOpenDeepLink: (url: string) => void;
@@ -312,8 +320,9 @@ export default function InstallationGuide({
)}
- {/* Blocks — for TV: first block, Quick Connect, last block */}
- {selectedApp && isTvPlatform && appConfig.subscriptionUrl ? (
+ {/* Blocks — for the Happ TV app: first block, Quick Connect, last block.
+ Other apps (or non-TV) render their blocks normally. */}
+ {selectedApp && isTvPlatform && isHappApp(selectedApp) && appConfig.subscriptionUrl ? (
<>
{selectedApp.blocks.length > 0 && (
{/* Code input */}
@@ -232,15 +237,15 @@ export default function TvQuickConnect({ subscriptionUrl, isLight }: Props) {
maxLength={5}
value={code}
onChange={(e) => setCode(e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, ''))}
- placeholder="A1B2C"
+ placeholder="12345"
autoComplete="one-time-code"
- inputMode="text"
+ inputMode="numeric"
className={inputClass}
/>