fix: Editing/saving fixes (#432)

* feat: table add button is now hidden when adding/editing

feat: disable every other action on editable table when editing/adding

feat: hide add button instead of disabling it when can't add

feat: disable every other action when adding/editing on the commissions
page

feat: disable every other action when adding/editing on the locales
page

feat: disable every other action when adding/editing on the
notifications page

feat: disable save buttons while waiting for server response on tables
and editable numbers

* chore: removed TODO
This commit is contained in:
Liordino Neto 2020-09-22 18:28:55 -03:00 committed by GitHub
parent 02474a0a6d
commit 0c3ae801d0
6 changed files with 62 additions and 18 deletions

View file

@ -54,8 +54,13 @@ const ETable = ({
}) => { }) => {
const [editingId, setEditingId] = useState(null) const [editingId, setEditingId] = useState(null)
const [adding, setAdding] = useState(false) const [adding, setAdding] = useState(false)
const [saving, setSaving] = useState(false)
const innerSave = async value => { const innerSave = async value => {
if (saving) return
setSaving(true)
const it = validationSchema.cast(value) const it = validationSchema.cast(value)
const index = R.findIndex(R.propEq('id', it.id))(data) const index = R.findIndex(R.propEq('id', it.id))(data)
const list = index !== -1 ? R.update(index, it, data) : R.prepend(it, data) const list = index !== -1 ? R.update(index, it, data) : R.prepend(it, data)
@ -63,11 +68,16 @@ const ETable = ({
if (!R.equals(data[index], it)) { if (!R.equals(data[index], it)) {
// no response means the save failed // no response means the save failed
const response = await save({ [name]: list }, it) const response = await save({ [name]: list }, it)
if (!response) return if (!response) {
setSaving(false)
return
}
} }
setAdding(false) setAdding(false)
setEditingId(null) setEditingId(null)
setEditing && setEditing(false)
setSaving(false)
} }
const onDelete = id => { const onDelete = id => {
@ -86,7 +96,10 @@ const ETable = ({
setEditing && setEditing(it, true) setEditing && setEditing(it, true)
} }
const addField = () => setAdding(true) const addField = () => {
setAdding(true)
setEditing && setEditing(true, true)
}
const widthIfEditNull = const widthIfEditNull =
enableDelete || enableToggle ? ACTION_COL_SIZE : ACTION_COL_SIZE * 2 enableDelete || enableToggle ? ACTION_COL_SIZE : ACTION_COL_SIZE * 2
@ -128,10 +141,8 @@ const ETable = ({
return ( return (
<TableCtx.Provider value={ctxValue}> <TableCtx.Provider value={ctxValue}>
<div className={classes.wrapper}> <div className={classes.wrapper}>
{showButtonOnEmpty && ( {showButtonOnEmpty && canAdd && (
<AddButton disabled={!canAdd} onClick={addField}> <AddButton onClick={addField}>{createText}</AddButton>
{createText}
</AddButton>
)} )}
{showTable && ( {showTable && (
<> <>
@ -185,7 +196,9 @@ const ETable = ({
lastOfGroup={isLastOfGroup} lastOfGroup={isLastOfGroup}
editing={editingId === it.id} editing={editingId === it.id}
disabled={ disabled={
forceDisable || (editingId && editingId !== it.id) forceDisable ||
(editingId && editingId !== it.id) ||
adding
} }
/> />
</Form> </Form>

View file

@ -1,7 +1,7 @@
import { useQuery, useMutation } from '@apollo/react-hooks' import { useQuery, useMutation } from '@apollo/react-hooks'
import gql from 'graphql-tag' import gql from 'graphql-tag'
import * as R from 'ramda' import * as R from 'ramda'
import React from 'react' import React, { useState } from 'react'
import { Table as EditableTable } from 'src/components/editableTable' import { Table as EditableTable } from 'src/components/editableTable'
import Section from 'src/components/layout/Section' import Section from 'src/components/layout/Section'
@ -38,6 +38,8 @@ const SAVE_CONFIG = gql`
` `
const Commissions = ({ name: SCREEN_KEY }) => { const Commissions = ({ name: SCREEN_KEY }) => {
const [isEditingDefault, setEditingDefault] = useState(false)
const [isEditingOverrides, setEditingOverrides] = useState(false)
const { data } = useQuery(GET_DATA) const { data } = useQuery(GET_DATA)
const [saveConfig] = useMutation(SAVE_CONFIG, { const [saveConfig] = useMutation(SAVE_CONFIG, {
refetchQueries: () => ['getData'] refetchQueries: () => ['getData']
@ -61,6 +63,9 @@ const Commissions = ({ name: SCREEN_KEY }) => {
return saveConfig({ variables: { config } }) return saveConfig({ variables: { config } })
} }
const onEditingDefault = (it, editing) => setEditingDefault(editing)
const onEditingOverrides = (it, editing) => setEditingOverrides(editing)
return ( return (
<> <>
<TitleSection title="Commissions" /> <TitleSection title="Commissions" />
@ -76,6 +81,8 @@ const Commissions = ({ name: SCREEN_KEY }) => {
validationSchema={schema} validationSchema={schema}
data={R.of(commission)} data={R.of(commission)}
elements={mainFields(currency)} elements={mainFields(currency)}
setEditing={onEditingDefault}
forceDisable={isEditingOverrides}
/> />
</Section> </Section>
<Section> <Section>
@ -91,6 +98,8 @@ const Commissions = ({ name: SCREEN_KEY }) => {
validationSchema={OverridesSchema} validationSchema={OverridesSchema}
data={commissionOverrides} data={commissionOverrides}
elements={overrides(data, currency, commissionOverrides)} elements={overrides(data, currency, commissionOverrides)}
setEditing={onEditingOverrides}
forceDisable={isEditingDefault}
/> />
</Section> </Section>
</> </>

View file

@ -89,6 +89,8 @@ const FiatCurrencyChangeAlert = ({ open, close, save }) => {
} }
const Locales = ({ name: SCREEN_KEY }) => { const Locales = ({ name: SCREEN_KEY }) => {
const [isEditingDefault, setEditingDefault] = useState(false)
const [isEditingOverrides, setEditingOverrides] = useState(false)
const { data } = useQuery(GET_DATA) const { data } = useQuery(GET_DATA)
const [saveConfig] = useMutation(SAVE_CONFIG, { const [saveConfig] = useMutation(SAVE_CONFIG, {
refetchQueries: () => ['getData'] refetchQueries: () => ['getData']
@ -119,6 +121,9 @@ const Locales = ({ name: SCREEN_KEY }) => {
return saveConfig({ variables: { config } }) return saveConfig({ variables: { config } })
} }
const onEditingDefault = (it, editing) => setEditingDefault(editing)
const onEditingOverrides = (it, editing) => setEditingOverrides(editing)
return ( return (
<> <>
<FiatCurrencyChangeAlert <FiatCurrencyChangeAlert
@ -138,6 +143,8 @@ const Locales = ({ name: SCREEN_KEY }) => {
validationSchema={LocaleSchema} validationSchema={LocaleSchema}
data={R.of(locale)} data={R.of(locale)}
elements={mainFields(data)} elements={mainFields(data)}
setEditing={onEditingDefault}
forceDisable={isEditingOverrides}
/> />
</Section> </Section>
<Section> <Section>
@ -151,8 +158,10 @@ const Locales = ({ name: SCREEN_KEY }) => {
initialValues={overridesDefaults} initialValues={overridesDefaults}
save={saveOverrides} save={saveOverrides}
validationSchema={OverridesSchema} validationSchema={OverridesSchema}
data={localeOverrides} data={localeOverrides ?? []}
elements={overrides(data, localeOverrides)} elements={overrides(data, localeOverrides)}
setEditing={onEditingOverrides}
forceDisable={isEditingDefault}
/> />
</Section> </Section>
</> </>

View file

@ -95,7 +95,7 @@ const Notifications = ({ name: SCREEN_KEY }) => {
<TitleSection title="Notifications" /> <TitleSection title="Notifications" />
<Section title="Setup" error={error && !section}> <Section title="Setup" error={error && !section}>
<Setup /> <Setup forceDisable={!!editingKey} />
</Section> </Section>
<Section title="Transaction alerts" error={error && section === 'tx'}> <Section title="Transaction alerts" error={error && section === 'tx'}>

View file

@ -1,5 +1,5 @@
import { Form, Formik } from 'formik' import { Form, Formik } from 'formik'
import React, { useContext } from 'react' import React, { useContext, useState } from 'react'
import * as Yup from 'yup' import * as Yup from 'yup'
import PromptWhenDirty from 'src/components/PromptWhenDirty' import PromptWhenDirty from 'src/components/PromptWhenDirty'
@ -17,6 +17,19 @@ const SingleFieldEditableNumber = ({
section, section,
className className
}) => { }) => {
const [saving, setSaving] = useState(false)
const innerSave = async (section, value) => {
if (saving) return
setSaving(true)
// no response means the save failed
await save(section, value)
setSaving(false)
}
const { const {
save, save,
data, data,
@ -38,7 +51,7 @@ const SingleFieldEditableNumber = ({
enableReinitialize enableReinitialize
initialValues={{ [name]: (data && data[name]) ?? '' }} initialValues={{ [name]: (data && data[name]) ?? '' }}
validationSchema={schema} validationSchema={schema}
onSubmit={it => save(section, schema.cast(it))} onSubmit={it => innerSave(section, schema.cast(it))}
onReset={() => { onReset={() => {
setEditing(name, false) setEditing(name, false)
}}> }}>

View file

@ -26,13 +26,13 @@ const sizes = {
} }
const width = R.sum(R.values(sizes)) + channelSize const width = R.sum(R.values(sizes)) + channelSize
const Row = ({ namespace }) => { const Row = ({ namespace, forceDisable }) => {
const { data: rawData, save: rawSave } = useContext(NotificationsCtx) const { data: rawData, save: rawSave } = useContext(NotificationsCtx)
const save = R.compose(rawSave(null), toNamespace(namespace)) const save = R.compose(rawSave(null), toNamespace(namespace))
const data = fromNamespace(namespace)(rawData) const data = fromNamespace(namespace)(rawData)
const disabled = !data || !data.active const disabled = forceDisable || !data || !data.active
const Cell = ({ name, disabled }) => { const Cell = ({ name, disabled }) => {
const value = !!(data && data[name]) const value = !!(data && data[name])
@ -58,7 +58,7 @@ const Row = ({ namespace }) => {
<Cell name="transactions" disabled={disabled} /> <Cell name="transactions" disabled={disabled} />
<Cell name="compliance" disabled={disabled} /> <Cell name="compliance" disabled={disabled} />
<Cell name="errors" disabled={disabled} /> <Cell name="errors" disabled={disabled} />
<Cell name="active" /> <Cell name="active" disabled={forceDisable} />
</Tr> </Tr>
) )
} }
@ -68,7 +68,7 @@ const useStyles = makeStyles({
width width
} }
}) })
const Setup = () => { const Setup = ({ forceDisable }) => {
const classes = useStyles() const classes = useStyles()
return ( return (
<Table className={classes.mainTable}> <Table className={classes.mainTable}>
@ -81,8 +81,8 @@ const Setup = () => {
))} ))}
</THead> </THead>
<TBody> <TBody>
<Row namespace="email" /> <Row namespace="email" forceDisable={forceDisable} />
<Row namespace="sms" /> <Row namespace="sms" forceDisable={forceDisable} />
</TBody> </TBody>
</Table> </Table>
) )