1- import React from 'react' ;
1+ import React , { useEffect , useState } from 'react' ;
22import PropTypes from 'prop-types' ;
3- import * as Yup from 'yup' ;
3+ import { ExclamationCircleIcon } from '@patternfly/react-icons' ;
4+ import {
5+ Button ,
6+ Form ,
7+ FormGroup ,
8+ TextInput ,
9+ Checkbox ,
10+ ActionGroup ,
11+ HelperText ,
12+ HelperTextItem ,
13+ FormHelperText ,
14+ } from '@patternfly/react-core' ;
415import { useDispatch } from 'react-redux' ;
5- import { noop } from '../../common/helpers' ;
6- import ForemanForm from '../common/forms/ForemanForm' ;
7- import TextField from '../common/forms/TextField' ;
8- import { translate as __ } from '../../common/I18n' ;
9- import { maxLengthMsg , requiredMsg } from '../common/forms/validators' ;
10- import { submitForm } from '../../redux/actions/common/forms' ;
16+ import { sprintf , translate as __ } from '../../common/I18n' ;
17+ import { APIActions } from '../../redux/API' ;
18+ import './bookmarkForm.css' ;
1119
1220const BookmarkForm = ( {
1321 url,
1422 controller,
15- onCancel,
1623 searchQuery,
1724 setModalClosed,
1825 bookmarks,
1926} ) => {
2027 const dispatch = useDispatch ( ) ;
21- const existsNamesRegex = new RegExp (
22- `^(?!(${ bookmarks . map ( ( { name } ) => name ) . join ( '|' ) } )$).+`
28+ const existingNames = bookmarks . map ( ( { name } ) => name ) ;
29+
30+ const NAME_MAX_LENGTH = 255 ;
31+ const NAME_MIN_LENGTH = 1 ;
32+ const SUCCESS_TYPE = 'success' ;
33+ const ERROR_TYPE = 'error' ;
34+ const BLANK_ERROR = "Can't be blank" ;
35+
36+ const nameTooLongMsg = sprintf (
37+ __ ( 'Name is too long, max %s' ) ,
38+ NAME_MAX_LENGTH
2339 ) ;
24- const bookmarkFormSchema = Yup . object ( ) . shape ( {
25- name : Yup . string ( )
26- . max ( ...maxLengthMsg ( 254 ) )
27- . required ( requiredMsg ( ) )
28- . matches ( existsNamesRegex , {
29- excludeEmptyString : true ,
30- message : __ ( 'name already exists' ) ,
31- } ) ,
32- query : Yup . string ( )
33- . max ( ...maxLengthMsg ( 4096 ) )
34- . required ( requiredMsg ( ) ) ,
35- } ) ;
3640
37- const handleSubmit = ( values , actions ) =>
41+ const nameExists = __ ( 'Name already exists' ) ;
42+ const nameShort = __ ( BLANK_ERROR ) ;
43+ const blankInputErrMsg = __ ( BLANK_ERROR ) ;
44+
45+ const [ name , setName ] = useState ( '' ) ;
46+ const [ query , setQuery ] = useState ( searchQuery ) ;
47+ const [ isPublic , setIsPublic ] = useState ( true ) ;
48+
49+ const [ nameErrorMsg , setNameErrorMsg ] = useState ( '' ) ;
50+ const [ nameValidated , setNameValidated ] = useState ( '' ) ;
51+ const [ queryErrorMsg , setQueryErrorMsg ] = useState ( '' ) ;
52+ const [ queryValidated , setQueryValidated ] = useState ( '' ) ;
53+
54+ const validateName = value => {
55+ if ( value . length > NAME_MAX_LENGTH ) {
56+ setNameValidated ( ERROR_TYPE ) ;
57+ setNameErrorMsg ( nameTooLongMsg ) ;
58+ } else if ( value . length < NAME_MIN_LENGTH ) {
59+ setNameValidated ( ERROR_TYPE ) ;
60+ setNameErrorMsg ( nameShort ) ;
61+ } else if ( existingNames . includes ( value ) ) {
62+ setNameValidated ( ERROR_TYPE ) ;
63+ setNameErrorMsg ( nameExists ) ;
64+ } else {
65+ setNameValidated ( SUCCESS_TYPE ) ;
66+ }
67+ } ;
68+
69+ const validateQueryLength = value => {
70+ if ( value . length < 1 ) {
71+ setQueryValidated ( ERROR_TYPE ) ;
72+ setQueryErrorMsg ( blankInputErrMsg ) ;
73+ } else {
74+ setQueryValidated ( SUCCESS_TYPE ) ;
75+ }
76+ } ;
77+
78+ const handleSubmit = ( ) => {
3879 dispatch (
39- submitForm ( {
80+ APIActions . post ( {
81+ key : 'BOOKMARKS_FORM_SUBMITTED' ,
4082 url,
41- values : { ...values , controller } ,
42- item : 'Bookmarks' ,
43- message : __ ( 'Bookmark was successfully created.' ) ,
44- successCallback : setModalClosed ,
45- actions,
83+ params : {
84+ public : isPublic ,
85+ controller,
86+ query,
87+ name,
88+ } ,
89+ handleSuccess : setModalClosed ,
90+ successToast : ( ) => __ ( 'Bookmark created.' ) ,
91+ errorToast : ( { response } ) =>
92+ // eslint-disable-next-line camelcase
93+ response ?. data ?. error ?. full_messages ?. [ 0 ] || response ,
4694 } )
4795 ) ;
96+ } ;
97+
98+ const isValidated =
99+ nameValidated === SUCCESS_TYPE && queryValidated === SUCCESS_TYPE ;
100+
101+ useEffect ( ( ) => {
102+ if ( searchQuery !== '' ) {
103+ validateQueryLength ( query ) ;
104+ }
105+ } ) ;
106+
107+ const handleNameChange = ( _event , value ) => {
108+ validateName ( value ) ;
109+ setName ( value ) ;
110+ } ;
111+
112+ const handleQueryChange = ( _event , value ) => {
113+ validateQueryLength ( value ) ;
114+ setQuery ( value ) ;
115+ } ;
116+
117+ const handleIsPublicChange = ( _event , value ) => {
118+ setIsPublic ( value ) ;
119+ } ;
48120
49121 return (
50- < ForemanForm
51- onSubmit = { handleSubmit }
52- initialValues = { {
53- public : true ,
54- query : searchQuery ,
55- } }
56- validationSchema = { bookmarkFormSchema }
57- onCancel = { onCancel }
58- >
59- < TextField name = "name" type = "text" required = "true" label = { __ ( 'Name' ) } />
60- < TextField
61- name = "query"
62- type = "textarea"
63- required = "true"
64- label = { __ ( 'Query' ) }
65- inputClassName = "col-md-8"
66- />
67- < TextField name = "public" type = "checkbox" label = { __ ( 'Public' ) } />
68- </ ForemanForm >
122+ < >
123+ < Form >
124+ < FormGroup label = { __ ( 'Name' ) } >
125+ < TextInput
126+ ouiaId = "name-input"
127+ id = "name-input"
128+ isRequired
129+ type = "text"
130+ name = "name"
131+ value = { name }
132+ onChange = { handleNameChange }
133+ validated = { nameValidated }
134+ />
135+ { nameValidated === ERROR_TYPE && (
136+ < FormHelperText >
137+ < HelperText >
138+ < HelperTextItem
139+ icon = { < ExclamationCircleIcon /> }
140+ variant = { nameValidated }
141+ >
142+ { nameErrorMsg }
143+ </ HelperTextItem >
144+ </ HelperText >
145+ </ FormHelperText >
146+ ) }
147+ </ FormGroup >
148+ < FormGroup label = { __ ( 'Query' ) } >
149+ < TextInput
150+ ouiaId = "query-input"
151+ id = "query-input"
152+ isRequired
153+ type = "text"
154+ name = "query"
155+ value = { query }
156+ onChange = { handleQueryChange }
157+ validated = { queryValidated }
158+ />
159+ { queryValidated === ERROR_TYPE && (
160+ < FormHelperText >
161+ < HelperText >
162+ < HelperTextItem
163+ icon = { < ExclamationCircleIcon /> }
164+ variant = { queryValidated }
165+ >
166+ { queryErrorMsg }
167+ </ HelperTextItem >
168+ </ HelperText >
169+ </ FormHelperText >
170+ ) }
171+ </ FormGroup >
172+ < Checkbox
173+ ouiaId = "isPublic-checkbox"
174+ id = "isPublic-checkbox"
175+ label = { __ ( 'Public' ) }
176+ isLabelBeforeButton
177+ isLabelWrapped
178+ isChecked = { isPublic }
179+ onChange = { handleIsPublicChange }
180+ />
181+ < ActionGroup >
182+ < Button
183+ ouiaId = "submit-btn"
184+ variant = "primary"
185+ isDisabled = { ! isValidated }
186+ onClick = { handleSubmit }
187+ >
188+ { __ ( 'Submit' ) }
189+ </ Button >
190+ < Button
191+ ouiaId = "cancel-btn"
192+ variant = "secondary"
193+ onClick = { setModalClosed }
194+ >
195+ { __ ( 'Cancel' ) }
196+ </ Button >
197+ </ ActionGroup >
198+ </ Form >
199+ </ >
69200 ) ;
70201} ;
71202
72203BookmarkForm . propTypes = {
73- onCancel : PropTypes . func ,
74204 controller : PropTypes . string . isRequired ,
75205 url : PropTypes . string . isRequired ,
76206 setModalClosed : PropTypes . func . isRequired ,
@@ -79,7 +209,6 @@ BookmarkForm.propTypes = {
79209} ;
80210
81211BookmarkForm . defaultProps = {
82- onCancel : noop ,
83212 bookmarks : [ ] ,
84213} ;
85214
0 commit comments