refactor(vendors): extract trade rejection message to satisfy length gate (SH-249)

The loading-aware gate pushed VendorTradeSpecialtiesField to 151 lines, one over
the changed-file maintainability cap. Move the rejection-message resolution and
the contract explanation to module scope; no behavior change.
This commit is contained in:
Codex Review Integration 2026-08-18 18:09:23 -03:00
parent 5d18b76143
commit cccb0e4ca7

View file

@ -84,6 +84,22 @@ interface VendorTradeSpecialtiesFieldProps {
tradeOptionsLoading?: boolean;
}
/**
* SH-249: an empty tradeOptions array means two different things. While the facets
* query is in flight it means "not loaded yet"; only once it settles does it mean
* "vocabulary genuinely unavailable". Failing open during the cold-fetch window let
* free text through the canonical gate permanently, because anything committed there
* is added to knownTradesRef and stays selectable after the real list arrives.
*
* SH-249: why a typed trade was refused. Extracted to module scope so the field
* component stays inside the maintainability gate's function-length cap.
*/
function resolveRejectionMessage(value: string, loading: boolean): string {
return loading
? "Trades are still loading. Wait for the list, then pick a trade."
: `"${value}" is not in the trades list. Pick a trade from the list.`;
}
export function VendorTradeSpecialtiesField({
control,
index,
@ -93,12 +109,6 @@ export function VendorTradeSpecialtiesField({
const [tradeInput, setTradeInput] = useState("");
const [feedbackMessage, setFeedbackMessage] = useState<string | null>(null);
const knownTradesRef = useRef<Set<string>>(new Set());
// SH-249: an empty tradeOptions array means two different things. While the
// facets query is in flight it means "not loaded yet"; only once it settles
// does it mean "vocabulary genuinely unavailable". Failing open during the
// cold-fetch window let free text through the canonical gate permanently,
// because anything committed there is added to knownTradesRef and stays
// selectable after the real list arrives.
const tradeListUnavailable = !tradeOptionsLoading && tradeOptions.length === 0;
const gateActive = tradeOptions.length > 0 || tradeOptionsLoading;
@ -125,11 +135,7 @@ export function VendorTradeSpecialtiesField({
}
const canonical = matchTradeOption(normalized, selectableTrades);
if (gateActive && !canonical) {
setFeedbackMessage(
tradeOptionsLoading
? "Trades are still loading. Wait for the list, then pick a trade."
: `"${normalized}" is not in the trades list. Pick a trade from the list.`,
);
setFeedbackMessage(resolveRejectionMessage(normalized, tradeOptionsLoading));
return;
}
const trade = canonical ?? normalized;