-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #533 from codeforpdx/issue-442/basic-information-form
Issue 442/basic information form
- Loading branch information
Showing
3 changed files
with
257 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,184 @@ | ||
// React Imports | ||
import React from 'react'; | ||
// MUI Imports | ||
import Typography from '@mui/material/Typography'; | ||
import React, { useState, useEffect } from 'react'; | ||
// Material UI Imports | ||
import Button from '@mui/material/Button'; | ||
import CheckIcon from '@mui/icons-material/Check'; | ||
import ClearIcon from '@mui/icons-material/Clear'; | ||
import FormControl from '@mui/material/FormControl'; | ||
import FormHelperText from '@mui/material/FormHelperText'; | ||
import Grid from '@mui/material/Grid'; | ||
import InputLabel from '@mui/material/InputLabel'; | ||
import MenuItem from '@mui/material/MenuItem'; | ||
import Select from '@mui/material/Select'; | ||
import TextField from '@mui/material/TextField'; | ||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; | ||
import { DatePicker } from '@mui/x-date-pickers/DatePicker'; | ||
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; | ||
import dayjs from 'dayjs'; | ||
// Hook Imports | ||
import { useCivicProfile, useNotification } from '@hooks'; | ||
// Component Imports | ||
import { FormSection } from '../Form'; | ||
|
||
const BasicInfo = () => <Typography>Basic Info</Typography>; | ||
/** | ||
* BasicInfo Component - A form to fill out basic user info | ||
* | ||
* @memberof CivicProfileForms | ||
* @name BasicInfo | ||
* @returns {React.JSX.Element} The BasicInfo Component | ||
*/ | ||
const BasicInfo = () => { | ||
const { data, add, isSuccess, storedDataset, refetch } = useCivicProfile(); | ||
const { addNotification } = useNotification(); | ||
const [formData, setFormData] = useState({ | ||
firstName: '', | ||
lastName: '', | ||
dateOfBirth: null, | ||
gender: 9 | ||
}); | ||
|
||
useEffect(() => { | ||
if (isSuccess) { | ||
setFormData((prevFormData) => ({ ...prevFormData, ...data })); | ||
} | ||
}, [isSuccess, data]); | ||
useEffect(() => { | ||
if (!storedDataset) { | ||
refetch(); | ||
} | ||
}, [storedDataset]); | ||
const handleChange = (e) => { | ||
if (e.$isDayjsObject) { | ||
setFormData((prevFormData) => ({ | ||
...prevFormData, | ||
dateOfBirth: e.toDate() | ||
})); | ||
} else if (e.target) { | ||
const { name, value } = e.target; | ||
setFormData((prevFormData) => ({ ...prevFormData, [name]: value })); | ||
} | ||
}; | ||
|
||
const handleSubmit = (e) => { | ||
e.preventDefault(); | ||
if (!isSuccess || !storedDataset) { | ||
return; | ||
} | ||
add(formData); | ||
addNotification('success', `Form submitted!`); | ||
}; | ||
|
||
const handleClear = () => { | ||
setFormData((prevFormData) => ({ | ||
...prevFormData, | ||
firstName: '', | ||
lastName: '', | ||
dateOfBirth: null, | ||
gender: 9 | ||
})); | ||
addNotification('success', `Form cleared!`); | ||
}; | ||
|
||
return ( | ||
<FormSection title="Basic Information"> | ||
<form aria-labelledby="add-contact-form" onSubmit={handleSubmit} autoComplete="off"> | ||
<Grid container spacing={2}> | ||
<Grid item xs={12} md={6}> | ||
<TextField | ||
id="hmis-basic-info-first-name" | ||
name="firstName" | ||
label="Legal first name" | ||
onChange={handleChange} | ||
value={formData.firstName} | ||
fullWidth | ||
autoFocus | ||
/> | ||
</Grid> | ||
<Grid item xs={12} md={6}> | ||
<TextField | ||
id="hmis-basic-info-last-name" | ||
name="lastName" | ||
label="Legal last name" | ||
onChange={handleChange} | ||
value={formData.lastName} | ||
fullWidth | ||
/> | ||
</Grid> | ||
<Grid item xs={12} md={6}> | ||
<FormControl fullWidth> | ||
<LocalizationProvider dateAdapter={AdapterDayjs}> | ||
<DatePicker | ||
id="hmis-basic-info-date-of-birth" | ||
name="dateOfBirth" | ||
label="Date of birth" | ||
onChange={handleChange} | ||
value={formData.dateOfBirth ? dayjs(formData.dateOfBirth) : null} | ||
format="YYYY-MM-DD" | ||
type="date" | ||
disableFuture | ||
openTo="year" | ||
views={['year', 'month', 'day']} | ||
/> | ||
</LocalizationProvider> | ||
<FormHelperText>YYYY-MM-DD</FormHelperText> | ||
</FormControl> | ||
</Grid> | ||
<Grid item xs={12} md={6}> | ||
<FormControl fullWidth> | ||
<InputLabel id="hmis-basic-info-gender">Gender</InputLabel> | ||
<Select | ||
id="hmis-basic-info-gender-select" | ||
name="gender" | ||
label="Gender" | ||
onChange={handleChange} | ||
value={formData.gender} | ||
labelId="hmis-basic-info-gender" | ||
defaultValue={9} | ||
> | ||
<MenuItem value={0}>Female</MenuItem> | ||
<MenuItem value={1}>Male</MenuItem> | ||
<MenuItem value={2}>Transgender male to female</MenuItem> | ||
<MenuItem value={3}>Transgender female to male</MenuItem> | ||
<MenuItem value={4}>Don't identify as male, female or transgender</MenuItem> | ||
<MenuItem value={8}>Don't know</MenuItem> | ||
<MenuItem value={9}>Decline to answer</MenuItem> | ||
</Select> | ||
</FormControl> | ||
</Grid> | ||
<Grid item xs={12} md={6}> | ||
<Button | ||
variant="outlined" | ||
type="button" | ||
label="Clear button" | ||
color="error" | ||
startIcon={<ClearIcon />} | ||
fullWidth | ||
sx={{ borderRadius: '20px' }} | ||
onClick={handleClear} | ||
aria-label="Clear button" | ||
> | ||
Clear | ||
</Button> | ||
</Grid> | ||
<Grid item xs={12} md={6}> | ||
<Button | ||
variant="contained" | ||
type="submit" | ||
label="Submit button" | ||
color="primary" | ||
startIcon={<CheckIcon />} | ||
fullWidth | ||
sx={{ borderRadius: '20px' }} | ||
disabled={!isSuccess} | ||
aria-label="Submit button" | ||
> | ||
Submit | ||
</Button> | ||
</Grid> | ||
</Grid> | ||
</form> | ||
</FormSection> | ||
); | ||
}; | ||
|
||
export default BasicInfo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,83 @@ | ||
import React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
import { expect, it, describe } from 'vitest'; | ||
import { vi, expect, it, describe } from 'vitest'; | ||
import { BasicInfo } from '@components/CivicProfileForms'; | ||
import { useCivicProfile } from '@hooks'; | ||
|
||
describe('Basic Info Form', () => { | ||
vi.mock('@hooks', async () => { | ||
const actual = await vi.importActual('@hooks'); | ||
|
||
return { | ||
...actual, | ||
useCivicProfile: vi.fn() | ||
}; | ||
}); | ||
|
||
describe('Basic info form', () => { | ||
it('renders', () => { | ||
const { getByText } = render(<BasicInfo />); | ||
expect(getByText('Basic Info')).not.toBeNull(); | ||
useCivicProfile.mockReturnValue({ data: {}, isSuccess: true, refetch: vi.fn() }); | ||
const { getByRole } = render(<BasicInfo />); | ||
const legalFirstName = getByRole('textbox', { name: 'Legal first name' }); | ||
expect(legalFirstName).not.toBeNull(); | ||
}); | ||
|
||
// TODO: Resolve test not passing | ||
// it('clears all input fields when you click the clear button', async () => { | ||
// const mockClear = vi.fn(); | ||
// const basicInfoProfile = { | ||
// legalFirstName: 'Jane', | ||
// legalLastName: 'Doe', | ||
// legalDOB: '1980-12-15', | ||
// legalGender: 1 | ||
// }; | ||
// useCivicProfile.mockReturnValue({ | ||
// add: mockClear, | ||
// isSuccess: true, | ||
// storedDataset: {}, | ||
// refetch: vi.fn() | ||
// }); | ||
// const { getByRole } = render(<BasicInfo />); | ||
// const legalFirstName = getByRole('textbox', { name: 'Legal first name' }); | ||
// const legalLastName = getByRole('textbox', { name: 'Legal last name' }); | ||
// const legalDOB = getByRole('textbox', { name: 'Choose date' }); | ||
// const legalGender = getByRole('combobox', { name: 'Gender' }); | ||
// const clearButton = getByRole('button', { name: 'Clear button' }); | ||
|
||
// await userEvent.type(legalFirstName, basicInfoProfile.legalFirstName); | ||
// await userEvent.type(legalLastName, basicInfoProfile.legalLastName); | ||
// await userEvent.type(legalDOB, basicInfoProfile.legalDOB); | ||
// await userEvent.type(legalGender, `${basicInfoProfile.legalGender}{enter}`); | ||
|
||
// await userEvent.click(clearButton); | ||
|
||
// expect(legalFirstName.value).toBe(''); | ||
// expect(legalLastName.value).toBe(''); | ||
// expect(legalDOB.value).toBe(null); | ||
// expect(legalGender.value).toBe(''); | ||
// }); | ||
|
||
// TODO: Resolve test not passing | ||
// it('submits a basic info profile update when you click the submit button', async () => { | ||
// const user = userEvent.setup(); | ||
// const mockAdd = vi.fn(); | ||
// const basicInfoProfile = { | ||
// legalFirstName: 'Jane', | ||
// legalLastName: 'Doe', | ||
// legalDOB: '1980-12-15', | ||
// legalGender: 1 | ||
// }; | ||
// useCivicProfile.mockReturnValue({ add: mockAdd, isSuccess: true }); | ||
// const { getByRole } = render(<BasicInfo />); | ||
// const legalFirstName = getByRole('textbox', { name: 'Legal first name' }); | ||
// const legalLastName = getByRole('textbox', { name: 'Legal last name' }); | ||
// const legalDOB = getByRole('textbox', { name: 'Choose date' }); | ||
// const legalGender = getByRole('combobox', { name: 'Gender' }); | ||
// const submitButton = getByRole('button', { name: 'Submit button' }); | ||
// await user.type(legalFirstName, basicInfoProfile.legalFirstName); | ||
// await user.type(legalLastName, basicInfoProfile.legalLastName); | ||
// await user.type(legalDOB, basicInfoProfile.legalDOB); | ||
// await user.type(legalGender, `${basicInfoProfile.legalGender}{enter}`); | ||
// await user.click(submitButton); | ||
// expect(mockAdd).toBeCalledWith(basicInfoProfile); | ||
// }); | ||
}); |