Three independent issues from the live test on 50198:
1. CfOrderModal poll timeout was 90s but ANCPI orders routinely take
60-180s end-to-end. The 50198 order completed at 129s (logs show
6 polls before docs matched), but the modal had already errored
out 39s before that with "Procesarea durează mai mult decât ne-am
așteptat". Bump to 180s + update the user-facing copy from "60 de
secunde" to "3 minute" so the expectation matches reality.
2. cfApiBase(useGisAc=true) routed pilot users to /api/cf which proxies
to gis-api → gis_core."CfExtract", but the ePay queue still writes
ONLY to architools_postgres."CfExtract". Pilot users were therefore
blind to their own fresh orders in the listing + catalog checks
(50198 invisible despite being completed + downloadable). Pin all
CF API calls to legacy /api/ancpi until Faza H mirrors writes to
gis-api too; the source of truth then becomes a single table.
3. Manual cleanup of one stuck order in gis_enrichment.CfExtract
(354686, pending since 2026-05-19) — never advanced past `pending`,
was showing up as "În coadă" in the Extrase CF tab for ~4 days.
Set status=cancelled with an explanatory errorMessage.
(Applied via direct SQL on postgres-gis; no code change for this.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related issues with the modal when the user kept clicking
around the map while in CF order mode:
1. LAYOUT BREAK (Marius screenshot — modal header clipped above
viewport): The V2 panel wrapper uses `backdrop-blur-md`. Per CSS
spec, an element with non-none backdrop-filter establishes a
containing block for `fixed`-positioned descendants. So
`fixed inset-0` on the modal was relative to the panel
(top-right, ~50px tall at min) instead of the viewport — the
modal anchored to the panel and overflowed up. Fix: render via
React's createPortal to document.body. The modal now escapes the
panel's stacking context entirely and centers in the viewport.
Also bumped z-index from 50 to 100 so the modal stays above the
MapLibre canvas + panel itself.
2. STATE CARRY-OVER: clicking a different parcel while the modal
was open silently re-targeted the modal at the new parcel — same
modal showing different cadref/sold mid-flow could mislead the
user about which parcel they were buying CF for. Fix:
FeatureInfoPanel now has a useEffect that closes the modal when
feature.cadastralRef / siruta / layerId changes. Modal stays
scoped to a single decision.
SSR guard: if (typeof document === "undefined") return null; before
the portal call so the modal doesn't blow up during server-side
render.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Marius: don't kick the user out to /parcel-sync just to connect ePay,
do everything inside the modal. The parcel-sync page also wasn't
helpful when reached (UAT selector empty), so the redirect was a
dead-end anyway.
State machine rewrite:
loading-status → GET /api/ancpi/session
not-connected → DELETED (replaced by transparent flow)
connecting → POST /api/ancpi/session with {} — server picks up
ANCPI_USERNAME/ANCPI_PASSWORD from env (Infisical
has them in /architools), connects silently
need-credentials → only if env creds are missing OR invalid: shows
an inline form (username / password / Conectează
button + privacy note "nu sunt păstrate la noi
după sfârșitul sesiunii")
no-credits / ready / placing / processing / done / error — as before
Flow for the happy path (Marius's case): user clicks "Comandă CF" →
modal shows "Conectare la ePay ANCPI…" for ~1s → "Verificare credite"
done → "Ești sigur? 1 credit, mai ai X" → confirm → animated steps
→ done. Zero page navigations.
Flow for the no-env case (other tenants or first-run): user sees
inline form, types credentials, presses Conectează → server stores
them in the in-memory session for the lifetime of the request,
modal continues straight to "ready".
Removed:
- goToParcelSync() handler + "Conectează ePay" deep-link button
- "not-connected" UI panel
- Phase value "not-connected" (no longer reachable)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Marius: click "Comandă CF" from the card itself, no new-tab to
parcel-sync. Show "Ești sigur? Costă 1 credit, mai ai X" first.
Animate the order through its phases until done.
New component cf-order-modal.tsx — a 7-state machine over a single
shadcn-style dialog:
loading-status — checks /api/ancpi/session for connection + credits
not-connected — ePay session offline → prompt to connect via
parcel-sync (the only place credentials live)
no-credits — 0 credits, can't proceed
ready — confirmation: 1 credit cost, current balance,
projected balance after the order, all in
rounded chips with Coins icon
placing — POST /api/ancpi/order, spinner on step 1
processing — poll /api/ancpi/orders every 3s until status
becomes completed/done/minioPath populated.
Shows live elapsed seconds; 90s timeout falls
through to error with "verifică din nou peste
câteva minute".
done — checkmark anim + "Descarcă PDF" if document URL
came back
error — destructive panel + Reîncearcă button
Animations (tailwindcss-animate utilities):
- Modal backdrop: fade-in 200ms
- Modal card: zoom-in-95 + slide-in-from-bottom 200ms
- Step rows: active row gets primary-tinted bg + Loader2 spin,
done rows turn emerald + Check icon zooms in 300ms
- Success/error final state: rounded badge + icon zooms in 500ms
Footer adapts per phase: Anulează+Confirmă (ready), Conectează ePay
(not-connected), Închide (loading/no-credits), Închide fereastra
(placing/processing — order continues in bg), Gata (done), Închide+
Reîncearcă (error).
Wires into feature-info-panel by replacing the "open /parcel-sync"
click handler with setCfModalOpen(true). Modal mounts at the
panel's root with fixed positioning + z-50 so it overlays the map.
Backdrop click dismisses except during placing/processing.
Uses the legacy /api/ancpi/* endpoints (not /api/cf/* gis-ac route)
per Marius's earlier decision to keep credit tracking on his own
ePay session.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>