You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
4.1 KiB
140 lines
4.1 KiB
/* |
|
GoToSocial |
|
Copyright (C) GoToSocial Authors admin@gotosocial.org |
|
SPDX-License-Identifier: AGPL-3.0-or-later |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU Affero General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU Affero General Public License for more details. |
|
|
|
You should have received a copy of the GNU Affero General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
*/ |
|
|
|
import getFormMutations from "./get-form-mutations"; |
|
|
|
import { useRef } from "react"; |
|
|
|
import type { |
|
MutationTrigger, |
|
UseMutationStateResult, |
|
} from "@reduxjs/toolkit/dist/query/react/buildHooks"; |
|
|
|
import type { |
|
FormSubmitEvent, |
|
FormSubmitFunction, |
|
FormSubmitResult, |
|
HookedForm, |
|
} from "./types"; |
|
|
|
interface UseFormSubmitOptions { |
|
changedOnly: boolean; |
|
onFinish?: ((_res: any) => void); |
|
} |
|
|
|
/** |
|
* Parse changed values from the hooked form into a request |
|
* body, and submit it using the given mutation trigger. |
|
* |
|
* This function basically wraps RTK Query's submit methods to |
|
* work with our hooked form interface. |
|
* |
|
* An `onFinish` callback function can be provided, which will |
|
* be executed on a **successful** run of the given MutationTrigger, |
|
* with the mutation result passed into it. |
|
* |
|
* If `changedOnly` is false, then **all** fields of the given HookedForm |
|
* will be submitted to the mutation endpoint, not just changed ones. |
|
* |
|
* The returned function and result can be triggered and read |
|
* from just like an RTK Query mutation hook result would be. |
|
* |
|
* See: https://redux-toolkit.js.org/rtk-query/usage/mutations#mutation-hook-behavior |
|
*/ |
|
export default function useFormSubmit( |
|
form: HookedForm, |
|
mutationQuery: readonly [MutationTrigger<any>, UseMutationStateResult<any, any>], |
|
opts: UseFormSubmitOptions = { changedOnly: true } |
|
): [ FormSubmitFunction, FormSubmitResult ] { |
|
if (!Array.isArray(mutationQuery)) { |
|
throw "useFormSubmit: mutationQuery was not an Array. Is a valid useMutation RTK Query provided?"; |
|
} |
|
|
|
const { changedOnly, onFinish } = opts; |
|
const [runMutation, mutationResult] = mutationQuery; |
|
const usedAction = useRef<FormSubmitEvent>(undefined); |
|
|
|
const submitForm = async(e: FormSubmitEvent) => { |
|
let action: FormSubmitEvent; |
|
|
|
if (typeof e === "string") { |
|
if (e !== "") { |
|
// String action name was provided. |
|
action = e; |
|
} else { |
|
// Empty string action name was provided. |
|
action = undefined; |
|
} |
|
} else if (e) { |
|
// Submit event action was provided. |
|
e.preventDefault(); |
|
if (e.nativeEvent.submitter) { |
|
// We want the name of the element that was invoked to submit this form, |
|
// which will be something that extends HTMLElement, though we don't know |
|
// what at this point. If it's an empty string, fall back to undefined. |
|
// |
|
// See: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter |
|
action = (e.nativeEvent.submitter as Object as { name: string }).name || undefined; |
|
} else { |
|
// No submitter defined. Fall back |
|
// to just use the FormSubmitEvent. |
|
action = e; |
|
} |
|
} else { |
|
// Void or null or something |
|
// else was provided. |
|
action = undefined; |
|
} |
|
|
|
usedAction.current = action; |
|
|
|
// Transform the hooked form into an object. |
|
const { |
|
mutationData, |
|
updatedFields, |
|
} = getFormMutations(form, { changedOnly }); |
|
|
|
// If there were no updated fields according to |
|
// the form parsing then there's nothing for us |
|
// to do, since remote and desired state match. |
|
if (updatedFields.length == 0) { |
|
return; |
|
} |
|
|
|
mutationData.action = action; |
|
|
|
try { |
|
const res = await runMutation(mutationData); |
|
if (onFinish) { |
|
onFinish(res); |
|
} |
|
} catch (e) { |
|
// eslint-disable-next-line no-console |
|
console.error(`caught error running mutation: ${e}`); |
|
} |
|
}; |
|
|
|
return [ |
|
submitForm, |
|
{ |
|
...mutationResult, |
|
action: usedAction.current |
|
} |
|
]; |
|
}
|
|
|