From d7ef177d026828596c934d6c421f9ece149b32ea Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Wed, 25 Oct 2023 11:20:04 +0200 Subject: [PATCH 001/236] feat: personal info page --- .../substeps/FullNamePersonalStep.js | 67 +++++++++++++++++++ .../ReimbursementAccount/subStepPropTypes.js | 9 +++ 2 files changed, 76 insertions(+) create mode 100644 src/pages/ReimbursementAccount/PersonalInfo/substeps/FullNamePersonalStep.js create mode 100644 src/pages/ReimbursementAccount/subStepPropTypes.js diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullNamePersonalStep.js b/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullNamePersonalStep.js new file mode 100644 index 000000000000..e74d1bb129c1 --- /dev/null +++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullNamePersonalStep.js @@ -0,0 +1,67 @@ +import React from 'react'; +import {View} from 'react-native'; +import useLocalize from '../../../../hooks/useLocalize'; +import styles from '../../../../styles/styles'; +import TextInput from '../../../../components/TextInput'; +import CONST from '../../../../CONST'; +import Form from '../../../../components/Form'; +import ONYXKEYS from '../../../../ONYXKEYS'; +import subStepPropTypes from '../../subStepPropTypes'; + +const propTypes = { + ...subStepPropTypes, +}; + +const validate = (values) => {}; + +function FullNamePersonalStep({onNext}) { + const {translate} = useLocalize(); + + return ( + +
+ + + props.onFieldChange({firstName: value})} + errorText={props.errors.firstName ? props.translate('bankAccount.error.firstName') : ''} + /> + + + props.onFieldChange({lastName: value})} + errorText={props.errors.lastName ? props.translate('bankAccount.error.lastName') : ''} + /> + + +
+
+ ); +} + +FullNamePersonalStep.propTypes = propTypes; +FullNamePersonalStep.defaultProps = defaultProps; +FullNamePersonalStep.displayName = 'FullNamePersonalStep'; + +export default compose(withOnyx({}))(FullNamePersonalStep); diff --git a/src/pages/ReimbursementAccount/subStepPropTypes.js b/src/pages/ReimbursementAccount/subStepPropTypes.js new file mode 100644 index 000000000000..058e0cc78c56 --- /dev/null +++ b/src/pages/ReimbursementAccount/subStepPropTypes.js @@ -0,0 +1,9 @@ +import PropTypes from 'prop-types'; + +const subStepPropTypes = { + isEditing: PropTypes.bool.isRequired, + onNext: PropTypes.func.isRequired, + onMove: PropTypes.func.isRequired, +}; + +export default subStepPropTypes; From 70e00562acef33a84af3118477d9873488693307 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Wed, 25 Oct 2023 15:14:24 +0200 Subject: [PATCH 002/236] Created Interactive Step Header --- src/components/InteractiveStepSubHeader.js | 100 ++++++++++++++++++ .../InteractiveStepSubHeader.stories.js | 54 ++++++++++ src/styles/styles.ts | 47 ++++++++ 3 files changed, 201 insertions(+) create mode 100644 src/components/InteractiveStepSubHeader.js create mode 100644 src/stories/InteractiveStepSubHeader.stories.js diff --git a/src/components/InteractiveStepSubHeader.js b/src/components/InteractiveStepSubHeader.js new file mode 100644 index 000000000000..63850230e0d2 --- /dev/null +++ b/src/components/InteractiveStepSubHeader.js @@ -0,0 +1,100 @@ +import React, {forwardRef, useState, useImperativeHandle} from 'react'; +import PropTypes from 'prop-types'; +import map from 'lodash/map'; +import {View} from 'react-native'; + +import CONST from '../CONST'; +import variables from '../styles/variables'; +import styles from '../styles/styles'; +import colors from '../styles/colors'; +import * as Expensicons from './Icon/Expensicons'; +import PressableWithFeedback from './Pressable/PressableWithFeedback'; +import Text from './Text'; +import Icon from './Icon'; + +const propTypes = { + stepNames: PropTypes.arrayOf(PropTypes.string).isRequired, + onStepSelected: PropTypes.func.isRequired, + startStep: PropTypes.number, +}; + +const defaultProps = { + startStep: 0, +}; + +const MIN_AMOUNT_FOR_EXPANDING = 3; +const MIN_AMOUNT_OF_STEPS = 2; + +function InteractiveStepSubHeader({stepNames, startStep, onStepSelected}, ref) { + const [currentStep, setCurrentStep] = useState(startStep); + useImperativeHandle( + ref, + () => ({ + moveNext: () => { + setCurrentStep((actualStep) => actualStep + 1); + }, + }), + [], + ); + + if (stepNames.length < MIN_AMOUNT_OF_STEPS) { + console.warn('InteractiveStepSubHeader: stepNames prop must have at least 2 elements'); + return null; + } + + const amountOfUnions = stepNames.length - 1; + + return ( + + {map(stepNames, (stepName, index) => { + const isCompletedStep = currentStep > index; + const isLockedStep = currentStep < index; + const isLockedLine = currentStep < index + 1; + const hasUnion = index < amountOfUnions; + + const moveToStep = () => { + if (isLockedStep) { + return; + } + setCurrentStep(index); + onStepSelected(stepNames[index]); + }; + return ( + + + {isCompletedStep ? ( + + ) : ( + {index + 1} + )} + + {hasUnion ? : null} + + ); + })} + + ); +} + +InteractiveStepSubHeader.propTypes = propTypes; +InteractiveStepSubHeader.defaultProps = defaultProps; +InteractiveStepSubHeader.displayName = 'InteractiveStepSubHeader'; + +export default forwardRef(InteractiveStepSubHeader); diff --git a/src/stories/InteractiveStepSubHeader.stories.js b/src/stories/InteractiveStepSubHeader.stories.js new file mode 100644 index 000000000000..4e932bc5a9d7 --- /dev/null +++ b/src/stories/InteractiveStepSubHeader.stories.js @@ -0,0 +1,54 @@ +/* eslint-disable react/jsx-props-no-spreading */ +import React, {useRef} from 'react'; +import {View, Button} from 'react-native'; + +import InteractiveStepSubHeader from '../components/InteractiveStepSubHeader'; + +/** + * We use the Component Story Format for writing stories. Follow the docs here: + * + * https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format + */ +const story = { + title: 'Components/InteractiveStepSubHeader', + component: InteractiveStepSubHeader, +}; + +function Template(args) { + // eslint-disable-next-line react/jsx-props-no-spreading + return ; +} + +// Arguments can be passed to the component by binding +// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +const Default = Template.bind({}); + +function BaseInteractiveStepSubHeader(props) { + const ref = useRef(null); + return ( + + +