mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Refactor editing components into their own file
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { ReactNode, createContext, useState, JSX } from 'react'
|
||||
import { DropdownOption } from '../common/FormComponents'
|
||||
import { DropdownOption } from '../common/editingComponents'
|
||||
|
||||
export type ModeType = 'read' | 'new' | 'edit'
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ import SaveIcon from '@mui/icons-material/Save'
|
||||
import { useEffect, useState, JSX } from 'react'
|
||||
import { DetailContextProvider, ModeType } from './Context/DetailContext'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { DropdownOption, DropdownSelector, EditableTextField, RadioSelector } from './common/FormComponents'
|
||||
import { EditableTextField } from './common/FormComponents'
|
||||
import { useDetailContext } from './hooks'
|
||||
import { DropdownOption, DropdownSelector, RadioSelector } from './common/editingComponents'
|
||||
|
||||
export type TabType = {
|
||||
title: string
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
import {
|
||||
Card,
|
||||
Typography,
|
||||
Box,
|
||||
Grid,
|
||||
Divider,
|
||||
Modal,
|
||||
Button,
|
||||
TextField,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
} from '@mui/material'
|
||||
import { Card, Typography, Box, Grid, Divider, Modal, Button, TextField } from '@mui/material'
|
||||
import { ReactNode, useState, ChangeEvent } from 'react'
|
||||
import { useDetailContext } from '../hooks'
|
||||
import { RegisterOptions, FieldValues, UseFormRegisterReturn, FieldErrors } from 'react-hook-form'
|
||||
|
||||
export const ArrayToTable = ({ array, half }: { array: Array<Array<ReactNode>>; half?: boolean }) => {
|
||||
const maxRowLength = Math.max(...array.map(row => row.length))
|
||||
@@ -149,101 +131,6 @@ export const EditableTextField = <T extends object>({
|
||||
return <DataValue<T> field={field} EditElement={editingComponent} />
|
||||
}
|
||||
|
||||
export type DropdownOption = { value: string; display: string }
|
||||
|
||||
export const DropdownSelector = <T extends object>({
|
||||
options,
|
||||
name,
|
||||
field,
|
||||
}: {
|
||||
options: Array<DropdownOption | string>
|
||||
name: string
|
||||
field: keyof T
|
||||
}) => {
|
||||
const { data, setEditData, editData } = useDetailContext<T>()
|
||||
const editingComponent = (
|
||||
<FormControl size="small">
|
||||
<InputLabel id={`${name}-multiselect-label`}>{name}</InputLabel>
|
||||
<Select
|
||||
labelId={`${name}-multiselect-label`}
|
||||
label={name}
|
||||
id={`${name}-multiselect`}
|
||||
value={(editData[field] || '') as string}
|
||||
onChange={(event: SelectChangeEvent) => setEditData({ ...editData, [field]: event.target.value })}
|
||||
sx={{ width: '12em' }}
|
||||
size="small"
|
||||
>
|
||||
{options.map(item => (
|
||||
<MenuItem key={getValue(item)} value={getValue(item)}>
|
||||
{getDisplay(item)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)
|
||||
|
||||
const option = options.find(option => getValue(option) === data[field])
|
||||
const displayValue = option ? getDisplay(option) : null
|
||||
return <DataValue<T> field={field} EditElement={editingComponent} displayValue={displayValue} />
|
||||
}
|
||||
|
||||
export const FormTextField = <T extends string>({
|
||||
register,
|
||||
errors,
|
||||
fieldName,
|
||||
label,
|
||||
required = false,
|
||||
}: {
|
||||
register: (name: T, options?: RegisterOptions<FieldValues, T> | undefined) => UseFormRegisterReturn<T>
|
||||
errors: FieldErrors<FieldValues>
|
||||
fieldName: T
|
||||
label: string
|
||||
required: boolean
|
||||
}) => (
|
||||
<TextField {...register(fieldName, { required: required })} error={!!errors[fieldName]} {...{ label, required }} />
|
||||
)
|
||||
|
||||
const getValue = (item: DropdownOption | string) => (typeof item === 'string' ? item : item.value)
|
||||
const getDisplay = (item: DropdownOption | string) => (typeof item === 'string' ? item : item.display)
|
||||
|
||||
export const RadioSelector = <T extends object>({
|
||||
options,
|
||||
name,
|
||||
field,
|
||||
}: {
|
||||
options: Array<DropdownOption | string>
|
||||
name: string
|
||||
field: keyof T
|
||||
}) => {
|
||||
const { data, setEditData, editData } = useDetailContext<T>()
|
||||
const editingComponent = (
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
aria-labelledby={`${name}-radio-selection`}
|
||||
name={name}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) =>
|
||||
setEditData({ ...editData, [field]: event?.currentTarget?.value })
|
||||
}
|
||||
value={editData[field]}
|
||||
sx={{ display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
{options.map(option => (
|
||||
<FormControlLabel
|
||||
key={getValue(option)}
|
||||
value={getValue(option)}
|
||||
control={<Radio />}
|
||||
label={getDisplay(option)}
|
||||
/>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
)
|
||||
|
||||
const option = options.find(option => getValue(option) === data[field])
|
||||
const displayValue = option ? getDisplay(option) : null
|
||||
return <DataValue<T> field={field} EditElement={editingComponent} displayValue={displayValue} />
|
||||
}
|
||||
|
||||
/*
|
||||
buttonText = Text for the button that opens modal
|
||||
children = Content of modal
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
import {
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
MenuItem,
|
||||
TextField,
|
||||
RadioGroup,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
} from '@mui/material'
|
||||
import { ChangeEvent, ReactNode } from 'react'
|
||||
import { RegisterOptions, FieldValues, UseFormRegisterReturn, FieldErrors } from 'react-hook-form'
|
||||
import { useDetailContext } from '../hooks'
|
||||
import { DataValue } from './FormComponents'
|
||||
|
||||
export type DropdownOption = { value: string; display: string }
|
||||
|
||||
export const DropdownSelector = <T extends object>({
|
||||
options,
|
||||
name,
|
||||
field,
|
||||
}: {
|
||||
options: Array<DropdownOption | string>
|
||||
name: string
|
||||
field: keyof T
|
||||
}) => {
|
||||
const { setEditData, editData } = useDetailContext<T>()
|
||||
const editingComponent = (
|
||||
<FormControl size="small">
|
||||
<InputLabel id={`${name}-multiselect-label`}>{name}</InputLabel>
|
||||
<Select
|
||||
labelId={`${name}-multiselect-label`}
|
||||
label={name}
|
||||
id={`${name}-multiselect`}
|
||||
value={(editData[field] || '') as string}
|
||||
onChange={(event: SelectChangeEvent) => setEditData({ ...editData, [field]: event.target.value })}
|
||||
sx={{ width: '12em' }}
|
||||
size="small"
|
||||
>
|
||||
{options.map(item => (
|
||||
<MenuItem key={getValue(item)} value={getValue(item)}>
|
||||
{getDisplay(item)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)
|
||||
|
||||
return <MultiSelector<T> {...{ editingComponent, field, options }} />
|
||||
}
|
||||
|
||||
export const FormTextField = <T extends string>({
|
||||
register,
|
||||
errors,
|
||||
fieldName,
|
||||
label,
|
||||
required = false,
|
||||
}: {
|
||||
register: (name: T, options?: RegisterOptions<FieldValues, T> | undefined) => UseFormRegisterReturn<T>
|
||||
errors: FieldErrors<FieldValues>
|
||||
fieldName: T
|
||||
label: string
|
||||
required: boolean
|
||||
}) => (
|
||||
<TextField {...register(fieldName, { required: required })} error={!!errors[fieldName]} {...{ label, required }} />
|
||||
)
|
||||
|
||||
const getValue = (item: DropdownOption | string) => (typeof item === 'string' ? item : item.value)
|
||||
const getDisplay = (item: DropdownOption | string) => (typeof item === 'string' ? item : item.display)
|
||||
|
||||
export const RadioSelector = <T extends object>({
|
||||
options,
|
||||
name,
|
||||
field,
|
||||
}: {
|
||||
options: Array<DropdownOption | string>
|
||||
name: string
|
||||
field: keyof T
|
||||
}) => {
|
||||
const { setEditData, editData } = useDetailContext<T>()
|
||||
const editingComponent = (
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
aria-labelledby={`${name}-radio-selection`}
|
||||
name={name}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) =>
|
||||
setEditData({ ...editData, [field]: event?.currentTarget?.value })
|
||||
}
|
||||
value={editData[field]}
|
||||
sx={{ display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
{options.map(option => (
|
||||
<FormControlLabel
|
||||
key={getValue(option)}
|
||||
value={getValue(option)}
|
||||
control={<Radio />}
|
||||
label={getDisplay(option)}
|
||||
/>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
)
|
||||
|
||||
return <MultiSelector<T> {...{ editingComponent, field, options }} />
|
||||
}
|
||||
|
||||
const MultiSelector = <T extends object>({
|
||||
options,
|
||||
field,
|
||||
editingComponent,
|
||||
}: {
|
||||
options: Array<DropdownOption | string>
|
||||
field: keyof T
|
||||
editingComponent: ReactNode
|
||||
}) => {
|
||||
const { data } = useDetailContext<T>()
|
||||
const option = options.find(option => getValue(option) === data[field])
|
||||
const displayValue = option ? getDisplay(option) : null
|
||||
return <DataValue<T> field={field} EditElement={editingComponent} displayValue={displayValue} />
|
||||
}
|
||||
@@ -16,7 +16,18 @@ export const AgeTab = () => {
|
||||
|
||||
// TODO: The date_meth options should come from db: distinct(now_loc.date_meth)
|
||||
const age = [
|
||||
['Dating method', radioSelection('date_meth', ['time_unit', 'absolute', 'composite'], 'dating-method')],
|
||||
[
|
||||
'Dating method',
|
||||
radioSelection(
|
||||
'date_meth',
|
||||
[
|
||||
{ value: 'time_unit', display: 'Time unit' },
|
||||
{ value: 'absolute', display: 'Absolute' },
|
||||
{ value: 'composite', display: 'Composite' },
|
||||
],
|
||||
'dating-method'
|
||||
),
|
||||
],
|
||||
[''],
|
||||
['Age (Ma)', 'Basis for age (Absolute)', 'Basis for age (Time Unit)', 'Basis for age (Fraction)'],
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user