colbymillerdev / react-native-progress-steps

A simple and fully customizable React Native component that implements a progress stepper UI.
MIT License
377 stars 147 forks source link

wrapping progress step with formik is impossible. #45

Closed cybercoder closed 4 years ago

cybercoder commented 4 years ago

wrapping progress step with formik is impossible.

colbymillerdev commented 4 years ago

Hello @cybercoder -

The <ProgressStep /> component should be the parent that wraps the content you wan't displayed inside of each step. In this case, try placing the Formik component inside of the desired <ProgressStep /> tag.

cybercoder commented 4 years ago

Hello @cybercoder -

The <ProgressStep /> component should be the parent that wraps the content you wan't displayed inside of each step. In this case, try placing the Formik component inside of the desired <ProgressStep /> tag.

If Formik being the child, then we need context api to handle enable/disable Next/Prev buttons. So i made some patches in your component and it's working for me.

colbymillerdev commented 4 years ago

@cybercoder Ok awesome! That's great to hear. Feel free to open a PR with any changes if you think they'd benefit other users of the library.

weslei-dias-vakt commented 4 years ago

@cybercoder How can i do this validation?

cybercoder commented 4 years ago

@cybercoder How can i do this validation?

just pass all props to lower component. i can't understand what you mean of validation.

cybercoder commented 4 years ago

@cybercoder Ok awesome! That's great to hear. Feel free to open a PR with any changes if you think they'd benefit other users of the library.

I did made the patch in previous version, I have no idea how i can make a PR with the patch in the new version. So i send you the patch file.

react-native-progress-steps+1.3.0.txt

cybercoder commented 4 years ago

Here is how i did handle formik:

This is the Wizard component:

    <View style={{flex: 1, marginHorizontal: 10}}>
      {/* <TouchableOpacity onPress={() => SampleInit().then(setData({...data}))}>
        <Text>Init Sample</Text>
      </TouchableOpacity> */}
      <ProgressSteps
        stepNumStyle={styles.stepNumStyle}
        progressBarColor="#009688"
        activeStepIconBorderColor="#009688"
        activeLabelColor="#009688"
        disabledStepIconColor="gray"
        labelColor="gray"
        completedStepIconColor="#009688"
        completedProgressBarColor="#009688"
        labelFontFamily={
          Platform.OS === 'android'
            ? 'iran_sans_mobile_fa_num'
            : 'IRANSansMobileFaNum'
        }>
        <Step1 data={data} label="step1" />
        <Step2 data={data} label="step2" />
        <Step3 data={data} label="step3" />
        <Step4 data={data} label="step4" navigation={navigation} />
      </ProgressSteps>
    </View>

And a example step using formik, yup and redux is like this:

import React, {useState} from 'react';
import {View} from 'react-native';
import {Input} from '../../../../../../components';

import {useSelector, useDispatch} from 'react-redux';
import {updateCargo} from '../../../../../../redux/actions';

import {ProgressStep} from 'react-native-progress-steps';
import {Formik} from 'formik';
import * as Yup from 'yup';
import Modal from 'react-native-modal';

import SelectType from './selectType';
import SelectTonne from './selectTonne';
import SelectPackaging from './selectPackaging';
import SelectLoadingType from './selectLoadingType';

import styles from '../../../../../../styles';

const validationSchema = Yup.object().shape({
  type: Yup.object().typeError('نوع‌محموله‌راتعیین‌فرمایید.'),
  quantity: Yup.number()
    .required('لطفا وزن نسبی محموله را وارد فرمایید.')
    .positive('وزن منفی؟')
    .typeError('عددواردفرمایید!'),
  packaging: Yup.object().typeError('نوع‌بسته‌بندی‌راتعیین‌فرمایید.'),
  load: Yup.object().typeError('حالت‌بار‌گیری‌راتعیین‌فرمایید.'),
  value: Yup.number()
    .transform((o, v) => v && parseFloat(v.replace(/,/g, '')))
    .required('لطفا ارزش نسبی محموله را وارد فرمایید.')
    .positive('ارزش منفی؟')
    .typeError('عددواردفرمایید!'),
});

const tonneList = [...Array(25).keys()];

