From a1c826549297d137c2b8cf45af511b451811f445 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Oct 2025 00:44:04 +0000 Subject: [PATCH 1/3] Separate proposal creation into two distinct steps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, Step 5 combined both go_prepare and go_submit operations in a single step, which was confusing to users. This change separates them into: - Step 5: Prepare proposal (go_prepare command + payment txId entry) - Step 6: Submit proposal (go_submit command + proposal hash entry) Changes: - Split Step 5 into two separate wizard steps - Removed unused collapse state management - Updated navigation logic to properly advance between steps - Modified useProposalSubmission hook to use callback for step advancement - Updated recovery flow to handle saved proposals correctly This makes the proposal creation process clearer and easier to understand. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/proposal/ProposalForm.jsx | 214 +++++++++--------- .../proposal/hooks/useProposalSubmission.js | 12 +- 2 files changed, 112 insertions(+), 114 deletions(-) diff --git a/src/components/proposal/ProposalForm.jsx b/src/components/proposal/ProposalForm.jsx index afbc721a..ea1cf231 100644 --- a/src/components/proposal/ProposalForm.jsx +++ b/src/components/proposal/ProposalForm.jsx @@ -1,7 +1,6 @@ -import React, {useState, useEffect, useMemo, useRef} from "react"; +import React, {useState, useEffect, useMemo, useRef, useCallback} from "react"; import {CopyToClipboard} from "react-copy-to-clipboard"; import swal from "sweetalert2"; -import {Collapse} from 'react-collapse'; import {useHistory} from "react-router"; import {useForm} from "react-hook-form"; import {ErrorMessage} from '@hookform/error-message'; @@ -46,8 +45,6 @@ function ProposalForm() { //COMPONENT STATES const [currentStep, setCurrentStep] = useState(0); const [openModal, setOpenModal] = useState(false); - const [collapse, setCollapse] = useState(true); - const [useCollapse, setUseCollapse] = useState(false); //PROPOSAL STATES const [title, setTitle] = useState(''); @@ -61,12 +58,15 @@ function ProposalForm() { const cancelSource = useMemo(() => axios.CancelToken.source(), []); + const onPaymentTxIdEntered = useCallback(() => { + next(); // Move to step 6 (submit proposal) + }, []); + const { enterPaymentTxId, enterProposalHash } = useProposalSubmission({ proposalUid, history, setSubmitCommand, - setUseCollapse, - setCollapse, + onPaymentTxIdEntered, }); const {register, handleSubmit, errors} = useForm({ @@ -179,10 +179,15 @@ function ProposalForm() { * @function */ const continueProposal = () => { - setCurrentStep(4); if (submitCommand !== "") { - setUseCollapse(true); - setCollapse(false); + // If submit command exists, go to step 6 (submit) + setCurrentStep(5); + } else if (prepareCommand !== "") { + // If only prepare command exists, go to step 5 (prepare) + setCurrentStep(4); + } else { + // Otherwise go to step 5 (prepare) to start fresh + setCurrentStep(4); } setOpenModal(false); } @@ -200,8 +205,6 @@ function ProposalForm() { confirmButtonText: 'Delete' }) if (swalConfirm.isConfirmed) { - setUseCollapse(false); - setCollapse(true); cancelCurrentProposal(); } } @@ -371,122 +374,115 @@ function ProposalForm() {
- 5Create proposal + 5Prepare proposal
- -
-
- - - - -
- -

- Prepare command is ready to be copied. Please copy and paste it into Syscoin Q.T console for payment txid. -

-
-
- -
+
+
+ - +
+ +

+ Prepare command is ready to be copied. Please copy and paste it into Syscoin Q.T console for payment txid. +

+
+
-
-
- - -

{message}

} - /> -
-
- - -
-
- - - - - -
- {/* Disclaimer about waiting before go_submit */} -
- Important: Please wait at least 5 minutes or 1 block confirmation after sending the payment transaction before running go_submit. Submitting too early may cause your proposal to fail. -
-
- - - - -
- -

- Submit command is ready to be copied. Please copy and paste it into Syscoin Q.T console to submit your proposal. This could take a couple minutes. -

-
-
+
+ + + +
+
+
+ + +

{message}

} + /> +
+ + +
+
+
+ +
+ 6Submit proposal +
+
+
+ {/* Disclaimer about waiting before go_submit */} +
+ Important: Please wait at least 5 minutes or 1 block confirmation after sending the payment transaction before running go_submit. Submitting too early may cause your proposal to fail. +
+
+ - +
+ +

+ Submit command is ready to be copied. Please copy and paste it into Syscoin Q.T console to submit your proposal. This could take a couple minutes. +

+
+
-
-
- - -

{message}

} - /> -
-
- - -
-
- +
+ + + +
+ +
+
+ + +

