Skip to content

Commit

Permalink
Editable Table Row (#803)
Browse files Browse the repository at this point in the history
* add edit input component

* add select option to the row component

* chnage the icon color

* put icons into box

---------

Signed-off-by: OlegMoshkovich <oleg.mosh@gmail.com>
  • Loading branch information
OlegMoshkovich authored Nov 7, 2023
1 parent e8c8555 commit fe3ebf3
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/Components/TableRow.fixture.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import Box from '@mui/material/Box'
import FixtureContext from '../FixtureContext'
import TableRow from './TableRow'


export default (
<FixtureContext>
<Box sx={{width: '400px'}}>
<TableRow heading='hello' subtext='hello' inputType='select' options={['Option1', 'Option2', 'Option3']}/>
</Box>
</FixtureContext>
)
116 changes: 116 additions & 0 deletions src/Components/TableRow.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React, {useState} from 'react'
import Box from '@mui/material/Box'
import Stack from '@mui/material/Stack'
import Typography from '@mui/material/Typography'
import IconButton from '@mui/material/IconButton'
import Input from '@mui/material/Input'
import Select from '@mui/material/Select'
import MenuItem from '@mui/material/MenuItem'
import EditIcon from '@mui/icons-material/Edit'
import SubmitIcon from '@mui/icons-material/Done'

/**
* Editable table row to be used to edit properties
*
* @param {object} props Component properties.
* @param {string} props.heading The non-editable heading displayed in the table row.
* @param {string} props.subtext The editable content of the table row.
* @param {('input'|'select')} [props.inputType='input'] The type of input component.
* @param {Array<string>} [props.options=[]] The options for the select component.
* @return {object} The rendered component.
*/
export default function CustomTableRow({heading, subtext, inputType = 'input', options = []}) {
const [isEditing, setIsEditing] = useState(false)
const [value, setValue] = useState(subtext)

const handleSubmit = () => {
setIsEditing(false)
}

const handleKeyDown = (event) => {
if (event.key === 'Enter') {
handleSubmit()
}
}

const commonStyles = {
height: '40px',
display: 'flex',
alignItems: 'center',
width: '50%',
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
}

const renderInputComponent = () => {
if (inputType === 'select') {
return (
<Select
value={value}
data-testid={'select'}
onChange={(e) => setValue(e.target.value)}
onBlur={() => setIsEditing(false)}
sx={{
...commonStyles,
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
borderColor: 'transparent',
},
}}
>
{options.map((option, index) => (
<MenuItem key={index} value={option}>
{option}
</MenuItem>
))}
</Select>
)
}

return (
<Input
sx={{...commonStyles, borderBottom: 'none'}}
disableUnderline
value={value}
onChange={(e) => setValue(e.target.value)}
onBlur={() => setIsEditing(false)}
onKeyDown={handleKeyDown}
/>
)
}

return (
<Stack
direction="row"
spacing={1}
alignItems="center"
justifyContent="space-between"
sx={{borderBottom: '1px solid gray'}}
>
<Typography variant="body1" sx={commonStyles}>
{heading}
</Typography>
{isEditing ? (
<>
{renderInputComponent()}
<Box sx={{width: '40px'}}>
<IconButton size="small" onClick={handleSubmit}>
<SubmitIcon fontSize="inherit" color='primary'/>
</IconButton>
</Box>
</>
) : (
<>
<Typography variant="body1" sx={commonStyles}>
{value}
</Typography>
<Box sx={{width: '40px'}}>
<IconButton size="small" onClick={() => setIsEditing(true)}>
<EditIcon fontSize="inherit" color='primary'/>
</IconButton>
</Box>
</>
)}
</Stack>
)
}
42 changes: 42 additions & 0 deletions src/Components/TableRow.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// CustomTableRow.test.js
import React from 'react'
import {render, fireEvent, screen} from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import CustomTableRow from './TableRow'


describe('<CustomTableRow />', () => {
test('renders heading and subtext', () => {
render(<CustomTableRow heading="Test Heading" subtext="Test Subtext"/>)
expect(screen.getByText('Test Heading')).toBeInTheDocument()
expect(screen.getByText('Test Subtext')).toBeInTheDocument()
})

test('shows input field when edit button is clicked', () => {
render(<CustomTableRow heading="Test Heading" subtext="Test Subtext"/>)
fireEvent.click(screen.getByRole('button')) // Click the edit button
expect(screen.getByDisplayValue('Test Subtext')).toBeInTheDocument()
})

it('switches to select editing mode', () => {
const {getByTestId} = render(
<CustomTableRow heading="Test Heading" subtext="Option 1" inputType="select" options={['Option 1', 'Option 2']}/>,
)

fireEvent.click(screen.getByRole('button')) // Click the edit button

const select = getByTestId('select')
expect(select).toBeInTheDocument()
})

test('submits edited text when Enter key is pressed', () => {
render(<CustomTableRow heading="Test Heading" subtext="Test Subtext"/>)
fireEvent.click(screen.getByRole('button')) // Click the edit button

const inputField = screen.getByDisplayValue('Test Subtext')
fireEvent.change(inputField, {target: {value: 'Updated Text'}})
fireEvent.keyDown(inputField, {key: 'Enter'})

expect(screen.getByText('Updated Text')).toBeInTheDocument()
})
})

0 comments on commit fe3ebf3

Please sign in to comment.