diff --git a/desktop/src/features/settings/ui/MobilePairingCard.tsx b/desktop/src/features/settings/ui/MobilePairingCard.tsx
index e15f54316b..0d58f86458 100644
--- a/desktop/src/features/settings/ui/MobilePairingCard.tsx
+++ b/desktop/src/features/settings/ui/MobilePairingCard.tsx
@@ -4,11 +4,10 @@ import {
Copy,
LoaderCircle,
RefreshCw,
- ShieldCheck,
TriangleAlert,
- X,
} from "lucide-react";
import { listen } from "@tauri-apps/api/event";
+import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import { toast } from "sonner";
import {
@@ -16,15 +15,9 @@ import {
confirmPairingSas,
startPairing,
} from "@/shared/api/tauri";
+import { cn } from "@/shared/lib/cn";
import { Button } from "@/shared/ui/button";
import { StyledQrCode } from "@/shared/ui/styled-qr-code";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
-} from "@/shared/ui/dialog";
import { SettingsOptionGroup, SettingsOptionRow } from "./SettingsOptionGroup";
import { SettingsSectionHeader } from "./SettingsSectionHeader";
import { writeTextToClipboard } from "@/shared/lib/clipboard";
@@ -39,6 +32,8 @@ type PairingStep =
| "done"
| "error";
+const PAIRING_CODE_DIGIT_POSITIONS = [0, 1, 2, 3, 4, 5] as const;
+
function pairingErrorMessage(error: unknown) {
const message =
error instanceof Error
@@ -58,114 +53,189 @@ function isPairingSessionTimeout(message: string) {
return message.toLowerCase().includes("session timed out");
}
-function PairingStatusDialog({
- onClose,
+function PairingStepIndicator({
+ complete,
+ label,
+ testId,
+}: {
+ complete: boolean;
+ label: string;
+ testId: string;
+}) {
+ const shouldReduceMotion = useReducedMotion() ?? false;
+ const hiddenState = shouldReduceMotion
+ ? { opacity: 0 }
+ : { filter: "blur(2px)", opacity: 0, scale: 0.25 };
+ const visibleState = shouldReduceMotion
+ ? { opacity: 1 }
+ : { filter: "blur(0px)", opacity: 1, scale: 1 };
+
+ return (
+
+
+
+ {complete ? : label}
+
+
+
+ );
+}
+
+function PairingSteps({ step }: { step: PairingStep }) {
+ const hasScanned =
+ step === "sas" || step === "transferring" || step === "done";
+ const hasConfirmed = step === "transferring" || step === "done";
+ const isPaired = step === "done";
+
+ return (
+
+ -
+
+
+
Scan QR code
+
+ Open Buzz on your mobile device and scan the code shown here.
+
+
+
+
+ -
+
+
+
Confirm mobile code
+
+ Check that the six-digit code matches on both devices, then confirm
+ it.
+
+
+
+
+ -
+
+
+
+ {isPaired ? "Paired" : "Pair your mobile app"}
+
+
+ {isPaired
+ ? "Your mobile app is now connected to this relay."
+ : "Your mobile app will connect after you confirm the code."}
+
+
+
+
+ );
+}
+
+function PairingCodeConfirmation({
onConfirm,
onDeny,
sasCode,
- step,
}: {
- onClose: () => void;
onConfirm: () => void;
onDeny: () => void;
- sasCode: string | null;
- step: PairingStep;
+ sasCode: string;
}) {
- const open = step === "sas" || step === "transferring" || step === "done";
+ const formattedCode = `${sasCode.slice(0, 3)} ${sasCode.slice(3, 6)}`;
return (
-