From c634d5bcd5bde6e4427da3540f4385870e344206 Mon Sep 17 00:00:00 2001 From: Keith Date: Sun, 4 Aug 2019 02:08:12 +0800 Subject: [PATCH] feat(neuron-ui): add dynamic validation on the network editor --- .../src/components/NetworkEditor/hooks.ts | 33 ++++++++++++++----- .../src/components/NetworkEditor/index.tsx | 30 ++++++++++++----- packages/neuron-ui/src/locales/en.json | 4 ++- packages/neuron-ui/src/locales/zh.json | 4 ++- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts index 428d2a985e..f65f54ee02 100644 --- a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts +++ b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts @@ -77,7 +77,7 @@ export const useInitialize = ( }, [dispatch, id, initialize, networks]) } -export const useInputs = (editor: EditorType) => { +export const useInputs = (editor: EditorType, usedNetworkNames: string[], t: any) => { return useMemo( () => [ { @@ -85,29 +85,46 @@ export const useInputs = (editor: EditorType) => { label: i18n.t('settings.network.edit-network.rpc-url'), tooltip: TooltipText.URL, placeholder: PlaceHolder.URL, + onGetErrorMessage: (url: string) => { + if (!url) { + return t('messages.url-required') + } + if (!/^https?:\/\//.test(url)) { + return t('messages.rpc-url-should-have-protocol') + } + if (/\s/.test(url)) { + return t('messages.rpc-url-should-have-no-whitespaces') + } + return '' + }, }, { ...editor.name, label: i18n.t('settings.network.edit-network.name'), tooltip: TooltipText.Name, placeholder: PlaceHolder.Name, + onGetErrorMessage: (name: string) => { + if (!name) { + return t('messages.name-required') + } + if (usedNetworkNames.includes(name)) { + return t('messages.network-name-used') + } + return '' + }, }, ], - [editor.remote, editor.name] + [editor.remote, editor.name, usedNetworkNames, t] ) } export const useIsInputsValid = (editor: EditorType, cachedNetwork: State.Network | undefined) => { - const invalidParams = useMemo(() => !editor.name.value || !editor.remote.value, [ - editor.name.value, - editor.remote.value, - ]) - + const [errors, setErrors] = useState([!cachedNetwork && !editor.name.value, !cachedNetwork && !editor.remote.value]) const notModified = useMemo( () => cachedNetwork && (cachedNetwork.name === editor.name.value && cachedNetwork.remote === editor.remote.value), [cachedNetwork, editor.name.value, editor.remote.value] ) - return { invalidParams, notModified } + return { errors, setErrors, notModified } } export const useHandleSubmit = ( diff --git a/packages/neuron-ui/src/components/NetworkEditor/index.tsx b/packages/neuron-ui/src/components/NetworkEditor/index.tsx index e41d6df20a..abe8c568e0 100644 --- a/packages/neuron-ui/src/components/NetworkEditor/index.tsx +++ b/packages/neuron-ui/src/components/NetworkEditor/index.tsx @@ -1,4 +1,4 @@ -import React, { useRef } from 'react' +import React, { useMemo, useRef } from 'react' import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Stack, PrimaryButton, DefaultButton, TextField } from 'office-ui-fabric-react' @@ -17,28 +17,42 @@ const NetworkEditor = ({ }: React.PropsWithoutRef>) => { const editor = useNetworkEditor() const [t] = useTranslation() - const inputs = useInputs(editor) + const cachedNetworks = useRef(networks) + const cachedNetwork = cachedNetworks.current.find(network => network.id === id) + const usedNetworkNames = useMemo( + () => networks.map(n => n.name).filter(name => name !== ((cachedNetwork && cachedNetwork.name) || '')), + [networks] + ) + const inputs = useInputs(editor, usedNetworkNames, t) const goBack = useGoBack(history) useInitialize(id, networks, editor.initialize, dispatch) - const cachedNetworks = useRef(networks) - const cachedNetwork = cachedNetworks.current.find(network => network.id === id) - const { invalidParams, notModified } = useIsInputsValid(editor, cachedNetwork) + const { errors, setErrors, notModified } = useIsInputsValid(editor, cachedNetwork) const handleSubmit = useHandleSubmit(id, editor.name.value, editor.remote.value, networks, history, dispatch) return (

{t('settings.network.edit-network.title')}

- {inputs.map(inputProps => ( + {inputs.map((inputProps, idx) => ( - + { + const errs = [...errors] + errs.splice(idx, 1, msg !== '') + setErrors(errs) + }} + /> ))} - +
) diff --git a/packages/neuron-ui/src/locales/en.json b/packages/neuron-ui/src/locales/en.json index f8d89f85e4..8d61e47694 100644 --- a/packages/neuron-ui/src/locales/en.json +++ b/packages/neuron-ui/src/locales/en.json @@ -239,7 +239,9 @@ "addr-copied": "Address has been copied to the clipboard", "qrcode-copied": "QR Code has been copied to the clipboard", "lock-arg-copied": "Lock Arg has been copied to the clipboard", - "transaction-not-found": "The transaction is not found" + "transaction-not-found": "The transaction is not found", + "rpc-url-should-have-protocol": "The RPC URL should start with http(s)://", + "rpc-url-should-have-no-whitespaces": "The RPC URL should have no whitespaces" }, "sync": { "syncing": "Syncing", diff --git a/packages/neuron-ui/src/locales/zh.json b/packages/neuron-ui/src/locales/zh.json index f119dcf655..2207934ff5 100644 --- a/packages/neuron-ui/src/locales/zh.json +++ b/packages/neuron-ui/src/locales/zh.json @@ -239,7 +239,9 @@ "addr-copied": "地址已复制到剪贴板", "qrcode-copied": "二维码已复制到剪贴板", "lock-arg-copied": "Lock Arg 已复制到剪贴板", - "transaction-not-found": "未找到交易" + "transaction-not-found": "未找到交易", + "network-address-should-have-protocol": "RPC 地址应以 http(s)//: 开始", + "network-address-should-have-no-whitespaces": "RPC 地址不能包含空格" }, "sync": { "syncing": "同步中",