import { makeStyles } from '@material-ui/core' import { Form, Formik } from 'formik' import * as R from 'ramda' import React, { useState, useEffect } from 'react' import { v4 } from 'uuid' import PromptWhenDirty from 'src/components/PromptWhenDirty' 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, TL1 } from 'src/components/typography' import TableCtx from './Context' import Header from './Header' import ERow from './Row' import styles from './Table.styles' const ACTION_COL_SIZE = 87 const DEFAULT_COL_SIZE = 100 const useStyles = makeStyles(styles) const getWidth = R.compose( R.reduce(R.add)(0), R.map(it => it.width ?? DEFAULT_COL_SIZE) ) const ETable = ({ name, title, titleLg, elements = [], data = [], save, error: externalError, rowSize = 'md', validationSchema, enableCreate, enableEdit, editWidth: outerEditWidth, enableDelete, deleteWidth = ACTION_COL_SIZE, enableToggle, toggleWidth = ACTION_COL_SIZE, onToggle, forceDisable, disableAdd, initialValues, setEditing, shouldOverrideEdit, editOverride, stripeWhen, disableRowEdit, groupBy, sortBy, createText = 'Add override', forceAdd = false }) => { const [editingId, setEditingId] = useState(null) const [adding, setAdding] = useState(false) const [saving, setSaving] = useState(false) const [error, setError] = useState(null) useEffect(() => setError(externalError), [externalError]) useEffect(() => { setError(null) setAdding(forceAdd) }, [forceAdd]) const innerSave = async value => { if (saving) return setSaving(true) const it = validationSchema.cast(value) const index = R.findIndex(R.propEq('id', it.id))(data) const list = index !== -1 ? R.update(index, it, data) : R.prepend(it, data) if (!R.equals(data[index], it)) { try { await save({ [name]: list }, it) } catch (err) { setSaving(false) return } } setAdding(false) setEditingId(null) setEditing && setEditing(false) setSaving(false) } 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 => { if (shouldOverrideEdit && shouldOverrideEdit(it)) return editOverride(it) setEditingId(it) setError(null) setEditing && setEditing(it, true) } const addField = () => { setAdding(true) setError(null) setEditing && setEditing(true, true) } const widthIfEditNull = enableDelete || enableToggle ? ACTION_COL_SIZE : ACTION_COL_SIZE * 2 const editWidth = R.defaultTo(widthIfEditNull)(outerEditWidth) const actionColSize = ((enableDelete && deleteWidth) ?? 0) + ((enableEdit && editWidth) ?? 0) + ((enableToggle && toggleWidth) ?? 0) const width = getWidth(elements) + actionColSize const classes = useStyles({ width }) const showButtonOnEmpty = !data.length && enableCreate && !adding const canAdd = !forceDisable && !editingId && !disableAdd && !adding const showTable = adding || data.length !== 0 const innerData = sortBy ? R.sortWith(sortBy)(data) : data const ctxValue = { elements, enableEdit, onEdit, clearError: () => setError(null), error: error, disableRowEdit, editWidth, enableDelete, onDelete, deleteWidth, enableToggle, rowSize, onToggle, toggleWidth, actionColSize, stripeWhen, forceAdd, DEFAULT_COL_SIZE } return (
{showButtonOnEmpty && canAdd && ( {createText} )} {showTable && ( <> {(title || enableCreate) && (
{title && titleLg && ( {title} )} {title && !titleLg && ( {title} )} {enableCreate && canAdd && ( {createText} )}
)}
{adding && (
)} {innerData.map((it, idx) => { const nextElement = innerData[idx + 1] const isLastOfGroup = groupBy && nextElement && nextElement[groupBy] !== it[groupBy] return (
) })}
)}
) } export default ETable