it('should fall back to using schema types', function() { let schema = yup.object({ string: yup.string(), number: yup.number(), date: yup.date(), bool: yup.bool(), array: yup.array().of(yup.string()), }) let wrapper = mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="string" /> <Form.Field name="number" /> <Form.Field name="date" /> <Form.Field name="bool" /> <Form.Field name="array" /> </Form> ) wrapper.assertSingle(`Input[name='string']`) wrapper.assertSingle(inputs.Number) wrapper.assertSingle(inputs.Bool) wrapper.assertSingle(inputs.Select) wrapper.assertSingle(inputs.Date) })
constructor (props, context) { super(props, context); const polyglot = new Polyglot({ phrases: props.phrases }); this.schema = yup.object({ name: yup.string().required(polyglot.t('name.required')), email: yup.string() .email(polyglot.t('email.invalid')) .required(polyglot.t('email.required')), body: yup.string().min(20).required(polyglot.t('body.required')) }); }
it('renders validation errors', async () => { props = { ...props, name: 'username', label: 'Username', placeholder: 'Username...', } const wrapper = mount( <Formik initialValues={{username: ''}} validationSchema={object().shape({ username: string().trim().required() })} render={() => (<Form><Input {...props}/></Form>)}/>) expect(wrapper.find(ErrorMessage).text()).to.be.null // Simulate an invalid username has been set wrapper.find("input[name='username']").simulate('change', {target: {id: 'username', value: ''}}) wrapper.find('form').simulate('submit') await tick() // Expect an error message to be rendered expect(wrapper.find(ErrorMessage).text()).to.be.equal('username is a required field') })
describe('Form Context', ()=> { var schema = yup.object({ name: yup.string().default('') }) it('should trigger an onSubmit in the Form', function(done) { var inst = tsp( <Form.Context> <Form onSubmit={sinon.spy(() => done())} schema={schema} defaultValue={{}} > <Form.Field name='name' type='text' className='test'/> </Form> <Form.Button type='submit' /> </Form.Context> ) inst .render() .find(Form.Button) .trigger('click') }) })
it('should use schema metadata', function() { let schema = yup.object({ string: yup.string().meta({ reactFormalType: 'number', }), }) mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="string" /> </Form> ).assertSingle(inputs.Number) })
render() { // This plays no "business" purpose, but is here to test that validation // constraints for the form can be dynamic const minLength = this.props.hasSearchTerm ? 2 : 3; const validationSchema = object().shape({ currentPokemon: string().min(minLength), }); return ( <div> <Heading level="4">Search for a pokemon name here!</Heading> <Spacer size="s" /> <Formik initialValues={{ currentPokemon: '' }} component={InnerForm} onSubmit={this.handleSubmit} validationSchema={validationSchema} validateOnChange={false} /> </div> ); }
render() { const { cursorVisibility, displayPrimaryID, displays, autoLaunch, devToolsShortcut, cookieName, cookieValue, cookieURL, } = this.state; const isValid = (errors, name) => !!_.get(errors, name); // // Forget disconnected displays if requested // // Handler for the forget button. // This updates the state, so that we can toggle the row style (ready to forget). // We also use Formik's setFieldValue to update the form values. These get sent to the // main process where it will delete this display from the settings store. // process to delete the display from the settings store. We use const forgetDisplay = (index, display, values, setFieldValue) => { const newDisplays = _.map(displays, (d) => { if (d.id === display.id) { return _.extend({}, d, { forgetting: !_.get(d, 'forgetting', false), }); } return d; }); setFieldValue(`displays[${index}].forgetting`, true); this.setState({ displays: newDisplays }); }; const generateDisplayRowClass = (display) => { const forgettingValue = _.get(_.find(displays, { id: display.id }), 'forgetting'); return classNames( display.connected ? '' : 'text-muted', forgettingValue ? 'table-danger' : '', ); }; return ( <Formik initialValues={{ displays, cursorVis: cursorVisibility, autoLaunch, devToolsShortcut, cookieName, cookieValue, cookieURL, }} onSubmit={(values, { setSubmitting }) => { setTimeout(() => { ipcRenderer.send('updateSettings', values); setSubmitting(false); }, 500); }} validationSchema={ object() .shape({ displays: array() .of( object() .shape({ url: string() .when('enabled', { is: true, then: string() .test( 'is-url', value => ( !!((validUrl.isHttpUri(value) || validUrl.isHttpsUri(value))) ), ) .required('Required'), }), }), ), }) } > {(props) => { const { values, errors, isSubmitting, handleChange, handleBlur, handleSubmit, setFieldValue, } = props; const { disconnectedDisplayTooltipOpen } = this.state; return ( <Container> <Row className="mt-3 justify-content-center"> <Col xs={10}> <Form className="border p-3 bg-light" onSubmit={handleSubmit} > <h1 className="text-center">Kiosk settings</h1> <hr /> <h2>Display configuration</h2> <Alert className="text-center" color="warning"> Stele is primarily designed to browser local content that you trust. <br /> Don't configure it to browse to web content you don't trust. </Alert> <FieldArray name="urls" render={() => ( <Table> <thead> <tr> <th>Enabled</th> <th>ID</th> <th>Resolution</th> <th>Orientation</th> <th>URL</th> <th>Keep Focus</th> </tr> </thead> <tbody> { values.displays.map((display, index) => ( <tr key={display.id} className={generateDisplayRowClass(display)} > <td> <Row> <Col xs={5}> <FormGroup row> <Col sm={{ size: 12 }}> <FormGroup check> <Input onChange={handleChange} type="checkbox" id={`displays[${index}].enabled`} checked={display.enabled} /> </FormGroup> </Col> </FormGroup> </Col> <Col xs={7}> {display.enabled && !display.connected ? ( <React.Fragment> <FaExclamationTriangle style={{ fontSize: '30px' }} className="text-warning" id={`displays-${index}-disconnected-warning`} /> <Tooltip isOpen={disconnectedDisplayTooltipOpen} toggle={this.toggleDisconnectedDisplayTooltip} placement="top" target={`displays-${index}-disconnected-warning`} > This window won't be displayed until the display is reconnected. </Tooltip> </React.Fragment> ) : ''} </Col> </Row> {!display.connected ? ( <Row> <Col className="mt-3 text-center"> <Button onClick={() => { forgetDisplay(index, display, values, setFieldValue); }} color="danger" > Forget </Button> <Input type="hidden" id={`displays[${index}].forgetting`} /> </Col> </Row> ) : '' } </td> <td>{display.id}</td> <td> {display.size.width} {' '} x {display.size.height} {display.id === displayPrimaryID ? ( <Fragment> <br /> <em>Primary display</em> </Fragment> ) : ''} {display.connected ? '' : ( <Fragment> <br /> <em>Display disconnected</em> </Fragment> ) } </td> <td> {display.rotation === 0 ? 'Horizontal' : 'Vertical'} </td> <td> <Field name={`displays[${index}].url`} render={({ field }) => ( <Input {...field} className="form-control" type="text" invalid={isValid(errors, `displays[${index}].url`)} value={values.displays[index].url} onChange={handleChange} onBlur={handleBlur} /> )} /> <FormFeedback invalid={errors.url}> A valid URL is required. <br /> The URL should start with http:// or https:// </FormFeedback> <FormText> Enter a URL for {' '} {display.id === displayPrimaryID ? 'the primary' : 'this'} {' '} display </FormText> </td> <td> <Col xs={5}> <FormGroup row> <Col sm={{ size: 12 }}> <FormGroup check> <Input onChange={handleChange} type="checkbox" id={`displays[${index}].forceFocus`} checked={display.forceFocus} /> </FormGroup> </Col> </FormGroup> </Col> </td> </tr> )) } </tbody> </Table> )} /> <Row> <Col> <Label for="autoLaunch"> <h2>Auto launch</h2> </Label> <FormGroup check> <Label check> <Input onChange={handleChange} type="checkbox" id="autoLaunch" checked={values.autoLaunch} /> {' '} Auto launch application on startup </Label> <FormText> This change will be made the next time your system restarts. </FormText> </FormGroup> </Col> <Col> <Label for="devToolsShortcut"> <h2>Dev tools</h2> </Label> <FormGroup check> <Label check> <Input onChange={handleChange} type="checkbox" id="devToolsShortcut" checked={values.devToolsShortcut} /> {' '} Enable dev tools shortcut </Label> <FormText> In production, the browser dev tools are generally inaccessible, even when using the default keyboard shortcuts. <br /> Check this box to enable the keyboard shortcut. <p> Windows & Linux - {' '} <kbd>Ctrl</kbd> {' '} + {' '} <kbd>Shift</kbd> {' '} + {' '} <kbd>I</kbd> </p> <p> macOs - {' '} <kbd>Cmd</kbd> {' '} + {' '} <kbd>Opt</kbd> {' '} + {' '} <kbd>I</kbd> </p> </FormText> </FormGroup> </Col> <Col> <FormGroup> <Label for="cursorVis"> <h2>Cursor visibility</h2> </Label> <select name="cursorVis" id="cursorVis" value={values.cursorVis} onChange={handleChange} onBlur={handleBlur} style={{ display: 'block' }} > <option value="show" label="Show" /> <option value="hide" label="Hide" /> <option value="hide_after_5" label="Hide after 5 seconds inactivity" /> <option value="hide_after_60" label="Hide after 60 seconds inactivity" /> </select> <FormText> Select mouse cursor visibility. Does not work with iFrames. </FormText> </FormGroup> </Col> </Row> <CookieForm values={values} handleChange={handleChange} handleBlur={handleBlur} /> <Button color="primary" type="submit" disabled={isSubmitting} > Save </Button> </Form> </Col> </Row> </Container> ); }} </Formik> ); }
import {object, string, ref} from 'yup' export default object().shape({ username: string().max(24).min(5).required(), nickname: string().max(16).min(5).required(), password: string().min(6).required(), passwordConfirm: string().sameAs(ref('password')).required(), email: string().max(48).email().required() })
}; PaymentForm.propTypes = { cartData: PropTypes.object, userData: PropTypes.object, }; export default withFormik({ mapPropsToValues: () => ({ number: '', exp_month: '', exp_year: '', cvc: '', }), validationSchema: Yup.object().shape({ number: Yup.string().required('Card number is required.'), exp_month: Yup.string().required('Expiry month is required.'), exp_year: Yup.string().required('Expiry year is required.'), cvc: Yup.string().required('Card CVC is required.'), }), handleSubmit: (values, { setSubmitting, props }) => { // console.log('handle submit', values, props); const { userData } = props; const user = userData !== null ? userData : {}; const orderId = randomstring.generate(6).toUpperCase(); const alertify = require('alertify.js'); // eslint-disable-line const productIds = props.cartData.items.map(item => item.id); $('.payment-form-btn').addClass('is-loading'); // add to analytics
className="button is-light" > Subscribe </button> </div> </div> </Container> ); } } export default withFormik({ mapPropsToValues: () => ({ email: '', }), validationSchema: Yup.object().shape({ email: Yup.string() .email('Invalid email address') .required('Email is required!'), }), handleSubmit: (values, { setSubmitting }) => { // console.log('handle submit', values, props); const alertify = require('alertify.js'); // eslint-disable-line apolloClient .mutate({ mutation: subscribeMutation, variables: values, }) .then(() => { alertify.alert('Subscribed successfully, thank you!'); setSubmitting(false);
const { object, string, number, date } = require('yup') const contactSchema = object({ name: string() .required(), age: number() .required() .positive() .integer(), email: string() .email(), website: string() .url(), createdOn: date() .default(() => new Date()) }) contactSchema.cast({ name: 'jimmy', age: '24', createdOn: '2014-09-23T19:25:25Z' })
render() { const searchFormSchema = yup.object({ firstname: yup.string().default(this.props.relay.variables.personFilters.firstname), middlename: yup.string().default(this.props.relay.variables.personFilters.middlename), lastname: yup.string().default(this.props.relay.variables.personFilters.lastname), email: yup.string().default(this.props.relay.variables.personFilters.email), phone: yup.string().default(this.props.relay.variables.personFilters.phone), zip: yup.string().default(this.props.relay.variables.personFilters.zip) }) return ( <div style={{height: this.state.windowHeight - 56, top: 56, position: 'absolute', overflow: 'scroll'}}> <div style={{ width: this.state.windowWidth * 0.4 - 40, margin: 20, position: 'fixed', top: 40 }} > <GCForm ref="form" schema={searchFormSchema} defaultValue={searchFormSchema.default()} value = {this.model} onChange = {model => { this.setState({model}) }} onSubmit={(data) => { this.setState({loading: true}) Object.keys(data).forEach((key) => { if (!data[key]) delete data[key] }) this.props.relay.setVariables({personFilters: data}, (readyState) => { if (readyState.ready) { this.setState({loading: false}) } }) }} > <h1 style={{ ...BernieText.title, marginTop: '0.5em', marginBottom: 0 }}>Search for Constituents</h1> <Form.Field name='firstname' label='First Name' fullWidth={true} /> <Form.Field name='middlename' label='Middle Name' fullWidth={true} /> <Form.Field name='lastname' label='Last Name' fullWidth={true} /> <Form.Field name='email' label='Email Address' fullWidth={true} /> <Form.Field name='phone' label='Phone Number' fullWidth={true} /> <Form.Field name='zip' label='Zip Code' fullWidth={true} /> <br /><br /> <Form.Button ref="submit" type='submit' label='Search' fullWidth={true} /> </GCForm> </div> <div style={{marginLeft: this.state.windowWidth * 0.4, width: this.state.windowWidth * 0.6}}> {this.renderSearchResults()} </div> </div> ) }
render() { if (!this.props.event) return <EventInvalid /> let eventTypeName = this.props.event.eventType.name.toLowerCase() if (eventTypeName.indexOf('phonebank') > -1) eventTypeName = 'phone bank party' const defaultHostMessage = this.props.event.fastFwdRequest ? this.props.event.fastFwdRequest.hostMessage : `Hello, neighbors! I'm hosting a ${eventTypeName} and I need a few more Bernie supporters to attend to make this event a big success. Will you please attend my event? ${publicEventsRootUrl + this.props.event.eventIdObfuscated} Thank you, ${this.props.event.host ? this.props.event.host.firstName : ''}` const formSchema = yup.object({ hostMessage: yup.string().default(this.props.event.hostMessage || defaultHostMessage).required(), }) return ( <MuiThemeProvider muiTheme={Styles.getMuiTheme(BernieTheme)}> <div style={this.styles.pageContainer} className="ffwdPageContainer"> <MutationHandler ref='mutationHandler' successMessage='Your request has been saved. We will review it and send it out to volunteers in your area ASAP!' mutationClass={CreateFastFwdRequest} mutationName='createFastFwdRequest' onSuccess={() => { setTimeout(() => { this.props.history.push('/events') }, 5000) }} /> <h1 style={BernieText.title}> Fast Fwd: Send a message to bring volunteers to your event </h1> <div zDepth={1} style={this.styles.detailsContainer} className="ffwdDetailsContainer"> <h3 style={{...BernieText.secondaryTitle, fontSize: '1.2rem'}}>Your Event Details:</h3> <EventPreview event={this.props.event} /> </div> <Paper style={this.styles.formContainer} className="ffwdFormContainer"> <GCForm schema={formSchema} defaultValue={formSchema.default()} value = {this.state.model} onChange={ model => { this.setState({ model }) }} onSubmit={(formValues) => { this.refs.mutationHandler.send({ eventId: this.props.event.id, ...formValues }) }} > <p style={BernieText.inputLabel}>Author a message below about your event and why people should come out. We'll forward it on to potential attendees in your area.</p> <Form.Field name='hostMessage' multiLine={true} fullWidth={true} label="Message From Host" /> <br /> <br /> <Form.Button type='submit' label='Submit' fullWidth={true} /> </GCForm> </Paper> </div> </MuiThemeProvider> ) }
value="Submit" color={color} bg={bg} mx={inputProps.mx || '0'} style={{ display: 'block' }} onClick={handleSubmit} inverted /> </form> ) } } const LoginCodeForm = withFormik({ mapPropsToValues: ({ params }) => ({ ...params }), validationSchema: yup.object().shape({ loginCode: yup.string() }), handleSubmit: (unformattedData, { props, setSubmitting, setErrors }) => { if (!unformattedData.loginCode) { setSubmitting(false) return null } const { loginCallback = null } = props const strippedLoginCode = unformattedData.loginCode.replace(/\D/g, '') const data = { login_code: strippedLoginCode } api .post(`v1/users/${props.userId}/exchange_login_code`, { data }) .then(json => { storage.set('authToken', json.auth_token) setSubmitting(false) // associate current session with authenticated user and update email
const reduxWrapper = connect( function mapStateToProps (state) { return { errorMessage: state.auth.registerError } }) const formikWrapper = withFormik({ mapPropsToValues: (props) => ({ email: '', password: '', password_confirm: '', name_first: '', name_last: '' }), validationSchema: yup.object().shape({ email: yup.string().email().label('Email') .required(t('register.emailErrorMissing')), password: yup.string().required(t('register.passwordErrorMissing')), password_confirm: yup.string() .equalTo('password', t('register.passwordErrorMismatch')) .required(t('register.passwordConfirmErrorMissing')), name_first: yup.string().required(t('register.nameFirstErrorMissing')), name_last: yup.string().required(t('register.nameLastErrorMissing')) }), handleSubmit: async (values, {props}) => { log.info(`Register request for ${values.email}`) // TODO: Handle backend register errors await props.dispatch(registerUser(values)) await props.onRegister(props.dispatch) props.handleSwitchToLogin() }
render() { if (!this.props.event) return <div style={{ textAlign: 'center', marginTop: '4em'}}> <h1 style={BernieText.title}>Invalid Event</h1> <p style={BernieText.default}>This event does not exist. If you've just recently created your event. this error may resolve itself in a short period of time. It's also possible your event was deleted. Please email <a href="mailto:help@berniesanders.com">help@berniesanders.com</a> if you need help.</p> </div> let event_type_name = 'volunteer event'; if(this.props.event.eventType.name.toLowerCase().indexOf('phone bank') > -1){ event_type_name = 'phone bank party' } if(this.props.event.eventType.name.toLowerCase().indexOf('barnstorm') > -1){ event_type_name = 'Barnstorm event' } let defaultHostMessage = this.props.event.fastFwdRequest ? this.props.event.fastFwdRequest.hostMessage : "Hello, neighbors!\n\nI'm hosting a " + event_type_name + " and I need a few more Bernie supporters " + "to attend to make this event a big success. " + "Will you please attend my event?\n\n" + publicEventsRootUrl + this.props.event.eventIdObfuscated + "\n\n" + "Thank you,\n\n" + (this.props.event.host ? this.props.event.host.firstName: "") let formSchema = yup.object({ hostMessage: yup.string().default(this.props.event.hostMessage || defaultHostMessage).required(), }) return ( <MuiThemeProvider muiTheme={Styles.getMuiTheme(BernieTheme)}> <div style={this.styles.pageContainer} className="ffwdPageContainer"> <MutationHandler ref='mutationHandler' successMessage='Your request has been saved. We will review it and send it out to volunteers in your area ASAP!' mutationClass={CreateFastFwdRequest} mutationName='createFastFwdRequest' onSuccess={() => { setTimeout(() => { this.props.history.push('/events') }, 5000) }} /> <h1 style={BernieText.title}> Fast Fwd: Send a message to bring volunteers to your event </h1> <div zDepth={1} style={this.styles.detailsContainer} className="ffwdDetailsContainer"> <p style={BernieText.secondaryTitle}>Your Event Details:</p> <EventPreview event={this.props.event} /> </div> <Paper style={this.styles.formContainer} className="ffwdFormContainer"> <GCForm schema={formSchema} defaultValue={formSchema.default()} value = {this.state.model} onChange={ model => { this.setState({ model }) }} onSubmit={(formValues) => { this.refs.mutationHandler.send({ eventId: this.props.event.id, ...formValues }) }} > <p style={BernieText.inputLabel}>Author a message below about your event and why people should come out. We'll forward it on to potential attendees in your area.</p> <Form.Field name='hostMessage' multiLine={true} fullWidth={true} label="Message From Host" /> <br /> <br /> <Form.Button type='submit' label='Submit' fullWidth={true} /> </GCForm> </Paper> </div> </MuiThemeProvider> ) }
import { Map } from 'immutable'; import yup from 'yup'; const Definition = Map({ name:'posts', keys: Map({ singular:'post', plural:'posts', }), sortBy:(a, b) => { return a.get('createdAt') < b.get('createdAt') }, loading: false, schema: yup.object({ title: yup.string().required('Title is required.'), state: yup.string().default('draft').matches(/(draft|published|archived)/), publishedDate: yup.date().default(new Date()), text: yup.string().default('').required('Text is required.'), }), populate:Map({ topics:'topics', user:'******', }) }); export default Definition;
var _ = require('lodash') , Clank = require('clank') , Resource = require('miniature') , yup = require('yup') var Range = yup.number().min(0).max(5).default(0) var Specify = yup.object({ times: yup.number().default(0), specify: yup.string() }); var BeforeAfter = yup.object({ before: yup.number().min(0).max(5), after: yup.number().min(0).max(5), }); var Day = yup.object({ started: yup.boolean().default(false), date: yup.date(), firstOfWeek: yup.date(), dayOfWeek: yup.number().min(0).max(7), week: yup.number().min(1).max(52), year: yup.number(), use: Range, suicide: Range, selfHarm: Range, pain: Range, sadness: Range,
render () { if (this.state.isFetching) { return ( <div className="loader-container"> <i className="fa fa-spinner fa-3x avatar-loader" /> </div> ) } return ( <div className="costume-form"> <div className="text-center mt-1"> <h1> {gon.name ? I18n.t('costumes.edit') : I18n.t('costumes.new_costume')} </h1> </div> <Formik initialValues={{ name: gon.name || '', desc: gon.desc || '', photos: gon.photos || [], photos_attachments_attributes: [] }} validationSchema={Yup.object().shape({ name: Yup.string().min(3, I18n.t('validations.min', { field: I18n.t('costumes.name'), min: 3 })).required(I18n.t('validations.required')), photos: Yup.array().required(I18n.t('validations.required')), desc: Yup.string(), photos_attachments_attributes: Yup.array(), })} onSubmit={this.onSubmit} > {props => { const { values, touched, errors, dirty, isSubmitting, handleChange, handleBlur, handleSubmit, handleReset, } = props; return ( <form onSubmit={handleSubmit}> <input id="name" placeholder={I18n.t('costumes.name')} type="text" value={values.name} onChange={handleChange} onBlur={handleBlur} className={ errors.name && touched.name ? 'text-input error' : 'text-input' } /> {errors.name && touched.name && <div className="input-feedback">{errors.name}</div>} <textarea id="desc" placeholder={I18n.t('costumes.desc')} type="text" value={values.desc} onChange={handleChange} onBlur={handleBlur} className={ errors.desc && touched.desc ? 'text-area error' : 'text-area' } /> {errors.desc && touched.desc && <div className="input-feedback">{errors.desc}</div>} <Dropzone onDrop={(photos) => { const newPhotos = {target: { value: [...values.photos, ...photos], name: 'photos', }} handleChange(newPhotos) }} className="image-container content-center" accept="image/jpeg" > <div className={ errors.photos && touched.photos ? 'dropzone-errors' : 'dropzone' } > <i className="fa fa-image fa-1x text-color-main mb-1" /> <p className="text text-color-main"> Choose photos </p> </div> </Dropzone> {errors.photos && touched.photos && <div className="input-feedback">{errors.photos}</div>} {values.photos.length > 0 && <div className="mb-1"/> } <div className="previews" > {values.photos.map((el, index) => { return( <div className="preview-container" key={el.preview} > <img className="preview" src={el.preview} /> <div className="delete" onClick={() => { if (gon.name) { handleChange({target: { value: [...values.photos_attachments_attributes, { id: el.id, _destroy: '1' }], name: 'photos_attachments_attributes', }}) } const newPhotos = {target: { value: values.photos.filter((el, i) => i !== index), name: 'photos', }} handleChange(newPhotos) }} > <i className="fa fa-times-circle fa-2x text-color-main" /> </div> </div> ) })} </div> <button className="btn btn-main" type="submit" disabled={isSubmitting} > Submit </button> </form> ); }} </Formik> </div> ) }
import React from "react"; import * as Yup from "yup"; import { Form, Scope, Input } from "@rocketseat/unform"; const initialData = { name: "Osvaldo", address: { street: "Rua São Paulo" } }; const schema = Yup.object().shape({ name: Yup.string().required("Campo obrigatório"), address: Yup.object().shape({ number: Yup.string() .min(3, "Número precisa 3 dígitos") .required("Campo obrigatório") }) }); function App() { function handleSubmit(data) { console.log(data); } return ( <Form schema={schema} initialData={initialData} onSubmit={handleSubmit}> <Input name="name" label="Nome:" /> <br /> <Scope path="address">
const UserModal = (props) => { let modalTitle = ''; let buttonText = ''; switch (props.mode) { case 'Add': modalTitle = 'Add User'; buttonText = 'Save User'; break; case 'Edit': modalTitle = 'Edit User'; buttonText = 'Save User'; break; case 'Delete': modalTitle = 'Delete User'; buttonText = 'Delete User'; break; default: break; } return ( <Formik initialValues={{ username: props.user.username ? props.user.username : '', accountExpired: props.user.accountNonExpired !== undefined ? !props.user.accountNonExpired : false, accountLocked: props.user.accountNonLocked !== undefined ? !props.user.accountNonLocked : false, credentialsExpired: props.user.credentialsNonExpired !== undefined ? !props.user.credentialsNonExpired : false, enabled: props.user.enabled !== undefined ? props.user.enabled : true, isUser: true, isAdmin: props.user.roles ? props.user.roles.filter(role => role.name === 'ROLE_ADMIN').length === 1 : false }} enableReinitialize={true} validationSchema={Yup.object().shape({ username: Yup.string().required('Required'), accountExpired: Yup.bool(), accountLocked: Yup.bool(), credentialsExpired: Yup.bool(), enabled: Yup.bool(), isUser: Yup.bool(), isAdmin: Yup.bool() })} isInitialValid={(formikBag) => { return formikBag.validationSchema.isValidSync(formikBag.initialValues); }} onSubmit={async (values, actions) => { let roles = [{id: 1, name: 'ROLE_USER'}]; if (values.isAdmin) { roles.push({id: 2, name: 'ROLE_ADMIN'}); } await props.submitCallback({ username: values.username, accountNonExpired: !values.accountExpired, accountNonLocked: !values.accountLocked, credentialsNonExpired: !values.credentialsExpired, enabled: values.enabled, roles: roles }); actions.setSubmitting(false); }} > {(formikProps) => ( <Modal isOpen={props.open} toggle={props.cancelCallback}> <ModalHeader toggle={props.cancelCallback}>{modalTitle}</ModalHeader> <Form onSubmit={e => e.preventDefault()}> <ModalBody> {props.errorMessage && <Label className="text-danger font-weight-bold">Error: {props.errorMessage}</Label>} {props.mode === 'Delete' && <p>Are you sure you want to delete {props.user.username}?</p> } {props.mode !== 'Delete' && <React.Fragment> <FormGroup row> <Label sm={4}>Username</Label> <Col sm={8}> <Input name="username" placeholder="Username" onChange={formikProps.handleChange} onBlur={formikProps.handleBlur} value={formikProps.values.username} invalid={formikProps.touched.username && formikProps.errors.username} disabled={props.mode === 'Edit'}/> </Col> </FormGroup> <FormGroup row> <Label sm={4} className="pt-0">Account Status</Label> <Col sm={8}> <FormGroup check> <Label check> <Input type="checkbox" name="accountExpired" onChange={formikProps.handleChange} onBlur={formikProps.handleBlur} checked={formikProps.values.accountExpired}/>Expired </Label> </FormGroup> <FormGroup check> <Label check> <Input type="checkbox" name="accountLocked" onChange={formikProps.handleChange} onBlur={formikProps.handleBlur} checked={formikProps.values.accountLocked}/>Locked </Label> </FormGroup> <FormGroup check> <Label check> <Input type="checkbox" name="credentialsExpired" onChange={formikProps.handleChange} onBlur={formikProps.handleBlur} checked={formikProps.values.credentialsExpired}/>Credentials Expired </Label> </FormGroup> <FormGroup check> <Label check> <Input type="checkbox" name="enabled" onChange={formikProps.handleChange} onBlur={formikProps.handleBlur} checked={formikProps.values.enabled}/>Enabled </Label> </FormGroup> </Col> </FormGroup> <FormGroup row> <Label sm={4} className="pt-0">Roles</Label> <Col sm={8}> <FormGroup check> <Label check> <Input type="checkbox" name="isUser" onChange={formikProps.handleChange} onBlur={formikProps.handleBlur} disabled={true} checked={true}/>User </Label> </FormGroup> <FormGroup check> <Label check> <Input type="checkbox" name="isAdmin" onChange={formikProps.handleChange} onBlur={formikProps.handleBlur} checked={formikProps.values.isAdmin}/>Admin </Label> </FormGroup> </Col> </FormGroup> </React.Fragment> } </ModalBody> <ModalFooter> <Button color="primary" onClick={formikProps.handleSubmit} disabled={!formikProps.isValid || formikProps.isSubmitting}> {buttonText}</Button> <Button color="primary" onClick={props.cancelCallback}> Cancel </Button> </ModalFooter> </Form> </Modal> )} </Formik> ); };
const invoiceValidationSchema = ({ cmscontactsupportedchars, cmsnamelocationsupportedchars, maxlocationlength, minlocationlength, mincontactlength, maxcontactlength, minnamelength, maxnamelength, minlineitemcollength, maxlineitemcollength, invoicefieldsupportedchars }) => Yup.object().shape({ name: Yup.string() .required("required") .min(minnamelength) .max(maxnamelength) .matches(...fieldMatcher("Name", cmsnamelocationsupportedchars)), location: Yup.string() .required("required") .min(minlocationlength) .max(maxlocationlength) .matches(...fieldMatcher("Location", cmsnamelocationsupportedchars)), contact: Yup.string() .required("required") .min(mincontactlength) .max(maxcontactlength) .matches(...fieldMatcher("Contact", cmscontactsupportedchars)), rate: Yup.number() .required("required") .min(5) .max(500), address: Yup.string().required("required"), lineitems: Yup.array() .of( Yup.object().shape({ type: Yup.string() .required("required") .oneOf(["1", "2", "3"]), domain: Yup.string() .required("required") .min(minlineitemcollength) .max(maxlineitemcollength) .matches(...fieldMatcher("Domain", invoicefieldsupportedchars)), subdomain: Yup.string() .required("required") .min(minlineitemcollength) .max(maxlineitemcollength) .matches(...fieldMatcher("Sub domain", invoicefieldsupportedchars)), description: Yup.string() .min(minlineitemcollength) .max(maxlineitemcollength) .matches( ...fieldMatcher("Description", invoicefieldsupportedchars) ), labour: Yup.number(), expense: Yup.number() }) ) .min(1) });
import yup from 'yup' export default yup.object({ name: yup.string().required('please enter name'), cost: yup.number().label('Cost').positive().min(1).max(10000000, 'max Cost 10000000'), percent: yup.string(), group: yup.string() });
describe('Field', () => { let schema = yup.object({ name: yup.string().default(''), more: yup.object().when('name', { is: 'jason', then: yup.object({ isCool: yup.bool(), }), }), }) class TestInput extends React.Component { render() { return ( <input value={this.props.value || ''} onChange={e => this.props.onChange(e, 'hi')} /> ) } } it('should pass props to inner type', function() { mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="name" type={TestInput} className="test" /> </Form> ) .find(TestInput) .instance() .props.className.should.include('test') // test invalid-field }) it('should fall back to using schema types', function() { let schema = yup.object({ string: yup.string(), number: yup.number(), date: yup.date(), bool: yup.bool(), array: yup.array().of(yup.string()), }) let wrapper = mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="string" /> <Form.Field name="number" /> <Form.Field name="date" /> <Form.Field name="bool" /> <Form.Field name="array" /> </Form> ) wrapper.assertSingle(`Input[name='string']`) wrapper.assertSingle(inputs.Number) wrapper.assertSingle(inputs.Bool) wrapper.assertSingle(inputs.Select) wrapper.assertSingle(inputs.Date) }) it('should use schema metadata', function() { let schema = yup.object({ string: yup.string().meta({ reactFormalType: 'number', }), }) mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="string" /> </Form> ).assertSingle(inputs.Number) }) it('should use type override', function() { let wrapper = mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="name" /> <Form.Field name="name" type="textarea" /> <Form.Field name="name" type={TestInput} /> </Form> ) wrapper.assertSingle(TestInput) wrapper.find(inputs.Input).length.should.equal(2) }) it('should fire onChange', function(done) { mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="name" type={TestInput} onChange={() => done()} /> </Form> ) .assertSingle('input') .simulate('change') }) it('ensures values are never undefined', function() { let wrapper = mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="name" /> </Form> ) expect(wrapper.assertSingle('Input').prop('value')).to.equal(null) }) it('maps value from string', function() { let spy = sinon.spy() mount( <Form schema={schema} defaultValue={{}} onChange={spy}> <Form.Field name="name" type={TestInput} mapFromValue="value" /> </Form> ) .assertSingle('input') .simulate('change', { value: 'john' }) spy.should.have.been.calledOnce.and.calledWith({ name: 'john' }) }) it('maps value from function', function() { let spy = sinon.spy() mount( <Form schema={schema} defaultValue={{}} onChange={spy}> <Form.Field name="name" type={TestInput} mapFromValue={e => e.value} /> </Form> ) .assertSingle('input') .simulate('change', { value: 'john' }) spy.should.have.been.calledOnce.and.calledWith({ name: 'john' }) }) it('gets value from accessor', function() { let spy = sinon.spy(model => model.other) let wrapper = mount( <Form schema={schema} defaultValue={{}} onChange={spy}> <Form.Field name="name" type={TestInput} mapToValue={spy} mapFromValue={{ other: e => e.value, }} /> </Form> ) spy.should.have.been.and.calledWith({}) wrapper.assertSingle('input').simulate('change', { value: 'john' }) spy.should.have.been.and.calledWith({ other: 'john' }) }) it('gets value from map accessor', function() { mount( <Form schema={schema} defaultValue={{ name: 'foo', lastName: 'bar' }}> <Form.Field name="name" type={TestInput} mapToValue={{ first: 'name', last: 'lastName', }} /> </Form> ) .assertSingle(TestInput) .prop('value') .should.eql({ first: 'foo', last: 'bar', }) }) it('gets value from map accessor functions', function() { mount( <Form schema={schema} defaultValue={{ name: 'foo', lastName: 'bar' }}> <Form.Field name="name" type={TestInput} mapToValue={{ first: v => v.name, last: v => v.lastName, }} /> </Form> ) .assertSingle(TestInput) .prop('value') .should.eql({ first: 'foo', last: 'bar', }) }) it('maps values from hash', function() { let spy = sinon.spy() mount( <Form schema={schema} defaultValue={{}} onChange={spy}> <Form.Field name="name" type={TestInput} mapFromValue={{ name: e => e.value, text: 'text', }} /> </Form> ) .assertSingle('input') .simulate('change', { value: 'john', text: 'hi' }) spy.should.have.been.calledOnce.and.calledWith({ name: 'john', text: 'hi' }) }) it('should pass all args to mapFromValue', function(done) { let spy = sinon.spy() mount( <Form schema={schema} defaultValue={{}} onChange={spy}> <Form.Field name="name" type={TestInput} mapFromValue={(...args) => { args.length.should.equal(2) args[1].should.equal('hi') done() }} /> </Form> ) .assertSingle('input') .simulate('change') }) describe('meta', () => { it('should pass meta to form', () => { let Input = ({ meta }) => { meta.invalid.should.equals(true) meta.valid.should.equals(false) meta.errors.should.eqls({ name: 'foo', }) return null } mount( <Form schema={schema} defaultValue={{}} defaultErrors={{ name: 'foo' }}> <Form.Field name="name" type={Input} /> </Form> ) }) it('should field onError should remove existing errors', () => { let errorSpy = sinon.spy() mount( <Form schema={schema} defaultValue={{}} defaultErrors={{ name: 'foo', bar: 'baz' }} onError={errorSpy} > <Form.Field name="name" type={TestInput} /> </Form> ) .find(TestInput) .props() .meta.onError({}) errorSpy.should.have.been.calledOnce.and.calledWith({ bar: 'baz' }) }) it('should field onError should update field errors', () => { let errorSpy = sinon.spy() mount( <Form schema={schema} defaultValue={{}} defaultErrors={{ name: 'foo', bar: 'baz' }} onError={errorSpy} > <Form.Field name="name" type={TestInput} /> </Form> ) .find(TestInput) .props() .meta.onError({ name: 'foo', 'name.first': 'baz' }) errorSpy.should.have.been.calledOnce.and.calledWith({ name: 'foo', 'name.first': 'baz', bar: 'baz', }) }) it('should field onError should replace field errors', () => { let errorSpy = sinon.spy() mount( <Form schema={schema} defaultValue={{}} defaultErrors={{ name: 'foo', bar: 'baz' }} onError={errorSpy} > <Form.Field name="name" type={TestInput} /> </Form> ) .find(TestInput) .props() .meta.onError({ 'name.first': 'baz' }) errorSpy.should.have.been.calledOnce.and.calledWith({ 'name.first': 'baz', bar: 'baz', }) }) }) describe('inclusive active matching', () => { it('should count path matches', function() { mount( <Form schema={schema} defaultValue={{}} defaultErrors={{ name: 'foo' }}> <Form.Field name="name" errorClass="invalid" /> </Form> ).assertSingle('input.invalid') }) it('should use inclusive active checking', function() { mount( <Form schema={schema} defaultValue={{}} defaultErrors={{ 'name.first': 'foo' }} > <Form.Field name="name" errorClass="invalid" /> </Form> ).assertSingle('input.invalid') }) it('should respect `exclusive`', function() { mount( <Form schema={schema} defaultValue={{}} defaultErrors={{ 'name.first': 'foo' }} > <Form.Field exclusive name="name" errorClass="invalid" /> </Form> ).assertNone('input.invalid') }) it('should respect `exclusive` and still have errors', () => { mount( <Form schema={schema} defaultValue={{}} defaultErrors={{ name: 'foo' }}> <Form.Field exclusive name="name" errorClass="invalid" /> </Form> ).assertSingle('input.invalid') }) }) xdescribe('form fields', () => { it('should inject onError', () => { mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="name" /> </Form> ) .find('input') .prop('onError') .should.be.a('function') }) // skip for now since name is still required. xit('should not inject onError for nameless fields', () => { mount( <Form schema={schema} defaultValue={{}}> <Form.Field /> </Form> ) .find('input') .prop('onError') .should.be.a('function') }) it('should propagate onError to form', () => { let spy = sinon.spy() mount( <Form schema={schema} defaultValue={{}} onError={spy}> <Form.Field name="name" /> </Form> ) .find('input') .prop('onError')({ foo: 'bar' }) spy.should.have.been.calledOnce.and.calledWith({ 'name.foo': 'bar', }) }) it('should properly prefix nested errors', () => { const onError = mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="name" /> </Form> ) .find('input') .prop('onError') onError({ foo: 'bar' }).should.eql({ 'name.foo': 'bar' }) onError({ '[1].foo': 'bar' }).should.eql({ 'name[1].foo': 'bar' }) onError({ '[1].baz.foo': 'bar' }).should.eql({ 'name[1].baz.foo': 'bar' }) }) }) it('should add inner ref', function() { let inst mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="name" type={TestInput} fieldRef={r => { inst = r }} /> </Form> ) ;(inst instanceof TestInput).should.be.true() }) it('should forward inner ref', function() { let inst mount( <Form schema={schema} defaultValue={{}}> <Form.Field name="name" type={TestInput} ref={r => { inst = r }} /> </Form> ) ;(inst instanceof TestInput).should.be.true() }) it('should work with conditional schema', function() { let render = name => ReactDOMServer.renderToString( <Form schema={schema} defaultValue={{ ...schema.default(), name }}> <Form.Field name="more.isCool" /> </Form> ) ;(() => render('jason')).should.not.throw() ;(() => render('john')).should.throw() }) })
import devboard from 'devboard'; import React from 'react'; import Button from 'components/Button'; import DateTimePickerInput from 'components/DateTimePickerInput'; import DropdownListInput from 'components/DropdownListInput'; import TextInput from 'components/TextInput'; import Form, { Field, Message } from 'components/Form'; import Label from 'components/Label'; import yup from 'yup'; const definecard = devboard.ns('Form'); const defaultStr = yup.string().default(''); const customerSchema = yup .object({ name: yup.object({ first: defaultStr .required('Please enter a first name'), last: defaultStr .required('Please enter a surname'), }), dateOfBirth: yup.date() .max(new Date(), 'Are you a time traveler?!'), colorId: yup.number() .nullable() .required('Please select a dank color'), });
/** * Using yup we can create our schemas for our form. */ import yup from 'yup'; export default yup.object().shape({ firstName: yup.string().required(), lastName: yup.string().required(), //yup comes with some handy validation functions, as you can see email validation for us! email: yup.string().email().required(), sex: yup.string().required() });
renderForm() { let event = this.props.event const people = this.props.listContainer.people.edges const host = (people.length === 0) ? null : people[0].node const eventSchema = yup.object({ name: yup .string() .default(event.name) .required(), eventTypeId: yup .string() .default(event.eventType.id) .required(), description: yup.string().default(event.description) .required(), rsvpEmailReminderHours: yup.number() .default(event.rsvpEmailReminderHours) .min(0) .nullable(), startDate: yup.date() .default(momentWithOffset(event.startDate, event.localUTCOffset).toDate()) .required(), localTimezone: yup.string() .default(event.localTimezone) .required(), duration: yup.object({ h: yup.number() .default(Math.floor(event.duration / 60)) .min(-1) .nullable() .required(), m: yup.number() .default(event.duration % 60) .min(-1).max(59) .nullable() .required(), }), venueName: yup.string().default(event.venueName) .required(), venueAddr1: yup.string().default(event.venueAddr1) .required(), venueAddr2: yup.string().default(event.venueAddr2) .nullable(), venueCity: yup.string().default(event.venueCity) .required(), venueState: yup.string().default(event.venueState) .required(), venueZip: yup.string().default(event.venueZip) .required(), venueCountry: yup.string().default(event.venueCountry) .required(), venueDirections: yup.string().default(event.venueDirections) .nullable(), capacity: yup.number() .default(event.capacity) .min(0) .required(), hostEmail: yup.string().email() .default((event.host) ? event.host.email : null), contactPhone: yup.string() .default(event.contactPhone), publicPhone: yup.boolean() .default(event.publicPhone), hostReceiveRsvpEmails: yup.boolean() .default(event.hostReceiveRsvpEmails), rsvpUseReminderEmail: yup.boolean() .default(event.rsvpUseReminderEmail), attendeeVolunteerShow: yup.string() .default(String(event.attendeeVolunteerShow)), attendeeVolunteerMessage: yup.string() .default(event.attendeeVolunteerMessage), isSearchable: yup.string() .default(String(event.isSearchable)), isOfficial: yup.boolean() .default(event.isOfficial) }); const form = ( <GCForm ref="form" schema={eventSchema} defaultValue={eventSchema.default()} onSubmit={ (data) => { data.description = this.refs.quill.getEditorContents(); data.duration = data.duration.h * 60 + data.duration.m; data.isSearchable = Number(data.isSearchable); if (host) data.hostId = host.id delete data.hostEmail this.props.onSubmit(data) }} > <InfoHeader content='Event Information' /> <Form.Field name='eventTypeId' type='select' label='Event Type' fullWidth={true} choices={this.eventTypes()} /> <br /> <Form.Field name='name' label='Event Name' fullWidth={true} /> <br /><br /> <label>Event Description</label> <ReactQuill defaultValue={event.description} theme="snow" ref="quill" /> <InfoHeader content='Event Date & Time' /> <Form.Field name='startDate' label='Start Date/Time' type='datetime' utcOffset={event.localUTCOffset} /> <Form.Field name='localTimezone' type='select' label='Time Zone' choices={this.timezones()} style={{ marginTop: 5 }} /><br/> <Form.Field name='duration.h' label="Duration (Hours)" type='number' min="0" /> <Form.Field name='duration.m' label="Duration (Minutes)" type='number' min="0" max="59" /> <InfoHeader content='Event Location' /> <Form.Field name='venueName' label='Venue Name' /> <Form.Field name='capacity' label="Venue Capacity (enter 0 for unlimited)" type='number' min="0" /><br/> <Form.Field name='venueAddr1' label='Address Line 1' fullWidth={true} /> <Form.Field name='venueAddr2' label='Address Line 2' fullWidth={true} /> <Form.Field name='venueCity' label='City' /> <Form.Field name='venueState' label='State' /> <Form.Field name='venueZip' label='Zip Code' /> <Form.Field name='venueCountry' label='Country' /> <Form.Field name='venueDirections' label='Directions to Venue' multiLine={true} fullWidth={true} /> <InfoHeader content='Event Host' /> {(host) ? `${host.firstName} ${host.lastName}` : 'No host name available'}<br /> <Form.Field name="hostEmail" type="email" label="Host Email" errorText={(host) ? null : 'No account found'} onChange={(value) => { this.props.relay.setVariables({personFilters: {email: value}}) }} /><br /> <Form.Field name="contactPhone" type="phone" label="Contact Phone" /><br/><br/> <Form.Field name="publicPhone" label="Make Contact Number Public" /><br/> <Form.Field name="hostReceiveRsvpEmails" label="Send Host RSVPs via Email" /> <InfoHeader content='Event Attendees' /> <Form.Field name="rsvpUseReminderEmail" label="Send Guests RSVP Email Reminder" /> <Form.Field name='rsvpEmailReminderHours' label="RSVP Reminder Hours" type='number' min="0" /><br/><br/> <Form.Field name="attendeeVolunteerShow" type='select' label="Ask Attendees to Volunteer" fullWidth={true} choices={this.volunteerShowOptions()} /> <Form.Field name='attendeeVolunteerMessage' label="Message for Event Volunteers" multiLine={true} fullWidth={true} /> <InfoHeader content='Event Settings' /> <Form.Field name='isSearchable' type='select' label='Make Event Public?' fullWidth={true} choices={this.eventSearchableOptions()} /> <Form.Field name="isOfficial" label="Mark as an official campaign event" /> <Form.Button style={ { display: "none" } } ref="submit" type='submit' label='Submit Changes' fullWidth={true} /> </GCForm>) return form }
const minEndTime = moment(item.min_end_time) if (!biddingEnds || biddingEnds.isBefore(minEndTime)) { biddingEnds = minEndTime } } if (biddingEnds && valueMoment.isAfter(biddingEnds)) { throw this.createError({ message: 'Bidding has ended' }) } return true }) }), username: yup.string(), share: yup.number() .integer() .min(1) .max(100) .when('$method', { is: 'patch', otherwise: yup.number().required() }) .when(['amount', '$settings.money'], { is: function (bid, money) { return bid === money }, then: yup.number() .test('less_than_last', function (value) { if (value === undefined) {