const optionsMode = { default: async (field, selectOptions, loadingOptions) => { if (selectOptions[field.key]?.length > 0) return; loadingOptions[field.key] = true; try { const res = await fetch(field.optionsEndpoint); const json = await res.json(); // selectOptions[field.key] = json?.data ?? []; const data = json?.data ?? []; const valueKey = field.valueKey ?? 'value'; const labelKey = field.labelKey ?? 'label'; selectOptions[field.key] = data.map((item) => { const baseOption = { value: item[valueKey], label: typeof labelKey === 'function' ? labelKey(item) : item[labelKey], }; if (field.key === 'FormulaInput') { return { ...baseOption, testid: item.TestSiteID, level: item.isCountStat, }; } return baseOption; }); } catch (err) { console.error("Failed to fetch options for", field.key, err); selectOptions[field.key] = []; } finally { loadingOptions[field.key] = false; } }, cascade: async (field, selectOptions, loadingOptions, form, lastFetched) => { const parentValue = field.dependsOn ? form?.[field.dependsOn] : null; // console.log(parentValue); // If has dependency and parent changed, or not fetched yet if (field.dependsOn) { // If parent value exists and already fetched for this parent value, skip if (selectOptions[field.key]?.length > 0 && lastFetched[field.key] === parentValue) { return; } // If no parent value, clear options if (!parentValue) { selectOptions[field.key] = []; return; } } else { // Non-dependent field, only fetch once if (selectOptions[field.key]?.length > 0) return; } let endpoint = field.optionsEndpoint; // Add parent parameter if exists if (parentValue && field.endpointParamKey) { endpoint += `?${field.endpointParamKey}=${parentValue}`; } loadingOptions[field.key] = true; try { const res = await fetch(endpoint); const json = await res.json(); // selectOptions[field.key] = json?.data ?? []; const data = json?.data ?? []; const valueKey = field.valueKey ?? 'value'; const labelKey = field.labelKey ?? 'label'; selectOptions[field.key] = data.map((item) => ({ value: item[valueKey], label: typeof labelKey === 'function' ? labelKey(item) : item[labelKey], })); // Track last fetched parent value for dependent fields if (field.dependsOn) { lastFetched[field.key] = parentValue; } } catch (err) { console.error("Failed to fetch options for", field.key, err); selectOptions[field.key] = []; } finally { loadingOptions[field.key] = false; } } }; export function useFormOptions(optMode = 'default') { const selectOptions = $state({}); const loadingOptions = $state({}); const lastFetched = $state({}); async function fetchOptions(field, form = null) { if (!field?.optionsEndpoint) return; const modeFn = optionsMode[optMode]; if (!modeFn) return; await modeFn(field, selectOptions, loadingOptions, form, lastFetched); } function clearDependentOptions(parentKey, dependentKeys, form) { dependentKeys.forEach(key => { selectOptions[key] = []; if (form) form[key] = ''; lastFetched[key] = null; }); } return { selectOptions, loadingOptions, lastFetched, fetchOptions, clearDependentOptions, }; }