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:
parent
02474a0a6d
commit
0c3ae801d0
6 changed files with 62 additions and 18 deletions
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -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'}>
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}}>
|
}}>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue