feat: notifications rework

This commit is contained in:
Taranto 2020-03-30 13:03:57 +01:00 committed by Josh Harvey
parent b6e7d98b72
commit ffa8713ee4
77 changed files with 2281 additions and 3269 deletions

View file

@ -1,124 +1,152 @@
import React, { memo } from 'react'
import { makeStyles } from '@material-ui/core'
import { Form, Formik } from 'formik'
import * as R from 'ramda'
import React, { useState } from 'react'
import { v4 } from 'uuid'
import {
Th,
ThDoubleLevel,
THead,
TBody,
Table,
TDoubleLevelHead
} from 'src/components/fake-table/Table'
import { startCase } from 'src/utils/string'
import Link from 'src/components/buttons/Link.js'
import { AddButton } from 'src/components/buttons/index.js'
import { TBody, Table } from 'src/components/fake-table/Table'
import { Info2 } from 'src/components/typography'
import Header from './Header'
import ERow from './Row'
import styles from './Table.styles'
import { DEFAULT_COL_SIZE, ACTION_COL_SIZE } from './consts'
const ETHead = memo(({ elements, className }) => {
const action = R.last(elements)
const useStyles = makeStyles(styles)
return (
<THead className={className?.root}>
{R.init(elements).map(({ name, size, display, textAlign }, idx) => (
<Th
id={name}
key={idx}
size={size}
textAlign={textAlign}
className={className?.cell}>
{display}
</Th>
))}
<Th size={action.size} action>
{startCase(action.name)}
</Th>
</THead>
)
})
const ETDoubleHead = memo(({ elements, className }) => {
const action = R.last(elements)
return (
<TDoubleLevelHead className={className?.root}>
{R.init(elements).map((element, idx) => {
if (Array.isArray(element)) {
return (
<ThDoubleLevel
key={idx}
title={element[0].display}
className={className?.cell}>
{R.map(({ name, size, display, textAlign }) => (
<Th key={name} id={name} size={size} textAlign={textAlign}>
{display}
</Th>
))(R.tail(element))}
</ThDoubleLevel>
)
}
const { name, size, display, textAlign } = element
return (
<Th id={idx} key={name} size={size} textAlign={textAlign}>
{display}
</Th>
)
})}
<Th size={action.size} action>
{startCase(action.name)}
</Th>
</TDoubleLevelHead>
)
})
const ETable = memo(
({
elements = [],
data = [],
save,
reset,
action,
initialValues,
validationSchema,
editing,
addingRow,
disableAction,
className,
double
}) => {
return (
<Table className={className}>
{!double && <ETHead elements={elements} />}
{double && (
<ETDoubleHead elements={elements} className={className?.head} />
)}
<TBody>
{addingRow && (
<ERow
elements={elements}
initialValues={initialValues}
save={save}
reset={reset}
validationSchema={validationSchema}
editing
/>
)}
{data.map((it, idx) => (
<ERow
key={idx}
initialValues={it}
elements={elements}
save={save}
reset={it => reset(it)}
action={action}
validationSchema={validationSchema}
disableAction={disableAction}
editing={editing[idx]}
/>
))}
</TBody>
</Table>
)
}
const getWidth = R.compose(
R.reduce(R.add)(0),
R.map(it => it.width ?? DEFAULT_COL_SIZE)
)
const ETable = ({
name,
title,
elements = [],
data = [],
save,
validationSchema,
enableCreate,
forceDisable,
disableAdd,
enableDelete,
initialValues,
enableEdit,
setEditing,
createText = 'Add override'
}) => {
const [editingId, setEditingId] = useState(null)
const [adding, setAdding] = useState(false)
const innerSave = async it => {
const index = R.findIndex(R.propEq('id', it.id))(data)
const list = index !== -1 ? R.update(index, it, data) : R.prepend(it, data)
// no response means the save failed
const response = await save({ [name]: list })
if (!response) return
setAdding(false)
setEditingId(null)
}
const onDelete = id => {
const list = R.reject(it => it.id === id, data)
return save({ [name]: list })
}
const onReset = () => {
setAdding(false)
setEditingId(null)
setEditing && setEditing(false)
}
const onEdit = it => {
setEditingId(it)
setEditing && setEditing(it, true)
}
const addField = () => setAdding(true)
const actionSize = enableEdit || enableDelete ? ACTION_COL_SIZE : 0
const width = getWidth(elements) + actionSize
const classes = useStyles({ width })
const showButtonOnEmpty = !data.length && enableCreate && !adding
const canAdd = !forceDisable && !editingId && !disableAdd && !adding
const showTable = adding || data.length !== 0
return (
<div className={classes.wrapper}>
{showButtonOnEmpty && (
<AddButton disabled={!canAdd} onClick={addField}>
{createText}
</AddButton>
)}
{showTable && (
<>
<div className={classes.outerHeader}>
{title && <Info2 className={classes.title}>{title}</Info2>}
{enableCreate && canAdd && (
<Link className={classes.addLink} onClick={addField}>
{createText}
</Link>
)}
</div>
<Table>
<Header
elements={elements}
enableEdit={enableEdit}
enableDelete={enableDelete}
/>
<TBody>
{adding && (
<Formik
initialValues={{ id: v4(), ...initialValues }}
onReset={onReset}
validationSchema={validationSchema}
onSubmit={innerSave}>
<Form>
<ERow
editing={true}
disabled={forceDisable}
enableEdit={enableEdit}
enableDelete={enableDelete}
elements={elements}
/>
</Form>
</Formik>
)}
{data.map((it, idx) => (
<Formik
key={it.id ?? idx}
enableReinitialize
initialValues={it}
onReset={onReset}
validationSchema={validationSchema}
onSubmit={innerSave}>
<Form>
<ERow
editing={editingId === it.id}
disabled={
forceDisable || (editingId && editingId !== it.id)
}
setEditing={onEdit}
onDelete={onDelete}
enableEdit={enableEdit}
enableDelete={enableDelete}
elements={elements}
/>
</Form>
</Formik>
))}
</TBody>
</Table>
</>
)}
</div>
)
}
export default ETable