"use client"; import { useState, useEffect, useCallback, useRef } from "react"; import { Loader2, LogOut, CreditCard, } from "lucide-react"; import { Button } from "@/shared/components/ui/button"; import { Badge } from "@/shared/components/ui/badge"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/shared/components/ui/tooltip"; import { cn } from "@/shared/lib/utils"; /* ------------------------------------------------------------------ */ /* Types */ /* ------------------------------------------------------------------ */ export type EpaySessionStatus = { connected: boolean; username?: string; connectedAt?: string; credits?: number; creditsCheckedAt?: string; }; /* ------------------------------------------------------------------ */ /* Component */ /* ------------------------------------------------------------------ */ export function EpayConnect({ onStatusChange, triggerConnect, }: { onStatusChange?: (status: EpaySessionStatus) => void; /** When set to true, triggers auto-connect (e.g. when user types UAT) */ triggerConnect?: boolean; }) { const [status, setStatus] = useState({ connected: false }); const [connecting, setConnecting] = useState(false); const [error, setError] = useState(""); const pollRef = useRef | null>(null); const cbRef = useRef(onStatusChange); cbRef.current = onStatusChange; const autoConnectAttempted = useRef(false); const autoConnectTimerRef = useRef | null>(null); const fetchStatus = useCallback(async () => { try { const res = await fetch("/api/ancpi/session"); const data = (await res.json()) as EpaySessionStatus; setStatus(data); cbRef.current?.(data); if (data.connected) setError(""); return data; } catch { /* silent */ return null; } }, []); // Poll every 30s — detect disconnection and allow re-connect useEffect(() => { void fetchStatus(); pollRef.current = setInterval(() => { void fetchStatus().then((data) => { if (data && !data.connected && autoConnectAttempted.current) { autoConnectAttempted.current = false; } }); }, 30_000); return () => { if (pollRef.current) clearInterval(pollRef.current); }; }, [fetchStatus]); const connect = useCallback(async () => { if (connecting || status.connected) return; setConnecting(true); setError(""); try { const res = await fetch("/api/ancpi/session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({}), }); const data = (await res.json()) as { success?: boolean; credits?: number; error?: string }; if (!res.ok || data.error) { setError(data.error ?? "Eroare conectare ePay"); } else { await fetchStatus(); } } catch { setError("Eroare retea"); } finally { setConnecting(false); } }, [connecting, status.connected, fetchStatus]); // Auto-connect when triggerConnect becomes true, with retry on failure useEffect(() => { if (!triggerConnect || status.connected || connecting || autoConnectAttempted.current) return; autoConnectAttempted.current = true; let cancelled = false; const maxRetries = 2; const attemptConnect = async (attempt: number) => { if (cancelled) return; // On first attempt, check session to avoid unnecessary connect if (attempt === 0) { const current = await fetchStatus(); if (cancelled) return; if (current?.connected) return; } setConnecting(true); setError(""); let shouldRetry = false; try { const res = await fetch("/api/ancpi/session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({}), }); const data = (await res.json()) as { success?: boolean; credits?: number; error?: string }; if (cancelled) return; if (!res.ok || data.error) { setError(data.error ?? "Eroare conectare ePay"); shouldRetry = attempt < maxRetries; } else { await fetchStatus(); } } catch { if (cancelled) return; setError("Eroare retea"); shouldRetry = attempt < maxRetries; } if (cancelled) return; if (shouldRetry) { // Keep connecting state true during retry wait autoConnectTimerRef.current = setTimeout(() => { void attemptConnect(attempt + 1); }, 3000); } else { setConnecting(false); } }; void attemptConnect(0); return () => { cancelled = true; if (autoConnectTimerRef.current) { clearTimeout(autoConnectTimerRef.current); autoConnectTimerRef.current = null; } }; }, [triggerConnect, status.connected, connecting, fetchStatus]); const disconnect = async () => { try { await fetch("/api/ancpi/session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "disconnect" }), }); autoConnectAttempted.current = false; if (autoConnectTimerRef.current) { clearTimeout(autoConnectTimerRef.current); autoConnectTimerRef.current = null; } await fetchStatus(); } catch { /* silent */ } }; return (
{/* Status pill */}
{connecting ? ( ) : status.connected ? ( ) : null} ePay {status.connected && status.credits != null && ( {status.credits} )}
{status.connected ? `${status.credits ?? "?"} credite ePay disponibile` : error ? error : connecting ? "Se conecteaza..." : "Se conecteaza automat la selectia UAT"}
{/* Logout button — only when connected */} {status.connected && ( )}
); }