diff --git a/public/locales/en.json b/public/locales/en.json index a0f35e8..5aabb33 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -886,7 +886,10 @@ "successMessage": "Name transferred successfully", "successMessage_plural": "Names transferred successfully", "successDescription": "Transferred <1>{{count, number}} name to <3 />.", - "successDescription_plural": "Transferred <1>{{count, number}} names to <3 />." + "successDescription_plural": "Transferred <1>{{count, number}} names to <3 />.", + + "progress": "Transferring <1>{{count, number}} name...", + "progress_plural": "Transferring <1>{{count, number}} names..." }, "nameUpdate": { @@ -912,7 +915,10 @@ "successMessage": "Name updated successfully", "successMessage_plural": "Names updated successfully", "successDescription": "Updated <1>{{count, number}} names.", - "successDescription_plural": "Updated <1>{{count, number}} names." + "successDescription_plural": "Updated <1>{{count, number}} names.", + + "progress": "Updating <1>{{count, number}} name...", + "progress_plural": "Updating <1>{{count, number}} names..." }, "noNamesResult": { diff --git a/src/pages/names/mgmt/NameEditForm.tsx b/src/pages/names/mgmt/NameEditForm.tsx new file mode 100644 index 0000000..0892422 --- /dev/null +++ b/src/pages/names/mgmt/NameEditForm.tsx @@ -0,0 +1,126 @@ +// Copyright (c) 2020-2021 Drew Lemmy +// This file is part of KristWeb 2 under GPL-3.0. +// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt +import { useState } from "react"; +import { Form, FormInstance } from "antd"; + +import { TFns } from "@utils/i18n"; + +import { Mode } from "./NameEditModal"; + +import { NamePicker } from "./NamePicker"; +import { AddressPicker } from "@comp/addresses/picker/AddressPicker"; +import { ARecordInput } from "./ARecordInput"; + +interface FormValues { + names: string[]; + recipient?: string; + aRecord?: string; +} + +interface Props { + name?: string; + aRecord?: string | null; + mode: Mode; + + submitting?: boolean; + onSubmit: () => void; + + tFns: TFns; +} + +interface NameEditFormHookResponse { + form: JSX.Element; + formInstance: FormInstance; + resetFields: () => void; +} + +export function useNameEditForm({ + name, + aRecord, + mode, + + submitting, + onSubmit, + + tFns +}: Props): NameEditFormHookResponse { + const { t, tStr } = tFns; + + const [formInstance] = Form.useForm(); + + // Used to filter out names owned by the recipient (for transfers) + const [names, setNames] = useState(); + const [recipient, setRecipient] = useState(); + + function onValuesChange(_: unknown, values: Partial) { + setNames(values.names || undefined); + setRecipient(values.recipient || undefined); + } + + function resetFields() { + formInstance.resetFields(); + setNames(undefined); + setRecipient(undefined); + } + + const form =
+ {/* Names */} + formInstance.setFieldsValue({ names })} + + multiple + allowAll + /> + + {/* Display the correct input; an address picker for transfer recipients, or + * a textbox for A records. */} + {mode === "transfer" + ? ( + // Transfer - Recipient + + ) + : ( + // Update - A record + + )} + ; + + return { form, formInstance, resetFields }; +} diff --git a/src/pages/names/mgmt/NameEditModal.tsx b/src/pages/names/mgmt/NameEditModal.tsx index fde1bb0..f8d3c09 100644 --- a/src/pages/names/mgmt/NameEditModal.tsx +++ b/src/pages/names/mgmt/NameEditModal.tsx @@ -19,9 +19,7 @@ import { NameOption, fetchNames, buildLUT } from "./lookupNames"; import { handleError } from "./handleErrors"; -import { NamePicker } from "./NamePicker"; -import { AddressPicker } from "@comp/addresses/picker/AddressPicker"; -import { ARecordInput } from "./ARecordInput"; +import { useNameEditForm } from "./NameEditForm"; import { showConfirmModal } from "./ConfirmModal"; import { SuccessNotifContent } from "./SuccessNotifContent"; @@ -29,12 +27,6 @@ export type Mode = "transfer" | "update"; -interface FormValues { - names: string[]; - recipient?: string; - aRecord?: string; -} - interface Props { visible: boolean; setVisible: Dispatch>; @@ -55,13 +47,8 @@ const tFns = useTFns(mode === "transfer" ? "nameTransfer." : "nameUpdate."); const { t, tKey, tStr, tErr } = tFns; - const [form] = Form.useForm(); const [submitting, setSubmitting] = useState(false); - // Used to filter out names owned by the recipient (for transfers) - const [names, setNames] = useState(); - const [recipient, setRecipient] = useState(); - // Confirmation modal used for when transferring multiple names. // This is created here to provide a translation context for the modal. const [confirmModal, contextHolder] = Modal.useModal(); @@ -76,6 +63,10 @@ // Used to decrypt the wallets for transfer/update const masterPassword = useMasterPasswordOnly(); + // Create the form. This is usually not rendered during submission. + const { form, formInstance, resetFields } + = useNameEditForm({ name, aRecord, mode, submitting, onSubmit, tFns }); + // Wrap the handleError function const onError = handleError.bind( handleError, @@ -142,7 +133,7 @@ setSubmitting(true); // Get the form values - const [err, values] = await awaitTo(form.validateFields()); + const [err, values] = await awaitTo(formInstance.validateFields()); if (err || !values) { // Validation errors are handled by the form setSubmitting(false); @@ -198,95 +189,32 @@ } } - function onValuesChange(_: unknown, values: Partial) { - setNames(values.names || undefined); - setRecipient(values.recipient || undefined); - } - function closeModal() { // Don't allow closing the modal while submitting if (submitting) return; - setVisible(false); - form.resetFields(); - setNames(undefined); - setRecipient(undefined); + resetFields(); } - const modal = -
- {/* Names */} - form.setFieldsValue({ names })} - - multiple - allowAll - /> - - {/* Display the correct input; an address picker for transfer recipients, - * or a textbox for A records. */} - {mode === "transfer" - ? ( - // Transfer - Recipient - - ) - : ( - // Update - A record - - )} - -
; - return <> - {modal} + + {/* Only render the form if not submitting */} + {!submitting && form} + + {/* TODO: Display a progress bar here */} + {/* Give the modals somewhere to find the context from. This is done * outside of the modal so that they don't get immediately destroyed when diff --git a/src/pages/names/mgmt/NamePicker.tsx b/src/pages/names/mgmt/NamePicker.tsx index 02a3f73..a94cd2e 100644 --- a/src/pages/names/mgmt/NamePicker.tsx +++ b/src/pages/names/mgmt/NamePicker.tsx @@ -24,7 +24,7 @@ import Debug from "debug"; const debug = Debug("kristweb:name-picker"); -const FETCH_THROTTLE = 500; +const FETCH_THROTTLE = 2000; export async function _fetchNames( t: TFunction, nameSuffix: string,