gristlabs_grist-core/app/client/lib/formUtils.ts
George Gevoian 0d005eb78d (core) Enable MFA configuration (and add SMS)
Summary:
Enables configuration of multi-factor authentication from the
account page (for users who sign in with email/password), and adds
SMS as an authentication method.

Test Plan: Project, browser and server tests.

Reviewers: paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D3215
2022-01-19 13:55:54 -08:00

55 lines
1.9 KiB
TypeScript

import {reportError} from 'app/client/models/errors';
import {BaseAPI} from 'app/common/BaseAPI';
import {dom, Observable} from 'grainjs';
/**
* Handles submission of an HTML form element.
*
* When the form is submitted, `onSubmit` will be called, followed by
* either `onSuccess` or `onError`, depending on whether `onSubmit` threw any
* unhandled errors. The `pending` observable is set to true until `onSubmit`
* resolves.
*/
export function handleSubmit<T>(
pending: Observable<boolean>,
onSubmit: (fields: { [key: string]: string }, form: HTMLFormElement) => Promise<T> = submitForm,
onSuccess: (v: T) => void = () => { /* noop */ },
onError: (e: unknown) => void = (e) => reportError(e as string | Error)
): (elem: HTMLFormElement) => void {
return dom.on('submit', async (e, form) => {
e.preventDefault();
try {
if (pending.get()) { return; }
pending.set(true);
const result = await onSubmit(formDataToObj(form), form).finally(() => pending.set(false));
onSuccess(result);
} catch (err) {
onError(err);
}
});
}
/**
* Convert a form to a JSON-stringifiable object, ignoring any File fields.
*/
export function formDataToObj(formElem: HTMLFormElement): { [key: string]: string } {
// Use FormData to collect values (rather than e.g. finding <input> elements) to ensure we get
// values from all form items correctly (e.g. checkboxes and textareas).
const formData = new FormData(formElem);
const data: { [key: string]: string } = {};
for (const [name, value] of formData.entries()) {
if (typeof value === 'string') {
data[name] = value;
}
}
return data;
}
/**
* Submit a form using BaseAPI. Send inputs as JSON, and interpret any reply as JSON.
*/
export async function submitForm(fields: { [key: string]: string }, form: HTMLFormElement): Promise<any> {
return BaseAPI.requestJson(form.action, {method: 'POST', body: JSON.stringify(fields)});
}