From c848f6c185760d20083d9c3a1dba849fc37094c2 Mon Sep 17 00:00:00 2001
From: German Urrustarazu
Date: Fri, 19 Aug 2022 14:42:50 -0300
Subject: [PATCH 01/36] temp updates
---
.../client/src/components/Dropdown.js | 4 +-
.../ProposalCreate/StepOne/FormConfig.js | 19 ++
.../ProposalCreate/StepOne/index.js | 259 ++++++++++--------
.../client/src/components/StepByStep/index.js | 53 ++--
.../client/src/components/common/Form.js | 15 +-
.../client/src/pages/ProposalCreate.js | 1 +
6 files changed, 213 insertions(+), 138 deletions(-)
create mode 100644 frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
diff --git a/frontend/packages/client/src/components/Dropdown.js b/frontend/packages/client/src/components/Dropdown.js
index b033e3342..8c9df47fa 100644
--- a/frontend/packages/client/src/components/Dropdown.js
+++ b/frontend/packages/client/src/components/Dropdown.js
@@ -26,7 +26,9 @@ const DropDown = forwardRef(
const [isOpen, setIsOpen] = useState(false);
const [innerValue, setInnerValue] = useState(defaultValue ?? { label });
- const openCloseDropdown = () => {
+ const openCloseDropdown = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
setIsOpen((status) => !status);
};
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
new file mode 100644
index 000000000..3adc42c5c
--- /dev/null
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
@@ -0,0 +1,19 @@
+import * as yup from 'yup';
+
+const initialValues = {
+ name: '',
+};
+const Schema = yup.object().shape({
+ name: yup
+ .string()
+ .trim()
+ .required('Please enter a proposal title')
+ .max(150, 'The maximum length for title is 128 characters'),
+});
+
+const stepOne = {
+ Schema,
+ initialValues,
+};
+
+export { stepOne };
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
index dfb5855f4..cad5aa762 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
@@ -6,12 +6,16 @@ import React, {
useState,
} from 'react';
import { Editor } from 'react-draft-wysiwyg';
+import { useForm, useWatch } from 'react-hook-form';
import { useParams } from 'react-router-dom';
import { useModalContext } from 'contexts/NotificationModal';
import { Dropdown, Error, UploadImageModal } from 'components';
import { Image } from 'components/Svg';
+import Form from 'components/common/Form';
+import Input from 'components/common/Input';
import { useCommunityDetails } from 'hooks';
import { kebabToString } from 'utils';
+import { yupResolver } from '@hookform/resolvers/yup';
import {
AtomicBlockUtils,
ContentState,
@@ -21,6 +25,8 @@ import {
SelectionState,
} from 'draft-js';
import { Map } from 'immutable';
+import pick from 'lodash/pick';
+import { stepOne } from './FormConfig';
import ImageChoices from './ImageChoices';
import TextBasedChoices from './TextBasedChoices';
@@ -65,6 +71,8 @@ const StepOne = ({
setStepValid,
onDataChange,
setPreCheckStepAdvance,
+ formRef,
+ moveToNextStep,
}) => {
const dropDownRef = useRef();
@@ -127,7 +135,7 @@ const StepOne = ({
const isValid = Object.keys(requiredFields).every(
(field) => stepData && requiredFields[field](stepData[field])
);
- setStepValid(isValid);
+ setStepValid(true);
}, [stepData, setStepValid, onDataChange, tabOption]);
useEffect(() => {
@@ -168,6 +176,7 @@ const StepOne = ({
const { strategy } = stepData ?? {};
+ console.log('formId > ', formRef);
useEffect(() => {
setPreCheckStepAdvance(() => {
if (!strategy) {
@@ -384,6 +393,26 @@ const StepOne = ({
const showTitleInputError = !checkValidTitleLength(stepData?.title ?? '');
+ const fieldsObj = Object.assign(
+ {},
+ stepOne.initialValues,
+ pick(stepData || {}, ['title'])
+ );
+ const { register, handleSubmit, formState, control, setValue, reset } =
+ useForm({
+ defaultValues: fieldsObj,
+ resolver: yupResolver(stepOne.Schema),
+ });
+
+ const { isDirty, isSubmitting, errors, submit } = formState;
+
+ const field = useWatch({ control, name: 'title' });
+ console.log('watchinig ', field);
+
+ const onSubmit = (data) => {
+ console.log('data submitted >>> ', data);
+ // moveToNextStep();
+ };
return (
<>
{showUploadImagesModal && (
@@ -392,126 +421,122 @@ const StepOne = ({
onDone={addImagesToEditor}
/>
)}
-
-
-
- Title *
-
-
- Give your proposal a title based on the decision or initiative being
- voted on. Best to keep it simple and specific.
-
-
- onDataChange({
- title: event.target.value,
- })
- }
- />
- {showTitleInputError && (
-
-
- The maximum length for Title is 128 characters
-
-
- )}
-
-
-
- Description *
-
-
- This is where you build the key information for the proposal: the
- details of what’s being voted on; background information for
- context; the expected costs and benefits of this collective
- decision.
-
-
]}
- customStyleMap={styleMap}
- blockRenderMap={extendedBlockRenderMap}
- />
-
-
-
Voting Strategy
-
- Select a strategy for how voting power is calculated. Voting
- strategies are set by community admins.
-
-
({
- label: vs.name,
- value: vs.key,
- })) ?? []
- }
- disabled={votingStrategies.length === 0}
- onSelectValue={onSelectStrategy}
- ref={dropDownRef}
- />
-
-
-
- Choices *
-
-
- Provide the specific options you’d like to cast votes for. Use
- Text-based presentation for choices that described in words. Use
- Visual for side-by-side visual options represented by images.
-
-
-
-
-
- Text-based
-
-
-
-
- Visual
-
-
-
+
+
+
+
>
);
};
diff --git a/frontend/packages/client/src/components/StepByStep/index.js b/frontend/packages/client/src/components/StepByStep/index.js
index 67432e226..140c4318b 100644
--- a/frontend/packages/client/src/components/StepByStep/index.js
+++ b/frontend/packages/client/src/components/StepByStep/index.js
@@ -20,6 +20,7 @@ function StepByStep({
const [isStepValid, setStepValid] = useState(false);
const [stepsData, setStepsData] = useState({});
const refs = React.useRef();
+ const formRef = React.useRef();
const onStepAdvance = (direction = 'next') => {
if (direction === 'next') {
@@ -122,6 +123,8 @@ function StepByStep({
const child = showPreStep ? preStep : steps[currentStep].component;
+ const { useHookForms = false } = steps[currentStep];
+
const getBackLabel = () => (
(
-
-
- Next
+ const getNextButton = ({ formRef } = {}) => {
+ console.log('formId', formRef);
+ return (
+
+ {
+ e.preventDefault();
+
+ formRef.current.dispatchEvent(
+ new Event('submit', { cancelable: true, bubbles: true })
+ );
+ }
+ : moveToNextStep
+ }
+ >
+ Next
+
-
- );
+ );
+ };
const getSubmitButton = () => (
@@ -165,6 +179,7 @@ function StepByStep({
);
+ console.log('currentStep', steps[currentStep]);
return (
<>
{blockNavigationOut && (
@@ -203,7 +218,7 @@ function StepByStep({
{steps.map((step, i) => getStepIcon(i, step.label))}
{currentStep < steps.length - 1 &&
!passNextToComp &&
- getNextButton()}
+ getNextButton(useHookForms ? { formRef } : undefined)}
{currentStep === steps.length - 1 &&
!passSubmitToComp &&
getSubmitButton()}
@@ -257,15 +272,21 @@ function StepByStep({
? { onSubmit: _onSubmit }
: undefined),
...(showPreStep ? { dismissPreStep } : undefined),
+ formId: `form-Id-${currentStep}`,
+ ...(useHookForms ? { formRef } : undefined),
})}
-
+ {/*
{currentStep < steps.length - 1 &&
!passNextToComp &&
- getNextButton()}
+ getNextButton({
+ formId: useHookForms ? `form-Id-${currentStep}` : undefined,
+ })}
{currentStep === steps.length - 1 &&
!passSubmitToComp &&
- getSubmitButton()}
-
+ getSubmitButton({
+ formId: useHookForms ? `form-Id-${currentStep}` : undefined,
+ })}
+
*/}
diff --git a/frontend/packages/client/src/components/common/Form.js b/frontend/packages/client/src/components/common/Form.js
index 825635e0e..e33089744 100644
--- a/frontend/packages/client/src/components/common/Form.js
+++ b/frontend/packages/client/src/components/common/Form.js
@@ -1,9 +1,16 @@
-import React from 'react';
+import React, { forwardRef } from 'react';
+
+const Form = forwardRef((props, ref) => {
+ const { removeInnerForm, children, onSubmit, formId } = props;
-export default function Form({ removeInnerForm, children, onSubmit }) {
return removeInnerForm ? (
<>{children}>
) : (
-
+
);
-}
+});
+
+export default Form;
diff --git a/frontend/packages/client/src/pages/ProposalCreate.js b/frontend/packages/client/src/pages/ProposalCreate.js
index 4fac40365..0301e4d49 100644
--- a/frontend/packages/client/src/pages/ProposalCreate.js
+++ b/frontend/packages/client/src/pages/ProposalCreate.js
@@ -123,6 +123,7 @@ export default function ProposalCreatePage() {
description:
'Some description of what you can write here that is useful.',
component:
,
+ useHookForms: true,
},
{
label: 'Set Date & Time',
From 004a626f4207a64d012a1e39471faa0f90076f8e Mon Sep 17 00:00:00 2001
From: German Urrustarazu
Date: Fri, 19 Aug 2022 16:53:36 -0300
Subject: [PATCH 02/36] updates
---
.../ProposalCreate/StepOne/FormConfig.js | 2 +-
.../ProposalCreate/StepOne/index.js | 58 +++++++------
.../components/StepByStep/NexStepButton.js | 27 ++++++
.../src/components/StepByStep/SubmitButton.js | 0
.../client/src/components/StepByStep/index.js | 86 ++++++++++---------
.../client/src/components/common/Form.js | 11 +--
6 files changed, 112 insertions(+), 72 deletions(-)
create mode 100644 frontend/packages/client/src/components/StepByStep/NexStepButton.js
create mode 100644 frontend/packages/client/src/components/StepByStep/SubmitButton.js
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
index 3adc42c5c..4840b9a91 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
@@ -1,7 +1,7 @@
import * as yup from 'yup';
const initialValues = {
- name: '',
+ title: '',
};
const Schema = yup.object().shape({
name: yup
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
index cad5aa762..b7a934fa1 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
@@ -71,7 +71,7 @@ const StepOne = ({
setStepValid,
onDataChange,
setPreCheckStepAdvance,
- formRef,
+ formId,
moveToNextStep,
}) => {
const dropDownRef = useRef();
@@ -176,7 +176,6 @@ const StepOne = ({
const { strategy } = stepData ?? {};
- console.log('formId > ', formRef);
useEffect(() => {
setPreCheckStepAdvance(() => {
if (!strategy) {
@@ -393,26 +392,41 @@ const StepOne = ({
const showTitleInputError = !checkValidTitleLength(stepData?.title ?? '');
+ console.log('step data comes with', stepData);
const fieldsObj = Object.assign(
{},
stepOne.initialValues,
pick(stepData || {}, ['title'])
);
- const { register, handleSubmit, formState, control, setValue, reset } =
- useForm({
- defaultValues: fieldsObj,
- resolver: yupResolver(stepOne.Schema),
- });
- const { isDirty, isSubmitting, errors, submit } = formState;
+ // const { register, handleSubmit, formState, control, setValue, reset } =
+ // useForm({
+
+ // resolver: yupResolver(stepOne.Schema),
+ // });
+
+ // const { isDirty, isSubmitting, errors, submit } = formState;
- const field = useWatch({ control, name: 'title' });
- console.log('watchinig ', field);
+ // const field = useWatch({ control, name: 'example' });
+ // console.log('watchinig ', field);
+ const { register, handleSubmit, watch, formState } = useForm({
+ defaultValues: fieldsObj,
+ });
const onSubmit = (data) => {
- console.log('data submitted >>> ', data);
- // moveToNextStep();
+ console.log('data on submit >>', data);
+ onDataChange(data);
+ moveToNextStep();
};
+
+ const { isDirty, isSubmitting, errors } = formState;
+
+ console.log(watch('example')); // watch input value by passing the name of it
+ // const onSubmit = (data) => {
+ // console.log('data submitted >>> ', data);
+ // // moveToNextStep();
+ // };
+
return (
<>
{showUploadImagesModal && (
@@ -422,13 +436,7 @@ const StepOne = ({
/>
)}
-
+
>
);
};
diff --git a/frontend/packages/client/src/components/StepByStep/NexStepButton.js b/frontend/packages/client/src/components/StepByStep/NexStepButton.js
new file mode 100644
index 000000000..ab51f8ee5
--- /dev/null
+++ b/frontend/packages/client/src/components/StepByStep/NexStepButton.js
@@ -0,0 +1,27 @@
+import React from 'react';
+
+const NextButton = ({
+ formId: formIdParam,
+ moveToNextStep,
+ disabled = false,
+} = {}) => {
+ const classNames = `button is-block has-background-yellow rounded-sm py-2 px-4 has-text-centered ${
+ disabled && 'is-disabled'
+ }`;
+
+ return (
+
+ {formIdParam ? (
+
+ Next
+
+ ) : (
+
+ Next
+
+ )}
+
+ );
+};
+
+export default NextButton;
diff --git a/frontend/packages/client/src/components/StepByStep/SubmitButton.js b/frontend/packages/client/src/components/StepByStep/SubmitButton.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/frontend/packages/client/src/components/StepByStep/index.js b/frontend/packages/client/src/components/StepByStep/index.js
index 140c4318b..9440d9b1b 100644
--- a/frontend/packages/client/src/components/StepByStep/index.js
+++ b/frontend/packages/client/src/components/StepByStep/index.js
@@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react';
import { Prompt } from 'react-router-dom';
import Loader from '../Loader';
import { ArrowLeft, CheckMark } from '../Svg';
+import NextButton from './NexStepButton';
function StepByStep({
finalLabel,
@@ -20,7 +21,6 @@ function StepByStep({
const [isStepValid, setStepValid] = useState(false);
const [stepsData, setStepsData] = useState({});
const refs = React.useRef();
- const formRef = React.useRef();
const onStepAdvance = (direction = 'next') => {
if (direction === 'next') {
@@ -125,6 +125,8 @@ function StepByStep({
const { useHookForms = false } = steps[currentStep];
+ const formId = useHookForms ? `form-Id-${currentStep}` : undefined;
+
const getBackLabel = () => (
{
- console.log('formId', formRef);
+ const getNextButton = ({ formId: formIdParam } = {}) => {
+ const classNames = `button is-block has-background-yellow rounded-sm py-2 px-4 has-text-centered ${
+ !isStepValid && 'is-disabled'
+ }`;
+
return (
-
{
- e.preventDefault();
-
- formRef.current.dispatchEvent(
- new Event('submit', { cancelable: true, bubbles: true })
- );
- }
- : moveToNextStep
- }
- >
- Next
-
+ {formIdParam ? (
+
+ Next
+
+ ) : (
+
+ Next
+
+ )}
);
};
- const getSubmitButton = () => (
+ const getSubmitButton = ({ formId: formIdParam } = {}) => (
-
- {finalLabel}
-
+ {formIdParam ? (
+
+ {finalLabel}
+
+ ) : (
+
+ {finalLabel}
+
+ )}
);
@@ -218,10 +228,11 @@ function StepByStep({
{steps.map((step, i) => getStepIcon(i, step.label))}
{currentStep < steps.length - 1 &&
!passNextToComp &&
- getNextButton(useHookForms ? { formRef } : undefined)}
+ getNextButton({ formId })}
+
{currentStep === steps.length - 1 &&
!passSubmitToComp &&
- getSubmitButton()}
+ getSubmitButton({ formId })}
{/* left panel mobile */}
+
{currentStep < steps.length - 1 &&
!passNextToComp &&
- getNextButton({
- formId: useHookForms ? `form-Id-${currentStep}` : undefined,
- })}
+ getNextButton({ formId })}
{currentStep === steps.length - 1 &&
!passSubmitToComp &&
- getSubmitButton({
- formId: useHookForms ? `form-Id-${currentStep}` : undefined,
- })}
-
*/}
+ getSubmitButton({ formId })}
+
diff --git a/frontend/packages/client/src/components/common/Form.js b/frontend/packages/client/src/components/common/Form.js
index e33089744..5a74b2b1e 100644
--- a/frontend/packages/client/src/components/common/Form.js
+++ b/frontend/packages/client/src/components/common/Form.js
@@ -1,16 +1,13 @@
-import React, { forwardRef } from 'react';
-
-const Form = forwardRef((props, ref) => {
- const { removeInnerForm, children, onSubmit, formId } = props;
+import React from 'react';
+const Form = ({ removeInnerForm = false, children, onSubmit, formId } = {}) => {
return removeInnerForm ? (
<>{children}>
) : (
-
);
-});
+};
export default Form;
From 63df4f23579b5e5c214707da738f4891b1998004 Mon Sep 17 00:00:00 2001
From: German Urrustarazu
Date: Fri, 19 Aug 2022 17:49:19 -0300
Subject: [PATCH 03/36] update
---
.../ProposalCreate/StepOne/FormConfig.js | 13 ++-
.../ProposalCreate/StepOne/index.js | 81 +++-------------
.../components/StepByStep/NexStepButton.js | 10 +-
.../src/components/StepByStep/SubmitButton.js | 28 ++++++
.../client/src/components/StepByStep/index.js | 93 +++++++------------
.../client/src/pages/CommunityCreate.js | 1 +
.../client/src/pages/ProposalCreate.js | 2 +
7 files changed, 97 insertions(+), 131 deletions(-)
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
index 4840b9a91..f98d949fc 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
@@ -1,19 +1,24 @@
import * as yup from 'yup';
-const initialValues = {
- title: '',
-};
+const formFields = ['title', 'strategy'];
+
const Schema = yup.object().shape({
- name: yup
+ title: yup
.string()
.trim()
.required('Please enter a proposal title')
.max(150, 'The maximum length for title is 128 characters'),
+ strategy: yup.string().required('Please select a strategy'),
});
+const initialValues = Object.assign(
+ {},
+ ...formFields.map((key) => ({ [key]: '' }))
+);
const stepOne = {
Schema,
initialValues,
+ formFields,
};
export { stepOne };
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
index b7a934fa1..3ecc13380 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
@@ -9,8 +9,9 @@ import { Editor } from 'react-draft-wysiwyg';
import { useForm, useWatch } from 'react-hook-form';
import { useParams } from 'react-router-dom';
import { useModalContext } from 'contexts/NotificationModal';
-import { Dropdown, Error, UploadImageModal } from 'components';
+import { Error, UploadImageModal } from 'components';
import { Image } from 'components/Svg';
+import Dropdown from 'components/common/Dropdown';
import Form from 'components/common/Form';
import Input from 'components/common/Input';
import { useCommunityDetails } from 'hooks';
@@ -30,8 +31,6 @@ import { stepOne } from './FormConfig';
import ImageChoices from './ImageChoices';
import TextBasedChoices from './TextBasedChoices';
-const checkValidTitleLength = (text) => text?.length <= 128;
-
// using a React component to render custom blocks
const ImageCaptionCustomBlock = (props) => {
return {props.children}
;
@@ -105,7 +104,6 @@ const StepOne = ({
useEffect(() => {
const requiredFields = {
- title: (text) => text?.trim().length > 0 && checkValidTitleLength(text),
description: (body) => body?.getCurrentContent().hasText(),
choices: (opts) => {
const getLabel = (o) => o?.value?.trim();
@@ -174,36 +172,6 @@ const StepOne = ({
},
};
- const { strategy } = stepData ?? {};
-
- useEffect(() => {
- setPreCheckStepAdvance(() => {
- if (!strategy) {
- openModal(
- React.createElement(Error, {
- error: (
-
- {
- closeModal();
- dropDownRef.current.focus();
- }}
- >
- Select Strategy
-
-
- ),
- errorTitle: 'Please select a strategy.',
- }),
- { classNameModalContent: 'rounded-sm' }
- );
- return false;
- }
- return true;
- });
- }, [strategy, setPreCheckStepAdvance, openModal, closeModal]);
-
const choices = useMemo(() => stepData?.choices || [], [stepData?.choices]);
const onCreateChoice = useCallback(() => {
@@ -253,15 +221,6 @@ const StepOne = ({
[onDataChange]
);
- const onSelectStrategy = (strategy) => {
- const strategySelected = votingStrategies?.find(
- (vs) => vs.key === strategy
- );
- onDataChange({
- strategy: { label: strategySelected.name, value: strategySelected.key },
- });
- };
-
const addImage = () => {
setShowUploadImagesModal(true);
};
@@ -388,38 +347,28 @@ const StepOne = ({
setShowUploadImagesModal(false);
};
- const defaultValueStrategy = stepData?.strategy;
-
- const showTitleInputError = !checkValidTitleLength(stepData?.title ?? '');
-
console.log('step data comes with', stepData);
const fieldsObj = Object.assign(
{},
stepOne.initialValues,
- pick(stepData || {}, ['title'])
+ pick(stepData || {}, stepOne.formFields)
);
- // const { register, handleSubmit, formState, control, setValue, reset } =
- // useForm({
-
- // resolver: yupResolver(stepOne.Schema),
- // });
-
- // const { isDirty, isSubmitting, errors, submit } = formState;
-
- // const field = useWatch({ control, name: 'example' });
- // console.log('watchinig ', field);
-
- const { register, handleSubmit, watch, formState } = useForm({
+ const { register, handleSubmit, watch, formState, control } = useForm({
defaultValues: fieldsObj,
+ resolver: yupResolver(stepOne.Schema),
});
+
const onSubmit = (data) => {
console.log('data on submit >>', data);
onDataChange(data);
moveToNextStep();
};
- const { isDirty, isSubmitting, errors } = formState;
+ const { isDirty, isSubmitting, isValid, errors } = formState;
+
+ console.log('ERRORS => ', errors);
+ console.log('isValid => ', isValid);
console.log(watch('example')); // watch input value by passing the name of it
// const onSubmit = (data) => {
@@ -482,17 +431,17 @@ const StepOne = ({
strategies are set by community admins.
({
label: vs.name,
value: vs.key,
})) ?? []
}
- disabled={votingStrategies.length === 0}
- onSelectValue={onSelectStrategy}
- ref={dropDownRef}
+ disabled={isSubmitting || votingStrategies.length === 0}
+ control={control}
/>
diff --git a/frontend/packages/client/src/components/StepByStep/NexStepButton.js b/frontend/packages/client/src/components/StepByStep/NexStepButton.js
index ab51f8ee5..694efd959 100644
--- a/frontend/packages/client/src/components/StepByStep/NexStepButton.js
+++ b/frontend/packages/client/src/components/StepByStep/NexStepButton.js
@@ -1,14 +1,16 @@
import React from 'react';
+import classnames from 'classnames';
const NextButton = ({
formId: formIdParam,
moveToNextStep,
disabled = false,
} = {}) => {
- const classNames = `button is-block has-background-yellow rounded-sm py-2 px-4 has-text-centered ${
- disabled && 'is-disabled'
- }`;
-
+ const classNames = classnames(
+ 'button is-block has-background-yellow rounded-sm py-2 px-4 has-text-centered',
+ { 'is-disabled': disabled },
+ { 'is-fullwidth': !!formIdParam }
+ );
return (
{formIdParam ? (
diff --git a/frontend/packages/client/src/components/StepByStep/SubmitButton.js b/frontend/packages/client/src/components/StepByStep/SubmitButton.js
index e69de29bb..2827eff19 100644
--- a/frontend/packages/client/src/components/StepByStep/SubmitButton.js
+++ b/frontend/packages/client/src/components/StepByStep/SubmitButton.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import classnames from 'classnames';
+
+export default function SubmitButton({
+ formId: formIdParam,
+ label = '',
+ disabled = false,
+ onSubmit = () => {},
+} = {}) {
+ const classNames = classnames(
+ 'button is-block has-background-yellow rounded-sm py-2 px-4 has-text-centered',
+ { 'is-disabled': disabled },
+ { 'is-fullwidth': !!formIdParam }
+ );
+ return (
+
+ {formIdParam ? (
+
+ {label}
+
+ ) : (
+
+ {label}
+
+ )}
+
+ );
+}
diff --git a/frontend/packages/client/src/components/StepByStep/index.js b/frontend/packages/client/src/components/StepByStep/index.js
index 9440d9b1b..688f6337c 100644
--- a/frontend/packages/client/src/components/StepByStep/index.js
+++ b/frontend/packages/client/src/components/StepByStep/index.js
@@ -1,8 +1,10 @@
import React, { useCallback, useState } from 'react';
import { Prompt } from 'react-router-dom';
+import { isValid } from 'date-fns';
import Loader from '../Loader';
import { ArrowLeft, CheckMark } from '../Svg';
import NextButton from './NexStepButton';
+import SubmitButton from './SubmitButton';
function StepByStep({
finalLabel,
@@ -12,6 +14,7 @@ function StepByStep({
isSubmitting,
submittingMessage,
passNextToComp = false,
+ showActionButtonLeftPannel = false,
passSubmitToComp = false,
blockNavigationOut = false,
blockNavigationText,
@@ -144,52 +147,11 @@ function StepByStep({
[onSubmit, stepsData]
);
- const getNextButton = ({ formId: formIdParam } = {}) => {
- const classNames = `button is-block has-background-yellow rounded-sm py-2 px-4 has-text-centered ${
- !isStepValid && 'is-disabled'
- }`;
-
- return (
-
- {formIdParam ? (
-
- Next
-
- ) : (
-
- Next
-
- )}
-
- );
- };
-
- const getSubmitButton = ({ formId: formIdParam } = {}) => (
-
- {formIdParam ? (
-
- {finalLabel}
-
- ) : (
-
- {finalLabel}
-
- )}
-
- );
+ const showNextButton = !passNextToComp || showActionButtonLeftPannel;
+ const showSubmitButton = !passSubmitToComp || showActionButtonLeftPannel;
console.log('currentStep', steps[currentStep]);
+
return (
<>
{blockNavigationOut && (
@@ -226,13 +188,21 @@ function StepByStep({
{currentStep > 0 && getBackLabel()}
{steps.map((step, i) => getStepIcon(i, step.label))}
- {currentStep < steps.length - 1 &&
- !passNextToComp &&
- getNextButton({ formId })}
-
- {currentStep === steps.length - 1 &&
- !passSubmitToComp &&
- getSubmitButton({ formId })}
+ {currentStep < steps.length - 1 && showNextButton && (
+
+ )}
+ {currentStep === steps.length - 1 && showSubmitButton && (
+
+ )}
{/* left panel mobile */}
- {currentStep < steps.length - 1 &&
- !passNextToComp &&
- getNextButton({ formId })}
- {currentStep === steps.length - 1 &&
- !passSubmitToComp &&
- getSubmitButton({ formId })}
+ {currentStep < steps.length - 1 && showNextButton && (
+
+ )}
+ {currentStep === steps.length - 1 && showSubmitButton && (
+
+ )}
diff --git a/frontend/packages/client/src/pages/CommunityCreate.js b/frontend/packages/client/src/pages/CommunityCreate.js
index 419933fcc..b977f81b7 100644
--- a/frontend/packages/client/src/pages/CommunityCreate.js
+++ b/frontend/packages/client/src/pages/CommunityCreate.js
@@ -162,6 +162,7 @@ export default function CommunityCreate() {
submittingMessage: 'Creating community...',
passNextToComp: true,
passSubmitToComp: true,
+ showActionButtonLeftPannel: true,
preStep: ,
blockNavigationOut: true && !data,
blockNavigationText:
diff --git a/frontend/packages/client/src/pages/ProposalCreate.js b/frontend/packages/client/src/pages/ProposalCreate.js
index 0301e4d49..134c4ed20 100644
--- a/frontend/packages/client/src/pages/ProposalCreate.js
+++ b/frontend/packages/client/src/pages/ProposalCreate.js
@@ -117,6 +117,8 @@ export default function ProposalCreatePage() {
blockNavigationOut: true && !data,
blockNavigationText:
'Proposal creation is not complete yet, are you sure you want to leave?',
+ passNextToComp: true,
+ showActionButtonLeftPannel: true,
steps: [
{
label: 'Draft Proposal',
From 48aeaedfb539824ef92d7012d75789fc4749e497 Mon Sep 17 00:00:00 2001
From: German Urrustarazu
Date: Fri, 19 Aug 2022 17:53:50 -0300
Subject: [PATCH 04/36] remove comment
---
.../client/src/components/ProposalCreate/StepOne/index.js | 6 ------
1 file changed, 6 deletions(-)
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
index 3ecc13380..c9636d309 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
@@ -370,12 +370,6 @@ const StepOne = ({
console.log('ERRORS => ', errors);
console.log('isValid => ', isValid);
- console.log(watch('example')); // watch input value by passing the name of it
- // const onSubmit = (data) => {
- // console.log('data submitted >>> ', data);
- // // moveToNextStep();
- // };
-
return (
<>
{showUploadImagesModal && (
From 21d16d7c80a0e8b14d3f94e59788a997e098effd Mon Sep 17 00:00:00 2001
From: German Urrustarazu
Date: Fri, 19 Aug 2022 18:08:11 -0300
Subject: [PATCH 05/36] remove output
---
.../client/src/components/ProposalCreate/StepOne/index.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
index c9636d309..9ae35b71b 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
@@ -347,7 +347,6 @@ const StepOne = ({
setShowUploadImagesModal(false);
};
- console.log('step data comes with', stepData);
const fieldsObj = Object.assign(
{},
stepOne.initialValues,
From d79e914d9ee9cea7e6502f1b941377fee028e25d Mon Sep 17 00:00:00 2001
From: German Urrustarazu
Date: Mon, 22 Aug 2022 14:29:24 -0300
Subject: [PATCH 06/36] updates
---
.../ProposalCreate/StepOne/Editor.js | 250 +++++++++++++++++
.../ProposalCreate/StepOne/FormConfig.js | 3 +-
.../ProposalCreate/StepOne/index.js | 252 ++----------------
.../client/src/pages/ProposalCreate.js | 6 +-
frontend/packages/client/src/utils.js | 4 +
5 files changed, 277 insertions(+), 238 deletions(-)
create mode 100644 frontend/packages/client/src/components/ProposalCreate/StepOne/Editor.js
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/Editor.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/Editor.js
new file mode 100644
index 000000000..0232ba045
--- /dev/null
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/Editor.js
@@ -0,0 +1,250 @@
+import React, { useEffect, useState } from 'react';
+import { Editor } from 'react-draft-wysiwyg';
+import { UploadImageModal } from 'components';
+import { Image } from 'components/Svg';
+import { customDraftToHTML, customHTMLtoDraft } from 'utils';
+import {
+ AtomicBlockUtils,
+ ContentState,
+ DefaultDraftBlockRenderMap,
+ EditorState,
+ Modifier,
+ SelectionState,
+} from 'draft-js';
+import { Map } from 'immutable';
+
+const options = ['blockType', 'inline', 'list', 'link', 'emoji'];
+const inline = {
+ options: ['bold', 'italic', 'underline'],
+};
+const list = {
+ options: ['unordered'],
+};
+const link = {
+ options: ['link'],
+ defaultTargetOption: '_blank',
+};
+
+const styleMap = {
+ IMAGE_CAPTION: {
+ fontFamily: 'Arimo',
+ fontStyle: 'normal',
+ fontWeight: 400,
+ fontSize: '12px',
+ },
+};
+
+// using a React component to render custom blocks
+const ImageCaptionCustomBlock = (props) => {
+ return {props.children}
;
+};
+const blockRenderMap = Map({
+ 'image-caption-block': {
+ // element is used during paste or html conversion to auto match your component;
+ // it is also retained as part of this.props.children and not stripped out. Example:
+ // element: "section",
+ wrapper: ,
+ },
+});
+
+// keep support for other draft default block types and add our image-caption type
+const extendedBlockRenderMap = DefaultDraftBlockRenderMap.merge(blockRenderMap);
+
+function AddImageOption({ addImage }) {
+ return (
+ <>
+
+ >
+ );
+}
+export default function CustomEditor({ onChange, value } = {}) {
+ const [localEditorState, setLocalEditorState] = useState(
+ EditorState.createEmpty()
+ );
+ const [updated, setUpdated] = useState(false);
+
+ useEffect(() => {
+ if (!updated) {
+ const defaultValue = value ? value : '';
+ console.log('loads content', defaultValue);
+ const blocksFromHtml = customHTMLtoDraft(defaultValue);
+ // const contentState = ContentState.createFromBlockArray(
+ // blocksFromHtml.contentBlocks,
+ // blocksFromHtml.entityMap
+ // );
+ const newEditorState = EditorState.createWithContent(blocksFromHtml);
+ setLocalEditorState(newEditorState);
+ }
+ }, [value]);
+
+ const onEditorStateChange = (editorState) => {
+ setUpdated(true);
+ setLocalEditorState(editorState);
+ return onChange(customDraftToHTML(editorState.getCurrentContent()));
+ };
+
+ const [showUploadImagesModal, setShowUploadImagesModal] = useState(false);
+
+ const addImage = () => {
+ setShowUploadImagesModal(true);
+ };
+
+ // const onEditorChange = (changes) => {
+ // setLocalEditorState(changes);
+ // onChange(changes);
+ // };
+
+ // function to update editor state
+ // used to insert more than one image at the time
+ function updateEditorState(
+ editorState,
+ { src, height, width, alt },
+ caption
+ ) {
+ const entityKey = editorState
+ .getCurrentContent()
+ .createEntity('IMAGE', 'MUTABLE', {
+ src,
+ height,
+ width,
+ alt,
+ })
+ .getLastCreatedEntityKey();
+
+ const selection = editorState.getSelection();
+
+ const currentFocusKey = selection.getFocusKey();
+
+ const newESWidthImageAndExtraBlock = AtomicBlockUtils.insertAtomicBlock(
+ editorState,
+ entityKey,
+ ' '
+ );
+ // user did not add caption text
+ if (caption.length === 0) {
+ return newESWidthImageAndExtraBlock;
+ }
+ // using cs: content state
+ const contentState = newESWidthImageAndExtraBlock.getCurrentContent();
+
+ const atomicBlockInserted = contentState.getBlockAfter(currentFocusKey);
+
+ // AtomicBlockUtils.insertAtomicBlock inserts an empty block right after the cursor position
+ const emptyBlockInserted = contentState.getBlockAfter(
+ atomicBlockInserted.getKey()
+ );
+
+ const lastBlockAddedKey = emptyBlockInserted.getKey();
+
+ // get existing blocks and
+ // filter and remove the last block added
+ // bc it's not necessary and caption block goes right after it
+ const blockMapArray = contentState
+ .getBlocksAsArray()
+ .filter((block) => block.getKey() !== lastBlockAddedKey);
+
+ // create new temporal content state to extract block with text
+ const tempCSWithCaption = ContentState.createFromText(caption);
+ // get the block with the text from temp content
+ const [tempBlockArray] = tempCSWithCaption.getBlocksAsArray();
+
+ // update block type so it's a custom type: image-caption
+ const csWithUpdatedBlock = Modifier.setBlockType(
+ ContentState.createFromBlockArray([tempBlockArray]),
+ SelectionState.createEmpty(tempBlockArray.key),
+ 'image-caption-block'
+ );
+ // get the block with custom type and with text
+ const [updatedBlock] = csWithUpdatedBlock.getBlocksAsArray();
+
+ const newBlockMapArray = blockMapArray.reduce(
+ (accumulator, currentValue) => {
+ if (currentValue.getKey() === atomicBlockInserted.getKey()) {
+ return [
+ ...accumulator,
+ currentValue,
+ updatedBlock,
+ emptyBlockInserted,
+ ];
+ }
+ return [...accumulator, currentValue];
+ },
+ []
+ );
+ // add block updated and concat empty block at the end
+ const newContentState = ContentState.createFromBlockArray(
+ newBlockMapArray,
+ contentState.getEntityMap()
+ );
+
+ // this keeps the history of the action
+ const editorStateWithImageAndCaption = EditorState.push(
+ newESWidthImageAndExtraBlock,
+ newContentState,
+ 'insert-fragment'
+ );
+
+ // move cursor to the end
+ const newState = EditorState.moveSelectionToEnd(
+ editorStateWithImageAndCaption
+ );
+ return newState;
+ }
+
+ const addImagesToEditor = (images, captionValues) => {
+ // captionValue
+ let tempEditorState = localEditorState;
+
+ for (let index = 0; index < images.length; index++) {
+ const image = images[index];
+ const caption = captionValues[index];
+ tempEditorState = updateEditorState(
+ tempEditorState,
+ {
+ src: image.imageUrl,
+ height: 'auto',
+ width: '100%',
+ alt: caption,
+ },
+ caption
+ );
+ }
+ setLocalEditorState(tempEditorState);
+ setShowUploadImagesModal(false);
+ };
+
+ const onDismissModal = () => {
+ setShowUploadImagesModal(false);
+ };
+ return (
+ <>
+ {showUploadImagesModal && (
+
+ )}
+ ]}
+ customStyleMap={styleMap}
+ blockRenderMap={extendedBlockRenderMap}
+ />
+ >
+ );
+}
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
index f98d949fc..de07679ec 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/FormConfig.js
@@ -1,6 +1,6 @@
import * as yup from 'yup';
-const formFields = ['title', 'strategy'];
+const formFields = ['title', 'strategy', 'body'];
const Schema = yup.object().shape({
title: yup
@@ -9,6 +9,7 @@ const Schema = yup.object().shape({
.required('Please enter a proposal title')
.max(150, 'The maximum length for title is 128 characters'),
strategy: yup.string().required('Please select a strategy'),
+ body: yup.string().required('Please enter a proposal description'),
});
const initialValues = Object.assign(
diff --git a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
index 9ae35b71b..75e09896b 100644
--- a/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
+++ b/frontend/packages/client/src/components/ProposalCreate/StepOne/index.js
@@ -1,70 +1,19 @@
-import React, {
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from 'react';
-import { Editor } from 'react-draft-wysiwyg';
-import { useForm, useWatch } from 'react-hook-form';
+import React, { useCallback, useEffect, useMemo } from 'react';
+import { Controller, useForm, useWatch } from 'react-hook-form';
import { useParams } from 'react-router-dom';
import { useModalContext } from 'contexts/NotificationModal';
-import { Error, UploadImageModal } from 'components';
-import { Image } from 'components/Svg';
import Dropdown from 'components/common/Dropdown';
import Form from 'components/common/Form';
import Input from 'components/common/Input';
import { useCommunityDetails } from 'hooks';
import { kebabToString } from 'utils';
import { yupResolver } from '@hookform/resolvers/yup';
-import {
- AtomicBlockUtils,
- ContentState,
- DefaultDraftBlockRenderMap,
- EditorState,
- Modifier,
- SelectionState,
-} from 'draft-js';
-import { Map } from 'immutable';
import pick from 'lodash/pick';
+import CustomEditor from './Editor';
import { stepOne } from './FormConfig';
import ImageChoices from './ImageChoices';
import TextBasedChoices from './TextBasedChoices';
-// using a React component to render custom blocks
-const ImageCaptionCustomBlock = (props) => {
- return {props.children}
;
-};
-const blockRenderMap = Map({
- 'image-caption-block': {
- // element is used during paste or html conversion to auto match your component;
- // it is also retained as part of this.props.children and not stripped out. Example:
- // element: "section",
- wrapper: ,
- },
-});
-
-// keep support for other draft default block types and add our image-caption type
-const extendedBlockRenderMap = DefaultDraftBlockRenderMap.merge(blockRenderMap);
-
-function AddImageOption({ addImage }) {
- return (
- <>
-
- >
- );
-}
-
const StepOne = ({
stepData,
setStepValid,
@@ -73,8 +22,6 @@ const StepOne = ({
formId,
moveToNextStep,
}) => {
- const dropDownRef = useRef();
-
const { communityId } = useParams();
const { data: community } = useCommunityDetails(communityId);
@@ -96,15 +43,10 @@ const StepOne = ({
() => stepData?.proposalType || 'text-based',
[stepData?.proposalType]
);
- const [localEditorState, setLocalEditorState] = useState(
- stepData?.description || EditorState.createEmpty()
- );
-
- const [showUploadImagesModal, setShowUploadImagesModal] = useState(false);
useEffect(() => {
const requiredFields = {
- description: (body) => body?.getCurrentContent().hasText(),
+ // description: (body) => body?.getCurrentContent().hasText(),
choices: (opts) => {
const getLabel = (o) => o?.value?.trim();
const getImageUrl = (o) => o?.choiceImgUrl?.trim();
@@ -136,10 +78,10 @@ const StepOne = ({
setStepValid(true);
}, [stepData, setStepValid, onDataChange, tabOption]);
- useEffect(() => {
- onDataChange({ description: localEditorState });
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [localEditorState]);
+ // useEffect(() => {
+ // onDataChange({ description: localEditorState });
+ // // eslint-disable-next-line react-hooks/exhaustive-deps
+ // }, [localEditorState]);
const setTab = (option) => () => {
onDataChange({
@@ -147,30 +89,9 @@ const StepOne = ({
});
};
- const onEditorChange = (changes) => {
- setLocalEditorState(changes);
- };
-
- const options = ['blockType', 'inline', 'list', 'link', 'emoji'];
- const inline = {
- options: ['bold', 'italic', 'underline'],
- };
- const list = {
- options: ['unordered'],
- };
- const link = {
- options: ['link'],
- defaultTargetOption: '_blank',
- };
-
- const styleMap = {
- IMAGE_CAPTION: {
- fontFamily: 'Arimo',
- fontStyle: 'normal',
- fontWeight: 400,
- fontSize: '12px',
- },
- };
+ // const onEditorChange = (changes) => {
+ // setLocalEditorState(changes);
+ // };
const choices = useMemo(() => stepData?.choices || [], [stepData?.choices]);
@@ -221,132 +142,6 @@ const StepOne = ({
[onDataChange]
);
- const addImage = () => {
- setShowUploadImagesModal(true);
- };
- const onDismissModal = () => {
- setShowUploadImagesModal(false);
- };
-
- // function to update editor state
- // used to insert more than one image at the time
- function updateEditorState(
- editorState,
- { src, height, width, alt },
- caption
- ) {
- const entityKey = editorState
- .getCurrentContent()
- .createEntity('IMAGE', 'MUTABLE', {
- src,
- height,
- width,
- alt,
- })
- .getLastCreatedEntityKey();
-
- const selection = editorState.getSelection();
-
- const currentFocusKey = selection.getFocusKey();
-
- const newESWidthImageAndExtraBlock = AtomicBlockUtils.insertAtomicBlock(
- editorState,
- entityKey,
- ' '
- );
- // user did not add caption text
- if (caption.length === 0) {
- return newESWidthImageAndExtraBlock;
- }
- // using cs: content state
- const contentState = newESWidthImageAndExtraBlock.getCurrentContent();
-
- const atomicBlockInserted = contentState.getBlockAfter(currentFocusKey);
-
- // AtomicBlockUtils.insertAtomicBlock inserts an empty block right after the cursor position
- const emptyBlockInserted = contentState.getBlockAfter(
- atomicBlockInserted.getKey()
- );
-
- const lastBlockAddedKey = emptyBlockInserted.getKey();
-
- // get existing blocks and
- // filter and remove the last block added
- // bc it's not necessary and caption block goes right after it
- const blockMapArray = contentState
- .getBlocksAsArray()
- .filter((block) => block.getKey() !== lastBlockAddedKey);
-
- // create new temporal content state to extract block with text
- const tempCSWithCaption = ContentState.createFromText(caption);
- // get the block with the text from temp content
- const [tempBlockArray] = tempCSWithCaption.getBlocksAsArray();
-
- // update block type so it's a custom type: image-caption
- const csWithUpdatedBlock = Modifier.setBlockType(
- ContentState.createFromBlockArray([tempBlockArray]),
- SelectionState.createEmpty(tempBlockArray.key),
- 'image-caption-block'
- );
- // get the block with custom type and with text
- const [updatedBlock] = csWithUpdatedBlock.getBlocksAsArray();
-
- const newBlockMapArray = blockMapArray.reduce(
- (accumulator, currentValue) => {
- if (currentValue.getKey() === atomicBlockInserted.getKey()) {
- return [
- ...accumulator,
- currentValue,
- updatedBlock,
- emptyBlockInserted,
- ];
- }
- return [...accumulator, currentValue];
- },
- []
- );
- // add block updated and concat empty block at the end
- const newContentState = ContentState.createFromBlockArray(
- newBlockMapArray,
- contentState.getEntityMap()
- );
-
- // this keeps the history of the action
- const editorStateWithImageAndCaption = EditorState.push(
- newESWidthImageAndExtraBlock,
- newContentState,
- 'insert-fragment'
- );
-
- // move cursor to the end
- const newState = EditorState.moveSelectionToEnd(
- editorStateWithImageAndCaption
- );
- return newState;
- }
-
- const addImagesToEditor = (images, captionValues) => {
- // captionValue
- let tempEditorState = localEditorState;
-
- for (let index = 0; index < images.length; index++) {
- const image = images[index];
- const caption = captionValues[index];
- tempEditorState = updateEditorState(
- tempEditorState,
- {
- src: image.imageUrl,
- height: 'auto',
- width: '100%',
- alt: caption,
- },
- caption
- );
- }
- setLocalEditorState(tempEditorState);
- setShowUploadImagesModal(false);
- };
-
const fieldsObj = Object.assign(
{},
stepOne.initialValues,
@@ -363,21 +158,16 @@ const StepOne = ({
onDataChange(data);
moveToNextStep();
};
+ const body = useWatch({ control, name: 'body' });
const { isDirty, isSubmitting, isValid, errors } = formState;
console.log('ERRORS => ', errors);
console.log('isValid => ', isValid);
+ console.log('body => ', body);
return (
<>
- {showUploadImagesModal && (
-
- )}
-