refactor: fix all Low findings from FLAWS_REPORT audit
- Auth: TOTP params from config, JWT error logging, audit log failure logging, replaced_by_hash validation on token rotation - Invoices: remove dead VAT code, consistent PDF permissions, WebP magic-byte detection, deduped exchange-rate fetches - Orders/Offers: multipart limit from config, use paginated() helper, payment method from DB in PDF - Projects: verify project exists before creating note - Attendance: action_type enum validation, consistent local-time shift_date construction, holiday attendance in work fund, trips.view permission on last-km query - Users: paginated() helper usage, remove duplicate dashboard keys, parallel currency conversion, single hashToken implementation - Frontend: memoized customInput, reliable print onload, modal prop standardization (isOpen), ConfirmModal type icons, id===0 key fallback, Login useCallback, CompanySettings ConfirmModal, Attendance timeout cleanup, Dashboard memoization, beforeunload dirty-state warnings on Invoice/Offer/Order detail - Schema: invoice_alert_log timestamp, config/env comment on Date.prototype.toJSON override - Utils: exchange-rate inflight dedup Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -108,7 +108,7 @@ export default function Attendance() {
|
||||
project_logs: [],
|
||||
active_project_id: null,
|
||||
});
|
||||
const [showLeaveModal, setShowLeaveModal] = useState(false);
|
||||
const [isLeaveModalOpen, setIsLeaveModalOpen] = useState(false);
|
||||
const [leaveForm, setLeaveForm] = useState({
|
||||
leave_type: "vacation",
|
||||
date_from: new Date().toISOString().split("T")[0],
|
||||
@@ -122,10 +122,11 @@ export default function Attendance() {
|
||||
const [projectLogs, setProjectLogs] = useState<ProjectLog[]>([]);
|
||||
const [activeProjectId, setActiveProjectId] = useState<number | null>(null);
|
||||
const [gpsConfirm, setGpsConfirm] = useState<{
|
||||
show: boolean;
|
||||
isOpen: boolean;
|
||||
action: string | null;
|
||||
}>({ show: false, action: null });
|
||||
}>({ isOpen: false, action: null });
|
||||
const geoAbortRef = useRef<AbortController | null>(null);
|
||||
const punchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const mountedRef = useRef(true);
|
||||
const latestActionRef = useRef<string | null>(null);
|
||||
|
||||
@@ -133,6 +134,7 @@ export default function Attendance() {
|
||||
return () => {
|
||||
mountedRef.current = false;
|
||||
if (geoAbortRef.current) geoAbortRef.current.abort();
|
||||
if (punchTimeoutRef.current) clearTimeout(punchTimeoutRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -176,7 +178,7 @@ export default function Attendance() {
|
||||
loadProjects();
|
||||
}, []);
|
||||
|
||||
useModalLock(showLeaveModal);
|
||||
useModalLock(isLeaveModalOpen);
|
||||
|
||||
if (!hasPermission("attendance.record")) return <Forbidden />;
|
||||
|
||||
@@ -234,7 +236,7 @@ export default function Attendance() {
|
||||
errorMsg = "Vypršel časový limit";
|
||||
}
|
||||
alert.error(errorMsg);
|
||||
setGpsConfirm({ show: true, action });
|
||||
setGpsConfirm({ isOpen: true, action });
|
||||
},
|
||||
{ enableHighAccuracy: true, timeout: 10000, maximumAge: 60000 },
|
||||
);
|
||||
@@ -257,7 +259,7 @@ export default function Attendance() {
|
||||
|
||||
if (result.success) {
|
||||
await fetchData();
|
||||
setTimeout(() => {
|
||||
punchTimeoutRef.current = setTimeout(() => {
|
||||
alert.success(result.data?.message || result.message || "Uloženo");
|
||||
}, 300);
|
||||
} else {
|
||||
@@ -368,7 +370,7 @@ export default function Attendance() {
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
setShowLeaveModal(false);
|
||||
setIsLeaveModalOpen(false);
|
||||
await fetchData();
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
alert.success(
|
||||
@@ -669,7 +671,7 @@ export default function Attendance() {
|
||||
{submitting ? "Zpracovávám..." : "Odchod"}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowLeaveModal(true)}
|
||||
onClick={() => setIsLeaveModalOpen(true)}
|
||||
className="admin-btn admin-btn-secondary w-full"
|
||||
>
|
||||
Žádost o nepřítomnost
|
||||
@@ -708,7 +710,7 @@ export default function Attendance() {
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setShowLeaveModal(true)}
|
||||
onClick={() => setIsLeaveModalOpen(true)}
|
||||
className="admin-btn admin-btn-secondary w-full"
|
||||
>
|
||||
Žádost o nepřítomnost
|
||||
@@ -1056,7 +1058,7 @@ export default function Attendance() {
|
||||
|
||||
{/* Leave Modal */}
|
||||
<AnimatePresence>
|
||||
{showLeaveModal && (
|
||||
{isLeaveModalOpen && (
|
||||
<motion.div
|
||||
className="admin-modal-overlay"
|
||||
initial={{ opacity: 0 }}
|
||||
@@ -1066,7 +1068,7 @@ export default function Attendance() {
|
||||
>
|
||||
<div
|
||||
className="admin-modal-backdrop"
|
||||
onClick={() => setShowLeaveModal(false)}
|
||||
onClick={() => setIsLeaveModalOpen(false)}
|
||||
/>
|
||||
<motion.div
|
||||
className="admin-modal"
|
||||
@@ -1187,7 +1189,7 @@ export default function Attendance() {
|
||||
<div className="admin-modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowLeaveModal(false)}
|
||||
onClick={() => setIsLeaveModalOpen(false)}
|
||||
className="admin-btn admin-btn-secondary"
|
||||
disabled={requestSubmitting}
|
||||
>
|
||||
@@ -1214,13 +1216,13 @@ export default function Attendance() {
|
||||
</AnimatePresence>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={gpsConfirm.show}
|
||||
isOpen={gpsConfirm.isOpen}
|
||||
onClose={() => {
|
||||
setGpsConfirm({ show: false, action: null });
|
||||
setGpsConfirm({ isOpen: false, action: null });
|
||||
setSubmitting(false);
|
||||
}}
|
||||
onConfirm={() => {
|
||||
setGpsConfirm({ show: false, action: null });
|
||||
setGpsConfirm({ isOpen: false, action: null });
|
||||
submitPunch(gpsConfirm.action!, {});
|
||||
}}
|
||||
title="GPS nedostupná"
|
||||
|
||||
Reference in New Issue
Block a user