export default (props) => {
  const dispatch = useDispatch();
  let {cargo} = useSelector((state) => state.order);

  let {loadTypes, packagingTypes, cargoTypes} = props.data;
  let [typeModalIsVisible, showTypeModal] = useState(false);
  let [isTonneModalVisible, showTonneModal] = useState(false);
  let [packagingModalIsVisible, showPackagingModal] = useState(false);
  let [loadingTypeModalIsVisible, showLoadingTypeModal] = useState(false);

  let [workerCount, setWorkerCount] = useState(0);

  let initialData = cargo
    ? {...cargo}
    : {
        type: null,
        load: null, //loadTypes.find((l) => l.title === 'عادی'),
        quantity: null,
        packaging: null,
        value: null,
      };

  return (
    <Formik
      initialValues={initialData}
      validationSchema={validationSchema}
      validateOnMount={validationSchema.isValidSync(initialData)}
      onSubmit={(values) => {
        if (JSON.stringify(values) !== JSON.stringify(cargo)) {
          dispatch(updateCargo(values));
        }
      }}>
      {({handleChange, values, handleSubmit, errors}) => (
        <ProgressStep
          {...props}
          label="مشخصات محموله"
          nextBtnText="ادامه"
          onNext={handleSubmit}
          nextBtnDisabled={!validationSchema.isValidSync(values)}
          nextBtnStyle={styles.nextBtnStyle}
          nextBtnTextStyle={styles.nextBtnTextStyle}>
          <View
            style={{
              flex: 1,
              justifyContent: 'center',
              alignItems: 'center',
              paddingBottom: 10,
            }}>
            <Input
              name="type"
              image="truck"
              placeholder="نوع محموله شما چیست؟"
              editable={false}
              value={values.type?.title}
              onPress={() => showTypeModal(true)}
              // error={errors.type}
            />
            <Input
              image="truck"
              placeholder="وزن محموله شما چقدر است؟"
              editable={false}
              name="quantity"
              value={
                values.quantity ? values.quantity.toString() + ' تن' : null
              }
              onPress={() => showTonneModal(true)}
              // error={errors.quantity}
            />
            <Input
              image="truck"
              placeholder="نوع بسته بندی محموله شما چیست؟"
              editable={false}
              value={values.packaging?.title}
              onPress={() => showPackagingModal(true)}
            />
            <Input
              image="truck"
              name="value"
              maxLength={13}
              onChangeText={handleChange('value')}
              keyboardType="number-pad"
              value={
                values.value
                  ? values.value
                      .replace(/,/g, '')
                      .replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
                  : null
              }
              placeholder="ارزش محموله شما چند تومان است؟"
              editable={true}
              onPress={() => {}}
              // error={errors.value}
            />
            <Input
              image="truck"
              placeholder="حالت بارگیری محموله چیست؟"
              editable={false}
              value={values?.load?.title}
              onPress={() => showLoadingTypeModal(true)}
            />
          </View>
          <Modal
            isVisible={typeModalIsVisible}
            style={styles.fullScreenModal}
            animationOutTiming={300}
            backdropTransitionOutTiming={0}
            useNativeDriver={true}
            backdropOpacity={0.3}
            onBackButtonPress={() => showTypeModal(false)}
            onBackdropPress={() => showTypeModal(false)}>
            <SelectType
              data={cargoTypes.docs}
              onSave={(typeData) => {
                values.type = typeData;
                showTypeModal(false);
              }}
            />
          </Modal>
          <Modal
            isVisible={isTonneModalVisible}
            style={styles.fullScreenModal}
            animationOutTiming={300}
            backdropTransitionOutTiming={0}
            useNativeDriver={true}
            backdropOpacity={0.3}
            onBackButtonPress={() => showTonneModal(false)}
            onBackdropPress={() => showTonneModal(false)}
            onSwipeComplete={() => showTonneModal(false)}
            swipeDirection={['up', 'left', 'right', 'down']}>
            <SelectTonne
              data={tonneList}
              onSave={(quantity) => {
                values.quantity = quantity;
                showTonneModal(false);
              }}
            />
          </Modal>
          <Modal
            isVisible={packagingModalIsVisible}
            style={styles.fullScreenModal}
            animationOutTiming={300}
            backdropTransitionOutTiming={0}
            useNativeDriver={true}
            backdropOpacity={0.3}
            onBackButtonPress={() => showPackagingModal(false)}
            onBackdropPress={() => showPackagingModal(false)}
            onSwipeComplete={() => showPackagingModal(false)}
            swipeDirection={['up', 'left', 'right', 'down']}>
            <SelectPackaging
              data={packagingTypes}
              onSave={(packaging) => {
                values.packaging = packaging;
                showPackagingModal(false);
              }}
            />
          </Modal>
          <Modal
            isVisible={loadingTypeModalIsVisible}
            style={styles.fullScreenModal}
            animationOutTiming={300}
            backdropTransitionOutTiming={0}
            useNativeDriver={true}
            backdropOpacity={0.3}
            onBackButtonPress={() => showLoadingTypeModal(false)}
            onBackdropPress={() => showLoadingTypeModal(false)}
            onSwipeComplete={() => showLoadingTypeModal(false)}
            swipeDirection={['up', 'left', 'right', 'down']}>
            <SelectLoadingType
              data={loadTypes}
              onSave={(load) => {
                values.load = load;
                showLoadingTypeModal(false);
              }}
            />
          </Modal>
        </ProgressStep>
      )}
    </Formik>
  );
};

Theres formik mistakes by me where must use setValue to handle fields value updates but i did them directly, which not related to this topic.