{message}

} + /> +
+
+ + +
+
diff --git a/src/components/proposal/hooks/useProposalSubmission.js b/src/components/proposal/hooks/useProposalSubmission.js index e76c7bf0..2aa65408 100644 --- a/src/components/proposal/hooks/useProposalSubmission.js +++ b/src/components/proposal/hooks/useProposalSubmission.js @@ -18,8 +18,7 @@ const useProposalSubmission = ({ proposalUid, history, setSubmitCommand, - setUseCollapse, - setCollapse, + onPaymentTxIdEntered, }) => { const ensureProposalUid = useCallback(async () => { if (!proposalUid) { @@ -91,8 +90,6 @@ const useProposalSubmission = ({ } setSubmitCommand(commandSubmit) - setUseCollapse(true) - setCollapse(false) await swal.fire({ icon: 'success', @@ -100,6 +97,11 @@ const useProposalSubmission = ({ timer: 2000, showConfirmButton: false, }) + + // Advance to the next step (Step 6: Submit proposal) + if (onPaymentTxIdEntered) { + onPaymentTxIdEntered() + } } catch (error) { logAxiosError('useProposalSubmission::enterPaymentTxId', error, { proposalUid, @@ -120,7 +122,7 @@ const useProposalSubmission = ({ clearCancelSource(cancelSource) } }, - [clearCancelSource, createCancelSource, ensureProposalUid, proposalUid, setCollapse, setSubmitCommand, setUseCollapse] + [clearCancelSource, createCancelSource, ensureProposalUid, proposalUid, setSubmitCommand, onPaymentTxIdEntered] ) const confirmProposalCompletion = useCallback( From 8a132ac47ac4f5dfa3fd4bba0d25ac50f95f081c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Oct 2025 02:18:28 +0000 Subject: [PATCH 2/3] Refactor proposal creation into separate components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created two new components to reduce bloat in ProposalForm.jsx: - PrepareProposal.jsx: Handles Step 5 (go_prepare command and payment txId) - SubmitProposal.jsx: Handles Step 6 (go_submit command and proposal hash) Changes: - Extracted Step 5 logic into PrepareProposal component - Extracted Step 6 logic into SubmitProposal component - Moved validation schemas to individual components - Removed unused imports from ProposalForm.jsx - Reduced ProposalForm.jsx from ~490 lines to ~390 lines - Improved code maintainability and reusability Benefits: - Cleaner, more modular code structure - Each component now has a single responsibility - Easier to test and maintain individual steps - Better separation of concerns 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/proposal/PrepareProposal.jsx | 101 +++++++++++++ src/components/proposal/ProposalForm.jsx | 153 ++------------------ src/components/proposal/SubmitProposal.jsx | 105 ++++++++++++++ 3 files changed, 219 insertions(+), 140 deletions(-) create mode 100644 src/components/proposal/PrepareProposal.jsx create mode 100644 src/components/proposal/SubmitProposal.jsx diff --git a/src/components/proposal/PrepareProposal.jsx b/src/components/proposal/PrepareProposal.jsx new file mode 100644 index 00000000..31751c2d --- /dev/null +++ b/src/components/proposal/PrepareProposal.jsx @@ -0,0 +1,101 @@ +import React from "react"; +import {CopyToClipboard} from "react-copy-to-clipboard"; +import {useForm} from "react-hook-form"; +import {ErrorMessage} from '@hookform/error-message'; +import {yupResolver} from '@hookform/resolvers'; +import * as yup from "yup"; +import swal from "sweetalert2"; + +const schema = yup.object().shape({ + paymentTxId: yup.string() + .test('len', 'Must be exactly 64 characters', val => val.length === 64) + .required('Payment txid is required') +}); + +/** + * Component to show the prepare proposal step (Step 5) + * @component + * @subcategory Proposal + * @example + * return ( + * + * ) + */ +function PrepareProposal({ prepareCommand, onSubmit, onCancel }) { + const {register, handleSubmit, errors} = useForm({ + mode: 'onSubmit', + resolver: yupResolver(schema) + }); + + /** + * function that triggers sweet alert to show the copy is successful + * @function + */ + const copyButton = () => { + swal.fire({ + icon: "success", + title: "Copied", + timer: 2000, + showConfirmButton: false, + }); + } + + return ( +
+
+
+ + + + +
+ +

+ Prepare command is ready to be copied. Please copy and paste it into Syscoin Q.T console for payment txid. +

+
+
+ +
+ + + +
+ +
+
+ + +

{message}

} + /> +
+
+ + +
+
+
+ ); +} + +export default PrepareProposal; diff --git a/src/components/proposal/ProposalForm.jsx b/src/components/proposal/ProposalForm.jsx index ea1cf231..db5ae20b 100644 --- a/src/components/proposal/ProposalForm.jsx +++ b/src/components/proposal/ProposalForm.jsx @@ -1,11 +1,6 @@ import React, {useState, useEffect, useMemo, useRef, useCallback} from "react"; -import {CopyToClipboard} from "react-copy-to-clipboard"; import swal from "sweetalert2"; import {useHistory} from "react-router"; -import {useForm} from "react-hook-form"; -import {ErrorMessage} from '@hookform/error-message'; -import {yupResolver} from '@hookform/resolvers'; -import * as yup from "yup"; import {checkProposal, prepareProposal, notCompletedProposal, destroyProposal} from "../../utils/request"; import {getAxiosErrorFooter, getAxiosErrorMessage, logAxiosError} from "../../utils/errorHandler"; @@ -15,21 +10,11 @@ import TitleProposal from './TitleProposal'; import DescriptionProposal from './DescriptionProposal'; import PaymentProposal from './PaymentProposal'; import ProposalPreview from "./ProposalPreview"; +import PrepareProposal from "./PrepareProposal"; +import SubmitProposal from "./SubmitProposal"; import axios from 'axios'; import useProposalSubmission from './hooks/useProposalSubmission'; - -const schema = yup.object().shape({ - paymentTxId: yup.string() - .test('len', 'Must be exactly 64 characters', val => val.length === 64) - .required('Payment txid is required') -}); -const schema2 = yup.object().shape({ - proposalHash: yup.string() - .test('len', 'Must be exactly 64 characters', val => val.length === 64) - .required('proposal hash is required') -}); - /** * Component to show the create Proposal form * @component @@ -69,15 +54,6 @@ function ProposalForm() { onPaymentTxIdEntered, }); - const {register, handleSubmit, errors} = useForm({ - mode: 'onSubmit', - resolver: yupResolver(schema) - }); - const {register: register2, handleSubmit: handleSubmit2, errors: errors2} = useForm({ - mode: 'onSubmit', - resolver: yupResolver(schema2) - }); - /** * UseEffect at mounting to get saved proposal * @function @@ -219,25 +195,12 @@ function ProposalForm() { /** * function to set next step of the proposal form - * @function + * @function */ const next = () => { setCurrentStep(currentStep + 1); }; - /** - * function that triggers sweet alert to show the copy is successful - * @function - */ - const copyButton = () => { - swal.fire({ - icon: "success", - title: "Copied", - timer: 2000, - showConfirmButton: false, - }); - } - /** * function that sets in the state the title from the input * @function @@ -377,112 +340,22 @@ function ProposalForm() { 5Prepare proposal
-
-
- - - - -
- -

- Prepare command is ready to be copied. Please copy and paste it into Syscoin Q.T console for payment txid. -

-
-
- -
- - - -
- -
-
- - -

{message}

} - /> -
-
- - -
-
+
6Submit proposal
-
- {/* Disclaimer about waiting before go_submit */} -
- Important: Please wait at least 5 minutes or 1 block confirmation after sending the payment transaction before running go_submit. Submitting too early may cause your proposal to fail. -
-
- - - - -
- -

- Submit command is ready to be copied. Please copy and paste it into Syscoin Q.T console to submit your proposal. This could take a couple minutes. -

-
-
- -
- - - -
- -
-
- - -

{message}

} - /> -
-
- - -
-
+
diff --git a/src/components/proposal/SubmitProposal.jsx b/src/components/proposal/SubmitProposal.jsx new file mode 100644 index 00000000..026872cf --- /dev/null +++ b/src/components/proposal/SubmitProposal.jsx @@ -0,0 +1,105 @@ +import React from "react"; +import {CopyToClipboard} from "react-copy-to-clipboard"; +import {useForm} from "react-hook-form"; +import {ErrorMessage} from '@hookform/error-message'; +import {yupResolver} from '@hookform/resolvers'; +import * as yup from "yup"; +import swal from "sweetalert2"; + +const schema = yup.object().shape({ + proposalHash: yup.string() + .test('len', 'Must be exactly 64 characters', val => val.length === 64) + .required('proposal hash is required') +}); + +/** + * Component to show the submit proposal step (Step 6) + * @component + * @subcategory Proposal + * @example + * return ( + * + * ) + */ +function SubmitProposal({ submitCommand, onSubmit, onCancel }) { + const {register, handleSubmit, errors} = useForm({ + mode: 'onSubmit', + resolver: yupResolver(schema) + }); + + /** + * function that triggers sweet alert to show the copy is successful + * @function + */ + const copyButton = () => { + swal.fire({ + icon: "success", + title: "Copied", + timer: 2000, + showConfirmButton: false, + }); + } + + return ( +
+
+ {/* Disclaimer about waiting before go_submit */} +
+ Important: Please wait at least 5 minutes or 1 block confirmation after sending the payment transaction before running go_submit. Submitting too early may cause your proposal to fail. +
+
+ + + + +
+ +

+ Submit command is ready to be copied. Please copy and paste it into Syscoin Q.T console to submit your proposal. This could take a couple minutes. +

+
+
+ +
+ + + +
+ +
+
+ + +

{message}

} + /> +
+
+ + +
+
+
+ ); +} + +export default SubmitProposal; From 04f730451ad58c162bdfff5ac8a8f88eb8e1d048 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Oct 2025 05:56:53 +0000 Subject: [PATCH 3/3] Fix lint issues in proposal components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix yup validation to handle null/undefined values - Use consistent quote style (single quotes) for imports - Fix useCallback dependency issue in ProposalForm - Add semicolons for consistency Changes: - PrepareProposal.jsx: Update quotes and add null check in yup validator - SubmitProposal.jsx: Update quotes and add null check in yup validator - ProposalForm.jsx: Fix useCallback to use functional setState 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/proposal/PrepareProposal.jsx | 18 +++++++++--------- src/components/proposal/ProposalForm.jsx | 2 +- src/components/proposal/SubmitProposal.jsx | 18 +++++++++--------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/components/proposal/PrepareProposal.jsx b/src/components/proposal/PrepareProposal.jsx index 31751c2d..20d10e54 100644 --- a/src/components/proposal/PrepareProposal.jsx +++ b/src/components/proposal/PrepareProposal.jsx @@ -1,14 +1,14 @@ -import React from "react"; -import {CopyToClipboard} from "react-copy-to-clipboard"; -import {useForm} from "react-hook-form"; +import React from 'react'; +import {CopyToClipboard} from 'react-copy-to-clipboard'; +import {useForm} from 'react-hook-form'; import {ErrorMessage} from '@hookform/error-message'; import {yupResolver} from '@hookform/resolvers'; -import * as yup from "yup"; -import swal from "sweetalert2"; +import * as yup from 'yup'; +import swal from 'sweetalert2'; const schema = yup.object().shape({ paymentTxId: yup.string() - .test('len', 'Must be exactly 64 characters', val => val.length === 64) + .test('len', 'Must be exactly 64 characters', val => val && val.length === 64) .required('Payment txid is required') }); @@ -37,12 +37,12 @@ function PrepareProposal({ prepareCommand, onSubmit, onCancel }) { */ const copyButton = () => { swal.fire({ - icon: "success", - title: "Copied", + icon: 'success', + title: 'Copied', timer: 2000, showConfirmButton: false, }); - } + }; return (
diff --git a/src/components/proposal/ProposalForm.jsx b/src/components/proposal/ProposalForm.jsx index db5ae20b..21ce6219 100644 --- a/src/components/proposal/ProposalForm.jsx +++ b/src/components/proposal/ProposalForm.jsx @@ -44,7 +44,7 @@ function ProposalForm() { const cancelSource = useMemo(() => axios.CancelToken.source(), []); const onPaymentTxIdEntered = useCallback(() => { - next(); // Move to step 6 (submit proposal) + setCurrentStep(prev => prev + 1); // Move to step 6 (submit proposal) }, []); const { enterPaymentTxId, enterProposalHash } = useProposalSubmission({ diff --git a/src/components/proposal/SubmitProposal.jsx b/src/components/proposal/SubmitProposal.jsx index 026872cf..e38f9c03 100644 --- a/src/components/proposal/SubmitProposal.jsx +++ b/src/components/proposal/SubmitProposal.jsx @@ -1,14 +1,14 @@ -import React from "react"; -import {CopyToClipboard} from "react-copy-to-clipboard"; -import {useForm} from "react-hook-form"; +import React from 'react'; +import {CopyToClipboard} from 'react-copy-to-clipboard'; +import {useForm} from 'react-hook-form'; import {ErrorMessage} from '@hookform/error-message'; import {yupResolver} from '@hookform/resolvers'; -import * as yup from "yup"; -import swal from "sweetalert2"; +import * as yup from 'yup'; +import swal from 'sweetalert2'; const schema = yup.object().shape({ proposalHash: yup.string() - .test('len', 'Must be exactly 64 characters', val => val.length === 64) + .test('len', 'Must be exactly 64 characters', val => val && val.length === 64) .required('proposal hash is required') }); @@ -37,12 +37,12 @@ function SubmitProposal({ submitCommand, onSubmit, onCancel }) { */ const copyButton = () => { swal.fire({ - icon: "success", - title: "Copied", + icon: 'success', + title: 'Copied', timer: 2000, showConfirmButton: false, }); - } + }; return (