Polish pass: removed lastTouched dead code, selective useWatch perf, token sweep, required-field messages, scroll-to-first-error, file prefill display, matrix sticky shadow
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useId, useMemo, useState } from "react";
|
||||
import { useEffect, useId, useMemo, useState } from "react";
|
||||
import type { StageSectionConfig, SelectOption } from "@/types/form";
|
||||
import type { UseFormRegister, FieldValues, FieldErrors } from "react-hook-form";
|
||||
import { FieldRenderer } from "./fields/FieldRenderer";
|
||||
@@ -20,8 +20,6 @@ interface StageSectionProps {
|
||||
defaultOpen: boolean;
|
||||
/** Option groups fetched from CiviCRM, keyed by option_group_id. */
|
||||
options: Record<number, SelectOption[]>;
|
||||
/** Optional last-checked-in timestamp for this stage (ISO date). */
|
||||
lastTouched?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,12 +41,22 @@ export function StageSection({
|
||||
isCurrent,
|
||||
defaultOpen,
|
||||
options,
|
||||
lastTouched,
|
||||
}: StageSectionProps) {
|
||||
const [open, setOpen] = useState(defaultOpen);
|
||||
const headingId = useId();
|
||||
const panelId = useId();
|
||||
|
||||
// Listen for programmatic expand requests (fired by EngagementForm when a
|
||||
// submit fails on a required field inside a collapsed section).
|
||||
useEffect(() => {
|
||||
const handler = (e: Event) => {
|
||||
const detail = (e as CustomEvent<{ sectionId: string }>).detail;
|
||||
if (detail?.sectionId === section.id) setOpen(true);
|
||||
};
|
||||
document.addEventListener("coop-checkin:expand-section", handler);
|
||||
return () => document.removeEventListener("coop-checkin:expand-section", handler);
|
||||
}, [section.id]);
|
||||
|
||||
const matrixFieldNames = useMemo(() => {
|
||||
const names = new Set<string>();
|
||||
for (const m of section.matrixGroups ?? []) {
|
||||
@@ -104,12 +112,6 @@ export function StageSection({
|
||||
<span className="tabular-nums">
|
||||
{fieldCount} {fieldCount === 1 ? "field" : "fields"}
|
||||
</span>
|
||||
{lastTouched && (
|
||||
<>
|
||||
<span aria-hidden>·</span>
|
||||
<span>Last touched {formatRelative(lastTouched)}</span>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
<Chevron open={open} />
|
||||
@@ -210,13 +212,3 @@ function Chevron({ open }: { open: boolean }) {
|
||||
);
|
||||
}
|
||||
|
||||
function formatRelative(iso: string): string {
|
||||
const then = new Date(iso).getTime();
|
||||
if (Number.isNaN(then)) return iso;
|
||||
const days = Math.round((Date.now() - then) / (1000 * 60 * 60 * 24));
|
||||
if (days <= 0) return "today";
|
||||
if (days === 1) return "yesterday";
|
||||
if (days < 30) return `${days} days ago`;
|
||||
if (days < 365) return `${Math.round(days / 30)} months ago`;
|
||||
return `${Math.round(days / 365)} years ago`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user