Files
app/src/admin/hooks/useTableSort.ts
BOHA 4f4b12f039 security: fix all Medium findings from FLAWS_REPORT audit
- Auth: TOTP replay protection with counter tracking, constant-time
  backup code comparison, atomic lockout increment, per-token logout
- Invoices/PDFs: net-based VAT calculation, dangerous URL scheme
  stripping in cleanQuillHtml, orders-pdf error handling
- Orders: reject item changes on status transition, cascading
  delete cleanup, take:1 with orderBy
- Projects: atomic rename collision handling, MIME/extension
  validation, empty customer name rejection
- Attendance: Czech public holiday awareness in frontend fund
  calculation, leave_hours 0 handling, invalid date NaN guard,
  bounded per-month queries in workfund
- Users/Admin: profile audit logging + password validation, session
  revocation guard, session ID validation, dashboard DB aggregation,
  soft-deleted record protection in scope templates
- Frontend: FormField label linkage, Pagination ARIA, error
  handling in OrderConfirmationModal, 401 propagation, GPS emoji
  hidden from screen readers, table sort state fix, geolocation
  race/abort cleanup, Leaflet popup DOM safety, Vehicles toggleActive
  minimal body, CompanySettings ref mutation fix, OfferDetail unlock
  abort, AttendanceBalances combined fetches
- Utils: env validation, Puppeteer concurrency mutex, invoice alert
  cron cleanup on shutdown, body limit alignment, TOTP error logging,
  trustProxy from env, symlink rejection, rate cache Map usage

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 08:24:14 +02:00

32 lines
805 B
TypeScript

import { useState, useCallback } from "react";
interface SortState {
sort: string;
order: "asc" | "desc";
}
export default function useTableSort(
defaultSort = "id",
defaultOrder: "asc" | "desc" = "desc",
) {
const [state, setState] = useState<SortState>({
sort: defaultSort,
order: defaultOrder,
});
const [userClicked, setUserClicked] = useState(false);
const handleSort = useCallback((column: string) => {
setUserClicked(true);
setState((prev) => {
if (prev.sort === column) {
return { sort: column, order: prev.order === "asc" ? "desc" : "asc" };
}
return { sort: column, order: "desc" };
});
}, []);
const activeSort = userClicked ? state.sort : null;
return { sort: state.sort, order: state.order, handleSort, activeSort };
}