fix: resolve frontend audit findings
Frontend security / security (push) Successful in 10s
Frontend verify / verify (push) Successful in 4m57s
Conventional commits / commits (pull_request) Successful in 28s
Frontend security / security (pull_request) Successful in 10s
Frontend verify / verify (pull_request) Successful in 5m10s
Frontend security / security (push) Successful in 10s
Frontend verify / verify (push) Successful in 4m57s
Conventional commits / commits (pull_request) Successful in 28s
Frontend security / security (pull_request) Successful in 10s
Frontend verify / verify (pull_request) Successful in 5m10s
Repair investment recovery, draft preservation, date validation, currency presentation, accessibility, and route error recovery. Correct Docker and dependency checks and consume explicit income roles.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams, useSearchParams } from "react-router";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
type BrokerageEvent,
|
||||
useBrokerageEvents,
|
||||
@@ -8,7 +9,7 @@ import { useScreenSync } from "@/features/tbank-connection";
|
||||
|
||||
type AccountEventsPageViewModel =
|
||||
| { state: "loading" }
|
||||
| { state: "error"; retry: () => void }
|
||||
| { state: "error"; retry: () => void; onReset: () => void }
|
||||
| {
|
||||
state: "loaded";
|
||||
events: BrokerageEvent[];
|
||||
@@ -31,12 +32,22 @@ function useAccountEventsPageViewModel(
|
||||
scopeId?: string,
|
||||
): AccountEventsPageViewModel {
|
||||
const { accountId: routeAccountId } = useParams();
|
||||
const accountId = scopeId ?? routeAccountId;
|
||||
const accountId = scopeId ?? routeAccountId ?? "";
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const appliedFrom = searchParams.get("from");
|
||||
const appliedTo = searchParams.get("to");
|
||||
const urlFrom = searchParams.get("from");
|
||||
const urlTo = searchParams.get("to");
|
||||
const validUrlPeriod = isValidPeriod(urlFrom, urlTo);
|
||||
const appliedFrom = validUrlPeriod ? urlFrom : null;
|
||||
const appliedTo = validUrlPeriod ? urlTo : null;
|
||||
const [draftFrom, setDraftFrom] = useState<string | null>(appliedFrom);
|
||||
const [draftTo, setDraftTo] = useState<string | null>(appliedTo);
|
||||
useEffect(() => {
|
||||
if (validUrlPeriod) return;
|
||||
const normalized = new URLSearchParams(searchParams);
|
||||
normalized.delete("from");
|
||||
normalized.delete("to");
|
||||
setSearchParams(normalized, { replace: true });
|
||||
}, [validUrlPeriod, searchParams, setSearchParams]);
|
||||
useEffect(() => {
|
||||
setDraftFrom(appliedFrom);
|
||||
setDraftTo(appliedTo);
|
||||
@@ -54,12 +65,18 @@ function useAccountEventsPageViewModel(
|
||||
},
|
||||
[events],
|
||||
);
|
||||
const onReset = () => {
|
||||
setDraftFrom(null);
|
||||
setDraftTo(null);
|
||||
setSearchParams({});
|
||||
};
|
||||
if (events.isLoading) return { state: "loading" };
|
||||
if ((events.isError || events.meta?.sync.state === "failed") && !events.data)
|
||||
return {
|
||||
state: "error",
|
||||
onReset,
|
||||
retry: () => {
|
||||
void sync.refresh();
|
||||
void sync.retry();
|
||||
},
|
||||
};
|
||||
if (!events.data) return { state: "loading" };
|
||||
@@ -72,26 +89,34 @@ function useAccountEventsPageViewModel(
|
||||
refreshing: events.isFetching || sync.refreshing,
|
||||
refreshError: events.isError || sync.sourceError || sync.transportError,
|
||||
retry: () => {
|
||||
void sync.refresh();
|
||||
void sync.retry();
|
||||
},
|
||||
draftFrom,
|
||||
draftTo,
|
||||
canApply:
|
||||
(draftFrom !== appliedFrom || draftTo !== appliedTo) &&
|
||||
(!draftFrom || !draftTo || draftFrom <= draftTo),
|
||||
isValidPeriod(draftFrom, draftTo),
|
||||
onDraftFromChange: setDraftFrom,
|
||||
onDraftToChange: setDraftTo,
|
||||
onApply: () =>
|
||||
onApply: () => {
|
||||
if (!isValidPeriod(draftFrom, draftTo)) return;
|
||||
setSearchParams({
|
||||
...(draftFrom ? { from: draftFrom } : {}),
|
||||
...(draftTo ? { to: draftTo } : {}),
|
||||
}),
|
||||
onReset: () => {
|
||||
setDraftFrom(null);
|
||||
setDraftTo(null);
|
||||
setSearchParams({});
|
||||
});
|
||||
},
|
||||
onReset,
|
||||
};
|
||||
}
|
||||
|
||||
const calendarDate = z.string().date();
|
||||
function isValidPeriod(from: string | null, to: string | null) {
|
||||
return (
|
||||
[from, to].every(
|
||||
(date) => date === null || calendarDate.safeParse(date).success,
|
||||
) &&
|
||||
(!from || !to || from <= to)
|
||||
);
|
||||
}
|
||||
|
||||
export { type AccountEventsPageViewModel, useAccountEventsPageViewModel };
|
||||
|
||||
Reference in New Issue
Block a user