@@ -32,6 +32,7 @@ export function CreateCampaignForm({
3232 const [ validationErrors , setValidationErrors ] = useState < FormErrors > (
3333 validateForm ( { ...INITIAL_VALUES , acceptedTokens : assetOptions . slice ( 0 , 1 ) } ) ,
3434 ) ;
35+ const [ touchedFields , setTouchedFields ] = useState < Set < string > > ( new Set ( ) ) ;
3536 const [ isSubmitting , setIsSubmitting ] = useState ( false ) ;
3637
3738 useEffect ( ( ) => {
@@ -51,7 +52,16 @@ export function CreateCampaignForm({
5152 function update ( field : keyof typeof INITIAL_VALUES , value : any ) {
5253 const nextValues = { ...values , [ field ] : value } ;
5354 setValues ( nextValues ) ;
54- setValidationErrors ( validateForm ( nextValues ) ) ;
55+ if ( touchedFields . has ( field ) ) {
56+ setValidationErrors ( validateForm ( nextValues ) ) ;
57+ }
58+ }
59+
60+ function handleFieldBlur ( field : string ) {
61+ const newTouched = new Set ( touchedFields ) ;
62+ newTouched . add ( field ) ;
63+ setTouchedFields ( newTouched ) ;
64+ setValidationErrors ( validateForm ( values ) ) ;
5565 }
5666
5767 function toggleToken ( token : string ) {
@@ -115,11 +125,12 @@ export function CreateCampaignForm({
115125 type = "text"
116126 value = { values . creator }
117127 onChange = { ( event ) => update ( 'creator' , event . target . value ) }
128+ onBlur = { ( ) => handleFieldBlur ( 'creator' ) }
118129 placeholder = "G... creator public key"
119- className = { validationErrors . creator ? 'input-error' : '' }
130+ className = { validationErrors . creator && touchedFields . has ( 'creator' ) ? 'input-error' : '' }
120131 required
121132 />
122- { validationErrors . creator ? (
133+ { validationErrors . creator && touchedFields . has ( 'creator' ) ? (
123134 < span className = "field-error" > { validationErrors . creator } </ span >
124135 ) : null }
125136 </ label >
@@ -130,13 +141,14 @@ export function CreateCampaignForm({
130141 type = "text"
131142 value = { values . title }
132143 onChange = { ( event ) => update ( 'title' , event . target . value ) }
144+ onBlur = { ( ) => handleFieldBlur ( 'title' ) }
133145 placeholder = "Stellar community design sprint"
134146 minLength = { 4 }
135147 maxLength = { 80 }
136- className = { validationErrors . title ? 'input-error' : '' }
148+ className = { validationErrors . title && touchedFields . has ( 'title' ) ? 'input-error' : '' }
137149 required
138150 />
139- { validationErrors . title ? (
151+ { validationErrors . title && touchedFields . has ( 'title' ) ? (
140152 < span className = "field-error" > { validationErrors . title } </ span >
141153 ) : null }
142154 </ label >
@@ -146,14 +158,15 @@ export function CreateCampaignForm({
146158 < textarea
147159 value = { values . description }
148160 onChange = { ( event ) => update ( 'description' , event . target . value ) }
161+ onBlur = { ( ) => handleFieldBlur ( 'description' ) }
149162 placeholder = "Describe what the campaign funds, who benefits, and the delivery plan."
150163 rows = { 5 }
151164 minLength = { 20 }
152165 maxLength = { 500 }
153- className = { validationErrors . description ? 'input-error' : '' }
166+ className = { validationErrors . description && touchedFields . has ( 'description' ) ? 'input-error' : '' }
154167 required
155168 />
156- { validationErrors . description ? (
169+ { validationErrors . description && touchedFields . has ( 'description' ) ? (
157170 < span className = "field-error" > { validationErrors . description } </ span >
158171 ) : null }
159172 </ label >
@@ -167,12 +180,13 @@ export function CreateCampaignForm({
167180 type = "checkbox"
168181 checked = { values . acceptedTokens . includes ( asset ) }
169182 onChange = { ( ) => toggleToken ( asset ) }
183+ onBlur = { ( ) => handleFieldBlur ( 'acceptedTokens' ) }
170184 />
171185 { asset }
172186 </ label >
173187 ) ) }
174188 </ div >
175- { validationErrors . acceptedTokens ? (
189+ { validationErrors . acceptedTokens && touchedFields . has ( 'acceptedTokens' ) ? (
176190 < span className = "field-error" > { validationErrors . acceptedTokens } </ span >
177191 ) : null }
178192 </ div >
@@ -185,10 +199,11 @@ export function CreateCampaignForm({
185199 step = "0.01"
186200 value = { values . targetAmount }
187201 onChange = { ( event ) => update ( 'targetAmount' , event . target . value ) }
188- className = { validationErrors . targetAmount ? 'input-error' : '' }
202+ onBlur = { ( ) => handleFieldBlur ( 'targetAmount' ) }
203+ className = { validationErrors . targetAmount && touchedFields . has ( 'targetAmount' ) ? 'input-error' : '' }
189204 required
190205 />
191- { validationErrors . targetAmount ? (
206+ { validationErrors . targetAmount && touchedFields . has ( 'targetAmount' ) ? (
192207 < span className = "field-error" > { validationErrors . targetAmount } </ span >
193208 ) : null }
194209 </ label >
@@ -201,10 +216,11 @@ export function CreateCampaignForm({
201216 step = "0.0001"
202217 value = { values . deadlineHours }
203218 onChange = { ( event ) => update ( 'deadlineHours' , event . target . value ) }
204- className = { validationErrors . deadlineHours ? 'input-error' : '' }
219+ onBlur = { ( ) => handleFieldBlur ( 'deadlineHours' ) }
220+ className = { validationErrors . deadlineHours && touchedFields . has ( 'deadlineHours' ) ? 'input-error' : '' }
205221 required
206222 />
207- { validationErrors . deadlineHours ? (
223+ { validationErrors . deadlineHours && touchedFields . has ( 'deadlineHours' ) ? (
208224 < span className = "field-error" > { validationErrors . deadlineHours } </ span >
209225 ) : null }
210226 </ label >
0 commit comments