feat: ZIP download, mobile fixes, click centering, tooltip

ZIP download:
- Both portal and RGI test page now create a single ZIP archive
  (Documente_eliberate_{appNo}.zip) instead of sequential downloads
- Uses JSZip (already in project dependencies)

Portal mobile:
- Basemap switcher drops below UAT card on mobile (top-14 sm:top-2)
- Selection toolbar at bottom-3 with z-30 (always visible)
- Click on feature centers map on that parcel (flyTo)

Tooltips:
- Green download icon: "Descarca arhiva ZIP cu documentele cererii X"
- Updated on both portal and RGI test page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-25 09:17:29 +02:00
parent 8acafe958b
commit 12ff629fbf
2 changed files with 58 additions and 37 deletions
+19 -17
View File
@@ -1,6 +1,7 @@
"use client";
import React, { useState, useCallback, useMemo, useEffect, useRef } from "react";
import JSZip from "jszip";
import { Button } from "@/shared/components/ui/button";
import { Input } from "@/shared/components/ui/input";
import { Label } from "@/shared/components/ui/label";
@@ -354,10 +355,10 @@ function IssuedDocsPanel({
const handleDownloadAll = useCallback(async () => {
if (!docs || docs.length === 0 || downloadingAll) return;
setDownloadingAll(true);
const zip = new JSZip();
let downloaded = 0;
let blocked = 0;
// Count duplicates by docType for naming (e.g. Receptie_tehnica_66903_2.pdf)
const typeCounts: Record<string, number> = {};
for (const d of docs) typeCounts[d.docType || "Document"] = (typeCounts[d.docType || "Document"] || 0) + 1;
const typeIdx: Record<string, number> = {};
@@ -382,30 +383,31 @@ function IssuedDocsPanel({
try {
const res = await fetch(url);
const ct = res.headers.get("content-type") || "";
if (ct.includes("application/json")) {
blocked++;
continue;
}
if (ct.includes("application/json")) { blocked++; continue; }
const blob = await res.blob();
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = filename;
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(a.href);
document.body.removeChild(a);
zip.file(filename, blob);
downloaded++;
// Small delay between downloads so browser doesn't block them
await new Promise((r) => setTimeout(r, 300));
} catch {
blocked++;
}
}
if (downloaded > 0) {
setDownloadProgress("Se creeaza arhiva ZIP...");
const zipBlob = await zip.generateAsync({ type: "blob" });
const a = document.createElement("a");
a.href = URL.createObjectURL(zipBlob);
a.download = `Documente_eliberate_${appNo}.zip`;
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(a.href);
document.body.removeChild(a);
}
setDownloadProgress(
blocked > 0
? `${downloaded} descarcat${downloaded !== 1 ? "e" : ""}, ${blocked} indisponibil${blocked !== 1 ? "e" : ""}`
: `${downloaded} document${downloaded !== 1 ? "e" : ""} descarcat${downloaded !== 1 ? "e" : ""}`,
? `${downloaded} in ZIP, ${blocked} indisponibil${blocked !== 1 ? "e" : ""}`
: `ZIP descarcat cu ${downloaded} document${downloaded !== 1 ? "e" : ""}`,
);
setDownloadingAll(false);
setTimeout(() => setDownloadProgress(""), 5000);
@@ -982,7 +984,7 @@ export default function RgiTestPage() {
</button>
</TooltipTrigger>
<TooltipContent side="right" className="text-xs max-w-xs">
<p className="font-semibold">Nr. {app.appNo} click descarca toate</p>
<p className="font-semibold">Descarca arhiva ZIP cu documentele cererii {app.appNo}</p>
<p>{app.applicationObject || "-"}</p>
<p>Status: {app.statusName || app.stateCode}</p>
<p>Rezolutie: {app.resolutionName || "-"}</p>