Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1741574eb2 |
@@ -5,6 +5,7 @@ import { useTranslations } from "next-intl";
|
|||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { PACKAGE_CATALOG, DEFAULT_PACKAGE_IDS, type PackageDef } from "@/lib/packages";
|
import { PACKAGE_CATALOG, DEFAULT_PACKAGE_IDS, type PackageDef } from "@/lib/packages";
|
||||||
import { isPersonalOrgName, displayOrgNameFor } from "@/lib/personal-org";
|
import { isPersonalOrgName, displayOrgNameFor } from "@/lib/personal-org";
|
||||||
|
import { THREEMA_GATEWAY } from "@/lib/threema-gateway-config";
|
||||||
import {
|
import {
|
||||||
configureStepSchema,
|
configureStepSchema,
|
||||||
billingStepSchema,
|
billingStepSchema,
|
||||||
@@ -814,6 +815,40 @@ export function OnboardingWizard({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Threema: show the bot's Threema ID
|
||||||
|
and QR right here in the wizard. The
|
||||||
|
instructions text refers to a QR
|
||||||
|
that isn't visible until after
|
||||||
|
provisioning — without this block
|
||||||
|
the message is confusing. The QR is
|
||||||
|
the platform's shared gateway QR
|
||||||
|
(*AIAGENT), identical for every
|
||||||
|
tenant, so we can render it before
|
||||||
|
the tenant even exists. */}
|
||||||
|
{pkg.id === "threema" && (
|
||||||
|
<div className="rounded-lg border border-accent/30 bg-surface-1 p-3 flex items-start gap-3">
|
||||||
|
<div className="bg-white p-1.5 rounded-md shrink-0">
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src={THREEMA_GATEWAY.qrCodePath}
|
||||||
|
alt={`QR code for ${THREEMA_GATEWAY.displayName}`}
|
||||||
|
width={96}
|
||||||
|
height={96}
|
||||||
|
style={{ display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-text-secondary leading-relaxed">
|
||||||
|
<div className="text-text-primary font-medium mb-1">
|
||||||
|
{tPkg("threemaBotIdHeading")}
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-sm text-accent mb-2">
|
||||||
|
{THREEMA_GATEWAY.displayName}
|
||||||
|
</div>
|
||||||
|
<div>{tPkg("threemaBotIdHint")}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{(pkg.secrets || []).map((field) => (
|
{(pkg.secrets || []).map((field) => (
|
||||||
<label key={field.key} className="block">
|
<label key={field.key} className="block">
|
||||||
<span className="text-xs text-text-secondary mb-1 block">
|
<span className="text-xs text-text-secondary mb-1 block">
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type {
|
|||||||
SkillPricing,
|
SkillPricing,
|
||||||
} from "@/types";
|
} from "@/types";
|
||||||
import { SkillCostDialog } from "./skill-cost-dialog";
|
import { SkillCostDialog } from "./skill-cost-dialog";
|
||||||
|
import { ThreemaQrModal } from "@/components/channel-users/threema-qr-modal";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
pkg: PackageDef;
|
pkg: PackageDef;
|
||||||
@@ -51,6 +52,11 @@ export function PackageCard({
|
|||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
// Phase 2.5: cost-disclosure flow + activation-request flow.
|
// Phase 2.5: cost-disclosure flow + activation-request flow.
|
||||||
const [showCostDialog, setShowCostDialog] = useState(false);
|
const [showCostDialog, setShowCostDialog] = useState(false);
|
||||||
|
// Threema: after a successful enable on customProvisioning, surface
|
||||||
|
// the gateway QR + bot Threema ID so the customer immediately knows
|
||||||
|
// how to add the assistant to their Threema contacts. Without this,
|
||||||
|
// the toggle just flips silently with no actionable info.
|
||||||
|
const [showThreemaInfo, setShowThreemaInfo] = useState(false);
|
||||||
const isPriced =
|
const isPriced =
|
||||||
(pricing?.dailyPriceChf ?? 0) > 0 || (pricing?.setupFeeChf ?? 0) > 0;
|
(pricing?.dailyPriceChf ?? 0) > 0 || (pricing?.setupFeeChf ?? 0) > 0;
|
||||||
|
|
||||||
@@ -79,6 +85,14 @@ export function PackageCard({
|
|||||||
throw new Error(err.error || `Provisioning failed (HTTP ${provRes.status})`);
|
throw new Error(err.error || `Provisioning failed (HTTP ${provRes.status})`);
|
||||||
}
|
}
|
||||||
await togglePackage(true);
|
await togglePackage(true);
|
||||||
|
// For Threema specifically: now that the relay's minted the
|
||||||
|
// per-tenant token and the package is enabled, show the
|
||||||
|
// gateway QR + bot Threema ID so the customer can add the
|
||||||
|
// assistant to their Threema contacts straight away. Other
|
||||||
|
// customProvisioning packages don't need this confirmation.
|
||||||
|
if (pkg.id === "threema") {
|
||||||
|
setShowThreemaInfo(true);
|
||||||
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
setError(e.message);
|
setError(e.message);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -320,6 +334,16 @@ export function PackageCard({
|
|||||||
busy={saving}
|
busy={saving}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Threema: post-enable confirmation showing the gateway QR
|
||||||
|
and bot Threema ID. Only rendered for the threema package
|
||||||
|
and only after a successful enable. The same modal is also
|
||||||
|
reachable later on the channel-users page. */}
|
||||||
|
{pkg.id === "threema" && (
|
||||||
|
<ThreemaQrModal
|
||||||
|
open={showThreemaInfo}
|
||||||
|
onClose={() => setShowThreemaInfo(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{showModal && (
|
{showModal && (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4">
|
||||||
<div className="w-full max-w-md bg-surface-1 border border-border rounded-2xl p-6 space-y-4 shadow-2xl shadow-black/40">
|
<div className="w-full max-w-md bg-surface-1 border border-border rounded-2xl p-6 space-y-4 shadow-2xl shadow-black/40">
|
||||||
|
|||||||
@@ -324,7 +324,9 @@
|
|||||||
"tryAgain": "Erneut versuchen",
|
"tryAgain": "Erneut versuchen",
|
||||||
"credentialsSaved": "Zugangsdaten gespeichert",
|
"credentialsSaved": "Zugangsdaten gespeichert",
|
||||||
"credentialsSavedTip": "Die eingegebenen Zugangsdaten sind sicher gespeichert und werden verwendet, sobald die Aktivierung vom Admin genehmigt wurde. Sie müssen sie nicht erneut eingeben.",
|
"credentialsSavedTip": "Die eingegebenen Zugangsdaten sind sicher gespeichert und werden verwendet, sobald die Aktivierung vom Admin genehmigt wurde. Sie müssen sie nicht erneut eingeben.",
|
||||||
"recommended": "Empfohlen"
|
"recommended": "Empfohlen",
|
||||||
|
"threemaBotIdHeading": "Bot-Threema-ID",
|
||||||
|
"threemaBotIdHint": "Sobald Ihr Mandant freigegeben ist, scannen Sie diesen QR-Code mit Threema, um den Assistenten zu Ihren Kontakten hinzuzufügen. Der QR-Code ist für jeden PieCed-Mandanten identisch — Sie können ihn schon jetzt speichern."
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"title": "Plattform-Admin",
|
"title": "Plattform-Admin",
|
||||||
|
|||||||
@@ -324,7 +324,9 @@
|
|||||||
"tryAgain": "Try again",
|
"tryAgain": "Try again",
|
||||||
"credentialsSaved": "credentials saved",
|
"credentialsSaved": "credentials saved",
|
||||||
"credentialsSavedTip": "The credentials you entered are securely stored and will be used as soon as admin approves the activation. You don't need to re-enter them.",
|
"credentialsSavedTip": "The credentials you entered are securely stored and will be used as soon as admin approves the activation. You don't need to re-enter them.",
|
||||||
"recommended": "Recommended"
|
"recommended": "Recommended",
|
||||||
|
"threemaBotIdHeading": "Bot Threema ID",
|
||||||
|
"threemaBotIdHint": "Once your tenant is approved, scan this QR with Threema to add the assistant to your contacts. The QR is the same for every PieCed tenant — you can save it now."
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"title": "Platform Admin",
|
"title": "Platform Admin",
|
||||||
|
|||||||
@@ -324,7 +324,9 @@
|
|||||||
"tryAgain": "Réessayer",
|
"tryAgain": "Réessayer",
|
||||||
"credentialsSaved": "identifiants enregistrés",
|
"credentialsSaved": "identifiants enregistrés",
|
||||||
"credentialsSavedTip": "Les identifiants saisis sont stockés en sécurité et seront utilisés dès l'approbation de l'activation par l'administrateur. Vous n'avez pas besoin de les ressaisir.",
|
"credentialsSavedTip": "Les identifiants saisis sont stockés en sécurité et seront utilisés dès l'approbation de l'activation par l'administrateur. Vous n'avez pas besoin de les ressaisir.",
|
||||||
"recommended": "Recommandé"
|
"recommended": "Recommandé",
|
||||||
|
"threemaBotIdHeading": "ID Threema du bot",
|
||||||
|
"threemaBotIdHint": "Une fois votre tenant approuvé, scannez ce QR avec Threema pour ajouter l'assistant à vos contacts. Le QR est identique pour chaque tenant PieCed — vous pouvez l'enregistrer dès maintenant."
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"title": "Admin plateforme",
|
"title": "Admin plateforme",
|
||||||
|
|||||||
@@ -324,7 +324,9 @@
|
|||||||
"tryAgain": "Riprova",
|
"tryAgain": "Riprova",
|
||||||
"credentialsSaved": "credenziali salvate",
|
"credentialsSaved": "credenziali salvate",
|
||||||
"credentialsSavedTip": "Le credenziali inserite sono memorizzate in modo sicuro e saranno utilizzate non appena l'attivazione viene approvata dall'amministratore. Non è necessario reinserirle.",
|
"credentialsSavedTip": "Le credenziali inserite sono memorizzate in modo sicuro e saranno utilizzate non appena l'attivazione viene approvata dall'amministratore. Non è necessario reinserirle.",
|
||||||
"recommended": "Consigliato"
|
"recommended": "Consigliato",
|
||||||
|
"threemaBotIdHeading": "ID Threema del bot",
|
||||||
|
"threemaBotIdHint": "Una volta approvato il suo tenant, scansioni questo QR con Threema per aggiungere l'assistente ai suoi contatti. Il QR è identico per ogni tenant PieCed — può salvarlo già adesso."
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"title": "Admin piattaforma",
|
"title": "Admin piattaforma",
|
||||||
|
|||||||
Reference in New Issue
Block a user