import { ref, nextTick } from "vue"; export function useSubmitHandler(options = {}) { const { onSuccess, onError, formRef, scrollFn, containerRef } = options; const loading = ref(false); const validationErrors = ref({}); const getFormRefs = () => { const refs = formRef?.value; if (!refs) return []; return Array.isArray(refs) ? refs : [refs]; }; const scrollToFirstError = async () => { if (!formRef?.value || !scrollFn) return; await nextTick(); const refsToSearch = getFormRefs(); for (const ref of refsToSearch) { if (!ref) continue; const components = ref.getValidationComponents(); if (!components) continue; const firstErrorComponent = components.find((c) => c.hasError); if (firstErrorComponent) { const container = containerRef?.value || containerRef; firstErrorComponent.focus(); scrollFn(firstErrorComponent, container); return; } } }; const execute = async (apiCallThunk) => { loading.value = true; validationErrors.value = {}; let allValid = true; const refsToValidate = getFormRefs(); if (refsToValidate.length > 0) { for (const ref of refsToValidate) { if (ref) { const success = await ref.validate(true); if (!success) { allValid = false; } } } } if (!allValid) { loading.value = false; await scrollToFirstError(); throw new Error("Frontend validation failed."); } try { const response = await apiCallThunk(); if (typeof onSuccess === "function") { await onSuccess(response); } else { return response; } } catch (error) { await handleError(error); } finally { loading.value = false; } }; const handleError = async (error) => { if (error?.response?.status === 422) { const errors = error.response.data.errors || {}; for (const key in errors) { const message = errors[key][0]; validationErrors.value[key] = message; } await scrollToFirstError(); } await nextTick(); if (typeof onError === "function") { await onError(error); } else { throw error; } }; return { loading, validationErrors, execute, }; }