Files
ArchiTools/src/modules/parcel-sync/components/connection-pill.tsx
T
AI Assistant b87c908415 fix(parcel-sync): static connection dots, legend position, mismatch labels
- ePay + eTerra pills: removed animate-ping, now show static green dot
  when connected (no more spinning appearance)
- Legend moved to top-left, hides when FeatureInfoPanel is open
  (no more overlap)
- Boundary mismatch parcels now show cadastral numbers as labels
  (orange for foreign, purple for edge parcels)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:39:01 +02:00

205 lines
7.2 KiB
TypeScript

"use client";
import {
Loader2,
LogOut,
Wifi,
WifiOff,
AlertTriangle,
} from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/shared/components/ui/dropdown-menu";
import { cn } from "@/shared/lib/utils";
import type { SessionStatus } from "./parcel-sync-types";
/* ------------------------------------------------------------------ */
/* Connection Status Pill */
/* ------------------------------------------------------------------ */
export function ConnectionPill({
session,
connecting,
connectionError,
onDisconnect,
}: {
session: SessionStatus;
connecting: boolean;
connectionError: string;
onDisconnect: () => void;
}) {
const elapsed = session.connectedAt
? Math.floor(
(Date.now() - new Date(session.connectedAt).getTime()) / 60_000,
)
: 0;
const elapsedLabel =
elapsed < 1
? "acum"
: elapsed < 60
? `${elapsed} min`
: `${Math.floor(elapsed / 60)}h ${elapsed % 60}m`;
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
className={cn(
"flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs font-medium transition-all",
"hover:shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
session.connected
? "border-emerald-200 bg-emerald-50/80 text-emerald-700 dark:border-emerald-800 dark:bg-emerald-950/40 dark:text-emerald-400"
: session.eterraMaintenance
? "border-amber-200 bg-amber-50/80 text-amber-600 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-400"
: connectionError
? "border-rose-200 bg-rose-50/80 text-rose-600 dark:border-rose-800 dark:bg-rose-950/40 dark:text-rose-400"
: "border-muted-foreground/20 bg-muted/50 text-muted-foreground",
)}
>
{connecting ? (
<Loader2 className="h-3 w-3 animate-spin" />
) : session.connected ? (
<span className="inline-flex h-2 w-2 rounded-full bg-emerald-500" />
) : session.eterraMaintenance ? (
<AlertTriangle className="h-3 w-3" />
) : connectionError ? (
<WifiOff className="h-3 w-3" />
) : (
<Wifi className="h-3 w-3 opacity-50" />
)}
<span className="hidden sm:inline">
{connecting
? "Se conectează…"
: session.connected
? "eTerra"
: session.eterraMaintenance
? "Mentenanță"
: connectionError
? "Eroare"
: "Deconectat"}
</span>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-72 p-0">
{/* Status header */}
<div
className={cn(
"px-3 py-2.5 border-b",
session.connected
? "bg-emerald-50/50 dark:bg-emerald-950/20"
: "bg-muted/30",
)}
>
<div className="flex items-center justify-between">
<DropdownMenuLabel className="p-0 text-xs font-semibold">
Conexiune eTerra
</DropdownMenuLabel>
{session.connected && (
<span className="text-[10px] text-emerald-600 dark:text-emerald-400 font-mono">
{elapsedLabel}
</span>
)}
</div>
{session.connected && session.username && (
<p className="text-[11px] text-muted-foreground mt-0.5 truncate">
{session.username}
</p>
)}
{connectionError && (
<p className="text-[11px] text-rose-500 mt-0.5">
{connectionError}
</p>
)}
</div>
{/* Maintenance banner */}
{!session.connected && session.eterraMaintenance && (
<div className="px-3 py-3 text-xs border-b bg-amber-50/50 dark:bg-amber-950/20">
<div className="flex items-start gap-2">
<AlertTriangle className="h-3.5 w-3.5 text-amber-500 mt-0.5 shrink-0" />
<div>
<p className="font-medium text-amber-700 dark:text-amber-400">
eTerra este în mentenanță
</p>
<p className="mt-1 text-[11px] text-amber-600/80 dark:text-amber-400/70">
Platforma ANCPI nu este disponibilă momentan. Conectarea va fi
reactivată automat când serviciul revine online.
</p>
{session.eterraHealthMessage && (
<p className="mt-1 text-[10px] opacity-60 font-mono">
{session.eterraHealthMessage}
</p>
)}
</div>
</div>
</div>
)}
{/* Info when not connected (and not in maintenance) */}
{!session.connected &&
!connectionError &&
!session.eterraMaintenance && (
<div className="px-3 py-3 text-xs text-muted-foreground">
<p>Conexiunea se face automat când începi scrii un UAT.</p>
<p className="mt-1 text-[11px] opacity-70">
Credențialele sunt preluate din configurarea serverului.
</p>
</div>
)}
{/* Error detail (only when NOT maintenance) */}
{!session.connected &&
connectionError &&
!session.eterraMaintenance && (
<div className="px-3 py-3 text-xs text-muted-foreground">
<p>
Conexiunea automată a eșuat. Verifică credențialele din
variabilele de mediu (ETERRA_USERNAME / ETERRA_PASSWORD).
</p>
</div>
)}
{/* Connected — active jobs info + disconnect */}
{session.connected && (
<>
{session.activeJobCount > 0 && (
<div className="px-3 py-2 border-b bg-amber-50/50 dark:bg-amber-950/20">
<p className="text-[11px] text-amber-700 dark:text-amber-400">
<span className="font-semibold">
{session.activeJobCount} job
{session.activeJobCount > 1 ? "-uri" : ""} activ
{session.activeJobCount > 1 ? "e" : ""}
</span>
{session.activeJobPhase && (
<span className="opacity-70">
{" "}
{session.activeJobPhase}
</span>
)}
</p>
</div>
)}
<DropdownMenuSeparator className="m-0" />
<div className="p-1.5">
<button
type="button"
className="flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-xs text-muted-foreground hover:bg-muted hover:text-foreground transition-colors"
onClick={onDisconnect}
>
<LogOut className="h-3 w-3" />
Deconectare
</button>
</div>
</>
)}
</DropdownMenuContent>
</DropdownMenu>
);
}