fix(frontend): auto-completed on finish time, dashboard links, list/calendar UX
Some checks failed
CI / build-and-test (pull_request) Has been cancelled

- Set status to completed when finish time parses (input + submit)
- Dashboard: last personal record by recent date+time; links on top 3 cards
- Hover scale+shadow on all dashboard-card; linked card padding via BEM
- Race list: full row links to race detail; same hover as before
- Calendar year grid: 3 columns, 2 on tablet, 1 on narrow
- Version 0.4.1

Made-with: Cursor
This commit is contained in:
Vaka.pro
2026-04-13 22:34:39 +03:00
parent 74f059593e
commit 4ea8faf16f
6 changed files with 130 additions and 85 deletions

View File

@@ -3,7 +3,7 @@ import { Link, useNavigate, useParams, useSearchParams } from "react-router-dom"
import { ApiError, createRace, getRaceById, updateRace } from "../api";
import type { CreateRacePayload, Race, RaceStatus, UpdateRacePayload } from "../api";
import { StartTimeSelects } from "../components/StartTimeSelects";
import { isRaceDateInPast } from "../lib";
import { isRaceDateInPast, parseFinishTimeToSeconds } from "../lib";
function slugify(text: string): string {
return text
@@ -151,7 +151,16 @@ export function RaceFormPage(): JSX.Element {
const handleChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
const { name, value } = event.target;
setForm((prev) => ({ ...prev, [name]: value }));
setForm((prev) => {
const next = { ...prev, [name]: value };
if (name === "finishTime") {
const trimmed = value.trim();
if (trimmed !== "" && parseFinishTimeToSeconds(trimmed) !== null) {
return { ...next, status: "completed" };
}
}
return next;
});
},
[],
);
@@ -170,10 +179,16 @@ export function RaceFormPage(): JSX.Element {
setIsSaving(true);
try {
const statusValue: RaceStatus | null =
const finishTrimmed = form.finishTime.trim();
const hasParsedFinish =
finishTrimmed !== "" && parseFinishTimeToSeconds(finishTrimmed) !== null;
let statusValue: RaceStatus | null =
form.status === "planned" || form.status === "registered" || form.status === "completed"
? form.status
: null;
if (hasParsedFinish) {
statusValue = "completed";
}
if (isEditMode && raceId) {
const payload: UpdateRacePayload = {