diff --git a/package.json b/package.json
index 6c5a13e..16954ab 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"connected-react-router": "^6.8.0",
- "date-fns": "^2.16.1",
+ "date-fns": "^2.9.0",
"formik": "^2.2.6",
"history": "4.10.1",
"immer": "^8.0.0",
@@ -23,7 +23,6 @@
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-helmet": "^6.1.0",
- "react-hook-form": "^6.13.1",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.0",
diff --git a/src/components/DatePickerField/index.js b/src/components/DatePickerField/index.js
new file mode 100644
index 0000000..dacac8f
--- /dev/null
+++ b/src/components/DatePickerField/index.js
@@ -0,0 +1,57 @@
+import React, { useState, useEffect } from 'react';
+import { useField } from 'formik';
+import Grid from '@material-ui/core/Grid';
+import {
+ MuiPickersUtilsProvider,
+ KeyboardDatePicker
+} from '@material-ui/pickers';
+import DateFnsUtils from '@date-io/date-fns';
+
+const DatePickerField = (props) => {
+ const [field, meta, helper] = useField(props);
+ const { touched, error } = meta;
+ const { setValue } = helper;
+ const isError = touched && error && true;
+ const { value } = field;
+ const [selectedDate, setSelectedDate] = useState(null);
+
+ useEffect(() => {
+ if (value) {
+ const date = new Date(value);
+ setSelectedDate(date);
+ }
+ }, [value]);
+
+ const _onChange = (date) => {
+ if (date) {
+ setSelectedDate(date);
+ try {
+ const ISODateString = date.toISOString();
+ setValue(ISODateString);
+ } catch (error) {
+ setValue(date);
+ }
+ } else {
+ setValue(date);
+ }
+ }
+
+ return (
+
+
+
+
+
+ );
+}
+
+export default DatePickerField
+
diff --git a/src/components/GoalForm/Loader.js b/src/components/GoalForm/Loader.js
deleted file mode 100644
index 6a935ef..0000000
--- a/src/components/GoalForm/Loader.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import React from 'react';
-import {Button, Grid} from "@material-ui/core";
-import {Skeleton} from "@material-ui/lab";
-
-const Loader = () => {
- return (
-
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default Loader;
diff --git a/src/components/GoalForm/index.js b/src/components/GoalForm/index.js
deleted file mode 100644
index 1561c82..0000000
--- a/src/components/GoalForm/index.js
+++ /dev/null
@@ -1,105 +0,0 @@
-import React from 'react';
-import {Grid, FormControlLabel, Slider, Button, Typography, Radio, RadioGroup, Box} from '@material-ui/core';
-import {useInjectReducer} from "redux-injectors";
-import { useSelector } from 'react-redux';
-import {createStructuredSelector} from "reselect";
-import { useFormContext, Controller } from "react-hook-form";
-import reducer from "pages/Profile/reducer";
-import {
- makeSelectGoals,
- makeSelectActivities,
- makeSelectRatesOfChange,
-} from "pages/Profile/selectors";
-
-const stateSelector = createStructuredSelector({
- goals: makeSelectGoals(),
- activities: makeSelectActivities(),
-});
-
-const key = 'profilePage'
-const GoalForm = () => {
- useInjectReducer({ key, reducer });
- const { goals, activities, ratesOfChange } = useSelector(stateSelector)
- const { control } = useFormContext()
-
- return (
-
-
- Goal
-
-
-
-
-
- {goals.map(({ label, value }) => (
-
-
-
- ))}
-
-
- }
- />
-
-
-
- Activity
-
-
- (
- onChange(value)}
- min={1.2}
- step={null}
- max={1.9}
- marks={activities}
- />
- )}
- />
-
-
-
-
- Rate of change
-
-
- (
- onChange(value)}
- min={0}
- step={0.1}
- max={1}
- valueLabelDisplay="auto"
- marks={ratesOfChange}
- />
- )}
- />
-
-
-
-
- );
-}
-
-export default GoalForm;
diff --git a/src/components/InputField/index.js b/src/components/InputField/index.js
new file mode 100644
index 0000000..073d3dc
--- /dev/null
+++ b/src/components/InputField/index.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import { at } from 'lodash';
+import { useField } from 'formik';
+import { TextField } from '@material-ui/core';
+
+const InputField = (props) => {
+ const [field, meta] = useField(props);
+
+ const _renderHelperText = () => {
+ const [touched, error] = at(meta, 'touched', 'error');
+ if (touched && error) {
+ return error;
+ }
+ }
+
+ return (
+
+ );
+}
+
+export default InputField
diff --git a/src/components/RadioField/index.js b/src/components/RadioField/index.js
new file mode 100644
index 0000000..aa9d97d
--- /dev/null
+++ b/src/components/RadioField/index.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import { at } from 'lodash';
+import { useField } from 'formik';
+import {
+ Radio,
+ FormControl,
+ FormControlLabel,
+ FormHelperText
+} from '@material-ui/core';
+
+const CheckboxField = ({ label, ...rest }) => {
+ const [field, meta, helper] = useField({ label, ...rest });
+ const { setValue } = helper;
+
+ const _renderHelperText = () => {
+ const [touched, error] = at(meta, 'touched', 'error');
+ if (touched && error) {
+ return {error};
+ }
+ }
+
+ const _onChange = (e) => {
+ setValue(e.target.checked);
+ }
+
+ return (
+
+ }
+ label={label}
+ />
+ {_renderHelperText()}
+
+ );
+}
+
+export default CheckboxField
diff --git a/src/components/SelectField/index.js b/src/components/SelectField/index.js
new file mode 100644
index 0000000..417262d
--- /dev/null
+++ b/src/components/SelectField/index.js
@@ -0,0 +1,48 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { at } from 'lodash';
+import { useField } from 'formik';
+import {
+ InputLabel,
+ FormControl,
+ Select,
+ MenuItem,
+ FormHelperText
+} from '@material-ui/core';
+
+const SelectField = ({ label, data, ...rest }) => {
+ const [field, meta] = useField({ label, data, ...rest });
+ const { value: selectedValue } = field;
+ const [touched, error] = at(meta, 'touched', 'error');
+ const isError = touched && error && true;
+
+ const _renderHelperText = () => {
+ if (isError) {
+ return {error};
+ }
+ }
+
+ return (
+
+ {label}
+
+ {_renderHelperText()}
+
+ );
+}
+
+SelectField.defaultProps = {
+ data: []
+};
+
+SelectField.propTypes = {
+ data: PropTypes.array.isRequired
+};
+
+export default SelectField;
diff --git a/src/components/SliderField/index.js b/src/components/SliderField/index.js
new file mode 100644
index 0000000..ee71567
--- /dev/null
+++ b/src/components/SliderField/index.js
@@ -0,0 +1,24 @@
+import React from 'react';
+import { at } from 'lodash';
+import { useField } from 'formik';
+import {
+ Slider,
+ FormControl,
+ FormControlLabel,
+ FormHelperText
+} from '@material-ui/core';
+
+const SliderField = ({ label, ...rest }) => {
+ const [field, meta, helper] = useField({ label, ...rest });
+ const { setValue } = helper;
+
+ const _onChange = (e) => {
+ setValue(e.target.checked);
+ }
+
+ return (
+
+ );
+}
+
+export default SliderField
diff --git a/src/pages/Profile/GoalForm/index.js b/src/pages/Profile/GoalForm/index.js
new file mode 100644
index 0000000..e578f62
--- /dev/null
+++ b/src/pages/Profile/GoalForm/index.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import {Grid, Typography, Box} from '@material-ui/core';
+import {useInjectReducer} from "redux-injectors";
+import { useSelector } from 'react-redux';
+import {createStructuredSelector} from "reselect";
+import reducer from "pages/Profile/reducer";
+import {
+ makeSelectGoals,
+ makeSelectActivities,
+ makeSelectRatesOfChange,
+} from "pages/Profile/selectors";
+
+import SelectField from 'components/SelectField';
+
+const stateSelector = createStructuredSelector({
+ goals: makeSelectGoals(),
+ activities: makeSelectActivities(),
+ ratesOfChange: makeSelectRatesOfChange(),
+});
+
+const key = 'profilePage'
+const GoalForm = () => {
+ useInjectReducer({ key, reducer });
+ const { goals, activities, ratesOfChange } = useSelector(stateSelector)
+
+ return (
+
+
+ Goal
+
+
+
+
+
+
+
+ Activity
+
+
+
+
+
+ Rate of change
+
+
+
+
+
+ );
+}
+
+export default GoalForm;
diff --git a/src/pages/Profile/PersonalDetailsForm/index.js b/src/pages/Profile/PersonalDetailsForm/index.js
new file mode 100644
index 0000000..1b6cc5f
--- /dev/null
+++ b/src/pages/Profile/PersonalDetailsForm/index.js
@@ -0,0 +1,86 @@
+import 'date-fns';
+import React from 'react';
+import {Typography, InputLabel, Grid, InputAdornment, Select, FormControl, MenuItem, TextField, Slider} from '@material-ui/core';
+import DatePickerField from 'components/DatePickerField'
+import InputField from 'components/InputField'
+import {useInjectReducer} from "redux-injectors";
+import { useSelector } from 'react-redux';
+import {createStructuredSelector} from "reselect";
+import reducer from "pages/Profile/reducer";
+import {
+ makeSelectActivities,
+ makeSelectGenders,
+} from "pages/Profile/selectors";
+import SelectField from "../../../components/SelectField";
+
+const stateSelector = createStructuredSelector({
+ activities: makeSelectActivities(),
+ genders: makeSelectGenders(),
+});
+
+const key = 'profilePage'
+const PersonalDetailsForm = () => {
+ useInjectReducer({ key, reducer });
+ const { genders } = useSelector(stateSelector)
+
+ return (
+
+
+ Personal details
+
+
+
+
+
+
+
+
+
+ cm
+ }}
+ />
+
+
+ Kg
+ }}
+ />
+
+
+ Kg
+ }}
+ />
+
+
+
+ );
+}
+export default PersonalDetailsForm
diff --git a/src/pages/Profile/ReviewProfileForm/index.js b/src/pages/Profile/ReviewProfileForm/index.js
new file mode 100644
index 0000000..1231114
--- /dev/null
+++ b/src/pages/Profile/ReviewProfileForm/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+
+const ReviewProfileForm = () => {
+ return (
+
+ ReviewProfileForm
+
+ );
+};
+
+export default ReviewProfileForm;
diff --git a/src/pages/Profile/index.js b/src/pages/Profile/index.js
index 9674528..ad1ca89 100644
--- a/src/pages/Profile/index.js
+++ b/src/pages/Profile/index.js
@@ -3,13 +3,12 @@ import { makeStyles } from '@material-ui/core/styles';
import {Paper, Stepper, Step, StepLabel, Button, Typography } from '@material-ui/core';
import {useInjectReducer, useInjectSaga} from "redux-injectors";
import { useDispatch } from 'react-redux';
-import { useForm, useFormContext, FormProvider } from "react-hook-form";
-import GoalForm from 'components/GoalForm';
-import PersonalDetailsForm from 'components/PersonalDetailsForm';
-import ReviewProfileForm from 'components/ReviewProfileForm';
+import { Formik, Form } from 'formik';
+import GoalForm from './GoalForm';
+import PersonalDetailsForm from './PersonalDetailsForm';
+import ReviewProfileForm from './ReviewProfileForm';
import reducer from "./reducer";
import saga from "./saga";
-import { updateProfileAction } from './actions'
const useStyles = makeStyles((theme) => ({
layout: {
@@ -47,7 +46,7 @@ const useStyles = makeStyles((theme) => ({
const steps = ['Your goal', 'Personal details', 'Review your profile'];
-const getStepContent = (step) => {
+const renderStepContent = (step) => {
switch (step) {
case 0:
return ;
@@ -60,40 +59,56 @@ const getStepContent = (step) => {
}
}
+const formInitialValues = {
+ gender: '',
+ goal: '',
+ birthday: '',
+ height: '',
+ weight: {
+ current: '',
+ goal: '',
+ },
+ rateOfChange: '',
+ activity: '',
+}
+
const key = 'profilePage'
const ProfilePage = () => {
- const classes = useStyles();
const [activeStep, setActiveStep] = useState(0);
- const methods = useForm({
- defaultValues: {
- gender: '',
- goal: 0,
- birthday: '',
- height: 0,
- weight: {
- current: 0,
- goal: 0,
- },
- rateOfChange: 0,
- activity: 0,
- }
- });
+ const isLastStep = activeStep === steps.length - 1;
+ const isFirstStep = activeStep === 0;
+ const classes = useStyles();
useInjectReducer({ key, reducer });
useInjectSaga({ key, saga });
- const dispatch = useDispatch()
+ const sleep = (ms) => {
+ return new Promise(resolve => setTimeout(resolve, ms));
+ }
+
+ const submitForm = async (values, actions) => {
+ console.log(JSON.stringify(values, null, 2));
+ actions.setSubmitting(false);
- const handleNext = () => {
setActiveStep(activeStep + 1);
- };
+ }
+
+ const handleSubmit = (values, actions) => {
+ if (isLastStep) {
+ submitForm(values, actions);
+ } else {
+ setActiveStep(activeStep + 1);
+ actions.setTouched({});
+ actions.setSubmitting(false);
+ }
+ }
const handleBack = () => {
setActiveStep(activeStep - 1);
- };
+ }
- const handleSubmitProfile = data => {
- console.log('data', data)
+ const handleNext = () => {
+ setActiveStep(activeStep + 1);
}
return (
@@ -121,29 +136,34 @@ const ProfilePage = () => {
) : (
-
-
+ )}
+
+ )}
diff --git a/src/pages/Profile/reducer.js b/src/pages/Profile/reducer.js
index dbbf8d1..34dbb50 100644
--- a/src/pages/Profile/reducer.js
+++ b/src/pages/Profile/reducer.js
@@ -34,19 +34,26 @@ export const initialState = {
goals: [
{
label: 'lose weight',
- value: -1,
+ value: 1,
},
{
label: 'maintain weight',
- value: 0,
+ value: 2,
},
{
label: 'put on weight',
- value: 1,
+ value: 3,
}
],
- ratesOfChange: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
- genders: ['male', 'female'],
+ ratesOfChange: [
+ { value: 1, label: '0 kg'},
+ { value: 2, label: '0.5 kg'},
+ { value: 3, label: '1 kg'},
+ ],
+ genders: [
+ {value: 1, label: 'male'},
+ {value: 2, label: 'female'},
+ ],
isLoading: false,
error: {},
gender: '',
diff --git a/yarn.lock b/yarn.lock
index 4d9d28c..79d8133 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4011,7 +4011,7 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
-date-fns@^2.16.1:
+date-fns@^2.9.0:
version "2.16.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b"
integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==
@@ -9536,11 +9536,6 @@ react-helmet@^6.1.0:
react-fast-compare "^3.1.1"
react-side-effect "^2.1.0"
-react-hook-form@^6.13.1:
- version "6.13.1"
- resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-6.13.1.tgz#b9c0aa61f746db8169ed5e1050de21cacb1947d6"
- integrity sha512-Q0N7MYcbA8SigYufb02h9z97ZKCpIbe62rywOTPsK4Ntvh6fRTGDXSuzWuRhLHhArLoWbGrWYSNSS4tlb+OFXg==
-
react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"