import { memo, useCallback, useEffect, useMemo, useState } from "react"; import axios from "axios"; import { Button, Checkbox, Input, Modal, ModalBody, ModalContent, ModalHeader, Select, SelectItem, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow, Textarea, Tooltip, type Selection, useDisclosure, } from "@heroui/react"; import { useTranslation } from "react-i18next"; type LogQso = { id: number; log_id: number; time_on?: string | null; band?: string | null; mode?: string | null; my_call?: string | null; dx_call?: string | null; my_locator?: string | null; my_rst?: string | null; dx_rst?: string | null; my_serial?: string | null; dx_serial?: string | null; rx_wwl?: string | null; log?: { id: number; round_id?: number | null; } | null; }; type WorkingQso = { loc_norm?: string | null; rloc_norm?: string | null; errors?: string[] | null; }; type QsoResult = { id: number; log_qso_id: number; matched_qso_id?: number | null; error_code?: string | null; error_side?: string | null; match_confidence?: string | null; error_detail?: string | null; is_nil?: boolean; is_duplicate?: boolean; is_busted_call?: boolean; is_busted_exchange?: boolean; is_time_out_of_window?: boolean; log_qso?: LogQso | null; matched_qso?: LogQso | null; working_qso?: WorkingQso | null; }; type QsoOverride = { id: number; evaluation_run_id: number; log_qso_id: number; forced_matched_log_qso_id?: number | null; forced_status?: string | null; reason?: string | null; }; type LogEntry = { id: number; pcall?: string | null; psect?: string | null; pband?: string | null; power_category?: string | null; sixhr_category?: boolean | null; pwwlo?: string | null; locator?: string | null; }; type PaginatedResponse = { data: T[]; current_page: number; last_page: number; total: number; }; type Props = { roundId: number | null; evaluationRunId: number; }; type OverrideForm = { status: string; matchedId: string; reason: string; saving: boolean; error?: string | null; success?: string | null; }; const statusOptions = [ { value: "AUTO", label: "AUTO" }, { value: "VALID", label: "VALID" }, { value: "INVALID", label: "INVALID" }, { value: "NIL", label: "NIL" }, { value: "DUPLICATE", label: "DUPLICATE" }, { value: "BUSTED_CALL", label: "BUSTED_CALL" }, { value: "BUSTED_EXCHANGE", label: "BUSTED_EXCHANGE" }, { value: "OUT_OF_WINDOW", label: "OUT_OF_WINDOW" }, ]; const issueOptions = [ { value: "PROBLEMS", label: "Všechny problémy" }, { value: "OK_ONLY", label: "Pouze v pořádku" }, { value: "ALL", label: "Všechny QSO" }, { value: "NOT_IN_COUNTERPART_LOG", label: "NOT_IN_COUNTERPART_LOG" }, { value: "NO_COUNTERPART_LOG", label: "NO_COUNTERPART_LOG" }, { value: "UNIQUE", label: "UNIQUE" }, { value: "DUP", label: "DUP" }, { value: "BUSTED_CALL", label: "BUSTED_CALL" }, { value: "BUSTED_RST", label: "BUSTED_RST" }, { value: "BUSTED_SERIAL", label: "BUSTED_SERIAL" }, { value: "BUSTED_LOCATOR", label: "BUSTED_LOCATOR" }, { value: "TIME_MISMATCH", label: "TIME_MISMATCH" }, { value: "OUT_OF_WINDOW", label: "OUT_OF_WINDOW" }, { value: "MISSING_LOCATOR", label: "Chybí lokátor" }, ]; const getFirstSelection = (keys: Selection) => { if (keys === "all") return ""; const [first] = Array.from(keys); return typeof first === "string" || typeof first === "number" ? String(first) : ""; }; type OverridePayload = { status: string; matchedId: string; reason: string; }; type QsoOverrideRowProps = { item: QsoResult; form?: OverrideForm; override?: QsoOverride; selected: boolean; onToggleSelected: (logQsoId: number, checked: boolean) => void; onOpenMatcher: (item: QsoResult) => void; onFieldChange: (logQsoId: number, field: keyof OverrideForm, value: string) => void; onReasonCommit: (logQsoId: number, reason: string) => void; onSave: (logQsoId: number, payload: OverridePayload) => void; problemLabel: (item: QsoResult) => string; errorDetailLabel: (item: QsoResult) => string | null; problemTooltip: (item: QsoResult) => string[] | null; t: (key: string) => string; }; const QsoOverrideRow = memo(function QsoOverrideRow({ item, form, override, selected, onToggleSelected, onOpenMatcher, onFieldChange, onReasonCommit, onSave, problemLabel, errorDetailLabel, problemTooltip, t, }: QsoOverrideRowProps) { const logQso = item.log_qso; const matched = item.matched_qso; const issue = problemLabel(item); const errorDetail = errorDetailLabel(item); const tooltipContent = problemTooltip(item); const highlightStatus = !!override?.forced_status && override.forced_status !== "AUTO"; const highlightMatched = override?.forced_matched_log_qso_id !== null && override?.forced_matched_log_qso_id !== undefined; const statusValue = form?.status ?? "AUTO"; const matchedId = form?.matchedId ?? ""; const [localReason, setLocalReason] = useState(form?.reason ?? override?.reason ?? ""); useEffect(() => { setLocalReason(form?.reason ?? override?.reason ?? ""); }, [form?.reason, override?.reason]); return (
onToggleSelected(item.log_qso_id, checked)} > Vybrat {logQso?.my_call ?? "—"} → {logQso?.dx_call ?? "—"} {logQso?.band ?? "—"} {logQso?.time_on ?? "—"} {tooltipContent ? ( {tooltipContent.map((line, index) => (
{line}
))}
} > {t("qso_problem_label") ?? "Problém"}: {issue} ) : ( {t("qso_problem_label") ?? "Problém"}: {issue} )} {t("qso_problem_side") ?? "Strana"}: {item.error_side ?? "—"} {t("qso_problem_confidence") ?? "Match"}: {item.match_confidence ?? "—"}
{errorDetail && (
{t("qso_problem_reason") ?? "Důvod"}:{" "} {errorDetail}
)}
Matched: {item.matched_qso_id ?? "—"}{" "} {matched ? `(${matched.my_call} → ${matched.dx_call})` : ""}
Stanice Odesl. Přijat. RST odesl. RST přijat. Loc DE Loc DX ID
{logQso?.my_call ?? "—"} {logQso?.my_serial ?? "—"} {logQso?.dx_serial ?? "—"} {logQso?.my_rst ?? "—"} {logQso?.dx_rst ?? "—"} {item.working_qso?.loc_norm ?? "—"} {item.working_qso?.rloc_norm ?? "—"} {logQso?.id ?? "—"}
{matched?.my_call ?? "—"} {matched?.my_serial ?? "—"} {matched?.dx_serial ?? "—"} {matched?.my_rst ?? "—"} {matched?.dx_rst ?? "—"} {matched?.my_locator ?? "—"} {matched?.rx_wwl ?? "—"} {matched?.id ?? "—"}
{item.working_qso?.errors && item.working_qso.errors.length > 0 && (
Errors: {item.working_qso.errors.join(", ")}
)}
{override?.reason && (
Důvod: {override.reason}
)}
{matchedId ? `Vybráno: ${matchedId}` : "AUTO"} {matchedId && ( )}