Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/components/Select-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react'
import { describe, it, expect, vi } from 'vitest'
import { render, screen, waitFor } from 'src/utilities/testingLibrary'
import userEvent from '@testing-library/user-event'
import { Select } from 'src/components/Select'

const options = [
{ label: 'Checking', value: 'checking' },
{ label: 'Savings', value: 'savings' },
]

const defaultProps = {
label: 'Account type',
name: 'account_type',
onChange: vi.fn(),
options,
value: '',
}

describe('Select', () => {
it('renders with default props', () => {
render(<Select {...defaultProps} />)

expect(screen.getByLabelText('Account type')).toBeInTheDocument()
expect(screen.getByText('Select a value')).toBeInTheDocument()
})

it('calls onChange with the selected value', async () => {
const user = userEvent.setup()
const handleChange = vi.fn()

render(<Select {...defaultProps} onChange={handleChange} />)

await user.click(screen.getByRole('combobox'))
await user.click(screen.getByRole('option', { name: 'Savings' }))

await waitFor(() =>
expect(handleChange).toHaveBeenCalledWith({
target: { name: 'account_type', value: 'savings' },
}),
)
})
})
73 changes: 73 additions & 0 deletions src/components/Select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react'
import FormControl from '@mui/material/FormControl'
import FormHelperText from '@mui/material/FormHelperText'
import InputLabel from '@mui/material/InputLabel'
import MenuItem from '@mui/material/MenuItem'
import MuiSelect, { SelectChangeEvent } from '@mui/material/Select'

export interface SelectOption {
label: string
value: string
}

export interface SelectProps {
'data-test'?: string
error?: boolean
fullWidth?: boolean
helperText?: string
label: string
name: string
onChange: (e: { target: { name: string; value: string } }) => void
options?: SelectOption[]
placeholder?: string
value: string
}

export const Select = ({
'data-test': dataTest,
error,
fullWidth = true,
helperText,
label,
name,
onChange,
options = [],
placeholder = 'Select a value',
value,
}: SelectProps) => {
const handleChange = (e: SelectChangeEvent) => {
onChange({ target: { name, value: e.target.value as string } })
}

return (
<FormControl error={error} fullWidth={fullWidth}>
<InputLabel id={`${name}-label`}>{label}</InputLabel>
<MuiSelect
displayEmpty={true}
inputProps={{ 'data-test': dataTest }}
label={label}
labelId={`${name}-label`}
name={name}
onChange={handleChange}
renderValue={(selected) => {
if (selected === '') {
return placeholder
}
const option = options.find((opt) => opt.value === selected)
return option ? option.label : selected
}}
value={value}
>
<MenuItem disabled={true} value="">
{placeholder}
</MenuItem>
{options.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</MuiSelect>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
)
}
3 changes: 3 additions & 0 deletions src/privacy/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// This is the ONLY file that @kyper related inputs should be directly imported

import { Radio, PASSWORD_VALIDATIONS } from '@kyper/input'
import { Select } from 'src/components/Select'
import { SelectionBox } from '@mxenabled/mxui'
import { UserFeedback } from '@kyper/userfeedback'
import { withProtection } from 'src/privacy/withProtection'
Expand All @@ -20,12 +21,14 @@ import { TextField } from '@mxenabled/mxui'

const ProtectedTextField = withProtection(TextField)
const ProtectedRadio = withProtection(Radio)
const ProtectedSelect = withProtection(Select)
const ProtectedSelectionBox = withProtection(SelectionBox)
const ProtectedUserFeedback = withProtection(UserFeedback)

export {
ProtectedTextField as TextField,
ProtectedRadio as Radio,
ProtectedSelect as Select,
ProtectedSelectionBox as SelectionBox,
ProtectedUserFeedback as UserFeedback,
PASSWORD_VALIDATIONS as PasswordValidations,
Expand Down
7 changes: 4 additions & 3 deletions src/views/manualAccount/ManualAccountForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,12 +309,13 @@ export const ManualAccountForm = React.forwardRef<HTMLInputElement, ManualAccoun
<div key={i} style={styles.selectInput}>
<Select
data-test="select-input"
errorText={errors[field.name]}
items={field.options}
error={!!errors[field.name]}
helperText={errors[field.name]}
label={field.label}
name={field.name}
onChange={handleTextInputChange}
placeholder={__('Select a value')}
options={field.options}
value={values[field.name]}
/>
</div>
)
Expand Down
Loading