chore(release): v2.4.35 — lint cleanup (68→0) + duplicate-Zavřít modal fix

UI fix:
- Close-only modals showing a redundant second close button now use
  hideCancel: ReceivedInvoices paid-detail modal (was two identical "Zavřít"
  buttons) and PlanCellModal "Den je součástí rozsahu".
- Add modal-duplicate-close test enforcing close-only modals set hideCancel.

Lint: cleared all 68 warnings → 0.
- preserve-caught-error: attach { cause } in ai.service / exchange-rates.
- no-require-imports: package.json version read via fs (APP_VERSION) instead
  of require(), avoiding a rootDir-expanding static JSON import.
- react-hooks/exhaustive-deps (11): ref-in-cleanup copies, derived-value
  useMemo wrapping, PlanGrid field extraction, stable nextKey useCallback,
  AuthContext documented cycle-break.
- no-explicit-any (53): precise route param/Prisma types, generic enrich*()
  preserving payload shape, minimal vite module type, frontend body/query-key
  types, SystemInfo for Settings.

Refactor (test enablement): shift-form types moved to dependency-free
shiftFormTypes.ts so the print-HTML builders are unit-testable without the
component graph; characterization test pins their output.

Gates: 649 tests pass, tsc -b clean, lint 0. Verified touched flows live
via Playwright (PlanWork CRUD + optimistic cache, warehouse form keys,
Settings system info, invoice detail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-13 18:35:31 +02:00
parent 907ee574e6
commit 1ee59b54bc
36 changed files with 954 additions and 140 deletions

View File

@@ -488,6 +488,7 @@ function DayInRangeModal(
onClose={onClose}
onSubmit={onClose}
submitText="Zavřít — ponechat rozsah beze změny"
hideCancel
maxWidth="md"
>
<Typography variant="body2" sx={{ mb: 2 }}>

View File

@@ -491,9 +491,11 @@ export default function PlanGrid({
}, [projects]);
// Memoize the day list so it isn't rebuilt on every render (only when the
// visible range changes). Stable identity also keeps the row map cheap.
const dateFrom = data?.date_from;
const dateTo = data?.date_to;
const days = useMemo(
() => (data ? eachDay(data.date_from, data.date_to) : []),
[data?.date_from, data?.date_to],
() => (dateFrom && dateTo ? eachDay(dateFrom, dateTo) : []),
[dateFrom, dateTo],
);
if (!data) return <LoadingState />;

View File

@@ -19,46 +19,22 @@ import {
} from "../utils/attendanceHelpers";
// ---------- Shared types ----------
export interface ShiftFormData {
user_id: string;
shift_date: string;
leave_type: string;
leave_hours: number;
arrival_date: string;
arrival_time: string;
break_start_date: string;
break_start_time: string;
break_end_date: string;
break_end_time: string;
departure_date: string;
departure_time: string;
notes: string;
}
export interface ProjectLog {
_key?: string;
id?: number;
project_id: string | number;
hours: string | number;
minutes: string | number;
}
export interface Project {
id: number | string;
project_number: string;
name: string;
}
export interface User {
id: number | string;
name: string;
}
export interface EditingRecord {
user_name: string;
shift_date: string;
}
// Definitions live in the dependency-free ./shiftFormTypes module; re-exported
// here so existing importers of ShiftFormModal keep working.
export type {
ShiftFormData,
ProjectLog,
Project,
User,
EditingRecord,
} from "./shiftFormTypes";
import type {
ShiftFormData,
ProjectLog,
Project,
User,
EditingRecord,
} from "./shiftFormTypes";
// ---------- Sub-component props ----------

View File

@@ -0,0 +1,44 @@
// Shared attendance shift-form types, kept in a dependency-free module so they
// can be imported without pulling in the ShiftFormModal component graph (which
// reaches MUI/import.meta files that don't compile under the CommonJS test
// project). ShiftFormModal re-exports these for backward compatibility.
export interface ShiftFormData {
user_id: string;
shift_date: string;
leave_type: string;
leave_hours: number;
arrival_date: string;
arrival_time: string;
break_start_date: string;
break_start_time: string;
break_end_date: string;
break_end_time: string;
departure_date: string;
departure_time: string;
notes: string;
}
export interface ProjectLog {
_key?: string;
id?: number;
project_id: string | number;
hours: string | number;
minutes: string | number;
}
export interface Project {
id: number | string;
project_number: string;
name: string;
}
export interface User {
id: number | string;
name: string;
}
export interface EditingRecord {
user_name: string;
shift_date: string;
}

View File

@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useMemo } from "react";
import { useQuery } from "@tanstack/react-query";
import MenuItem from "@mui/material/MenuItem";
import { Select } from "../../ui";
@@ -26,7 +26,7 @@ export default function ReservationPicker({
}),
);
const reservations = result?.data ?? [];
const reservations = useMemo(() => result?.data ?? [], [result?.data]);
// When item/project change, the loaded reservation list changes. If the
// currently-selected reservation is no longer available, clear it and notify