diff --git a/src/app/(modules)/wds/page.tsx b/src/app/(modules)/wds/page.tsx
index 49fcf58..8b33469 100644
--- a/src/app/(modules)/wds/page.tsx
+++ b/src/app/(modules)/wds/page.tsx
@@ -13,6 +13,9 @@ import {
Clock,
MapPin,
Search,
+ AlertTriangle,
+ WifiOff,
+ Activity,
} from "lucide-react";
import { Button } from "@/shared/components/ui/button";
import { Input } from "@/shared/components/ui/input";
@@ -50,6 +53,14 @@ type QueueState = {
completedCycles: number;
};
+type SyncStatus = "running" | "error" | "waiting" | "idle";
+
+type CurrentActivity = {
+ city: string;
+ step: string;
+ startedAt: string;
+} | null;
+
const STEPS: StepName[] = [
"sync_terenuri",
"sync_cladiri",
@@ -64,6 +75,10 @@ const STEP_LABELS: Record
Sincronizarea ruleaza automat Vineri, Sambata si Duminica noaptea (23:00-04:00). Procesarea e intercalata intre orase si se reia de - unde a ramas. + unde a ramas. Pagina se actualizeaza automat la fiecare {syncStatus === "running" ? "15" : "60"} secunde.
Prioritate: P1 = primele procesate, P2 = urmatoarele, P3 = adaugate
diff --git a/src/app/api/eterra/weekend-sync/route.ts b/src/app/api/eterra/weekend-sync/route.ts
index 02a8c98..441e74a 100644
--- a/src/app/api/eterra/weekend-sync/route.ts
+++ b/src/app/api/eterra/weekend-sync/route.ts
@@ -1,8 +1,14 @@
import { NextResponse } from "next/server";
import { PrismaClient, Prisma } from "@prisma/client";
+import {
+ isWeekendWindow,
+ getWeekendSyncActivity,
+} from "@/modules/parcel-sync/services/weekend-deep-sync";
const prisma = new PrismaClient();
+const g = globalThis as { __parcelSyncRunning?: boolean };
+
const KV_NAMESPACE = "parcel-sync-weekend";
const KV_KEY = "queue-state";
@@ -116,8 +122,25 @@ export async function GET() {
dbStats: statsMap.get(c.siruta) ?? { terenuri: 0, cladiri: 0, total: 0, enriched: 0 },
}));
+ // Determine live sync status
+ const running = !!g.__parcelSyncRunning;
+ const activity = getWeekendSyncActivity();
+ const inWindow = isWeekendWindow();
+ const hasErrors = state.cities.some((c) =>
+ (Object.values(c.steps) as StepStatus[]).some((s) => s === "error"),
+ );
+
+ type SyncStatus = "running" | "error" | "waiting" | "idle";
+ let syncStatus: SyncStatus = "idle";
+ if (running) syncStatus = "running";
+ else if (hasErrors) syncStatus = "error";
+ else if (inWindow) syncStatus = "waiting";
+
return NextResponse.json({
state: { ...state, cities: citiesWithStats },
+ syncStatus,
+ currentActivity: activity,
+ inWeekendWindow: inWindow,
});
}
diff --git a/src/modules/parcel-sync/services/weekend-deep-sync.ts b/src/modules/parcel-sync/services/weekend-deep-sync.ts
index 8a67f99..4746a59 100644
--- a/src/modules/parcel-sync/services/weekend-deep-sync.ts
+++ b/src/modules/parcel-sync/services/weekend-deep-sync.ts
@@ -22,6 +22,22 @@ import { sendEmail } from "@/core/notifications/email-service";
const prisma = new PrismaClient();
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
+/* ------------------------------------------------------------------ */
+/* Live activity tracking (globalThis — same process) */
+/* ------------------------------------------------------------------ */
+
+const g = globalThis as {
+ __weekendSyncActivity?: {
+ city: string;
+ step: string;
+ startedAt: string;
+ } | null;
+};
+
+export function getWeekendSyncActivity() {
+ return g.__weekendSyncActivity ?? null;
+}
+
/* ------------------------------------------------------------------ */
/* City queue configuration */
/* ------------------------------------------------------------------ */
@@ -315,6 +331,7 @@ export async function runWeekendDeepSync(): Promise ${timeStr}
+ Generat automat de ArchiTools Weekend Sync
+ Weekend Sync — Eroare
+
+
+
+
+ Oras
+ ${city.name} (${city.county})
+
+
+ Pas
+ ${stepLabel[step]}
+
+
+ Eroare
+ ${errorMsg}
+