From 3b9800434f4baef68844068beee256bbf11495c9 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Tue, 26 Nov 2019 15:02:36 +0200 Subject: [PATCH 01/18] intial setup --- client/src/components/StepsQuestions/index.js | 314 ++++-------------- .../StepsQuestions/{ => old}/UploadImg.js | 0 .../StepsQuestions/{ => old}/index.css | 0 .../components/StepsQuestions/old/index.js | 252 ++++++++++++++ .../subcomponents/TypesQuestion.js | 32 ++ .../subcomponents/WelcomeMessage.js | 26 ++ .../StepsQuestions/subcomponents/index.js | 3 + client/src/components/index.js | 4 +- client/src/pages/addNewSitSpot/index.js | 171 +--------- .../pages/addNewSitSpot/{ => old}/fakeData.js | 2 +- .../pages/addNewSitSpot/{ => old}/index.css | 0 client/src/pages/addNewSitSpot/old/index.js | 164 +++++++++ client/src/pages/addNewSitSpot/style.css | 12 + client/src/staticDataSet/questions.js | 4 + 14 files changed, 581 insertions(+), 403 deletions(-) rename client/src/components/StepsQuestions/{ => old}/UploadImg.js (100%) rename client/src/components/StepsQuestions/{ => old}/index.css (100%) create mode 100644 client/src/components/StepsQuestions/old/index.js create mode 100644 client/src/components/StepsQuestions/subcomponents/TypesQuestion.js create mode 100644 client/src/components/StepsQuestions/subcomponents/WelcomeMessage.js create mode 100644 client/src/components/StepsQuestions/subcomponents/index.js rename client/src/pages/addNewSitSpot/{ => old}/fakeData.js (95%) rename client/src/pages/addNewSitSpot/{ => old}/index.css (100%) create mode 100644 client/src/pages/addNewSitSpot/old/index.js create mode 100644 client/src/pages/addNewSitSpot/style.css create mode 100644 client/src/staticDataSet/questions.js diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index 7d9c9bc..d602af3 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -1,252 +1,84 @@ import React from 'react'; -import propTypes from 'prop-types'; -import { Steps, Button, Select, Radio } from 'antd'; -import { getCountryNames, getCities } from 'full-countries-cities'; - -import UploadImg from './UploadImg'; - -import './index.css'; +import { Steps } from 'antd'; +import subcomponents from './subcomponents'; +import questions from '../../staticDataSet/questions'; const { Step } = Steps; -const BusinessTypes = Object.freeze({ - stay: 'place to stay', - eat: 'place to eat or drink', - shop: 'place to shop', -}); - -const ButtonInfo = Object.freeze({ - START: 'Start', - NEXT: 'Next', - PREVIOUS: 'Previous', - DONE: 'Done', - TYPE: 'primary', - MESSAGE: 'Processing complete!', -}); - -const renderError = msg => ( -
-

{msg}

-
-); - -const checkError = (currentStep, errors) => { - if (currentStep === 1) { - if (errors.name) { - return renderError(errors.name); - } - } else if (currentStep === 3) { - if (errors.country) { - return renderError(errors.country); - } - } else if (currentStep === 4) { - if (errors.city) { - return renderError(errors.city); - } - } else if (currentStep === 5) { - if (errors.businessType) { - return renderError(errors.businessType); - } - } - return undefined; -}; - -const renderInput = (values, currentStep, funcs) => { - const stateKey = currentStep === 1 ? 'name' : 'linkSite'; - return ( - { - funcs.handleChange(event.target.value, stateKey); - }} - /> - ); -}; - -const renderOptions = list => { - const { Option } = Select; - - return list.map(item => ( - - )); -}; - -const dropDownFilter = (input, option) => - option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0; - -const renderSelect = (values, currentStep, funcs) => { - const stateKey = currentStep === 3 ? 'country' : 'city'; - let cities; - if (currentStep === 4) { - cities = values.country ? getCities(values.country) : []; - } - return ( - - ); -}; - -const renderRadio = (values, funcs) => ( - - {Object.entries(BusinessTypes).map(([key, value]) => ( - - funcs.handleChange(event.target.value, 'businessType') - } - > - {value} - - ))} - -); - -const renderQuestion = ( - questions, - values, - currentStep, - funcs, - classes, - required -) => ( -
- {currentStep > 0 && ( -
-

- {questions[currentStep].title} - {required[currentStep] ? ( - * - ) : ( - '' - )} -

-
- )} - {questions[currentStep].imgUrl && ( -
- img question ({ + content: subcomponents[type], + ...rest, +})); + +export default class StepsQuestions extends React.Component { + state = { + currentStep: 0, + data: questions.reduce( + (acc, { key }) => (key ? { ...acc, [key]: '' } : acc), + {} + ), + }; + + handleStateChange = ({ key, value }) => + this.setState(({ data }) => ({ data: { ...data, [key]: value } })); + + renderContent = () => + questionsAndComponents.map(({ content: Content, stepNo, key }) => { + const { data } = this.state; + return ( + this.handleStateChange({ key, value })} /> + ); + }); + + renderSteps = () => { + const { currentStep } = this.state; + return ( +
+ + {questionsAndComponents.map(({ stepNo }) => ( + + ))} +
- )} - {currentStep === 0 && ( -

{questions[0].message}

- )} - {currentStep <= 2 && - currentStep > 0 && - renderInput(values, currentStep, funcs)} - {currentStep >= 3 && - currentStep < 5 && - renderSelect(values, currentStep, funcs, classes)} + ); + }; - {currentStep === 5 && renderRadio(values, funcs)} - {currentStep >= 6 && currentStep <= 7 && ( - - )} -
-); + prev = () => + this.setState(({ currentStep }) => ({ currentStep: currentStep - 1 })); -const renderButton = (text, type, func, checkRequirdStep = false) => ( - -); + next = () => + this.setState(({ currentStep }) => ({ currentStep: currentStep + 1 })); -const StepsQuestions = ({ - questions, - currentStep, - values, - funcs, - classes, - required, - errors, -}) => ( -
- - {questions.map(({ id }) => ( - - ))} - -
- {renderQuestion(questions, values, currentStep, funcs, classes, required)} -
-
- {checkError(currentStep, errors)} -
- {currentStep < questions.length - 1 && - renderButton( - currentStep === 0 ? ButtonInfo.START : ButtonInfo.NEXT, - ButtonInfo.TYPE, - currentStep === 0 || currentStep === 2 || currentStep === 6 - ? funcs.next - : funcs.handleValidate, - true + render() { + const { currentStep } = this.state; + // const { onSubmit } = this.props; + // console.log(this.state.questions); + return ( +
+ {this.renderSteps()} + {this.renderContent()} +
+ {currentStep > 0 && ( + )} - - {currentStep === questions.length - 1 && - renderButton(ButtonInfo.DONE, ButtonInfo.TYPE, funcs.onSubmit)} - - {currentStep > 0 && renderButton(ButtonInfo.PREVIOUS, null, funcs.prev)} + {currentStep < questions.length - 1 && ( + + )} + {currentStep === questions.length - 1 && ( + + )} +
-
-
-); - -StepsQuestions.propTypes = { - currentStep: propTypes.number.isRequired, - classes: propTypes.arrayOf(propTypes.string), - questions: propTypes.arrayOf(propTypes.any).isRequired, - funcs: propTypes.shape({ - next: propTypes.func.isRequired, - prev: propTypes.func.isRequired, - handleChange: propTypes.func.isRequired, - onSubmit: propTypes.func.isRequired, - handleValidate: propTypes.func.isRequired, - }).isRequired, - values: propTypes.shape({ - name: propTypes.string.isRequired, - linkSite: propTypes.string.isRequired, - country: propTypes.string.isRequired, - city: propTypes.string.isRequired, - businessType: propTypes.string.isRequired, - imgUrlOne: propTypes.string, - imgUrlTwo: propTypes.string, - }).isRequired, - required: propTypes.objectOf(propTypes.bool), - errors: propTypes.objectOf(propTypes.any), -}; - -StepsQuestions.defaultProps = { - classes: '', - required: {}, - errors: {}, -}; - -export default StepsQuestions; + ); + } +} diff --git a/client/src/components/StepsQuestions/UploadImg.js b/client/src/components/StepsQuestions/old/UploadImg.js similarity index 100% rename from client/src/components/StepsQuestions/UploadImg.js rename to client/src/components/StepsQuestions/old/UploadImg.js diff --git a/client/src/components/StepsQuestions/index.css b/client/src/components/StepsQuestions/old/index.css similarity index 100% rename from client/src/components/StepsQuestions/index.css rename to client/src/components/StepsQuestions/old/index.css diff --git a/client/src/components/StepsQuestions/old/index.js b/client/src/components/StepsQuestions/old/index.js new file mode 100644 index 0000000..7d9c9bc --- /dev/null +++ b/client/src/components/StepsQuestions/old/index.js @@ -0,0 +1,252 @@ +import React from 'react'; +import propTypes from 'prop-types'; +import { Steps, Button, Select, Radio } from 'antd'; +import { getCountryNames, getCities } from 'full-countries-cities'; + +import UploadImg from './UploadImg'; + +import './index.css'; + +const { Step } = Steps; + +const BusinessTypes = Object.freeze({ + stay: 'place to stay', + eat: 'place to eat or drink', + shop: 'place to shop', +}); + +const ButtonInfo = Object.freeze({ + START: 'Start', + NEXT: 'Next', + PREVIOUS: 'Previous', + DONE: 'Done', + TYPE: 'primary', + MESSAGE: 'Processing complete!', +}); + +const renderError = msg => ( +
+

{msg}

+
+); + +const checkError = (currentStep, errors) => { + if (currentStep === 1) { + if (errors.name) { + return renderError(errors.name); + } + } else if (currentStep === 3) { + if (errors.country) { + return renderError(errors.country); + } + } else if (currentStep === 4) { + if (errors.city) { + return renderError(errors.city); + } + } else if (currentStep === 5) { + if (errors.businessType) { + return renderError(errors.businessType); + } + } + return undefined; +}; + +const renderInput = (values, currentStep, funcs) => { + const stateKey = currentStep === 1 ? 'name' : 'linkSite'; + return ( + { + funcs.handleChange(event.target.value, stateKey); + }} + /> + ); +}; + +const renderOptions = list => { + const { Option } = Select; + + return list.map(item => ( + + )); +}; + +const dropDownFilter = (input, option) => + option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0; + +const renderSelect = (values, currentStep, funcs) => { + const stateKey = currentStep === 3 ? 'country' : 'city'; + let cities; + if (currentStep === 4) { + cities = values.country ? getCities(values.country) : []; + } + return ( + + ); +}; + +const renderRadio = (values, funcs) => ( + + {Object.entries(BusinessTypes).map(([key, value]) => ( + + funcs.handleChange(event.target.value, 'businessType') + } + > + {value} + + ))} + +); + +const renderQuestion = ( + questions, + values, + currentStep, + funcs, + classes, + required +) => ( +
+ {currentStep > 0 && ( +
+

+ {questions[currentStep].title} + {required[currentStep] ? ( + * + ) : ( + '' + )} +

+
+ )} + {questions[currentStep].imgUrl && ( +
+ img question +
+ )} + {currentStep === 0 && ( +

{questions[0].message}

+ )} + {currentStep <= 2 && + currentStep > 0 && + renderInput(values, currentStep, funcs)} + {currentStep >= 3 && + currentStep < 5 && + renderSelect(values, currentStep, funcs, classes)} + + {currentStep === 5 && renderRadio(values, funcs)} + {currentStep >= 6 && currentStep <= 7 && ( + + )} +
+); + +const renderButton = (text, type, func, checkRequirdStep = false) => ( + +); + +const StepsQuestions = ({ + questions, + currentStep, + values, + funcs, + classes, + required, + errors, +}) => ( +
+ + {questions.map(({ id }) => ( + + ))} + +
+ {renderQuestion(questions, values, currentStep, funcs, classes, required)} +
+
+ {checkError(currentStep, errors)} +
+ {currentStep < questions.length - 1 && + renderButton( + currentStep === 0 ? ButtonInfo.START : ButtonInfo.NEXT, + ButtonInfo.TYPE, + currentStep === 0 || currentStep === 2 || currentStep === 6 + ? funcs.next + : funcs.handleValidate, + true + )} + + {currentStep === questions.length - 1 && + renderButton(ButtonInfo.DONE, ButtonInfo.TYPE, funcs.onSubmit)} + + {currentStep > 0 && renderButton(ButtonInfo.PREVIOUS, null, funcs.prev)} +
+
+
+); + +StepsQuestions.propTypes = { + currentStep: propTypes.number.isRequired, + classes: propTypes.arrayOf(propTypes.string), + questions: propTypes.arrayOf(propTypes.any).isRequired, + funcs: propTypes.shape({ + next: propTypes.func.isRequired, + prev: propTypes.func.isRequired, + handleChange: propTypes.func.isRequired, + onSubmit: propTypes.func.isRequired, + handleValidate: propTypes.func.isRequired, + }).isRequired, + values: propTypes.shape({ + name: propTypes.string.isRequired, + linkSite: propTypes.string.isRequired, + country: propTypes.string.isRequired, + city: propTypes.string.isRequired, + businessType: propTypes.string.isRequired, + imgUrlOne: propTypes.string, + imgUrlTwo: propTypes.string, + }).isRequired, + required: propTypes.objectOf(propTypes.bool), + errors: propTypes.objectOf(propTypes.any), +}; + +StepsQuestions.defaultProps = { + classes: '', + required: {}, + errors: {}, +}; + +export default StepsQuestions; diff --git a/client/src/components/StepsQuestions/subcomponents/TypesQuestion.js b/client/src/components/StepsQuestions/subcomponents/TypesQuestion.js new file mode 100644 index 0000000..785c6f1 --- /dev/null +++ b/client/src/components/StepsQuestions/subcomponents/TypesQuestion.js @@ -0,0 +1,32 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { Radio } from 'antd'; + +const BusinessTypes = Object.freeze({ + stay: 'place to stay', + eat: 'place to eat or drink', + shop: 'place to shop', +}); + +const TypeQuestion = ({ value, handleStateChange }) => ( +
+ + {Object.entries(BusinessTypes).map(([key, text]) => ( + handleStateChange(e.target.value)} + > + {text} + + ))} + +
+); + +TypeQuestion.propTypes = { + value: PropTypes.string.isRequired, + handleStateChange: PropTypes.func.isRequired, +}; +export default TypeQuestion; diff --git a/client/src/components/StepsQuestions/subcomponents/WelcomeMessage.js b/client/src/components/StepsQuestions/subcomponents/WelcomeMessage.js new file mode 100644 index 0000000..37389e7 --- /dev/null +++ b/client/src/components/StepsQuestions/subcomponents/WelcomeMessage.js @@ -0,0 +1,26 @@ +// import React from 'react'; +// import { Radio } from 'antd'; + +// const BusinessTypes = Object.freeze({ +// stay: 'place to stay', +// eat: 'place to eat or drink', +// shop: 'place to shop', +// }); +// export default (values, handleStateChange) => ( +//
+// +// {Object.entries(BusinessTypes).map(([key, value]) => ( +// {} +// // handleStateChange({ businessType: event.target.value }) +// } +// > +// {value} +// +// ))} +// +//
+// ); diff --git a/client/src/components/StepsQuestions/subcomponents/index.js b/client/src/components/StepsQuestions/subcomponents/index.js new file mode 100644 index 0000000..95e49d7 --- /dev/null +++ b/client/src/components/StepsQuestions/subcomponents/index.js @@ -0,0 +1,3 @@ +import TypeQuestion from './TypesQuestion'; + +export default { TypeQuestion }; diff --git a/client/src/components/index.js b/client/src/components/index.js index aceccd2..d8cf1a5 100644 --- a/client/src/components/index.js +++ b/client/src/components/index.js @@ -11,7 +11,8 @@ import MagicalFactor from './MagicalFactor'; import Review from './Review'; import ImageCarousel from './ImageCarousel'; import Layout from './Layout'; -import StepsQuestions from './StepsQuestions'; +import StepsQuestions from './StepsQuestions/old'; +import StepsQuestions2 from './StepsQuestions'; export { Button, @@ -28,4 +29,5 @@ export { ImageCarousel, Layout, StepsQuestions, + StepsQuestions2, }; diff --git a/client/src/pages/addNewSitSpot/index.js b/client/src/pages/addNewSitSpot/index.js index f07a79b..083760e 100644 --- a/client/src/pages/addNewSitSpot/index.js +++ b/client/src/pages/addNewSitSpot/index.js @@ -1,164 +1,15 @@ -import React, { Component } from 'react'; -import propTypes from 'prop-types'; +import React from 'react'; +import { StepsQuestions2 as Steps } from '../../components'; -import addPlaceValidation from '../../utils'; -import { addPlace } from '../../services/api'; +import './style.css'; -import { StepsQuestions } from '../../components'; -import Questions from './fakeData'; +const onSubmit = something => something; -import './index.css'; +const AddNewSitspot = () => ( +
+
+ +
+); -const Classes = [ - 'welcome', - 'name', - 'website', - 'country', - 'city', - 'type', - 'upload-img', - 'upload-img', -]; - -class AddNewSitSpot extends Component { - state = { - data: { - name: '', - linkSite: '', - country: '', - city: '', - businessType: '', - img1: undefined, - img2: undefined, - }, - errors: { - name: null, - country: null, - city: null, - businessType: null, - }, - currentStep: 0, - }; - - onSubmit = () => { - const { - data, - data: { businessType }, - } = this.state; - const { history } = this.props; - const formData = new FormData(); - Object.entries(data).forEach( - ([key, value]) => !!value && formData.append(key, value) - ); - - addPlace(formData).then(({ data: id }) => - history.push(`/add-review/${businessType}/${id}`) - ); - }; - - handleChange = (value, dataKey) => { - this.setState( - prevState => ({ - ...prevState, - data: { ...prevState.data, [dataKey]: value }, - }), - () => this.handleValidate(false) - ); - }; - - handleError = (value, errKey) => { - this.setState(prevState => ({ - ...prevState, - errors: { ...prevState.errors, [errKey]: value || null }, - })); - }; - - handleValidate = checkEvent => { - const { - data: { name, country, city, businessType }, - currentStep, - } = this.state; - - if (currentStep === 1) { - addPlaceValidation.placeValidName - .validate({ name }) - .then(() => { - if (checkEvent) this.next(); - this.handleError(null, 'name'); - }) - .catch(err => { - this.handleError(err.message, 'name'); - }); - } else if (currentStep === 3) { - addPlaceValidation.placeValidCountry - .validate({ country }) - .then(() => { - if (checkEvent) this.next(); - this.handleError(null, 'country'); - }) - .catch(err => this.handleError(err.message, 'country')); - } else if (currentStep === 4) { - addPlaceValidation.placeValidCity - .validate({ city }) - .then(() => { - if (checkEvent) this.next(); - this.handleError(null, 'city'); - }) - .catch(err => this.handleError(err.message, 'city')); - } else if (currentStep === 5) { - addPlaceValidation.placeValidBusinessType - .validate({ businessType }) - .then(() => { - if (checkEvent) this.next(); - this.handleError(null, 'businessType'); - }) - .catch(err => this.handleError(err.message, 'businessType')); - } - // else if (currentStep === 0) { - // this.next(); - // } - }; - - next = () => - this.setState(({ currentStep }) => ({ - currentStep: currentStep + 1, - })); - - prev = () => - this.setState(({ currentStep }) => ({ - currentStep: currentStep - 1, - })); - - render() { - const { currentStep, data, errors } = this.state; - - return ( -
-
-
- -
-
- ); - } -} - -AddNewSitSpot.propTypes = { - history: propTypes.shape({ push: propTypes.func.isRequired }).isRequired, -}; -export default AddNewSitSpot; +export default AddNewSitspot; diff --git a/client/src/pages/addNewSitSpot/fakeData.js b/client/src/pages/addNewSitSpot/old/fakeData.js similarity index 95% rename from client/src/pages/addNewSitSpot/fakeData.js rename to client/src/pages/addNewSitSpot/old/fakeData.js index f6026c0..0c6636c 100644 --- a/client/src/pages/addNewSitSpot/fakeData.js +++ b/client/src/pages/addNewSitSpot/old/fakeData.js @@ -1,4 +1,4 @@ -import nameImg from '../../assets/question-1.png'; +import nameImg from '../../../assets/question-1.png'; const Questions = [ { diff --git a/client/src/pages/addNewSitSpot/index.css b/client/src/pages/addNewSitSpot/old/index.css similarity index 100% rename from client/src/pages/addNewSitSpot/index.css rename to client/src/pages/addNewSitSpot/old/index.css diff --git a/client/src/pages/addNewSitSpot/old/index.js b/client/src/pages/addNewSitSpot/old/index.js new file mode 100644 index 0000000..5115783 --- /dev/null +++ b/client/src/pages/addNewSitSpot/old/index.js @@ -0,0 +1,164 @@ +import React, { Component } from 'react'; +import propTypes from 'prop-types'; + +import addPlaceValidation from '../../../utils'; +import { addPlace } from '../../../services/api'; + +import { StepsQuestions } from '../../../components'; +import Questions from './fakeData'; + +import './index.css'; + +const Classes = [ + 'welcome', + 'name', + 'website', + 'country', + 'city', + 'type', + 'upload-img', + 'upload-img', +]; + +class AddNewSitSpot extends Component { + state = { + data: { + name: '', + linkSite: '', + country: '', + city: '', + businessType: '', + img1: undefined, + img2: undefined, + }, + errors: { + name: null, + country: null, + city: null, + businessType: null, + }, + currentStep: 0, + }; + + onSubmit = () => { + const { + data, + data: { businessType }, + } = this.state; + const { history } = this.props; + const formData = new FormData(); + Object.entries(data).forEach( + ([key, value]) => !!value && formData.append(key, value) + ); + + addPlace(formData).then(({ data: id }) => + history.push(`/add-review/${businessType}/${id}`) + ); + }; + + handleChange = (value, dataKey) => { + this.setState( + prevState => ({ + ...prevState, + data: { ...prevState.data, [dataKey]: value }, + }), + () => this.handleValidate(false) + ); + }; + + handleError = (value, errKey) => { + this.setState(prevState => ({ + ...prevState, + errors: { ...prevState.errors, [errKey]: value || null }, + })); + }; + + handleValidate = checkEvent => { + const { + data: { name, country, city, businessType }, + currentStep, + } = this.state; + + if (currentStep === 1) { + addPlaceValidation.placeValidName + .validate({ name }) + .then(() => { + if (checkEvent) this.next(); + this.handleError(null, 'name'); + }) + .catch(err => { + this.handleError(err.message, 'name'); + }); + } else if (currentStep === 3) { + addPlaceValidation.placeValidCountry + .validate({ country }) + .then(() => { + if (checkEvent) this.next(); + this.handleError(null, 'country'); + }) + .catch(err => this.handleError(err.message, 'country')); + } else if (currentStep === 4) { + addPlaceValidation.placeValidCity + .validate({ city }) + .then(() => { + if (checkEvent) this.next(); + this.handleError(null, 'city'); + }) + .catch(err => this.handleError(err.message, 'city')); + } else if (currentStep === 5) { + addPlaceValidation.placeValidBusinessType + .validate({ businessType }) + .then(() => { + if (checkEvent) this.next(); + this.handleError(null, 'businessType'); + }) + .catch(err => this.handleError(err.message, 'businessType')); + } + // else if (currentStep === 0) { + // this.next(); + // } + }; + + next = () => + this.setState(({ currentStep }) => ({ + currentStep: currentStep + 1, + })); + + prev = () => + this.setState(({ currentStep }) => ({ + currentStep: currentStep - 1, + })); + + render() { + const { currentStep, data, errors } = this.state; + + return ( +
+
+
+ +
+
+ ); + } +} + +AddNewSitSpot.propTypes = { + history: propTypes.shape({ push: propTypes.func.isRequired }).isRequired, +}; +export default AddNewSitSpot; diff --git a/client/src/pages/addNewSitSpot/style.css b/client/src/pages/addNewSitSpot/style.css new file mode 100644 index 0000000..ff91c17 --- /dev/null +++ b/client/src/pages/addNewSitSpot/style.css @@ -0,0 +1,12 @@ +.add-place__wrapper { + margin: 0 10%; + } + + .add-place__header { + background: url('../../assets/images/addrecom.png') no-repeat center bottom/cover; + height: 12vh; + } + + .steps__btn { + margin-right: 1rem; + } \ No newline at end of file diff --git a/client/src/staticDataSet/questions.js b/client/src/staticDataSet/questions.js new file mode 100644 index 0000000..795f5ab --- /dev/null +++ b/client/src/staticDataSet/questions.js @@ -0,0 +1,4 @@ +export default [ + { stepNo: 0, key: 'type', question: 'something?', type: 'TypeQuestion' }, + { stepNo: 1, key: 'name', question: 'welcome?', type: 'TypeQuestion' }, +]; From d1230a1150ccb44e21e609697710a4c52c9a1538 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Tue, 26 Nov 2019 15:41:46 +0200 Subject: [PATCH 02/18] title in steps --- client/src/components/StepsQuestions/index.js | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index d602af3..d9f4e2d 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -23,16 +23,23 @@ export default class StepsQuestions extends React.Component { this.setState(({ data }) => ({ data: { ...data, [key]: value } })); renderContent = () => - questionsAndComponents.map(({ content: Content, stepNo, key }) => { - const { data } = this.state; - return ( - this.handleStateChange({ key, value })} - /> - ); - }); + questionsAndComponents.map( + ({ content: Component, stepNo, key, question }) => { + const { data } = this.state; + return ( +
+

{question}

+ + this.handleStateChange({ key, value }) + } + /> +
+ ); + } + ); renderSteps = () => { const { currentStep } = this.state; From 9112a95e7cbf1386e92d8ccba5d9d707c05c9cf9 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Tue, 26 Nov 2019 16:04:52 +0200 Subject: [PATCH 03/18] input question --- client/src/components/StepsQuestions/index.js | 3 +- .../subcomponents/InputQuestion.js | 16 ++++++++++ .../subcomponents/TypesQuestion.js | 32 ------------------- .../StepsQuestions/subcomponents/index.js | 5 +-- client/src/staticDataSet/questions.js | 5 +-- 5 files changed, 23 insertions(+), 38 deletions(-) create mode 100644 client/src/components/StepsQuestions/subcomponents/InputQuestion.js delete mode 100644 client/src/components/StepsQuestions/subcomponents/TypesQuestion.js diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index d9f4e2d..7f9038f 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -27,10 +27,9 @@ export default class StepsQuestions extends React.Component { ({ content: Component, stepNo, key, question }) => { const { data } = this.state; return ( -
+

{question}

this.handleStateChange({ key, value }) diff --git a/client/src/components/StepsQuestions/subcomponents/InputQuestion.js b/client/src/components/StepsQuestions/subcomponents/InputQuestion.js new file mode 100644 index 0000000..92a8b76 --- /dev/null +++ b/client/src/components/StepsQuestions/subcomponents/InputQuestion.js @@ -0,0 +1,16 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const InputQuestion = ({ value, handleStateChange }) => ( + handleStateChange(e.target.value)} + /> +); +InputQuestion.propTypes = { + value: PropTypes.string.isRequired, + handleStateChange: PropTypes.func.isRequired, +}; +export default InputQuestion; diff --git a/client/src/components/StepsQuestions/subcomponents/TypesQuestion.js b/client/src/components/StepsQuestions/subcomponents/TypesQuestion.js deleted file mode 100644 index 785c6f1..0000000 --- a/client/src/components/StepsQuestions/subcomponents/TypesQuestion.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { Radio } from 'antd'; - -const BusinessTypes = Object.freeze({ - stay: 'place to stay', - eat: 'place to eat or drink', - shop: 'place to shop', -}); - -const TypeQuestion = ({ value, handleStateChange }) => ( -
- - {Object.entries(BusinessTypes).map(([key, text]) => ( - handleStateChange(e.target.value)} - > - {text} - - ))} - -
-); - -TypeQuestion.propTypes = { - value: PropTypes.string.isRequired, - handleStateChange: PropTypes.func.isRequired, -}; -export default TypeQuestion; diff --git a/client/src/components/StepsQuestions/subcomponents/index.js b/client/src/components/StepsQuestions/subcomponents/index.js index 95e49d7..fb1aeeb 100644 --- a/client/src/components/StepsQuestions/subcomponents/index.js +++ b/client/src/components/StepsQuestions/subcomponents/index.js @@ -1,3 +1,4 @@ -import TypeQuestion from './TypesQuestion'; +import TypeQuestion from './TypeQuestion'; +import InputQuestion from './InputQuestion'; -export default { TypeQuestion }; +export default { TypeQuestion, InputQuestion }; diff --git a/client/src/staticDataSet/questions.js b/client/src/staticDataSet/questions.js index 795f5ab..f31d6c5 100644 --- a/client/src/staticDataSet/questions.js +++ b/client/src/staticDataSet/questions.js @@ -1,4 +1,5 @@ export default [ - { stepNo: 0, key: 'type', question: 'something?', type: 'TypeQuestion' }, - { stepNo: 1, key: 'name', question: 'welcome?', type: 'TypeQuestion' }, + { stepNo: 0, key: 'name', question: 'name?', type: 'InputQuestion' }, + { stepNo: 1, key: 'link', question: 'link?', type: 'InputQuestion' }, + { stepNo: 2, key: 'type', question: 'something?', type: 'TypeQuestion' }, ]; From 72e876890f00ef2aeb3fdd0a2b530b6e9340bf93 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Tue, 26 Nov 2019 16:06:07 +0200 Subject: [PATCH 04/18] renamed typequestion --- .../subcomponents/TypeQuestion.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 client/src/components/StepsQuestions/subcomponents/TypeQuestion.js diff --git a/client/src/components/StepsQuestions/subcomponents/TypeQuestion.js b/client/src/components/StepsQuestions/subcomponents/TypeQuestion.js new file mode 100644 index 0000000..785c6f1 --- /dev/null +++ b/client/src/components/StepsQuestions/subcomponents/TypeQuestion.js @@ -0,0 +1,32 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { Radio } from 'antd'; + +const BusinessTypes = Object.freeze({ + stay: 'place to stay', + eat: 'place to eat or drink', + shop: 'place to shop', +}); + +const TypeQuestion = ({ value, handleStateChange }) => ( +
+ + {Object.entries(BusinessTypes).map(([key, text]) => ( + handleStateChange(e.target.value)} + > + {text} + + ))} + +
+); + +TypeQuestion.propTypes = { + value: PropTypes.string.isRequired, + handleStateChange: PropTypes.func.isRequired, +}; +export default TypeQuestion; From 24e2e938ad916af2d18f40b3fb164892776379a1 Mon Sep 17 00:00:00 2001 From: asem1789 Date: Wed, 27 Nov 2019 10:17:48 +0200 Subject: [PATCH 05/18] remove all old files Relates #8 --- .../StepsQuestions/old/UploadImg.js | 86 ------ .../components/StepsQuestions/old/index.css | 132 --------- .../components/StepsQuestions/old/index.js | 252 ------------------ client/src/components/index.js | 2 - .../src/pages/addNewSitSpot/old/fakeData.js | 26 -- client/src/pages/addNewSitSpot/old/index.css | 96 ------- client/src/pages/addNewSitSpot/old/index.js | 164 ------------ 7 files changed, 758 deletions(-) delete mode 100644 client/src/components/StepsQuestions/old/UploadImg.js delete mode 100644 client/src/components/StepsQuestions/old/index.css delete mode 100644 client/src/components/StepsQuestions/old/index.js delete mode 100644 client/src/pages/addNewSitSpot/old/fakeData.js delete mode 100644 client/src/pages/addNewSitSpot/old/index.css delete mode 100644 client/src/pages/addNewSitSpot/old/index.js diff --git a/client/src/components/StepsQuestions/old/UploadImg.js b/client/src/components/StepsQuestions/old/UploadImg.js deleted file mode 100644 index d2f4b02..0000000 --- a/client/src/components/StepsQuestions/old/UploadImg.js +++ /dev/null @@ -1,86 +0,0 @@ -import React, { Component } from 'react'; -import { Upload, Icon, message } from 'antd'; -import propTypes from 'prop-types'; - -import './index.css'; - -const getBase64 = (img, callback) => { - const reader = new FileReader(); - reader.addEventListener('load', () => callback(reader.result)); - reader.readAsDataURL(img); -}; - -const beforeUpload = file => { - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; - - if (!isJpgOrPng) { - message.error('you can only upload JPG/PNG file!'); - } - const isLt2M = file.size / 1024 / 1024 < 2; - if (!isLt2M) { - message.error('Image must smaller than 2MB'); - } - - return isJpgOrPng && isLt2M; -}; - -class UploadImg extends Component { - state = { - loading: false, - }; - - handleChange = info => { - if (info.file.status === 'uploading') { - this.setState({ loading: true }); - } else if (info.file.status === 'done') { - // Get this url from response in real world. - getBase64(info.file.originFileObj, imgUrl => { - const { handleChange } = this.props; - handleChange(imgUrl, 'img1'); - this.setState({ loading: false }); - }); - } - }; - - render() { - const { loading } = this.state; - const { values } = this.props; - const imgUrl = values.img1; - - const uploadButton = ( -
- -
Upload
-
- ); - - return ( -
-
- - {imgUrl ? ( - avatar - ) : ( - uploadButton - )} - -
-
- ); - } -} - -UploadImg.propTypes = { - values: propTypes.objectOf(propTypes.any).isRequired, - handleChange: propTypes.func.isRequired, -}; - -export default UploadImg; diff --git a/client/src/components/StepsQuestions/old/index.css b/client/src/components/StepsQuestions/old/index.css deleted file mode 100644 index 521d65d..0000000 --- a/client/src/components/StepsQuestions/old/index.css +++ /dev/null @@ -1,132 +0,0 @@ -/* ================================= */ -/* Basic style */ -/* ================================= */ - -.steps { - padding: 3rem 0; -} - -.country-w-city .ant-select-selection-selected-value { - line-height: 5rem; - font-size: 2rem; -} - -.steps-content { - min-height: 30rem; - margin-top: 2rem; - border-radius: 6px; - padding: 0 0.4rem; -} - -.steps-action__buttons { - display: flex; - justify-content: center; - flex-direction: row-reverse; - margin-top: 24px; -} - -.steps .title { - text-align: start; - font-size: 1.6rem; - margin-bottom: 2.5rem; -} - -.img__box { - width: 75%; - display: flex; - justify-content: center; - margin: 0 auto; -} - -.img__box--img { - width: 100%; - height: auto; -} - -.steps .input { - display: block; - width: 90%; - font-family: inherit; - font-weight: 600; - font-size: 2rem; - border: 0; - outline: none; - background-color: inherit; - padding: 0.8rem 0.2rem; - margin: 2rem auto; - cursor: text; - border-bottom: 0.1rem solid #4fb0ae; -} - -.input:focus { - border-bottom: 0; -} - -.input::placeholder { - color: #4fb0aeb7; - font-size: 1.8rem; - letter-spacing: 0.1rem; - word-spacing: 0.2rem; -} - -.website__title, -.country__title, -.city__title { - margin-bottom: 9rem; -} - -.welcome__message { - text-align: justify; - font-size: 1.8rem; - font-weight: 500; - line-height: 1.6em; -} - -.span-required { - color: red; - font-size: 3.5rem; - line-height: 0; - position: relative; - top: 0.8rem; -} - -.error-box { - padding: 0.3rem 0; - background-color: #ffbaba; -} - -.error-box__message { - color: #d8000c; - text-align: center; -} - -/* ================================= */ -/* Type COMPONENT */ -/* ================================= */ - -.type__title { - margin-bottom: 7rem; -} - -/* ================================= */ -/* BUTTON STYLE */ -/* ================================= */ -.steps .steps-action .steps__btn { - width: 30%; -} - -.steps .steps-action .steps__btn--left { - position: relative; - right: 1.5rem; -} - -.steps .steps-action .steps__btn--right { - position: relative; - left: 1.5rem; -} - -@media only screen and (max-width: 400px) { - #add-place .ant-steps-horizontal:not(.ant-steps-label-vertical) .ant-steps-item { - margin: 0; - } -} diff --git a/client/src/components/StepsQuestions/old/index.js b/client/src/components/StepsQuestions/old/index.js deleted file mode 100644 index 7d9c9bc..0000000 --- a/client/src/components/StepsQuestions/old/index.js +++ /dev/null @@ -1,252 +0,0 @@ -import React from 'react'; -import propTypes from 'prop-types'; -import { Steps, Button, Select, Radio } from 'antd'; -import { getCountryNames, getCities } from 'full-countries-cities'; - -import UploadImg from './UploadImg'; - -import './index.css'; - -const { Step } = Steps; - -const BusinessTypes = Object.freeze({ - stay: 'place to stay', - eat: 'place to eat or drink', - shop: 'place to shop', -}); - -const ButtonInfo = Object.freeze({ - START: 'Start', - NEXT: 'Next', - PREVIOUS: 'Previous', - DONE: 'Done', - TYPE: 'primary', - MESSAGE: 'Processing complete!', -}); - -const renderError = msg => ( -
-

{msg}

-
-); - -const checkError = (currentStep, errors) => { - if (currentStep === 1) { - if (errors.name) { - return renderError(errors.name); - } - } else if (currentStep === 3) { - if (errors.country) { - return renderError(errors.country); - } - } else if (currentStep === 4) { - if (errors.city) { - return renderError(errors.city); - } - } else if (currentStep === 5) { - if (errors.businessType) { - return renderError(errors.businessType); - } - } - return undefined; -}; - -const renderInput = (values, currentStep, funcs) => { - const stateKey = currentStep === 1 ? 'name' : 'linkSite'; - return ( - { - funcs.handleChange(event.target.value, stateKey); - }} - /> - ); -}; - -const renderOptions = list => { - const { Option } = Select; - - return list.map(item => ( - - )); -}; - -const dropDownFilter = (input, option) => - option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0; - -const renderSelect = (values, currentStep, funcs) => { - const stateKey = currentStep === 3 ? 'country' : 'city'; - let cities; - if (currentStep === 4) { - cities = values.country ? getCities(values.country) : []; - } - return ( - - ); -}; - -const renderRadio = (values, funcs) => ( - - {Object.entries(BusinessTypes).map(([key, value]) => ( - - funcs.handleChange(event.target.value, 'businessType') - } - > - {value} - - ))} - -); - -const renderQuestion = ( - questions, - values, - currentStep, - funcs, - classes, - required -) => ( -
- {currentStep > 0 && ( -
-

- {questions[currentStep].title} - {required[currentStep] ? ( - * - ) : ( - '' - )} -

-
- )} - {questions[currentStep].imgUrl && ( -
- img question -
- )} - {currentStep === 0 && ( -

{questions[0].message}

- )} - {currentStep <= 2 && - currentStep > 0 && - renderInput(values, currentStep, funcs)} - {currentStep >= 3 && - currentStep < 5 && - renderSelect(values, currentStep, funcs, classes)} - - {currentStep === 5 && renderRadio(values, funcs)} - {currentStep >= 6 && currentStep <= 7 && ( - - )} -
-); - -const renderButton = (text, type, func, checkRequirdStep = false) => ( - -); - -const StepsQuestions = ({ - questions, - currentStep, - values, - funcs, - classes, - required, - errors, -}) => ( -
- - {questions.map(({ id }) => ( - - ))} - -
- {renderQuestion(questions, values, currentStep, funcs, classes, required)} -
-
- {checkError(currentStep, errors)} -
- {currentStep < questions.length - 1 && - renderButton( - currentStep === 0 ? ButtonInfo.START : ButtonInfo.NEXT, - ButtonInfo.TYPE, - currentStep === 0 || currentStep === 2 || currentStep === 6 - ? funcs.next - : funcs.handleValidate, - true - )} - - {currentStep === questions.length - 1 && - renderButton(ButtonInfo.DONE, ButtonInfo.TYPE, funcs.onSubmit)} - - {currentStep > 0 && renderButton(ButtonInfo.PREVIOUS, null, funcs.prev)} -
-
-
-); - -StepsQuestions.propTypes = { - currentStep: propTypes.number.isRequired, - classes: propTypes.arrayOf(propTypes.string), - questions: propTypes.arrayOf(propTypes.any).isRequired, - funcs: propTypes.shape({ - next: propTypes.func.isRequired, - prev: propTypes.func.isRequired, - handleChange: propTypes.func.isRequired, - onSubmit: propTypes.func.isRequired, - handleValidate: propTypes.func.isRequired, - }).isRequired, - values: propTypes.shape({ - name: propTypes.string.isRequired, - linkSite: propTypes.string.isRequired, - country: propTypes.string.isRequired, - city: propTypes.string.isRequired, - businessType: propTypes.string.isRequired, - imgUrlOne: propTypes.string, - imgUrlTwo: propTypes.string, - }).isRequired, - required: propTypes.objectOf(propTypes.bool), - errors: propTypes.objectOf(propTypes.any), -}; - -StepsQuestions.defaultProps = { - classes: '', - required: {}, - errors: {}, -}; - -export default StepsQuestions; diff --git a/client/src/components/index.js b/client/src/components/index.js index d8cf1a5..38cdc3d 100644 --- a/client/src/components/index.js +++ b/client/src/components/index.js @@ -11,7 +11,6 @@ import MagicalFactor from './MagicalFactor'; import Review from './Review'; import ImageCarousel from './ImageCarousel'; import Layout from './Layout'; -import StepsQuestions from './StepsQuestions/old'; import StepsQuestions2 from './StepsQuestions'; export { @@ -28,6 +27,5 @@ export { SearchResult, ImageCarousel, Layout, - StepsQuestions, StepsQuestions2, }; diff --git a/client/src/pages/addNewSitSpot/old/fakeData.js b/client/src/pages/addNewSitSpot/old/fakeData.js deleted file mode 100644 index 0c6636c..0000000 --- a/client/src/pages/addNewSitSpot/old/fakeData.js +++ /dev/null @@ -1,26 +0,0 @@ -import nameImg from '../../../assets/question-1.png'; - -const Questions = [ - { - id: 0, - title: 'welcome', - message: - 'Thank you for sharing your “sitspot”. You’re on your way to support a deserving tourism business and enlighten other conscious travelers like you. Our simple questionnaire will take 15 minutes at most to complete, and will prompt you to share the details that your fellow conscious travelers will find most helpful.', - }, - { id: 1, title: 'What is the name of the business? ', imgUrl: nameImg }, - { - id: 2, - title: - 'If it’s easy enough for you, please indicate their website address. This will help us ensure we list the correct establishment.', - }, - { id: 3, title: 'In which country is this buisness located?' }, - { id: 4, title: 'What is the nearest city?' }, - { id: 5, title: 'What type of business is it?' }, - { - id: 6, - title: - 'Upload 1 picture if you can. It will help us identify your sitspot. You will be able to upload more pictures at the end of the questionnaire', - }, -]; - -export default Questions; diff --git a/client/src/pages/addNewSitSpot/old/index.css b/client/src/pages/addNewSitSpot/old/index.css deleted file mode 100644 index a9094d6..0000000 --- a/client/src/pages/addNewSitSpot/old/index.css +++ /dev/null @@ -1,96 +0,0 @@ -.add-place__wrapper { - margin: 0 10%; -} - -.add-place__header { - background: url('../../assets/images/addrecom.png') no-repeat center bottom/cover; - height: 12vh; -} - -.steps__btn { - margin-right: 1rem; -} - -/* ================= override on style antd STEPS */ - -#add-place .ant-steps-horizontal { - display: flex; - justify-content: center; -} - -#add-place .ant-steps-item-tail { - top: -0.9rem; - left: 2.8rem; - z-index: -1; - transform: rotate(270deg); - padding: 1rem 0 0px !important; -} - -#add-place .ant-steps-item-icon { - margin: 0; -} - -/* ================= override on style antd SELECT */ - -#add-place .ant-select { - width: 100%; - outline: 0; -} - -#add-place .ant-select-selection { - border: 0; - outline: 0; - border-bottom: 1px solid gray; - background-color: inherit; - height: 5rem; -} - -#add-place .ant-select-arrow { - font-size: 2rem; -} - -/* ================= override on style antd Radio */ - -#add-place .ant-radio-group { - display: flex; - flex-direction: column; - align-items: center; -} - -#add-place .ant-radio-button-wrapper { - margin-bottom: 1.5rem; - width: 70%; - text-align: center; - height: auto; - padding: 1rem 1.5rem; -} - -div.type>div>label.ant-radio-button-wrapper>span { - font-size: 1.8rem; -} - -/* ================= override on style antd UPload image */ - -#add-place .ant-upload-picture-card-wrapper { - display: flex; - justify-content: center; -} - -#add-place .ant-upload-select-picture-card { - height: 20rem; - width: 90%; - margin: 0 auto; -} - -.anticon-plus { - font-size: 3rem; - font-weight: 200; -} - -.ant-upload-text { - font-size: 2.5rem; -} - -.anticon-loading { - font-size: 3rem; -} diff --git a/client/src/pages/addNewSitSpot/old/index.js b/client/src/pages/addNewSitSpot/old/index.js deleted file mode 100644 index 5115783..0000000 --- a/client/src/pages/addNewSitSpot/old/index.js +++ /dev/null @@ -1,164 +0,0 @@ -import React, { Component } from 'react'; -import propTypes from 'prop-types'; - -import addPlaceValidation from '../../../utils'; -import { addPlace } from '../../../services/api'; - -import { StepsQuestions } from '../../../components'; -import Questions from './fakeData'; - -import './index.css'; - -const Classes = [ - 'welcome', - 'name', - 'website', - 'country', - 'city', - 'type', - 'upload-img', - 'upload-img', -]; - -class AddNewSitSpot extends Component { - state = { - data: { - name: '', - linkSite: '', - country: '', - city: '', - businessType: '', - img1: undefined, - img2: undefined, - }, - errors: { - name: null, - country: null, - city: null, - businessType: null, - }, - currentStep: 0, - }; - - onSubmit = () => { - const { - data, - data: { businessType }, - } = this.state; - const { history } = this.props; - const formData = new FormData(); - Object.entries(data).forEach( - ([key, value]) => !!value && formData.append(key, value) - ); - - addPlace(formData).then(({ data: id }) => - history.push(`/add-review/${businessType}/${id}`) - ); - }; - - handleChange = (value, dataKey) => { - this.setState( - prevState => ({ - ...prevState, - data: { ...prevState.data, [dataKey]: value }, - }), - () => this.handleValidate(false) - ); - }; - - handleError = (value, errKey) => { - this.setState(prevState => ({ - ...prevState, - errors: { ...prevState.errors, [errKey]: value || null }, - })); - }; - - handleValidate = checkEvent => { - const { - data: { name, country, city, businessType }, - currentStep, - } = this.state; - - if (currentStep === 1) { - addPlaceValidation.placeValidName - .validate({ name }) - .then(() => { - if (checkEvent) this.next(); - this.handleError(null, 'name'); - }) - .catch(err => { - this.handleError(err.message, 'name'); - }); - } else if (currentStep === 3) { - addPlaceValidation.placeValidCountry - .validate({ country }) - .then(() => { - if (checkEvent) this.next(); - this.handleError(null, 'country'); - }) - .catch(err => this.handleError(err.message, 'country')); - } else if (currentStep === 4) { - addPlaceValidation.placeValidCity - .validate({ city }) - .then(() => { - if (checkEvent) this.next(); - this.handleError(null, 'city'); - }) - .catch(err => this.handleError(err.message, 'city')); - } else if (currentStep === 5) { - addPlaceValidation.placeValidBusinessType - .validate({ businessType }) - .then(() => { - if (checkEvent) this.next(); - this.handleError(null, 'businessType'); - }) - .catch(err => this.handleError(err.message, 'businessType')); - } - // else if (currentStep === 0) { - // this.next(); - // } - }; - - next = () => - this.setState(({ currentStep }) => ({ - currentStep: currentStep + 1, - })); - - prev = () => - this.setState(({ currentStep }) => ({ - currentStep: currentStep - 1, - })); - - render() { - const { currentStep, data, errors } = this.state; - - return ( -
-
-
- -
-
- ); - } -} - -AddNewSitSpot.propTypes = { - history: propTypes.shape({ push: propTypes.func.isRequired }).isRequired, -}; -export default AddNewSitSpot; From 232e26eeadb99944e4a7e431876b27b2a9016a79 Mon Sep 17 00:00:00 2001 From: asem1789 Date: Wed, 27 Nov 2019 10:33:07 +0200 Subject: [PATCH 06/18] write CountryOrCity subComponent Relates #8 --- client/src/components/StepsQuestions/index.js | 43 +++++++++------ .../subcomponents/CountryOrCity.js | 55 +++++++++++++++++++ .../subcomponents/WelcomeMessage.js | 33 +++-------- .../StepsQuestions/subcomponents/index.js | 4 +- client/src/staticDataSet/questions.js | 21 ++++++- 5 files changed, 111 insertions(+), 45 deletions(-) create mode 100644 client/src/components/StepsQuestions/subcomponents/CountryOrCity.js diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index 7f9038f..810dc0f 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -22,23 +22,34 @@ export default class StepsQuestions extends React.Component { handleStateChange = ({ key, value }) => this.setState(({ data }) => ({ data: { ...data, [key]: value } })); - renderContent = () => - questionsAndComponents.map( - ({ content: Component, stepNo, key, question }) => { - const { data } = this.state; - return ( -
-

