UNPKG

react-native-gravityform

Version:

A component for including Gravity Forms on React Native apps via the Wordpress API

325 lines (298 loc) 12 kB
import React, { Component } from 'react' import { ScrollView, View, Text, TouchableOpacity } from 'react-native' // import ValidationComponent from 'react-native-form-validator' import base64 from 'react-native-base64' import { AddressField, CheckboxField, EmailField, HiddenField, HtmlField, NameField, NumberField, PhoneField, RadioField, SectionField, SelectField, TextField, } from './fieldComponents' export default class GravityForm extends Component { constructor(props) { super(props) this.siteURL = this.props.siteURL this.formID = this.props.formID const credentials = this.props.credentials const credentialString = `${credentials.userName}:${credentials.password}` this.encodedCredentials = base64.encode(credentialString) this.style = this.props.style this.state = { formData: {}, fieldValues: {}, isLoading: true, isSending: false, submitSuccess: false, submitFailure: false, } this.handleFieldChange = this.handleFieldChange.bind(this) } componentDidMount() { this.fetchFormData() .then(formData => { this.setState({ formData }) return this.setDefaultValues(formData) }) .then(() => this.setState({ isLoading: false })) .catch(err => console.warn('There was a problem retrieving form data: ', err)) } fetchFormData() { return new Promise((resolve, reject) => { fetch(`${this.siteURL}/wp-json/gf/v2/forms/${this.formID}`, { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${this.encodedCredentials}`, } }) .then(response => response.json().then(formData => resolve(formData))) .catch(err => reject('ERROR: ', err)) }) } values = {} setDefaultValues(formData) { return new Promise((resolve, reject) => { let fieldCount = formData.fields.length formData.fields.forEach(field => { switch (field.type) { case 'html': case 'section': fieldCount-- break case 'name': case 'address': fieldCount = fieldCount + field.inputs.length this.populateComplexValues(field) break case 'checkbox': fieldCount = fieldCount + field.inputs.length this.populateCheckboxValues(field) break case 'radio': case 'select': this.populateChoiceValues(field) break default: if (field.id == '36') console.log(field) this.populateSimpleValue(field) break } }) if (Object.keys(this.state.fieldValues).length == fieldCount) resolve() setTimeout(() => reject('"setDefaultValues" function timed out. Field values never populated completely.'), 5000) }) } populateComplexValues(field) { field.inputs.forEach(input => { if (input.choices) { const selected = input.choices.filter(choice => choice.isSelected) this.setState({ fieldValues: { ...this.state.fieldValues, [input.id]: selected.length ? selected[0].value : '', [field.id]: { ...this.state.fieldValues[field.id], [input.id]: selected[0] ? selected[0].value : '' } } }) } else { this.setState({ fieldValues: { ...this.state.fieldValues, [input.id]: input.defaultValue ? input.defaultValue : '', [field.id]: { ...this.state.fieldValues[field.id], [input.id]: input.defaultValue ? input.defaultValue : '' } } }) } }) } populateCheckboxValues(field) { field.inputs.forEach((input, index) => { this.setState({ fieldValues: { ...this.state.fieldValues, [input.id]: field.choices[index].isSelected ? field.choices[index].value : false, [field.id]: { ...this.state.fieldValues[field.id], [input.id]: field.choices[index].isSelected ? field.choices[index].value : false, } } }) }) } populateChoiceValues(field) { const selected = field.choices.filter(choice => { return choice.isSelected }) this.setState({ fieldValues: { ...this.state.fieldValues, [field.id]: selected.length ? selected[0].value : '' } }) } populateSimpleValue(field) { this.setState({ fieldValues: { ...this.state.fieldValues, [field.id]: field.defaultValue } }) } fieldHidden(field) { if (field.visibility != 'visible') return true if (typeof field.conditionalLogic == 'object' && field.conditionalLogic !== null) { return this.handleConditionalLogic(field) } return false } handleConditionalLogic(field) { const rulesMet = field.conditionalLogic.rules.map(rule => { let conditionalValue = this.state.fieldValues[rule.fieldId] if (typeof conditionalValue == 'object') { matchKey = Object.keys(conditionalValue).filter(key => this.state.fieldValues[key] == rule.value)[0] conditionalValue = matchKey ? this.state.fieldValues[matchKey] : false } switch (rule.operator) { case 'is': return conditionalValue == rule.value case 'is not': return conditionalValue != rule.value case 'greater than': return conditionalValue > rule.value case 'less than': return conditionalValue < rule.value case 'contains': return conditionalValue.indexOf(rule.value) >= 0 case 'starts with': return conditionalValue.indexOf(rule.value) == 0 case 'ends with': return conditionalValue.indexOf(rule.value) == conditionalValue.length - rule.value.length } }) if (field.conditionalLogic.actionType == 'show') { return field.conditionalLogic.logicType == 'all' ? rulesMet.indexOf(false) >= 0 : rulesMet.indexOf(true) < 0 } else { return field.conditionalLogic.logicType == 'all' ? rulesMet.indexOf(true) < 0 : rulesMet.indexOf(false) >= 0 } } handleFieldChange(fieldId, value, inputId) { if (inputId) { this.setState({ fieldValues: { ...this.state.fieldValues, [inputId]: value, [fieldId]: { ...this.state.fieldValues[fieldId], [inputId]: value, }, } }) } else { this.setState({ fieldValues: { ...this.state.fieldValues, [fieldId]: value, } }) } } submitForm() { this.setState({ isSending: true }) let formData = {} let fieldCount = Object.keys(this.state.fieldValues).length Object.keys(this.state.fieldValues).forEach(key => { if (typeof this.state.fieldValues[key] == 'object' && this.state.fieldValues[key] !== null) { fieldCount-- } else { formData = { ...formData, [key]: this.state.fieldValues[key] } } if (Object.keys(formData).length == fieldCount) this.postFormData(formData) }) } postFormData(formData) { fetch(`${this.siteURL}/wp-json/gf/v2/forms/${this.formID}/entries`, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': `Basic ${this.encodedCredentials}`, }, body: JSON.stringify(formData), }) .then(() => this.setState({ isSending: false })) .catch(err => console.error('ERROR: ', err)); } fieldComponents = { address: AddressField, checkbox: CheckboxField, email: EmailField, hidden: HiddenField, html: HtmlField, name: NameField, number: NumberField, phone: PhoneField, radio: RadioField, section: SectionField, select: SelectField, text: TextField, } render() { if (this.state.isLoading) { return ( <View style={{ flex: 1, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center' }}> <Text>Fetching Gravity Form...</Text> </View> ) } if (this.state.isSending) { return ( <View style={{ flex: 1, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center' }}> <Text>Submitting Form...</Text> </View> ) } let parentHidden = false const fields = this.state.formData.fields && this.state.formData.fields.map((field) => { if (Object.keys(this.fieldComponents).indexOf(field.type) < 0) { console.warn(`React Native Gravityform: No field component currently available for type "${field.type}".`) return } const FieldComponent = this.fieldComponents[field.type || 'text'] if (field.type == 'section') parentHidden = this.fieldHidden(field) return ( <View key={field.id.toString()} style={{ display: this.fieldHidden(field) || parentHidden ? 'none' : 'flex' }} > <FieldComponent data={field} onChange={this.handleFieldChange} style={this.style} value={this.state.fieldValues[field.id]} /> </View> ) }) return ( <ScrollView style={this.style.formWrapper}> {this.state.formData.title.length > 0 && !this.props.hideFormTitle && <View style={this.style.formHeader}> <Text style={this.style.formTitle}>{this.state.formData.title}</Text> </View> } {fields} {this.state.formData.button && <View style={this.style.formFooter}> <TouchableOpacity onPress={() => this.submitForm()} style={this.style.button}> <Text style={this.style.buttonText}>{this.state.formData.button.text}</Text> </TouchableOpacity> </View> } </ScrollView> ) } }