Skrytí osobních údajů #1
Nezobrazovat detail logu anonymnímu uživateli #2
This commit is contained in:
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Pagination } from "@heroui/react";
|
||||
import { useUserStore } from "@/stores/userStore";
|
||||
import { useContestStore } from "@/stores/contestStore";
|
||||
|
||||
type LogItem = {
|
||||
id: number;
|
||||
@@ -14,13 +15,11 @@ type LogItem = {
|
||||
tdate?: string | null;
|
||||
pcall?: string | null;
|
||||
rcall?: string | null; // pokud backend vrátí, jinak zobrazíme prázdně
|
||||
pwwlo?: string | null;
|
||||
psect?: string | null;
|
||||
pband?: string | null;
|
||||
power_watt?: number | null;
|
||||
claimed_qso_count?: number | null;
|
||||
claimed_score?: number | null;
|
||||
remarks_eval?: string | null;
|
||||
file_id?: number | null;
|
||||
file?: {
|
||||
id: number;
|
||||
@@ -46,6 +45,7 @@ type LogsTableProps = {
|
||||
export default function LogsTable({ roundId, perPage = 50, refreshKey = 0, contestId = null }: LogsTableProps) {
|
||||
const { t } = useTranslation("common");
|
||||
const user = useUserStore((s) => s.user);
|
||||
const selectedRound = useContestStore((s) => s.selectedRound);
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [items, setItems] = useState<LogItem[]>([]);
|
||||
@@ -53,6 +53,49 @@ export default function LogsTable({ roundId, perPage = 50, refreshKey = 0, conte
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [page, setPage] = useState(1);
|
||||
const [lastPage, setLastPage] = useState(1);
|
||||
const [finalPublished, setFinalPublished] = useState(false);
|
||||
const isAdmin = !!user?.is_admin;
|
||||
|
||||
useEffect(() => {
|
||||
if (isAdmin) {
|
||||
setFinalPublished(true);
|
||||
return;
|
||||
}
|
||||
if (!roundId) {
|
||||
setFinalPublished(false);
|
||||
return;
|
||||
}
|
||||
const officialRunId =
|
||||
selectedRound?.id === roundId ? selectedRound?.official_evaluation_run_id ?? null : null;
|
||||
if (!officialRunId) {
|
||||
setFinalPublished(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let active = true;
|
||||
(async () => {
|
||||
try {
|
||||
const res = await axios.get<{ status?: string | null; result_type?: string | null }>(
|
||||
`/api/evaluation-runs/${officialRunId}`,
|
||||
{
|
||||
headers: { Accept: "application/json" },
|
||||
withCredentials: true,
|
||||
}
|
||||
);
|
||||
if (!active) return;
|
||||
const isFinal =
|
||||
res.data?.status === "SUCCEEDED" && res.data?.result_type === "FINAL";
|
||||
setFinalPublished(isFinal);
|
||||
} catch {
|
||||
if (!active) return;
|
||||
setFinalPublished(false);
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
active = false;
|
||||
};
|
||||
}, [roundId, selectedRound?.official_evaluation_run_id, isAdmin]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!roundId) return;
|
||||
@@ -101,13 +144,11 @@ export default function LogsTable({ roundId, perPage = 50, refreshKey = 0, conte
|
||||
const columns = [
|
||||
{ key: "parsed", label: "" },
|
||||
{ key: "pcall", label: "PCall" },
|
||||
{ key: "pwwlo", label: "PWWLo" },
|
||||
{ key: "pband", label: "PBand" },
|
||||
{ key: "psect", label: "PSect" },
|
||||
{ key: "power_watt", label: "SPowe" },
|
||||
{ key: "claimed_qso_count", label: "QSO" },
|
||||
{ key: "claimed_score", label: "Body" },
|
||||
{ key: "remarks_eval", label: "remarks_eval" },
|
||||
{ key: "claimed_score", label: "Deklarované body" },
|
||||
...(user ? [{ key: "actions", label: "" }] : []),
|
||||
];
|
||||
|
||||
@@ -116,23 +157,7 @@ export default function LogsTable({ roundId, perPage = 50, refreshKey = 0, conte
|
||||
waiting ? (t("logs_waiting_processing") as string) || "Čekám na zpracování" : value || "—";
|
||||
const formatNumber = (value: number | null | undefined) => (value === null || value === undefined ? "—" : String(value));
|
||||
|
||||
const renderRemarksEval = (raw: string | null | undefined) => {
|
||||
if (!raw) return "—";
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(raw);
|
||||
if (Array.isArray(parsed)) {
|
||||
const lines = parsed
|
||||
.filter((item) => typeof item === "string" && item.trim() !== "")
|
||||
.map((item, idx) => <div key={idx}>{item}</div>);
|
||||
if (lines.length > 0) return lines;
|
||||
}
|
||||
} catch {
|
||||
// fall through to show raw string
|
||||
}
|
||||
|
||||
return <div>{raw}</div>;
|
||||
};
|
||||
const canNavigate = isAdmin || finalPublished;
|
||||
|
||||
const handleDelete = async (id: number, e?: React.MouseEvent) => {
|
||||
e?.stopPropagation();
|
||||
@@ -162,13 +187,15 @@ export default function LogsTable({ roundId, perPage = 50, refreshKey = 0, conte
|
||||
<TableRow
|
||||
key={item.id}
|
||||
onClick={() => {
|
||||
if (contestId && roundId) {
|
||||
if (contestId && roundId && canNavigate) {
|
||||
navigate(`/contests/${contestId}/rounds/${roundId}/logs/${item.id}`, {
|
||||
state: { from: `${location.pathname}${location.search}` },
|
||||
});
|
||||
}
|
||||
}}
|
||||
className={contestId && roundId ? "cursor-pointer hover:bg-default-100" : undefined}
|
||||
className={
|
||||
contestId && roundId && canNavigate ? "cursor-pointer hover:bg-default-100" : undefined
|
||||
}
|
||||
>
|
||||
{(columnKey) => {
|
||||
if (columnKey === "actions") {
|
||||
@@ -206,7 +233,6 @@ export default function LogsTable({ roundId, perPage = 50, refreshKey = 0, conte
|
||||
}
|
||||
if (columnKey === "parsed") {
|
||||
const parsedClaimed = !!item.parsed_claimed;
|
||||
const parsedAny = !!item.parsed;
|
||||
const symbol = parsedClaimed ? "✓" : "↻";
|
||||
const color = parsedClaimed ? "text-green-600" : "text-blue-600";
|
||||
return (
|
||||
@@ -215,9 +241,6 @@ export default function LogsTable({ roundId, perPage = 50, refreshKey = 0, conte
|
||||
</TableCell>
|
||||
);
|
||||
}
|
||||
if (columnKey === "remarks_eval") {
|
||||
return <TableCell>{renderRemarksEval(item.remarks_eval)}</TableCell>;
|
||||
}
|
||||
if (columnKey === "power_watt" || columnKey === "claimed_qso_count" || columnKey === "claimed_score") {
|
||||
return <TableCell>{formatNumber((item as any)[columnKey as string])}</TableCell>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user