import { useEffect, useRef, useState } from "react"; import { ActivityIndicator, Text, TouchableOpacity, View } from "react-native"; import { TrueSheet, type SheetDetent } from "@lodev09/react-native-true-sheet"; import { Ionicons } from "@expo/vector-icons"; import { useTranslation } from "react-i18next"; import { useColors } from "../lib/theme"; import { useDeviceApprovalStore } from "../stores/deviceApproval"; /** * Sheet das auf dem NEUEN Gerät erscheint nachdem es Approval angefordert hat. * * Zeigt: * - 6-stelligen Code (zum visuellen Vergleich mit dem anderen Gerät) * - Status: "Warte auf Bestätigung..." / "Bestätigt ✓" / "Abgelehnt" * - "Per E-Mail senden" Fallback-Button * * Pollt alle 2.5s den Status (Realtime ist nicht zuverlässig auf einem * Gerät das noch keinen registrierten Device-Slot hat). * * Caller (DeviceLimitReachedSheet) füllt store.outgoing → dieses Sheet öffnet. * Bei status="approved" → caller triggert register-Retry. */ export function DeviceApprovalPendingSheet(props: { /** Wird aufgerufen wenn Approval = approved. Caller soll dann register retryen. */ onApproved?: () => void; }) { const { t } = useTranslation(); const colors = useColors(); const sheetRef = useRef(null); const outgoing = useDeviceApprovalStore((s) => s.outgoing); const emailSent = useDeviceApprovalStore((s) => s.outgoingEmailSent); const error = useDeviceApprovalStore((s) => s.outgoingError); const pollOutgoing = useDeviceApprovalStore((s) => s.pollOutgoing); const sendEmailFallback = useDeviceApprovalStore((s) => s.sendEmailFallback); const clearOutgoing = useDeviceApprovalStore((s) => s.clearOutgoing); const [sendingEmail, setSendingEmail] = useState(false); // Sheet open/close based on store useEffect(() => { if (outgoing) sheetRef.current?.present(); else sheetRef.current?.dismiss(); }, [outgoing]); // Polling useEffect(() => { if (!outgoing || outgoing.status !== "pending") return; const interval = setInterval(() => pollOutgoing(), 2500); return () => clearInterval(interval); }, [outgoing, pollOutgoing]); // Trigger onApproved useEffect(() => { if (outgoing?.status === "approved") { props.onApproved?.(); } }, [outgoing?.status, props]); if (!outgoing) return null; const isPending = outgoing.status === "pending"; const isApproved = outgoing.status === "approved"; const isRejected = outgoing.status === "rejected"; const isExpired = outgoing.status === "expired"; async function handleSendEmail() { setSendingEmail(true); try { await sendEmailFallback(); } finally { setSendingEmail(false); } } return ( clearOutgoing()} > {isApproved ? t("device_approval.pending_approved_title") : isRejected ? t("device_approval.pending_rejected_title") : isExpired ? t("device_approval.pending_expired_title") : t("device_approval.pending_title")} {isApproved ? t("device_approval.pending_approved_subtitle") : isRejected ? t("device_approval.pending_rejected_subtitle") : isExpired ? t("device_approval.pending_expired_subtitle") : t("device_approval.pending_subtitle")} {/* CODE BOX */} {isPending ? ( {t("device_approval.code_label")} {outgoing.code} {t("device_approval.waiting")} ) : null} {error ? ( {error} ) : null} {/* Email-Fallback */} {isPending ? ( {sendingEmail ? ( ) : ( {emailSent ? t("device_approval.email_already_sent") : t("device_approval.send_email")} )} ) : null} {/* Close button (only if not pending) */} {!isPending ? ( { sheetRef.current?.dismiss(); clearOutgoing(); }} activeOpacity={0.7} style={{ paddingVertical: 14, borderRadius: 12, backgroundColor: isApproved ? "#22c55e" : "rgba(0,0,0,0.06)", alignItems: "center", }} > {isApproved ? t("device_approval.continue") : t("device_approval.close")} ) : ( { sheetRef.current?.dismiss(); clearOutgoing(); }} activeOpacity={0.7} style={{ paddingVertical: 10, alignItems: "center", }} > {t("device_approval.cancel")} )} ); }