From 73f1af185f8f41e329909cf4658c37ad365929ab Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 29 May 2026 23:55:53 +0200 Subject: [PATCH] feat(tenant): make connect panel dismissible after connecting --- src/app/[locale]/tenants/[name]/page.tsx | 1 + src/components/tenants/connect-panel.tsx | 97 ++++++++++++++++++++++-- src/messages/de.json | 4 +- src/messages/en.json | 4 +- src/messages/fr.json | 4 +- src/messages/it.json | 4 +- 6 files changed, 104 insertions(+), 10 deletions(-) diff --git a/src/app/[locale]/tenants/[name]/page.tsx b/src/app/[locale]/tenants/[name]/page.tsx index 0923245..1632729 100644 --- a/src/app/[locale]/tenants/[name]/page.tsx +++ b/src/app/[locale]/tenants/[name]/page.tsx @@ -225,6 +225,7 @@ export default async function TenantDetailPage({ unreachable). */}
diff --git a/src/components/tenants/connect-panel.tsx b/src/components/tenants/connect-panel.tsx index 1b70328..d41b760 100644 --- a/src/components/tenants/connect-panel.tsx +++ b/src/components/tenants/connect-panel.tsx @@ -1,5 +1,6 @@ "use client"; +import { useEffect, useState } from "react"; import { useTranslations } from "next-intl"; import { THREEMA_GATEWAY } from "@/lib/threema-gateway-config"; @@ -16,11 +17,16 @@ import { THREEMA_GATEWAY } from "@/lib/threema-gateway-config"; * NO channel is enabled it says so explicitly (a running assistant with * no channel is unreachable). * + * Once a customer has connected they don't need the steps every visit, + * so the panel is dismissible: clicking "I've connected" collapses it + * to a slim row and remembers that per-tenant (localStorage). The slim + * row keeps a "Show connection details" toggle so it's never lost. + * The no-channel warning is NOT dismissible — it's an actionable alert, + * not reference material. + * * It is intentionally complementary to ChannelUsers below it: * - ConnectPanel → "how do *I* reach the assistant" * - ChannelUsers → "*who* is allowed to reach it" - * The Threema/Telegram/Discord steps reference the authorised-users - * list rather than duplicating it. */ // Render order is fixed (not the order packages happen to appear in @@ -40,10 +46,15 @@ const CHANNEL_STEPS_KEY: Record = { discord: "discordSteps", }; +const dismissKey = (tenantName: string) => + `pieced:connect-hidden:${tenantName}`; + export function ConnectPanel({ + tenantName, enabledChannels, phase, }: { + tenantName: string; enabledChannels: string[]; /** Tenant phase — connection details only "work" once it's Ready. */ phase: string; @@ -53,7 +64,41 @@ export function ConnectPanel({ const channels = CHANNEL_ORDER.filter((c) => enabledChannels.includes(c)); const ready = phase === "Ready" || phase === "Running" || phase === "Active"; - // No channel at all → the assistant is unreachable. Make it loud. + // Dismissed state is read from localStorage after mount to avoid a + // hydration mismatch (server has no localStorage). `hydrated` gates + // the collapsed view so the first paint matches the server output. + const [collapsed, setCollapsed] = useState(false); + const [hydrated, setHydrated] = useState(false); + + useEffect(() => { + try { + setCollapsed(localStorage.getItem(dismissKey(tenantName)) === "1"); + } catch { + /* private mode / storage disabled — just stay expanded */ + } + setHydrated(true); + }, [tenantName]); + + const dismiss = () => { + setCollapsed(true); + try { + localStorage.setItem(dismissKey(tenantName), "1"); + } catch { + /* no-op */ + } + }; + + const reopen = () => { + setCollapsed(false); + try { + localStorage.removeItem(dismissKey(tenantName)); + } catch { + /* no-op */ + } + }; + + // No channel at all → the assistant is unreachable. Make it loud and + // keep it non-dismissible (it's an alert, not reference material). if (channels.length === 0) { return (
@@ -85,11 +130,51 @@ export function ConnectPanel({ ); } + // Collapsed: a slim, unobtrusive row with a toggle to bring the full + // panel back. Only shown once hydrated so SSR/CSR agree. + if (hydrated && collapsed) { + return ( +
+ {t("title")} + +
+ ); + } + return (
-

- {t("title")} -

+
+

+ {t("title")} +

+ +

{t("description")}

diff --git a/src/messages/de.json b/src/messages/de.json index 86cb207..7e837b1 100644 --- a/src/messages/de.json +++ b/src/messages/de.json @@ -1005,6 +1005,8 @@ "threemaBotIdLabel": "Threema-ID", "threemaSteps": "1. Öffnen Sie Threema und scannen Sie diesen QR-Code (oder fügen Sie die obige ID als Kontakt hinzu).\n2. Senden Sie eine Nachricht, um den Chat zu starten.\nStellen Sie sicher, dass Ihre eigene Threema-ID in der Liste der autorisierten Benutzer unten steht – nur gelistete IDs erhalten eine Antwort.", "telegramSteps": "Öffnen Sie den verbundenen Telegram-Bot und senden Sie ihm eine Nachricht, um den Chat zu starten. Nur die Benutzer-IDs in der Liste der autorisierten Benutzer unten erhalten eine Antwort.", - "discordSteps": "Schreiben Sie dem verbundenen Discord-Bot oder erwähnen Sie ihn in einem Kanal, dem er beigetreten ist. Nur die Benutzer-IDs in der Liste der autorisierten Benutzer unten erhalten eine Antwort." + "discordSteps": "Schreiben Sie dem verbundenen Discord-Bot oder erwähnen Sie ihn in einem Kanal, dem er beigetreten ist. Nur die Benutzer-IDs in der Liste der autorisierten Benutzer unten erhalten eine Antwort.", + "dismiss": "Verbunden", + "show": "Verbindungsdetails anzeigen" } } diff --git a/src/messages/en.json b/src/messages/en.json index 3f9a20c..cc30343 100644 --- a/src/messages/en.json +++ b/src/messages/en.json @@ -1005,6 +1005,8 @@ "threemaBotIdLabel": "Threema ID", "threemaSteps": "1. Open Threema and scan this QR code (or add the ID above as a contact).\n2. Send it a message to start chatting.\nMake sure your own Threema ID is on the authorised users list below — only listed IDs get a reply.", "telegramSteps": "Open the Telegram bot you connected and send it a message to start chatting. Only the user IDs on the authorised users list below get a reply.", - "discordSteps": "Message the Discord bot you connected, or mention it in a channel it has joined. Only the user IDs on the authorised users list below get a reply." + "discordSteps": "Message the Discord bot you connected, or mention it in a channel it has joined. Only the user IDs on the authorised users list below get a reply.", + "dismiss": "I've connected", + "show": "Show connection details" } } diff --git a/src/messages/fr.json b/src/messages/fr.json index 32c40c3..5c301a5 100644 --- a/src/messages/fr.json +++ b/src/messages/fr.json @@ -1005,6 +1005,8 @@ "threemaBotIdLabel": "Identifiant Threema", "threemaSteps": "1. Ouvrez Threema et scannez ce QR code (ou ajoutez l'identifiant ci-dessus comme contact).\n2. Envoyez-lui un message pour commencer à discuter.\nAssurez-vous que votre propre identifiant Threema figure dans la liste des utilisateurs autorisés ci-dessous — seuls les identifiants listés reçoivent une réponse.", "telegramSteps": "Ouvrez le bot Telegram que vous avez connecté et envoyez-lui un message pour commencer à discuter. Seuls les identifiants utilisateur de la liste des utilisateurs autorisés ci-dessous reçoivent une réponse.", - "discordSteps": "Écrivez au bot Discord que vous avez connecté, ou mentionnez-le dans un salon qu'il a rejoint. Seuls les identifiants utilisateur de la liste des utilisateurs autorisés ci-dessous reçoivent une réponse." + "discordSteps": "Écrivez au bot Discord que vous avez connecté, ou mentionnez-le dans un salon qu'il a rejoint. Seuls les identifiants utilisateur de la liste des utilisateurs autorisés ci-dessous reçoivent une réponse.", + "dismiss": "Je suis connecté", + "show": "Afficher les détails de connexion" } } diff --git a/src/messages/it.json b/src/messages/it.json index 80bb215..ff2d0e2 100644 --- a/src/messages/it.json +++ b/src/messages/it.json @@ -1005,6 +1005,8 @@ "threemaBotIdLabel": "ID Threema", "threemaSteps": "1. Apri Threema e scansiona questo codice QR (oppure aggiungi l'ID sopra come contatto).\n2. Inviagli un messaggio per iniziare a chattare.\nAssicurati che il tuo ID Threema sia presente nell'elenco degli utenti autorizzati qui sotto: solo gli ID elencati ricevono una risposta.", "telegramSteps": "Apri il bot Telegram che hai collegato e inviagli un messaggio per iniziare a chattare. Solo gli ID utente nell'elenco degli utenti autorizzati qui sotto ricevono una risposta.", - "discordSteps": "Scrivi al bot Discord che hai collegato, oppure menzionalo in un canale a cui si è unito. Solo gli ID utente nell'elenco degli utenti autorizzati qui sotto ricevono una risposta." + "discordSteps": "Scrivi al bot Discord che hai collegato, oppure menzionalo in un canale a cui si è unito. Solo gli ID utente nell'elenco degli utenti autorizzati qui sotto ricevono una risposta.", + "dismiss": "Mi sono collegato", + "show": "Mostra dettagli di connessione" } }