Last active
July 5, 2018 19:13
-
-
Save 1-800-jono/af9206b1937c998d95e127550c37eb44 to your computer and use it in GitHub Desktop.
React JS file - this is a multi-step form. Upload a CV/Resume then it gets analyzed on the server for keywords. This keywords are sent back as a response and then it populates the proper fields accordingly. Using React.js and Apollo.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import { gql, graphql, compose } from 'react-apollo'; | |
import request from 'superagent'; | |
import LoadingFetch from '../helpers/LoadingFetch'; | |
import SingleInput from '../forms/SingleInput'; | |
class AddEditTalent extends Component { | |
constructor() { | |
super(); | |
this.handleSubmit = this.handleSubmit.bind(this); | |
this.uploadImage = this.uploadImage.bind(this); | |
this.handleInputChange = this.handleInputChange.bind(this); | |
this.populateTalent = this.populateTalent.bind(this); | |
this.uploadPDF = this.uploadPDF.bind(this); | |
this.displayFileName = this.displayFileName.bind(this); | |
this.state = { | |
talent: null, | |
logoMessage: 'Click to upload CV', | |
talentSaved: false, | |
firstName: '', | |
lastName: '', | |
email: '', | |
phone: '', | |
address: '', | |
city: '', | |
state: '', | |
country: '', | |
citizenship: '', | |
postalCode: '', | |
cv: '', | |
website: '', | |
github: '', | |
bitbucket: '', | |
stackoverflow: '', | |
linkedin: '', | |
medium: '', | |
quora: '', | |
blog: '', | |
eventbrite: '', | |
typeform: '', | |
twitter: '', | |
salaryExpectation: 0, | |
whyInterview: '', | |
currentJobTitle: '', | |
active: true, | |
uploadFileName: 'No File', | |
uploadStatus: 'Waiting for file', | |
} | |
} | |
componentDidMount() { | |
if (this.props.id) { | |
if (this.props.data.loading) { | |
return setTimeout(() => this.componentDidMount(), 50); | |
} else { | |
if (this.props.data.talent) this.populateTalent(this.props.data.talent); | |
} | |
} | |
} | |
populateTalent(e) { | |
this.setState({ | |
firstName: this.props.data.talent.contact[0].firstName || '', | |
lastName: this.props.data.talent.contact[0].lastName || '', | |
email: this.props.data.talent.contact[0].email || '', | |
phone: this.props.data.talent.contact[0].phone || '', | |
address: this.props.data.talent.contact[0].address || '', | |
city: this.props.data.talent.contact[0].city || '', | |
region: this.props.data.talent.contact[0].region || '', | |
country: this.props.data.talent.contact[0].country || '', | |
citizenship: this.props.data.talent.profile.citizenship || '', | |
postalCode: this.props.data.talent.contact[0].postalCode || '', | |
cv: this.props.data.talent.source.cv || '', | |
website: this.props.data.talent.source.website || '', | |
github: this.props.data.talent.source.github || '', | |
bitbucket: this.props.data.talent.source.bitbucket || '', | |
stackoverflow: this.props.data.talent.source.stackoverflow || '', | |
linkedin: this.props.data.talent.source.linkedin || '', | |
medium: this.props.data.talent.source.medium || '', | |
quora: this.props.data.talent.source.quora || '', | |
blog: this.props.data.talent.source.blog || '', | |
eventbrite: this.props.data.talent.source.eventbrite || '', | |
typeform: this.props.data.talent.source.typeform || '', | |
twitter: this.props.data.talent.source.twitter || '', | |
salaryExpectation: this.props.data.talent.work.salaryExpectation || '', | |
whyInterview: this.props.data.talent.profile.whyInterview || '', | |
currentJobTitle: this.props.data.talent.profile.currentJobTitle || '', | |
talent: this.props.data.talent | |
}) | |
} | |
handleInputChange(e) { | |
const name = e.target.name; | |
this.setState({ | |
[name]: e.target.value, | |
talentSaved: false | |
}); | |
} | |
uploadImage(e) { | |
const formData = new FormData(); | |
const logoFile = e.target.files[0]; | |
formData.append('file', logoFile) | |
request.post(`${process.env.REACT_APP_BRAVE_FILE_UPLOAD}`) | |
.send(formData) | |
.end((err, response) => { | |
if (err) { | |
console.log(err); | |
} else if (response.ok) { | |
const fileURL = JSON.parse(response.text).data.files[0].url; | |
this.setState({ | |
//Use api image url | |
logo: fileURL, | |
//Removes "add logo" text | |
logoMessage: null | |
}) | |
} | |
}); | |
} | |
//Display file name for input file | |
displayFileName(e) { | |
const fileName = this.pdfInput.files[0].name ? this.pdfInput.files[0].name : null; | |
this.setState({ | |
uploadFileName: fileName, | |
}); | |
this.uploadPDF(e); | |
} | |
//Upload PDF JD to server | |
uploadPDF(e) { | |
let formData = new FormData(); | |
const pdfFile = this.pdfInput.files[0]; | |
formData.append('file', pdfFile); | |
//console.log(`${process.env.REACT_APP_CORS_URL}${process.env.REACT_APP_BRAVE_FILE_UPLOAD}`); | |
request.post(`${process.env.REACT_APP_BRAVE_FILE_UPLOAD}`) | |
.send(formData) | |
.on('progress', e => { | |
this.setState({ uploadStatus: 'Uploading CV'}); | |
}) | |
.end((err, response) => { | |
if(err) { | |
console.log(err); | |
} else if(response.ok) { | |
const fileURL = JSON.parse(response.text).data.files[0].url; | |
this.setState({ | |
cv: fileURL, | |
//uploadComplete: true, | |
uploadStatus: 'Upload Complete' | |
}); | |
} | |
}); | |
} | |
render() { | |
if (this.props.id && this.props.data.loading) { | |
return (<LoadingFetch />); | |
} | |
if (this.props.id && this.props.data.error) { | |
return ( | |
<p>No Talent with this ID. {this.props.data.error.toString()}</p> | |
) | |
} | |
return ( | |
<form className="add-talent" onSubmit={this.handleSubmit}> | |
<div className="add-talent__info"> | |
<h2 className="add-talent__heading">{ this.props.id ? `Talent: ${this.props.id}` : 'Add a new talent' }</h2> | |
<div className="add-talent__top wrapper mb1"> | |
<div className="add-talent-info"> | |
<label className="form__label form__2col add-talent__label pr3"> | |
First Name | |
<input type="text" className="form__text-input" placeholder="First Name" onChange={this.handleInputChange} value={this.state.firstName} name="firstName"/> | |
</label> | |
<label className="form__label form__2col add-talent__label"> | |
Last Name | |
<input type="text" className="form__text-input" placeholder="Last Name" onChange={this.handleInputChange} value={this.state.lastName} name="lastName"/> | |
</label> | |
<label className="form__label form__2col add-talent__label pr3"> | |
Email Address | |
<input type="text" className="form__text-input" placeholder="Email Address" onChange={this.handleInputChange} value={this.state.email} name="email"/> | |
</label> | |
<label className="form__label form__2col add-talent__label"> | |
Phone Number | |
<input type="tel" className="form__text-input" placeholder="Phone Number" onChange={this.handleInputChange} value={this.state.phone} name="phone"/> | |
</label> | |
<label className="form__label add-talent__label"> | |
Address | |
<input type="text" className="form__text-input" placeholder="Address" onChange={this.handleInputChange} value={this.state.address || ''} name="address"/> | |
</label> | |
<label className="form__label form__2col add-talent__label pr3"> | |
City | |
<input type="text" className="form__text-input" placeholder="City" onChange={this.handleInputChange} value={this.state.city || ''} name="city"/> | |
</label> | |
<label className="form__label form__2col add-talent__label"> | |
State or Region | |
<input type="text" className="form__text-input" placeholder="State or Region" onChange={this.handleInputChange} value={this.state.region || ''} name="region"/> | |
</label> | |
<label className="form__label form__2col add-talent__label pr3"> | |
Postal Code | |
<input type="text" className="form__text-input" placeholder="Postal Code" onChange={this.handleInputChange} value={this.state.postalCode || ''} name="postalCode"/> | |
</label> | |
<label className="form__label form__2col add-talent__label"> | |
Country | |
<input type="text" className="form__text-input" placeholder="Country" onChange={this.handleInputChange} value={this.state.country || ''} name="country"/> | |
</label> | |
<label className="form__label form__2col add-talent__label"> | |
Citizenship | |
<input type="text" className="form__text-input" placeholder="Citizenship" onChange={this.handleInputChange} value={this.state.citizenship || ''} name="citizenship"/> | |
</label> | |
</div> | |
</div> | |
<div className="add-talent__middle wrapper"> | |
</div> | |
<div className="add-talent__bio wrapper"> | |
<label className="form__label add-talent__label"> | |
Why Hire | |
<textarea className="form__text-input form__textarea" placeholder="Brief Paragraph on why to hire or interview" onChange={this.handleInputChange} value={this.state.whyInterview} name="whyInterview"></textarea> | |
</label> | |
<SingleInput type="text" label="Salary Expectation" name="salaryExpectation" value={this.state.salaryExpectation || ''} placeholder="$55,000" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3" /> | |
<SingleInput type="text" label="Current Job Title" name="currentJobTitle" value={this.state.currentJobTitle || ''} placeholder="Graphic Designer" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3" /> | |
{/*<SingleInput type="file" label="CV" name="cv" placeholder="URL of CV File" onChange={this.uploadPDF} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3 form__upload-label" />*/} | |
<label htmlFor="form-file" className="form__upload-label add-talent__label form__2col pr3 form__label"> | |
Upload CV - <span className="form__upload-placeholder">{this.state.uploadFileName}</span><br/> | |
<div className="btn mb0">Upload</div> | |
<span className={`black-30 f7 pl3 ${this.state.uploadStatus === 'Upload Complete' && 'color__positive'}`}>{this.state.uploadStatus}</span> | |
<input type="file" id="form-file" className="form__upload" ref={(input) => this.pdfInput = input} onChange={this.displayFileName}/> | |
</label> | |
<SingleInput type="text" label="Website" name="website" value={this.state.website || ''} placeholder="https://www.website.com" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col" /> | |
<SingleInput type="text" label="Github" name="github" value={this.state.github || ''} placeholder="github URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3" /> | |
<SingleInput type="text" label="Bitbucket" name="bitbucket" value={this.state.bitbucket || ''} placeholder="bitbucket URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3" /> | |
<SingleInput type="text" label="StackOverflow" name="stackoverflow" value={this.state.stackoverflow || ''} placeholder="Stackoverflow URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col" /> | |
<SingleInput type="text" label="LinkedIn" name="linkedin" value={this.state.linkedin || ''} placeholder="LinkedIn URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3" /> | |
<SingleInput type="text" label="Medium" name="medium" value={this.state.medium || ''} placeholder="Medium URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col" /> | |
<SingleInput type="text" label="Quora" name="quora" value={this.state.quora || ''} placeholder="Quora URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3" /> | |
<SingleInput type="text" label="Blog" name="blog" value={this.state.blog || ''} placeholder="Blog URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col" /> | |
<SingleInput type="text" label="EventBrite" name="eventbrite" value={this.state.eventbrite || ''} placeholder="EventBrite URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3" /> | |
<SingleInput type="text" label="Typeform" name="typeform" value={this.state.typeform || ''} placeholder="Typeform URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col" /> | |
<SingleInput type="text" label="Twitter" name="twitter" value={this.state.twitter || ''} placeholder="Twitter URL" onChange={this.handleInputChange} extraInputClass="form__text-input" extraLabelClass="add-talent__label form__2col pr3" /> | |
<button id="btn-talent-save" className="form__submit right" type="submit" className={"btn btn--ghost "+(this.state.talentSaved ? 'btn--disabled' : '')}>Submit</button> | |
</div> | |
</div> | |
</form> | |
); | |
} | |
handleSubmit(e) { | |
const submitBtn = document.getElementById('btn-talent-save'); | |
submitBtn.classList.add('btn--processing'); | |
e.preventDefault(); | |
//if (!this.props.id) {} | |
const id = this.props.id || this.state.id; | |
const firstName = this.state.firstName; | |
const lastName = this.state.lastName; | |
const email = this.state.email; | |
const phone = this.state.phone; | |
const address = this.state.address; | |
const city = this.state.city; | |
const state = this.state.state; | |
const country = this.state.country; | |
const citizenship = this.state.citizenship; | |
const postalCode = this.state.postalCode; | |
const cv = this.state.cv; | |
const website = this.state.website; | |
const github = this.state.github; | |
const bitbucket = this.state.bitbucket; | |
const stackoverflow = this.state.stackoverflow; | |
const linkedin = this.state.linkedin; | |
const medium = this.state.medium; | |
const quora = this.state.quora; | |
const blog = this.state.blog; | |
const eventbrite = this.state.eventbrite; | |
const typeform = this.state.typeform; | |
const twitter = this.state.twitter; | |
const salaryExpectation = this.state.salaryExpectation; | |
const whyInterview = this.state.whyInterview; | |
const currentJobTitle = this.state.currentJobTitle; | |
const description = this.state.description; | |
const active = true; | |
this.props.mutate({ | |
variables: { | |
id, | |
firstName, | |
lastName, | |
email, | |
phone, | |
address, | |
city, | |
state, | |
country, | |
citizenship, | |
postalCode, | |
cv, | |
website, | |
github, | |
bitbucket, | |
stackoverflow, | |
linkedin, | |
medium, | |
quora, | |
blog, | |
eventbrite, | |
typeform, | |
twitter, | |
salaryExpectation, | |
whyInterview, | |
currentJobTitle, | |
description, | |
active, | |
}, | |
}) | |
.then(() => { | |
// this.props.handleCloseModal(); | |
submitBtn.classList.remove('btn--processing'); | |
this.setState({ | |
talentSaved: true, | |
}); | |
//this.props.handleCloseModal(); | |
}) | |
.catch(error => { | |
const getNetworkErrors = error => error.networkError.response.json().then(e => e.errors.map(e => e.message).join(',')) | |
if (error.networkError) { | |
//this.props.handleCloseModal(); | |
getNetworkErrors(error).then(console.log) | |
} else { | |
console.log(error.message) | |
} | |
submitBtn.classList.remove('btn--processing'); | |
}); | |
} | |
} | |
export const TalentQuery = gql` | |
query TalentQuery($id: String){ | |
talent(id: $id) { | |
id | |
contact { | |
firstName | |
lastName | |
phone | |
address | |
city | |
country | |
region | |
postalCode | |
} | |
source { | |
cv | |
website | |
github | |
bitbucket | |
stackoverflow | |
medium | |
quora | |
blog | |
eventbrite | |
typeform | |
} | |
profile { | |
whyInterview | |
citizenship | |
} | |
work { | |
salaryExpectation | |
currentJobTitle | |
} | |
} | |
} | |
` | |
export const pushTalentMutation = gql` | |
mutation pushTalent( | |
$id: String, | |
$firstName: String!, | |
$lastName: String!, | |
$email: String!, | |
$phone: String, | |
$address: String, | |
$city: String, | |
$region: String, | |
$country: String, | |
$citizenship: [String], | |
$postalCode: String, | |
$cv: String, | |
$website: String, | |
$github: String, | |
$bitbucket: String, | |
$stackoverflow: String, | |
$linkedin: String, | |
$medium: String, | |
$quora: String, | |
$blog: String, | |
$eventbrite: String, | |
$typeform: String, | |
$twitter: String, | |
$salaryExpectation: String, | |
$whyInterview: String, | |
$currentJobTitle: String, | |
) { | |
pushTalent( | |
input: { | |
id: $id | |
contact: [{ | |
firstName: $firstName | |
lastName: $lastName | |
email: $email | |
phone: $phone | |
address: $address | |
city: $city | |
country: $country | |
region: $region | |
postalCode: $postalCode | |
}] | |
source: { | |
cv: $cv | |
website: $website | |
github: $github | |
bitbucket: $bitbucket | |
stackoverflow: $stackoverflow | |
linkedin: $linkedin | |
medium: $medium | |
quora: $quora | |
blog: $blog | |
eventbrite: $eventbrite | |
typeform: $typeform | |
twitter: $twitter | |
} | |
profile: { | |
whyInterview: $whyInterview | |
citizenship: $citizenship | |
} | |
work: { | |
salaryExpectation: $salaryExpectation | |
currentJobTitle: $currentJobTitle | |
} | |
} | |
) { | |
id | |
contact { | |
firstName | |
lastName | |
phone | |
address | |
city | |
country | |
region | |
postalCode | |
} | |
source { | |
cv | |
website | |
github | |
bitbucket | |
stackoverflow | |
medium | |
quora | |
blog | |
eventbrite | |
typeform | |
} | |
profile { | |
whyInterview | |
citizenship | |
} | |
work { | |
salaryExpectation | |
currentJobTitle | |
} | |
} | |
} | |
` | |
const TalentFormWithData = compose( | |
graphql(pushTalentMutation, { | |
options: (props) => ({ | |
refetchQueries: [ | |
// { query: TalentAllQuery }, | |
{ query: TalentQuery, variables: { id: props.id } }, | |
], | |
}) | |
}), | |
graphql(TalentQuery, { | |
options: (ownProps) => ({ | |
variables: { | |
id: ownProps.id | |
} | |
}), | |
skip: (ownProps) => !ownProps.id, | |
}) | |
)(AddEditTalent) | |
export default TalentFormWithData; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment