From 488e6166721032b6f95063fdcebf74fd285f912c Mon Sep 17 00:00:00 2001 From: kamil2333UBB Date: Mon, 4 May 2026 15:38:18 +0200 Subject: [PATCH 1/5] feat: add interactive feature selection to report dialog --- .../dialogs/report/report-dialog.tsx | 396 +++++++++--------- src/lib/locales/en/keywords.ts | 2 + src/lib/locales/pl/keywords.ts | 2 + src/lib/locales/translation.ts | 2 + src/lib/report/generate-report-pdf.ts | 10 +- 5 files changed, 208 insertions(+), 204 deletions(-) diff --git a/src/components/dialogs/report/report-dialog.tsx b/src/components/dialogs/report/report-dialog.tsx index 3a8d2d5f..b4b4b519 100644 --- a/src/components/dialogs/report/report-dialog.tsx +++ b/src/components/dialogs/report/report-dialog.tsx @@ -12,7 +12,7 @@ import { import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { useTranslation } from "react-i18next"; -import { FileText, X } from "lucide-react"; +import { FileText, X, Check } from "lucide-react"; import { ICON } from "@/lib/utils/const"; import { CANVAS_ID } from "@/components/pixi/canvas/hooks/useCanvasContext"; import { MarkingsStore } from "@/lib/stores/Markings"; @@ -55,6 +55,16 @@ export function ReportDialog({ className }: ReportDialogProps) { const [addressLine4, setAddressLine4] = useState(""); const [reportLanguage, setReportLanguage] = useState(i18n.language); + const markingsLeft = MarkingsStore(CANVAS_ID.LEFT).use(state => state.markings); + const markingsRight = MarkingsStore(CANVAS_ID.RIGHT).use(state => state.markings); + + const allFeatures = useMemo(() => { + const labels = new Set([...markingsLeft.map(m => m.label), ...markingsRight.map(m => m.label)]); + return Array.from(labels).sort((a, b) => a - b); + },[markingsLeft, markingsRight]); + + const[selectedLabels, setSelectedLabels] = useState([]); + useEffect(() => { if (!isOpen) return; setReportDateTime(formatReportDateTime(new Date())); @@ -65,38 +75,24 @@ export function ReportDialog({ className }: ReportDialogProps) { setAddressLine3(reportDefaults?.addressLine3 ?? ""); setAddressLine4(reportDefaults?.addressLine4 ?? ""); setReportLanguage(i18n.language); - }, [isOpen, reportDefaults]); - - const workingMode = WorkingModeStore.use(state => state.workingMode); - const leftCount = MarkingsStore(CANVAS_ID.LEFT).use( - state => state.markings.length - ); - const rightCount = MarkingsStore(CANVAS_ID.RIGHT).use( - state => state.markings.length - ); + setSelectedLabels(allFeatures); + }, [isOpen, reportDefaults, allFeatures]); - const matchedFeatures = useMemo(() => { - const left = MarkingsStore(CANVAS_ID.LEFT).state.markings; - const right = MarkingsStore(CANVAS_ID.RIGHT).state.markings; - return getMatchedFeatures(left, right); - }, [leftCount, rightCount]); + const toggleFeature = (label: number) => { + setSelectedLabels(prev => + prev.includes(label) ? prev.filter(l => l !== label) : [...prev, label] + ); + }; - const pairedFeatures = useMemo(() => { - const left = MarkingsStore(CANVAS_ID.LEFT).state.markings; - const right = MarkingsStore(CANVAS_ID.RIGHT).state.markings; - return getPairedByLabel(left, right); - }, [leftCount, rightCount]); + const matchedFeaturesCount = useMemo(() => + getMatchedFeatures(markingsLeft, markingsRight).length,[markingsLeft, markingsRight]); - const availableCount = includeMatchedOnly - ? matchedFeatures.length - : pairedFeatures.length; - const selectedCount = availableCount; const generateReportLabel = t("Generate report", { ns: "keywords" }); - + const workingMode = WorkingModeStore.use(state => state.workingMode); const canGenerate = workingMode === WORKING_MODE.FINGERPRINT && - leftCount > 0 && - rightCount > 0; + markingsLeft.length > 0 && + markingsRight.length > 0; const onGenerate = async () => { if (!canGenerate) return; @@ -104,7 +100,6 @@ export function ReportDialog({ className }: ReportDialogProps) { setIsGenerating(true); const now = new Date(); const timestamp = formatReportDateTime(now); - setReportDateTime(timestamp); await generateReportPdfWithDialog({ includeMatchedOnly, reportDateTime: timestamp, @@ -117,6 +112,7 @@ export function ReportDialog({ className }: ReportDialogProps) { addressLine3.trim(), addressLine4.trim(), ], + selectedLabels, }); toast.success(t("Report generated", { ns: "tooltip" })); setIsOpen(false); @@ -158,209 +154,207 @@ export function ReportDialog({ className }: ReportDialogProps) { - - - - {t("Report generation", { ns: "keywords" })} - - - {t("Generate PDF report", { ns: "description" })} - + + + +
+ + {t("Report generation", { ns: "keywords" })} + + + {t("Generate PDF report", { ns: "description" })} + +
-
-
-
-
- {t("Matched features", { ns: "keywords" })}:{" "} - {matchedFeatures.length} -
-
- {t("Selected features", { ns: "keywords" })} - : {selectedCount} -
-
- {t("Selected features", { ns: "keywords" })} - : {selectedCount} -
-
+
+ +
+
+
+ + +
-
+ +
+ + setPerformedBy(e.target.value)} + className="flex h-10 w-full rounded-md border border-input bg-background shadow-sm hover:border-primary/50 transition-colors" /> - {t("Include matched only", { ns: "keywords" })} - +
-
-
- - -
-
- -
- -
-
+
+ + setDepartment(e.target.value)} + className="flex h-10 w-full rounded-md border border-input bg-background shadow-sm hover:border-primary/50 transition-colors" + /> +
-
-