refactor: use localDateTimeToUtcIso in component and clean up tests
- Import and call localDateTimeToUtcIso in the add-game onSubmit handler instead of duplicating the conversion inline; also applies the null/ invalid-date safety from the utility to the component - Remove the redundant "incompatible with datetime-local" test case (its intent is better expressed as a code comment than a test assertion) - Move the datetime-local incompatibility explanation into a NOTE comment on the utility function's JSDoc https://claude.ai/code/session_0148fgZiXpyvGX8ZX3BFRGCs
This commit is contained in:
parent
1ef37fa8db
commit
4288f14a79
3 changed files with 9 additions and 15 deletions
|
|
@ -41,15 +41,4 @@ describe("localDateTimeToUtcIso", () => {
|
||||||
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
|
expect(result).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("the returned ISO string is incompatible with datetime-local input format", () => {
|
|
||||||
// This documents WHY we need a hidden input instead of setting the
|
|
||||||
// datetime-local input's value directly. datetime-local only accepts
|
|
||||||
// "YYYY-MM-DDTHH:MM" — a 'Z' suffix makes the value invalid and the
|
|
||||||
// browser silently clears the field.
|
|
||||||
const result = localDateTimeToUtcIso("2026-03-11T10:00");
|
|
||||||
expect(result).not.toBeNull();
|
|
||||||
expect(result).toContain("Z");
|
|
||||||
// The value does NOT match the datetime-local format (no Z allowed)
|
|
||||||
expect(result).not.toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,12 @@
|
||||||
* to hold the converted UTC value before form submission.
|
* to hold the converted UTC value before form submission.
|
||||||
*
|
*
|
||||||
* Returns null when value is empty, nullish, or not a valid date.
|
* Returns null when value is empty, nullish, or not a valid date.
|
||||||
|
*
|
||||||
|
* NOTE: The returned ISO string (e.g. "2026-03-11T17:00:00.000Z") is intentionally
|
||||||
|
* incompatible with datetime-local inputs, which only accept "YYYY-MM-DDTHH:MM".
|
||||||
|
* Setting a Z-suffixed string on a datetime-local input causes browsers to silently
|
||||||
|
* clear the field. Always write the result to a separate hidden input, not back to
|
||||||
|
* the datetime-local input itself.
|
||||||
*/
|
*/
|
||||||
export function localDateTimeToUtcIso(value: string | null | undefined): string | null {
|
export function localDateTimeToUtcIso(value: string | null | undefined): string | null {
|
||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Form, Link } from "react-router";
|
import { Form, Link } from "react-router";
|
||||||
import { Fragment, useState, useEffect, useMemo } from "react";
|
import { Fragment, useState, useEffect, useMemo } from "react";
|
||||||
|
import { localDateTimeToUtcIso } from "~/lib/date-utils";
|
||||||
import type { Route } from "./+types/admin.sports-seasons.$id.events.$eventId.bracket";
|
import type { Route } from "./+types/admin.sports-seasons.$id.events.$eventId.bracket";
|
||||||
|
|
||||||
import { loader, action } from "./admin.sports-seasons.$id.events.$eventId.bracket.server";
|
import { loader, action } from "./admin.sports-seasons.$id.events.$eventId.bracket.server";
|
||||||
|
|
@ -732,10 +733,8 @@ export default function EventBracket({
|
||||||
const scheduledAtLocal = form.elements.namedItem("scheduledAtLocal") as HTMLInputElement;
|
const scheduledAtLocal = form.elements.namedItem("scheduledAtLocal") as HTMLInputElement;
|
||||||
// Write the UTC ISO string into the hidden input that IS submitted
|
// Write the UTC ISO string into the hidden input that IS submitted
|
||||||
const scheduledAtHidden = form.elements.namedItem("scheduledAt") as HTMLInputElement;
|
const scheduledAtHidden = form.elements.namedItem("scheduledAt") as HTMLInputElement;
|
||||||
if (scheduledAtLocal?.value && scheduledAtHidden) {
|
if (scheduledAtHidden) {
|
||||||
// datetime-local inputs reject ISO strings with a 'Z' suffix and silently
|
scheduledAtHidden.value = localDateTimeToUtcIso(scheduledAtLocal?.value) ?? "";
|
||||||
// clear their value, so we use a separate hidden input for the UTC value.
|
|
||||||
scheduledAtHidden.value = new Date(scheduledAtLocal.value).toISOString();
|
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<input type="hidden" name="intent" value="add-game" />
|
<input type="hidden" name="intent" value="add-game" />
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue