Skip to content

Commit 6ff16f7

Browse files
osiastedianclaude
andauthored
Simplify Proposal Creation and Sending Process (#163)
* Separate proposal creation into two distinct steps 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 <noreply@anthropic.com> * Refactor proposal creation into separate components 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 <noreply@anthropic.com> * Fix lint issues in proposal components - 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 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e09aec3 commit 6ff16f7

4 files changed

Lines changed: 246 additions & 169 deletions

File tree

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import React from 'react';
2+
import {CopyToClipboard} from 'react-copy-to-clipboard';
3+
import {useForm} from 'react-hook-form';
4+
import {ErrorMessage} from '@hookform/error-message';
5+
import {yupResolver} from '@hookform/resolvers';
6+
import * as yup from 'yup';
7+
import swal from 'sweetalert2';
8+
9+
const schema = yup.object().shape({
10+
paymentTxId: yup.string()
11+
.test('len', 'Must be exactly 64 characters', val => val && val.length === 64)
12+
.required('Payment txid is required')
13+
});
14+
15+
/**
16+
* Component to show the prepare proposal step (Step 5)
17+
* @component
18+
* @subcategory Proposal
19+
* @example
20+
* return (
21+
* <PrepareProposal
22+
* prepareCommand={prepareCommand}
23+
* onSubmit={handlePaymentTxId}
24+
* onCancel={handleCancel}
25+
* />
26+
* )
27+
*/
28+
function PrepareProposal({ prepareCommand, onSubmit, onCancel }) {
29+
const {register, handleSubmit, errors} = useForm({
30+
mode: 'onSubmit',
31+
resolver: yupResolver(schema)
32+
});
33+
34+
/**
35+
* function that triggers sweet alert to show the copy is successful
36+
* @function
37+
*/
38+
const copyButton = () => {
39+
swal.fire({
40+
icon: 'success',
41+
title: 'Copied',
42+
timer: 2000,
43+
showConfirmButton: false,
44+
});
45+
};
46+
47+
return (
48+
<div>
49+
<div className="form-group article">
50+
<div className="cli-command-container">
51+
<textarea
52+
className="styled"
53+
name="prepareCommand"
54+
id="prepareCommand"
55+
rows="5"
56+
disabled
57+
value={prepareCommand}
58+
></textarea>
59+
<CopyToClipboard
60+
text={prepareCommand}
61+
onCopy={copyButton}
62+
>
63+
<button className="copy-icon" type="button" title="Copy command">📋</button>
64+
</CopyToClipboard>
65+
</div>
66+
<small>
67+
<p style={{lineHeight: "1.5"}}>
68+
Prepare command is ready to be copied. Please copy and paste it into Syscoin Q.T console for payment txid.
69+
</p>
70+
</small>
71+
</div>
72+
73+
<div className="form-actions-spaced">
74+
<CopyToClipboard
75+
text={prepareCommand}
76+
onCopy={copyButton}
77+
>
78+
<button className="btn btn--blue" type="button">Copy Command</button>
79+
</CopyToClipboard>
80+
</div>
81+
82+
<form className="input-form" onSubmit={handleSubmit(onSubmit)}>
83+
<div className="form-group">
84+
<label htmlFor="paymentTxId">Payment txid</label>
85+
<input type="text" id="paymentTxId" ref={register} name="paymentTxId" className="styled" maxLength="64"/>
86+
<ErrorMessage
87+
errors={errors}
88+
name="paymentTxId"
89+
render={({message}) => <small><p style={{lineHeight: '1.5'}}>{message}</p></small>}
90+
/>
91+
</div>
92+
<div className="form-actions-spaced">
93+
<button className="btn btn-outline-primary" type="button" onClick={onCancel}>Cancel</button>
94+
<button className="btn btn--blue" type="submit">Next</button>
95+
</div>
96+
</form>
97+
</div>
98+
);
99+
}
100+
101+
export default PrepareProposal;

src/components/proposal/ProposalForm.jsx

Lines changed: 33 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
import React, {useState, useEffect, useMemo, useRef} from "react";
2-
import {CopyToClipboard} from "react-copy-to-clipboard";
1+
import React, {useState, useEffect, useMemo, useRef, useCallback} from "react";
32
import swal from "sweetalert2";
4-
import {Collapse} from 'react-collapse';
53
import {useHistory} from "react-router";
6-
import {useForm} from "react-hook-form";
7-
import {ErrorMessage} from '@hookform/error-message';
8-
import {yupResolver} from '@hookform/resolvers';
9-
import * as yup from "yup";
104

115
import {checkProposal, prepareProposal, notCompletedProposal, destroyProposal} from "../../utils/request";
126
import {getAxiosErrorFooter, getAxiosErrorMessage, logAxiosError} from "../../utils/errorHandler";
@@ -16,21 +10,11 @@ import TitleProposal from './TitleProposal';
1610
import DescriptionProposal from './DescriptionProposal';
1711
import PaymentProposal from './PaymentProposal';
1812
import ProposalPreview from "./ProposalPreview";
13+
import PrepareProposal from "./PrepareProposal";
14+
import SubmitProposal from "./SubmitProposal";
1915
import axios from 'axios';
2016
import useProposalSubmission from './hooks/useProposalSubmission';
2117

22-
23-
const schema = yup.object().shape({
24-
paymentTxId: yup.string()
25-
.test('len', 'Must be exactly 64 characters', val => val.length === 64)
26-
.required('Payment txid is required')
27-
});
28-
const schema2 = yup.object().shape({
29-
proposalHash: yup.string()
30-
.test('len', 'Must be exactly 64 characters', val => val.length === 64)
31-
.required('proposal hash is required')
32-
});
33-
3418
/**
3519
* Component to show the create Proposal form
3620
* @component
@@ -46,8 +30,6 @@ function ProposalForm() {
4630
//COMPONENT STATES
4731
const [currentStep, setCurrentStep] = useState(0);
4832
const [openModal, setOpenModal] = useState(false);
49-
const [collapse, setCollapse] = useState(true);
50-
const [useCollapse, setUseCollapse] = useState(false);
5133

5234
//PROPOSAL STATES
5335
const [title, setTitle] = useState('');
@@ -61,21 +43,15 @@ function ProposalForm() {
6143

6244
const cancelSource = useMemo(() => axios.CancelToken.source(), []);
6345

46+
const onPaymentTxIdEntered = useCallback(() => {
47+
setCurrentStep(prev => prev + 1); // Move to step 6 (submit proposal)
48+
}, []);
49+
6450
const { enterPaymentTxId, enterProposalHash } = useProposalSubmission({
6551
proposalUid,
6652
history,
6753
setSubmitCommand,
68-
setUseCollapse,
69-
setCollapse,
70-
});
71-
72-
const {register, handleSubmit, errors} = useForm({
73-
mode: 'onSubmit',
74-
resolver: yupResolver(schema)
75-
});
76-
const {register: register2, handleSubmit: handleSubmit2, errors: errors2} = useForm({
77-
mode: 'onSubmit',
78-
resolver: yupResolver(schema2)
54+
onPaymentTxIdEntered,
7955
});
8056

8157
/**
@@ -179,10 +155,15 @@ function ProposalForm() {
179155
* @function
180156
*/
181157
const continueProposal = () => {
182-
setCurrentStep(4);
183158
if (submitCommand !== "") {
184-
setUseCollapse(true);
185-
setCollapse(false);
159+
// If submit command exists, go to step 6 (submit)
160+
setCurrentStep(5);
161+
} else if (prepareCommand !== "") {
162+
// If only prepare command exists, go to step 5 (prepare)
163+
setCurrentStep(4);
164+
} else {
165+
// Otherwise go to step 5 (prepare) to start fresh
166+
setCurrentStep(4);
186167
}
187168
setOpenModal(false);
188169
}
@@ -200,8 +181,6 @@ function ProposalForm() {
200181
confirmButtonText: 'Delete'
201182
})
202183
if (swalConfirm.isConfirmed) {
203-
setUseCollapse(false);
204-
setCollapse(true);
205184
cancelCurrentProposal();
206185
}
207186
}
@@ -216,25 +195,12 @@ function ProposalForm() {
216195

217196
/**
218197
* function to set next step of the proposal form
219-
* @function
198+
* @function
220199
*/
221200
const next = () => {
222201
setCurrentStep(currentStep + 1);
223202
};
224203

225-
/**
226-
* function that triggers sweet alert to show the copy is successful
227-
* @function
228-
*/
229-
const copyButton = () => {
230-
swal.fire({
231-
icon: "success",
232-
title: "Copied",
233-
timer: 2000,
234-
showConfirmButton: false,
235-
});
236-
}
237-
238204
/**
239205
* function that sets in the state the title from the input
240206
* @function
@@ -371,122 +337,25 @@ function ProposalForm() {
371337
</div>
372338

373339
<div className="wizard-head">
374-
<span>5</span>Create proposal
340+
<span>5</span>Prepare proposal
375341
</div>
376342
<div className={`wizard-body ${currentStep === 4 ? "" : "collapsed"}`}>
377-
<Collapse
378-
isOpened={collapse}
379-
initialStyle={{height: 0, overflow: 'hidden'}}
380-
>
381-
<div className="form-group article">
382-
<div className="cli-command-container">
383-
<textarea
384-
className="styled"
385-
name="prepareCommand"
386-
id="prepareCommand"
387-
rows="5"
388-
disabled
389-
value={prepareCommand}
390-
></textarea>
391-
<CopyToClipboard
392-
text={prepareCommand}
393-
onCopy={copyButton}
394-
>
395-
<button className="copy-icon" type="button" title="Copy command">📋</button>
396-
</CopyToClipboard>
397-
</div>
398-
<small>
399-
<p style={{lineHeight: "1.5"}}>
400-
Prepare command is ready to be copied. Please copy and paste it into Syscoin Q.T console for payment txid.
401-
</p>
402-
</small>
403-
</div>
404-
405-
<div className="form-actions-spaced">
406-
<CopyToClipboard
407-
text={prepareCommand}
408-
onCopy={copyButton}
409-
>
410-
<button className="btn btn--blue" type="button">Copy Command</button>
411-
</CopyToClipboard>
412-
</div>
413-
414-
<form className="input-form" onSubmit={handleSubmit(enterPaymentTxId)}>
415-
<div className="form-group">
416-
<label htmlFor="paymentTxId">Payment txid</label>
417-
<input type="text" id="paymentTxId" ref={register} name="paymentTxId" className="styled" maxLength="64"/>
418-
<ErrorMessage
419-
errors={errors}
420-
name="paymentTxId"
421-
render={({message}) => <small><p style={{lineHeight: '1.5'}}>{message}</p></small>}
422-
/>
423-
</div>
424-
<div className="form-actions-spaced">
425-
<button className="btn btn-outline-primary" type="button" onClick={cancelProposalBtn}>Cancel</button>
426-
<button className="btn btn--blue" type="submit">Next</button>
427-
</div>
428-
</form>
429-
430-
</Collapse>
431-
432-
433-
<Collapse
434-
isOpened={useCollapse}
435-
initialStyle={{height: 0, overflow: 'hidden'}}
436-
>
437-
<div className="form-group article">
438-
{/* Disclaimer about waiting before go_submit */}
439-
<div className="alert alert-warning mb-3 py-2 px-3" role="alert">
440-
<strong>Important:</strong> Please wait at least <b>5 minutes</b> or <b>1 block confirmation</b> after sending the payment transaction before running <code>go_submit</code>. Submitting too early may cause your proposal to fail.
441-
</div>
442-
<div className="cli-command-container">
443-
<textarea
444-
className="styled"
445-
name="submitCommand"
446-
id="submitCommand"
447-
rows="5"
448-
disabled
449-
value={submitCommand}
450-
></textarea>
451-
<CopyToClipboard
452-
text={submitCommand}
453-
onCopy={copyButton}
454-
>
455-
<button className="copy-icon" type="button" title="Copy command">📋</button>
456-
</CopyToClipboard>
457-
</div>
458-
<small>
459-
<p style={{lineHeight: "1.5"}}>
460-
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.
461-
</p>
462-
</small>
463-
</div>
464-
465-
<div className="form-actions-spaced">
466-
<CopyToClipboard
467-
text={submitCommand}
468-
onCopy={copyButton}
469-
>
470-
<button className="btn btn--blue" type="button">Copy Command</button>
471-
</CopyToClipboard>
472-
</div>
343+
<PrepareProposal
344+
prepareCommand={prepareCommand}
345+
onSubmit={enterPaymentTxId}
346+
onCancel={cancelProposalBtn}
347+
/>
348+
</div>
473349

474-
<form className="input-form" onSubmit={handleSubmit2(enterProposalHash)}>
475-
<div className="form-group">
476-
<label htmlFor="proposalHash">Proposal hash</label>
477-
<input type="text" id="proposalHash" ref={register2} name="proposalHash" className="styled" maxLength="64"/>
478-
<ErrorMessage
479-
errors={errors2}
480-
name="proposalHash"
481-
render={({message}) => <small><p style={{lineHeight: '1.5'}}>{message}</p></small>}
482-
/>
483-
</div>
484-
<div className="form-actions-spaced">
485-
<button className="btn btn-outline-primary" type="button" onClick={cancelProposalBtn}>Cancel</button>
486-
<button className="btn btn--blue" type="submit">Submit</button>
487-
</div>
488-
</form>
489-
</Collapse>
350+
<div className="wizard-head">
351+
<span>6</span>Submit proposal
352+
</div>
353+
<div className={`wizard-body ${currentStep === 5 ? "" : "collapsed"}`}>
354+
<SubmitProposal
355+
submitCommand={submitCommand}
356+
onSubmit={enterProposalHash}
357+
onCancel={cancelProposalBtn}
358+
/>
490359
</div>
491360
</div>
492361
</div>

0 commit comments

Comments
 (0)