{question}

- - this.handleStateChange({ key, value }) - } - /> -
- ); + renderContent = currentStep => { + const { + data, + data: { country }, + } = this.state; + return questionsAndComponents.map( + ({ content: Component, stepNo, key, question, options = {} }) => { + const newOptions = { ...options }; + if (key === 'city') { + newOptions.countrySelected = country; + } + if (currentStep === stepNo) + return ( +
+

{question}

+ + this.handleStateChange({ key, value }) + } + /> +
+ ); + return ''; } ); + }; renderSteps = () => { const { currentStep } = this.state; @@ -66,7 +77,7 @@ export default class StepsQuestions extends React.Component { return (
{this.renderSteps()} - {this.renderContent()} + {this.renderContent(currentStep)}
{currentStep > 0 && ( + )} {currentStep > 0 && ( )} - {currentStep < questions.length - 1 && ( + {currentStep < questions.length - 1 && currentStep > 0 && ( From 461d93311efe457c7f05b2c6b29791b903c824ae Mon Sep 17 00:00:00 2001 From: asem1789 Date: Wed, 27 Nov 2019 12:38:21 +0200 Subject: [PATCH 09/18] make style for steps-component --- client/src/components/StepsQuestions/index.js | 2 + .../src/components/StepsQuestions/style.css | 75 +++++++++++++++++++ .../subcomponents/ImageUpload.js | 0 .../subcomponents/InputQuestion.js | 2 +- client/src/pages/addNewSitSpot/index.js | 4 +- client/src/pages/addNewSitSpot/style.css | 39 +++++++--- client/src/staticDataSet/questions.js | 33 ++++++-- 7 files changed, 135 insertions(+), 20 deletions(-) create mode 100644 client/src/components/StepsQuestions/style.css create mode 100644 client/src/components/StepsQuestions/subcomponents/ImageUpload.js diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index 3eb0551..f6fef5e 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -3,6 +3,8 @@ import { Steps } from 'antd'; import subcomponents from './subcomponents'; import questions from '../../staticDataSet/questions'; +import './style.css'; + const { Step } = Steps; const questionsAndComponents = questions.map(({ type, ...rest }) => ({ diff --git a/client/src/components/StepsQuestions/style.css b/client/src/components/StepsQuestions/style.css new file mode 100644 index 0000000..05fe9f3 --- /dev/null +++ b/client/src/components/StepsQuestions/style.css @@ -0,0 +1,75 @@ +/* Basic Style */ +.steps-wrapper{ + margin: 2rem 0; +} + +/* BUTTON STYLE */ +.form-controls { + +} + +/* InputQuestions Style */ +.step__input { + display: block; + width: 90%; + font-family: inherit; + font-weight: 600; + font-size: 2rem; + border: 0; + outline: none; + background-color: inherit; + padding: 0.8rem 0.2rem; + margin: 2rem auto; + cursor: text; + border-bottom: 0.1rem solid #4fb0ae; +} + +.step__input:focus { + border-bottom: 0; +} + +.step__input::placeholder { + color: #4fb0aeb7; + font-size: 1.8rem; + letter-spacing: 0.1rem; + word-spacing: 0.2rem; +} + +/* ================= override on style antd SELECT */ + +#add-place .ant-select { + width: 100%; + outline: 0; +} + +#add-place .ant-select-selection { + border: 0; + outline: 0; + border-bottom: 1px solid gray; + background-color: inherit; + height: 5rem; +} + +#add-place .ant-select-arrow { + font-size: 2rem; +} + +/* ================= override on style antd Radio */ + +#add-place .ant-radio-group { + display: flex; + flex-direction: column; + align-items: center; +} + +#add-place .ant-radio-button-wrapper { + margin-bottom: 1.5rem; + width: 70%; + text-align: center; + height: auto; + padding: 1rem 1.5rem; +} + +div.type>div>label.ant-radio-button-wrapper>span { + font-size: 1.8rem; +} \ No newline at end of file diff --git a/client/src/components/StepsQuestions/subcomponents/ImageUpload.js b/client/src/components/StepsQuestions/subcomponents/ImageUpload.js new file mode 100644 index 0000000..e69de29 diff --git a/client/src/components/StepsQuestions/subcomponents/InputQuestion.js b/client/src/components/StepsQuestions/subcomponents/InputQuestion.js index 92a8b76..58dd17b 100644 --- a/client/src/components/StepsQuestions/subcomponents/InputQuestion.js +++ b/client/src/components/StepsQuestions/subcomponents/InputQuestion.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; const InputQuestion = ({ value, handleStateChange }) => ( handleStateChange(e.target.value)} diff --git a/client/src/pages/addNewSitSpot/index.js b/client/src/pages/addNewSitSpot/index.js index 083760e..304c12b 100644 --- a/client/src/pages/addNewSitSpot/index.js +++ b/client/src/pages/addNewSitSpot/index.js @@ -8,7 +8,9 @@ const onSubmit = something => something; const AddNewSitspot = () => (
- +
+ +
); diff --git a/client/src/pages/addNewSitSpot/style.css b/client/src/pages/addNewSitSpot/style.css index ff91c17..70c068a 100644 --- a/client/src/pages/addNewSitSpot/style.css +++ b/client/src/pages/addNewSitSpot/style.css @@ -1,12 +1,27 @@ -.add-place__wrapper { - margin: 0 10%; - } - - .add-place__header { - background: url('../../assets/images/addrecom.png') no-repeat center bottom/cover; - height: 12vh; - } - - .steps__btn { - margin-right: 1rem; - } \ No newline at end of file +.add-place__header { + background: url('../../assets/images/addrecom.png') no-repeat center bottom/cover; + height: 12vh; +} + +.add-place__content { + margin: 0 10%; +} + +/* ================= override on style antd STEPS */ + +#add-place .ant-steps-horizontal { + display: flex; + justify-content: center; +} + +#add-place .ant-steps-item-tail { + top: -0.9rem; + left: 2.8rem; + z-index: -1; + transform: rotate(270deg); + padding: 1rem 0 0px !important; +} + +#add-place .ant-steps-item-icon { + margin: 0; +} \ No newline at end of file diff --git a/client/src/staticDataSet/questions.js b/client/src/staticDataSet/questions.js index d9c5cbb..e328d30 100644 --- a/client/src/staticDataSet/questions.js +++ b/client/src/staticDataSet/questions.js @@ -1,20 +1,41 @@ export default [ - { stepNo: 0, key: 'welcome', question: 'welcome' }, - { stepNo: 1, key: 'name', question: 'name?', type: 'InputQuestion' }, - { stepNo: 2, key: 'link', question: 'link?', type: 'InputQuestion' }, + { + stepNo: 0, + key: 'welcome', + question: + 'Thank you for sharing your “sitspot”. You’re on your way to support a deserving tourism business and enlighten other conscious travelers like you. Our simple questionnaire will take 15 minutes at most to complete, and will prompt you to share the details that your fellow conscious travelers will find most helpful.', + }, + { + stepNo: 1, + key: 'name', + question: 'What is the name of the business?', + type: 'InputQuestion', + }, + { + stepNo: 2, + key: 'link', + question: + 'If it’s easy enough for you, please indicate their website address. This will help us ensure we list the correct establishment.', + type: 'InputQuestion', + }, { stepNo: 3, key: 'country', - question: 'something?', + question: 'In which country is this buisness located?', type: 'CountryOrCity', options: { type: 'country' }, }, { stepNo: 4, key: 'city', - question: 'something?', + question: 'What is the nearest city?', type: 'CountryOrCity', options: { type: 'city' }, }, - { stepNo: 5, key: 'type', question: 'something?', type: 'TypeQuestion' }, + { + stepNo: 5, + key: 'type', + question: 'What type of business is it?', + type: 'TypeQuestion', + }, ]; From cce9a028941655f71e7e46b302af4eb92ecd70e1 Mon Sep 17 00:00:00 2001 From: asem1789 Date: Wed, 27 Nov 2019 13:17:44 +0200 Subject: [PATCH 10/18] make style fore steps-component --- client/src/components/StepsQuestions/index.js | 56 ++++++++++++------- .../src/components/StepsQuestions/style.css | 28 +++++++++- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index 95f1f0a..9adc678 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import { Steps } from 'antd'; +import { Steps, Button } from 'antd'; import subcomponents from './subcomponents'; import questions from '../../staticDataSet/questions'; @@ -37,17 +37,19 @@ export default class StepsQuestions extends React.Component { } if (currentStep === stepNo) return ( -
+

{question}

- {Component && ( - - this.handleStateChange({ key, value }) - } - /> - )} +
+ {Component && ( + + this.handleStateChange({ key, value }) + } + /> + )} +
); return ''; @@ -84,24 +86,40 @@ export default class StepsQuestions extends React.Component { {this.renderContent(currentStep)}
{currentStep === 0 && ( - + )} {currentStep > 0 && ( - + )} {currentStep < questions.length - 1 && currentStep > 0 && ( - + )} {currentStep === questions.length - 1 && ( - + )}
diff --git a/client/src/components/StepsQuestions/style.css b/client/src/components/StepsQuestions/style.css index 05fe9f3..3b49024 100644 --- a/client/src/components/StepsQuestions/style.css +++ b/client/src/components/StepsQuestions/style.css @@ -3,11 +3,36 @@ margin: 2rem 0; } +.content-wrapper { + min-height: 20rem; +} + +.content__component { + margin: 2.5rem 0; +} + /* BUTTON STYLE */ .form-controls { - + display: flex; + justify-content: center; + margin-top: 24px; +} + +.steps__btn { + width: 30%; +} + +.steps__btn--right { + position: relative; + left: 1.5rem; } +.steps__btn--left { + position: relative; + right: 1.5rem; +} + + /* InputQuestions Style */ .step__input { display: block; @@ -19,7 +44,6 @@ outline: none; background-color: inherit; padding: 0.8rem 0.2rem; - margin: 2rem auto; cursor: text; border-bottom: 0.1rem solid #4fb0ae; } From 7382b92dc7d73067423580021e3b7ebb1a9c02e2 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Wed, 27 Nov 2019 15:08:42 +0200 Subject: [PATCH 11/18] new error display --- .../components/StepsQuestions/subcomponents/ErrorDisplay.js | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 client/src/components/StepsQuestions/subcomponents/ErrorDisplay.js diff --git a/client/src/components/StepsQuestions/subcomponents/ErrorDisplay.js b/client/src/components/StepsQuestions/subcomponents/ErrorDisplay.js new file mode 100644 index 0000000..8d6e53b --- /dev/null +++ b/client/src/components/StepsQuestions/subcomponents/ErrorDisplay.js @@ -0,0 +1,6 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const ErrorDisplay = ({ error }) => {error}; +ErrorDisplay.propTypes = { error: PropTypes.string.isRequired }; +export default ErrorDisplay; From ed7af7db92d4d6642e637ad0e81b61cf094cd99d Mon Sep 17 00:00:00 2001 From: amoodaa Date: Wed, 27 Nov 2019 15:18:40 +0200 Subject: [PATCH 12/18] pushed intiial validations --- client/src/components/StepsQuestions/index.js | 12 ++++++++++-- .../StepsQuestions/subcomponents/CountryOrCity.js | 2 ++ .../components/StepsQuestions/subcomponents/index.js | 8 +++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index 9adc678..efb31d4 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -2,13 +2,15 @@ import React from 'react'; import { Steps, Button } from 'antd'; import subcomponents from './subcomponents'; import questions from '../../staticDataSet/questions'; - import './style.css'; +const { ErrorDisplay } = questions; + const { Step } = Steps; const questionsAndComponents = questions.map(({ type, ...rest }) => ({ content: subcomponents[type], + error: null, ...rest, })); @@ -19,18 +21,22 @@ export default class StepsQuestions extends React.Component { (acc, { key }) => (key ? { ...acc, [key]: '' } : acc), {} ), + isError: false, }; handleStateChange = ({ key, value }) => this.setState(({ data }) => ({ data: { ...data, [key]: value } })); + changeIsError = isError => this.setState({ isError }); + renderContent = currentStep => { const { data, data: { country }, + isError, } = this.state; return questionsAndComponents.map( - ({ content: Component, stepNo, key, question, options = {} }) => { + ({ content: Component, stepNo, key, question, options = {}, error }) => { const newOptions = { ...options }; if (key === 'city') { newOptions.countrySelected = country; @@ -44,11 +50,13 @@ export default class StepsQuestions extends React.Component { this.handleStateChange({ key, value }) } /> )} + {isError && }
); diff --git a/client/src/components/StepsQuestions/subcomponents/CountryOrCity.js b/client/src/components/StepsQuestions/subcomponents/CountryOrCity.js index ea4be68..87ef1a1 100644 --- a/client/src/components/StepsQuestions/subcomponents/CountryOrCity.js +++ b/client/src/components/StepsQuestions/subcomponents/CountryOrCity.js @@ -19,6 +19,7 @@ const dropDownFilter = (input, option) => const CountryOrCity = ({ value, handleStateChange, + // changeIsError, options: { type, countrySelected = '' }, }) => { let data; @@ -46,6 +47,7 @@ const CountryOrCity = ({ CountryOrCity.propTypes = { value: PropTypes.string.isRequired, handleStateChange: PropTypes.func.isRequired, + // changeIsError: PropTypes.func.isRequired, options: PropTypes.shape({ type: PropTypes.string.isRequired, countrySelected: PropTypes.string, diff --git a/client/src/components/StepsQuestions/subcomponents/index.js b/client/src/components/StepsQuestions/subcomponents/index.js index 83ecb14..4b6efd5 100644 --- a/client/src/components/StepsQuestions/subcomponents/index.js +++ b/client/src/components/StepsQuestions/subcomponents/index.js @@ -1,5 +1,11 @@ import TypeQuestion from './TypeQuestion'; import InputQuestion from './InputQuestion'; import CountryOrCity from './CountryOrCity'; +import ErrorDisplay from './ErrorDisplay'; -export default { TypeQuestion, InputQuestion, CountryOrCity }; +export default { + TypeQuestion, + InputQuestion, + CountryOrCity, + ErrorDisplay, +}; From f6d328c396eb23117603b5aa9a82cf614597d0bd Mon Sep 17 00:00:00 2001 From: amoodaa Date: Wed, 27 Nov 2019 15:43:58 +0200 Subject: [PATCH 13/18] 2nd setup of error handling --- client/src/components/StepsQuestions/index.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index efb31d4..a53f718 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -4,13 +4,12 @@ import subcomponents from './subcomponents'; import questions from '../../staticDataSet/questions'; import './style.css'; -const { ErrorDisplay } = questions; +const { ErrorDisplay } = subcomponents; const { Step } = Steps; const questionsAndComponents = questions.map(({ type, ...rest }) => ({ content: subcomponents[type], - error: null, ...rest, })); @@ -21,22 +20,22 @@ export default class StepsQuestions extends React.Component { (acc, { key }) => (key ? { ...acc, [key]: '' } : acc), {} ), - isError: false, + error: '', }; handleStateChange = ({ key, value }) => this.setState(({ data }) => ({ data: { ...data, [key]: value } })); - changeIsError = isError => this.setState({ isError }); + changeIsError = error => this.setState({ error }); renderContent = currentStep => { const { data, data: { country }, - isError, + error, } = this.state; return questionsAndComponents.map( - ({ content: Component, stepNo, key, question, options = {}, error }) => { + ({ content: Component, stepNo, key, question, options = {} }) => { const newOptions = { ...options }; if (key === 'city') { newOptions.countrySelected = country; @@ -56,8 +55,8 @@ export default class StepsQuestions extends React.Component { } /> )} - {isError && }
+ {error && }
); return ''; @@ -81,8 +80,11 @@ export default class StepsQuestions extends React.Component { prev = () => this.setState(({ currentStep }) => ({ currentStep: currentStep - 1 })); - next = () => - this.setState(({ currentStep }) => ({ currentStep: currentStep + 1 })); + next = () => { + const { error } = this.state; + if (!error) + this.setState(({ currentStep }) => ({ currentStep: currentStep + 1 })); + }; render() { const { currentStep } = this.state; From c1e1f1e753f2c7ce583a3d9c5434098ee98ee812 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Thu, 28 Nov 2019 10:09:54 +0200 Subject: [PATCH 14/18] validition done --- client/src/components/StepsQuestions/index.js | 40 +++++++++++++++---- client/src/staticDataSet/questions.js | 6 +++ client/src/utils/addPlaceValidation.js | 26 ++---------- client/src/utils/index.js | 14 +------ 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index a53f718..32bb043 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -2,6 +2,7 @@ import React from 'react'; import { Steps, Button } from 'antd'; import subcomponents from './subcomponents'; import questions from '../../staticDataSet/questions'; +import requiredStringSchema from '../../utils/addPlaceValidation'; import './style.css'; const { ErrorDisplay } = subcomponents; @@ -12,7 +13,10 @@ const questionsAndComponents = questions.map(({ type, ...rest }) => ({ content: subcomponents[type], ...rest, })); - +const requiredDictionary = questions.reduce( + (acc, { required, key }) => ({ ...acc, [key]: required }), + {} +); export default class StepsQuestions extends React.Component { state = { currentStep: 0, @@ -23,8 +27,22 @@ export default class StepsQuestions extends React.Component { error: '', }; + validateCurrentField = () => { + const { currentStep, data } = this.state; + const [key, value] = Object.entries(data)[currentStep]; + if (requiredDictionary[key]) + return requiredStringSchema(key) + .validate(value) + .then(() => this.setState({ error: '' })) + .catch(({ message }) => this.setState({ error: message })); + return Promise.resolve(value); + }; + handleStateChange = ({ key, value }) => - this.setState(({ data }) => ({ data: { ...data, [key]: value } })); + this.setState( + ({ data }) => ({ data: { ...data, [key]: value } }), + this.validateCurrentField + ); changeIsError = error => this.setState({ error }); @@ -78,13 +96,19 @@ export default class StepsQuestions extends React.Component { }; prev = () => - this.setState(({ currentStep }) => ({ currentStep: currentStep - 1 })); + this.setState(({ currentStep }) => ({ + currentStep: currentStep - 1, + error: '', + })); - next = () => { - const { error } = this.state; - if (!error) - this.setState(({ currentStep }) => ({ currentStep: currentStep + 1 })); - }; + next = () => + this.validateCurrentField().then(() => { + const { error } = this.state; + if (!error) + this.setState(({ currentStep }) => ({ + currentStep: currentStep + 1, + })); + }); render() { const { currentStep } = this.state; diff --git a/client/src/staticDataSet/questions.js b/client/src/staticDataSet/questions.js index e328d30..0b11141 100644 --- a/client/src/staticDataSet/questions.js +++ b/client/src/staticDataSet/questions.js @@ -2,18 +2,21 @@ export default [ { stepNo: 0, key: 'welcome', + required: false, question: 'Thank you for sharing your “sitspot”. You’re on your way to support a deserving tourism business and enlighten other conscious travelers like you. Our simple questionnaire will take 15 minutes at most to complete, and will prompt you to share the details that your fellow conscious travelers will find most helpful.', }, { stepNo: 1, key: 'name', + required: true, question: 'What is the name of the business?', type: 'InputQuestion', }, { stepNo: 2, key: 'link', + required: true, question: 'If it’s easy enough for you, please indicate their website address. This will help us ensure we list the correct establishment.', type: 'InputQuestion', @@ -21,6 +24,7 @@ export default [ { stepNo: 3, key: 'country', + required: true, question: 'In which country is this buisness located?', type: 'CountryOrCity', options: { type: 'country' }, @@ -28,6 +32,7 @@ export default [ { stepNo: 4, key: 'city', + required: true, question: 'What is the nearest city?', type: 'CountryOrCity', options: { type: 'city' }, @@ -35,6 +40,7 @@ export default [ { stepNo: 5, key: 'type', + required: true, question: 'What type of business is it?', type: 'TypeQuestion', }, diff --git a/client/src/utils/addPlaceValidation.js b/client/src/utils/addPlaceValidation.js index 235629a..539165e 100644 --- a/client/src/utils/addPlaceValidation.js +++ b/client/src/utils/addPlaceValidation.js @@ -1,24 +1,6 @@ -import * as yup from 'yup'; +import { string } from 'yup'; -const placeValidName = yup.object().shape({ - name: yup.string().required('Name of business is required'), -}); +const requiredStringSchema = message => + string().required(`${message} is required'`); -const placeValidCountry = yup.object().shape({ - country: yup.string().required('Country is required'), -}); - -const placeValidCity = yup.object().shape({ - city: yup.string().required('City is required'), -}); - -const placeValidBusinessType = yup.object().shape({ - businessType: yup.string().required('Business Type is required'), -}); - -export { - placeValidName, - placeValidCountry, - placeValidCity, - placeValidBusinessType, -}; +export default requiredStringSchema; diff --git a/client/src/utils/index.js b/client/src/utils/index.js index c5b72da..bf63671 100644 --- a/client/src/utils/index.js +++ b/client/src/utils/index.js @@ -1,13 +1,3 @@ -import { - placeValidName, - placeValidCountry, - placeValidCity, - placeValidBusinessType, -} from './addPlaceValidation'; +import requiredStringSchema from './addPlaceValidation'; -export default { - placeValidName, - placeValidCountry, - placeValidCity, - placeValidBusinessType, -}; +export default requiredStringSchema; From 741f1a8058a7546f79cae2d097957d36e93e6043 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Thu, 28 Nov 2019 10:22:54 +0200 Subject: [PATCH 15/18] fixed a bug with indeces we manually entered --- client/src/components/StepsQuestions/index.js | 10 +++++----- client/src/staticDataSet/questions.js | 8 +------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index 32bb043..f61b658 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -53,14 +53,14 @@ export default class StepsQuestions extends React.Component { error, } = this.state; return questionsAndComponents.map( - ({ content: Component, stepNo, key, question, options = {} }) => { + ({ content: Component, key, question, options = {} }, index) => { const newOptions = { ...options }; if (key === 'city') { newOptions.countrySelected = country; } - if (currentStep === stepNo) + if (currentStep === index) return ( -
+

{question}

{Component && ( @@ -87,8 +87,8 @@ export default class StepsQuestions extends React.Component { return (
- {questionsAndComponents.map(({ stepNo }) => ( - + {questionsAndComponents.map(({ key }) => ( + ))}
diff --git a/client/src/staticDataSet/questions.js b/client/src/staticDataSet/questions.js index 0b11141..6c84086 100644 --- a/client/src/staticDataSet/questions.js +++ b/client/src/staticDataSet/questions.js @@ -1,28 +1,24 @@ export default [ { - stepNo: 0, key: 'welcome', required: false, question: 'Thank you for sharing your “sitspot”. You’re on your way to support a deserving tourism business and enlighten other conscious travelers like you. Our simple questionnaire will take 15 minutes at most to complete, and will prompt you to share the details that your fellow conscious travelers will find most helpful.', }, { - stepNo: 1, key: 'name', required: true, question: 'What is the name of the business?', type: 'InputQuestion', }, { - stepNo: 2, key: 'link', - required: true, + required: false, question: 'If it’s easy enough for you, please indicate their website address. This will help us ensure we list the correct establishment.', type: 'InputQuestion', }, { - stepNo: 3, key: 'country', required: true, question: 'In which country is this buisness located?', @@ -30,7 +26,6 @@ export default [ options: { type: 'country' }, }, { - stepNo: 4, key: 'city', required: true, question: 'What is the nearest city?', @@ -38,7 +33,6 @@ export default [ options: { type: 'city' }, }, { - stepNo: 5, key: 'type', required: true, question: 'What type of business is it?', From 470d89a55c2fea74e928ec51ead4f78de7de86e8 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Thu, 28 Nov 2019 11:37:26 +0200 Subject: [PATCH 16/18] image upload --- .../subcomponents/ImageUpload.js | 0 .../subcomponents/ImageUploader.js | 75 +++++++++++++++++++ .../StepsQuestions/subcomponents/index.js | 2 + client/src/staticDataSet/questions.js | 8 +- 4 files changed, 84 insertions(+), 1 deletion(-) delete mode 100644 client/src/components/StepsQuestions/subcomponents/ImageUpload.js create mode 100644 client/src/components/StepsQuestions/subcomponents/ImageUploader.js diff --git a/client/src/components/StepsQuestions/subcomponents/ImageUpload.js b/client/src/components/StepsQuestions/subcomponents/ImageUpload.js deleted file mode 100644 index e69de29..0000000 diff --git a/client/src/components/StepsQuestions/subcomponents/ImageUploader.js b/client/src/components/StepsQuestions/subcomponents/ImageUploader.js new file mode 100644 index 0000000..f0c617e --- /dev/null +++ b/client/src/components/StepsQuestions/subcomponents/ImageUploader.js @@ -0,0 +1,75 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Upload, Icon, message } from 'antd'; + +function getBase64(img, callback) { + const reader = new FileReader(); + reader.addEventListener('load', () => callback(reader.result)); + reader.readAsDataURL(img); +} + +function beforeUpload(file) { + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; + if (!isJpgOrPng) { + message.error('You can only upload JPG/PNG file!'); + } + const isLt3M = file.size / 1024 / 1024 < 3; + if (!isLt3M) { + message.error('Image must smaller than 3MB!'); + } + return isJpgOrPng && isLt3M; +} + +class ImageUploader extends React.Component { + state = { + loading: false, + }; + + handleChange = info => { + if (info.file.status === 'uploading') { + this.setState({ loading: true }); + return; + } + if (info.file.status === 'done') { + const { handleStateChange } = this.props; + // Get this url from response in real world. + getBase64(info.file.originFileObj, imageUrl => { + handleStateChange(imageUrl); + this.setState({ loading: false }); + }); + } + }; + + render() { + const { value: imageUrl } = this.props; + const { loading } = this.state; + const uploadButton = ( +
+ +
Upload
+
+ ); + return ( + + {imageUrl ? ( + avatar + ) : ( + uploadButton + )} + + ); + } +} +ImageUploader.propTypes = { + value: PropTypes.string.isRequired, + handleStateChange: PropTypes.func.isRequired, +}; +export default ImageUploader; diff --git a/client/src/components/StepsQuestions/subcomponents/index.js b/client/src/components/StepsQuestions/subcomponents/index.js index 4b6efd5..82e51fa 100644 --- a/client/src/components/StepsQuestions/subcomponents/index.js +++ b/client/src/components/StepsQuestions/subcomponents/index.js @@ -2,10 +2,12 @@ import TypeQuestion from './TypeQuestion'; import InputQuestion from './InputQuestion'; import CountryOrCity from './CountryOrCity'; import ErrorDisplay from './ErrorDisplay'; +import ImageUploader from './ImageUploader'; export default { TypeQuestion, InputQuestion, CountryOrCity, ErrorDisplay, + ImageUploader, }; diff --git a/client/src/staticDataSet/questions.js b/client/src/staticDataSet/questions.js index 6c84086..ce0c415 100644 --- a/client/src/staticDataSet/questions.js +++ b/client/src/staticDataSet/questions.js @@ -27,7 +27,7 @@ export default [ }, { key: 'city', - required: true, + required: false, question: 'What is the nearest city?', type: 'CountryOrCity', options: { type: 'city' }, @@ -38,4 +38,10 @@ export default [ question: 'What type of business is it?', type: 'TypeQuestion', }, + { + key: 'image', + required: false, + question: 'Upload an image please', + type: 'ImageUploader', + }, ]; From 90267adc8fac8fd5ef8308bf9b5508119ccfa437 Mon Sep 17 00:00:00 2001 From: asem1789 Date: Thu, 28 Nov 2019 13:38:12 +0200 Subject: [PATCH 17/18] make request to add newPlace and make some style for message error Relates #8 --- client/src/components/StepsQuestions/index.js | 13 +++-- .../src/components/StepsQuestions/style.css | 12 +++++ .../subcomponents/ErrorDisplay.js | 8 +++- client/src/components/index.js | 4 +- client/src/pages/addNewSitSpot/index.js | 47 +++++++++++++++---- server/controllers/routes/place.js | 4 +- server/controllers/validation/place.js | 4 +- 7 files changed, 71 insertions(+), 21 deletions(-) diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index f61b658..59fce0d 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -1,4 +1,5 @@ import React from 'react'; +import propTypes from 'prop-types'; import { Steps, Button } from 'antd'; import subcomponents from './subcomponents'; import questions from '../../staticDataSet/questions'; @@ -17,6 +18,7 @@ const requiredDictionary = questions.reduce( (acc, { required, key }) => ({ ...acc, [key]: required }), {} ); + export default class StepsQuestions extends React.Component { state = { currentStep: 0, @@ -111,9 +113,8 @@ export default class StepsQuestions extends React.Component { }); render() { - const { currentStep } = this.state; - // const { onSubmit } = this.props; - // console.log(this.state.questions); + const { onSubmit } = this.props; + const { currentStep, data } = this.state; return (
{this.renderSteps()} @@ -150,7 +151,7 @@ export default class StepsQuestions extends React.Component { @@ -160,3 +161,7 @@ export default class StepsQuestions extends React.Component { ); } } + +StepsQuestions.propTypes = { + onSubmit: propTypes.func.isRequired, +}; diff --git a/client/src/components/StepsQuestions/style.css b/client/src/components/StepsQuestions/style.css index 3b49024..fb34ecc 100644 --- a/client/src/components/StepsQuestions/style.css +++ b/client/src/components/StepsQuestions/style.css @@ -59,6 +59,18 @@ word-spacing: 0.2rem; } +/* ================== Error Display */ + +.error-box { + padding: 0.3rem 0; + background-color: #ffbaba; +} + +.error-box__message { + color: #d8000c; + text-align: center; +} + /* ================= override on style antd SELECT */ #add-place .ant-select { diff --git a/client/src/components/StepsQuestions/subcomponents/ErrorDisplay.js b/client/src/components/StepsQuestions/subcomponents/ErrorDisplay.js index 8d6e53b..b99ac50 100644 --- a/client/src/components/StepsQuestions/subcomponents/ErrorDisplay.js +++ b/client/src/components/StepsQuestions/subcomponents/ErrorDisplay.js @@ -1,6 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; -const ErrorDisplay = ({ error }) => {error}; +const ErrorDisplay = ({ error }) => ( +
+

{error}

+
+); + ErrorDisplay.propTypes = { error: PropTypes.string.isRequired }; + export default ErrorDisplay; diff --git a/client/src/components/index.js b/client/src/components/index.js index 38cdc3d..aceccd2 100644 --- a/client/src/components/index.js +++ b/client/src/components/index.js @@ -11,7 +11,7 @@ import MagicalFactor from './MagicalFactor'; import Review from './Review'; import ImageCarousel from './ImageCarousel'; import Layout from './Layout'; -import StepsQuestions2 from './StepsQuestions'; +import StepsQuestions from './StepsQuestions'; export { Button, @@ -27,5 +27,5 @@ export { SearchResult, ImageCarousel, Layout, - StepsQuestions2, + StepsQuestions, }; diff --git a/client/src/pages/addNewSitSpot/index.js b/client/src/pages/addNewSitSpot/index.js index 304c12b..2d6d2a5 100644 --- a/client/src/pages/addNewSitSpot/index.js +++ b/client/src/pages/addNewSitSpot/index.js @@ -1,17 +1,44 @@ import React from 'react'; -import { StepsQuestions2 as Steps } from '../../components'; +import propTypes from 'prop-types'; +import { StepsQuestions } from '../../components'; +import { addPlace } from '../../services/api'; import './style.css'; -const onSubmit = something => something; +class AddNewSitspot extends React.Component { + state = { + loading: false, + }; -const AddNewSitspot = () => ( -
-
-
- -
-
-); + onSubmit = data => { + const { history } = this.props; + const { type } = data; + const formData = new FormData(); + + Object.entries(data).forEach( + ([key, value]) => !!value && formData.append(key, value) + ); + + addPlace(formData).then(({ data: id }) => + history.push(`/add-review/${type}/${id}`) + ); + }; + + render() { + const { loading } = this.state; + return ( +
+
+
+ {!loading ? : ''} +
+
+ ); + } +} + +AddNewSitspot.propTypes = { + history: propTypes.shape({ push: propTypes.func.isRequired }).isRequired, +}; export default AddNewSitspot; diff --git a/server/controllers/routes/place.js b/server/controllers/routes/place.js index bc830ad..80f6ae1 100644 --- a/server/controllers/routes/place.js +++ b/server/controllers/routes/place.js @@ -4,9 +4,9 @@ const { place } = require('../validation'); const post = (req, res, next) => { const body = { ...req.body }; - const { name, linkSite, country, city, businessType, img1 } = body; + const { name, link, country, city, type, img1 } = body; place - .validate({ name, linkSite, country, city, businessType }) + .validate({ name, link, country, city, type }) .then(() => { if (img1) return upload(img1); diff --git a/server/controllers/validation/place.js b/server/controllers/validation/place.js index b89c8a8..624432d 100644 --- a/server/controllers/validation/place.js +++ b/server/controllers/validation/place.js @@ -2,8 +2,8 @@ const { object, string } = require('yup'); module.exports = object().shape({ name: string().required(), - linkSite: string(), + link: string(), country: string().required(), city: string().required(), - businessType: string().required(), + type: string().required(), }); From b698225a4be09e83ddb3001772dcfa8541bc5e09 Mon Sep 17 00:00:00 2001 From: amoodaa Date: Thu, 28 Nov 2019 13:46:25 +0200 Subject: [PATCH 18/18] COMPONENT DONEEE, with onSubmit --- client/src/components/StepsQuestions/index.js | 9 ++++++--- client/src/pages/addNewSitSpot/index.js | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/client/src/components/StepsQuestions/index.js b/client/src/components/StepsQuestions/index.js index 59fce0d..2226a97 100644 --- a/client/src/components/StepsQuestions/index.js +++ b/client/src/components/StepsQuestions/index.js @@ -1,6 +1,6 @@ import React from 'react'; import propTypes from 'prop-types'; -import { Steps, Button } from 'antd'; +import { Steps, Button, Spin } from 'antd'; import subcomponents from './subcomponents'; import questions from '../../staticDataSet/questions'; import requiredStringSchema from '../../utils/addPlaceValidation'; @@ -113,9 +113,11 @@ export default class StepsQuestions extends React.Component { }); render() { - const { onSubmit } = this.props; + const { onSubmit, loading } = this.props; const { currentStep, data } = this.state; - return ( + return loading ? ( + + ) : (
{this.renderSteps()} {this.renderContent(currentStep)} @@ -164,4 +166,5 @@ export default class StepsQuestions extends React.Component { StepsQuestions.propTypes = { onSubmit: propTypes.func.isRequired, + loading: propTypes.bool.isRequired, }; diff --git a/client/src/pages/addNewSitSpot/index.js b/client/src/pages/addNewSitSpot/index.js index 2d6d2a5..00f86f4 100644 --- a/client/src/pages/addNewSitSpot/index.js +++ b/client/src/pages/addNewSitSpot/index.js @@ -11,6 +11,7 @@ class AddNewSitspot extends React.Component { }; onSubmit = data => { + this.setState({ loading: true }); const { history } = this.props; const { type } = data; const formData = new FormData(); @@ -30,7 +31,7 @@ class AddNewSitspot extends React.Component {
- {!loading ? : ''} +
);