Advertisement
Guest User

Swap component

a guest
Aug 15th, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.51 KB | None | 0 0
  1. import PropTypes from 'prop-types'
  2. import React from 'react'
  3. import { swapOptions, validationStatuses } from 'Core/constants'
  4. import { Select } from '../../../../FormElements'
  5. import { AddButton } from '../AddButton'
  6. import { RemoveButton } from '../RemoveButton'
  7. import { connect } from 'react-redux'
  8. import { getFlattenCategories } from 'SRC/modules/categories/selectors'
  9. import { AdsBrandsApi } from 'SRC/modules/ads/brands/api'
  10. import { AdsProductsApi } from 'SRC/modules/ads/products/api'
  11. import {
  12. setFormField,
  13. unsetFormField,
  14. setFormForValidationField,
  15. unsetFormForValidationField,
  16. setFormFieldValidity
  17. } from '../../../../../actions'
  18. import { requiredValidator } from 'Core/validators'
  19. import { getFieldValidity } from '../../../../../selectors'
  20.  
  21. export class Swap extends React.Component {
  22. constructor (props) {
  23. super(props)
  24.  
  25. this.maxSwapCount = 3
  26.  
  27. this.state = {
  28. swapCounter: 1,
  29. selectedSwap: null,
  30. swapps: [this.getDefaultSwapState()]
  31. }
  32. }
  33.  
  34. getDefaultSwapState = () => ({
  35. selectedCategory: null,
  36. categoryOptions: {},
  37. brands: [],
  38. isBrandsLoading: true,
  39. selectedBrand: null,
  40. products: [],
  41. isProductsLoading: true,
  42. selectedProduct: null,
  43. specificationValues1: [],
  44. selectedSpecification1: null,
  45. specificationValues2: [],
  46. selectedSpecification2: null
  47. })
  48.  
  49. getSwapField = () => ({
  50. id: 'swapp',
  51. title: 'Zamjena',
  52. name: 'swapp',
  53. options: swapOptions.map(item => ({label: item.title, value: item.value})),
  54. onChange: this.onSwapChange,
  55. isRequired: true
  56. })
  57.  
  58. getSwappsArray = () => {
  59. const swapps = []
  60. for (let i = 0; i < this.state.swapCounter; i++) {
  61. swapps.push(i)
  62. }
  63. return swapps
  64. }
  65.  
  66. getSwapItem = (index) => {
  67. const items = []
  68.  
  69. if (this.state.swapCounter > 1 && index > 0) {
  70. items.push({
  71. type: 'button'
  72. })
  73. }
  74.  
  75. if (this.state.selectedSwap && this.state.selectedSwap !== 'No') {
  76. items.push({
  77. id: `swapps-category-${index}`,
  78. type: 'select',
  79. title: 'Kategorija',
  80. name: 'category',
  81. options: this.props.categories
  82. .filter(category => category.swappPresence)
  83. .map(category => ({label: category.title, value: category.id})),
  84. isRequired: true,
  85. onChange: this.onCategoryChange,
  86. isNeedSaveValueToStore: false,
  87. isNeedValidate: false,
  88. onFocus: this.onFocus,
  89. onBlur: this.onBlur,
  90. index
  91. })
  92.  
  93. if (this.state.swapps[index] && this.state.swapps[index].selectedCategory) {
  94. if (this.isBrandAvailableForCategory(this.state.swapps[index].categoryOptions)) {
  95. items.push({
  96. id: `swapps-brand-${index}`,
  97. type: 'select',
  98. title: 'Proizvođač',
  99. name: 'brand',
  100. options: this.state.swapps[index].brands,
  101. onChange: this.onBrandChange,
  102. isRequired: true,
  103. isLoading: this.state.swapps[index].isBrandsLoading,
  104. isNeedSaveValueToStore: false,
  105. isNeedValidate: false,
  106. onFocus: this.onFocus,
  107. onBlur: this.onBlur,
  108. index
  109. })
  110. }
  111.  
  112. if (this.isProductAvailableForCategory(this.state.swapps[index].categoryOptions)) {
  113. items.push({
  114. id: `swapps-product-${index}`,
  115. type: 'select',
  116. title: 'Model',
  117. name: 'product',
  118. options: this.state.swapps[index].products,
  119. isRequired: true,
  120. isLoading: this.state.swapps[index].isProductsLoading,
  121. onChange: this.onProductChange,
  122. isNeedSaveValueToStore: false,
  123. isNeedValidate: false,
  124. onFocus: this.onFocus,
  125. onBlur: this.onBlur,
  126. index
  127. })
  128. }
  129.  
  130. if (this.isSpecificationsAvailableForCategory(this.state.swapps[index].categoryOptions)) {
  131. if (this.state.swapps[index].categoryOptions.swappSpecification1) {
  132. items.push({
  133. id: 'swapps-specification-1',
  134. type: 'select',
  135. title: `${this.state.swapps[index].categoryOptions.swappSpecification1.title}`,
  136. name: 'specification1',
  137. options: this.state.swapps[index].specificationValues1,
  138. value: this.state.swapps[index].selectedSpecification1,
  139. isNeedSaveValueToStore: false,
  140. isNeedValidate: false,
  141. onChange: this.onSpecificationChange1,
  142. index
  143. })
  144. }
  145. if (this.state.swapps[index].categoryOptions.swappSpecification2) {
  146. items.push({
  147. id: 'swapps-specification-2',
  148. type: 'select',
  149. title: `${this.state.swapps[index].categoryOptions.swappSpecification2.title}`,
  150. name: 'specification2',
  151. options: this.state.swapps[index].specificationValues2,
  152. value: this.state.swapps[index].selectedSpecification2,
  153. isNeedSaveValueToStore: false,
  154. isNeedValidate: false,
  155. onChange: this.onSpecificationChange2,
  156. index
  157. })
  158. }
  159. }
  160. }
  161. }
  162.  
  163. return items
  164. }
  165.  
  166. onSwapChange = async e => {
  167. const value = e.target.value
  168. await this.setState(prevState => {
  169. return {
  170. ...this.state,
  171. selectedSwap: value,
  172. swapps: prevState.selectedSwap && prevState.selectedSwap !== 'No' && (value === 'No' || !value) ? [] : prevState.swapps,
  173. swapCounter: 1
  174. }
  175. })
  176. if (value === 'No' || !value) {
  177. this.unsetSwappsValuesFromStore()
  178. this.unsetSwappsFieldsForValidation()
  179. } else {
  180. this.setSwappsFieldsForValidation()
  181. }
  182. }
  183.  
  184. onCategoryChange = async e => {
  185. const value = Number(e.target.value)
  186. const index = Number(e.target.dataset.index)
  187. const filteredCategory = this.props.categories.filter(item => item.id === value)
  188. let categoryOptions = {}
  189. if (filteredCategory.length) {
  190. categoryOptions = {
  191. requiredAdOptions: filteredCategory[0].requiredAdOptions,
  192. swappSpecification1: filteredCategory[0].swappSpecification1,
  193. swappSpecification2: filteredCategory[0].swappSpecification2
  194. }
  195. }
  196. await this.saveSwappsToState(index, {
  197. selectedCategory: value,
  198. categoryOptions,
  199. brands: [],
  200. selectedBrand: null,
  201. products: [],
  202. specificationValues1: [],
  203. selectedSpecification1: null,
  204. specificationValues2: [],
  205. selectedSpecification2: null
  206. })
  207.  
  208. this.setSwappsValuesInStore()
  209. this.setSwappsFieldsForValidation()
  210.  
  211. if (this.isBrandAvailableForCategory(categoryOptions)) {
  212. await this.loadBrandsToState(value, index)
  213. }
  214.  
  215. if (this.isSpecificationsAvailableForCategory(categoryOptions)) {
  216. await this.loadSpecificationsToState(index)
  217. }
  218. }
  219.  
  220. isBrandAvailableForCategory = (category = {}) => {
  221. return category && (category.requiredAdOptions === 'BrandModel' || category.requiredAdOptions === 'BrandOnly')
  222. }
  223.  
  224. isProductAvailableForCategory = (category = {}) => {
  225. return category && category.requiredAdOptions === 'BrandModel'
  226. }
  227.  
  228. isSpecificationsAvailableForCategory = (category = {}) => {
  229. return category &&
  230. (category.requiredAdOptions === 'BrandOnly' || category.requiredAdOptions === null) &&
  231. (category.swappSpecification1 || category.swappSpecification2)
  232. }
  233.  
  234. loadBrandsToState = async (category, index) => {
  235. await this.saveSwappsToState(index, {
  236. isBrandsLoading: true
  237. })
  238. const api = new AdsBrandsApi()
  239. const brands = await api.getBrandsByCategory(category)
  240. await this.saveSwappsToState(index, {
  241. brands: brands.map(brand => ({label: brand.name, value: brand.id})),
  242. isBrandsLoading: false
  243. })
  244. }
  245.  
  246. onBrandChange = async e => {
  247. const value = Number(e.target.value)
  248. const index = Number(e.target.dataset.index)
  249. await this.saveSwappsToState(index, {
  250. selectedBrand: value,
  251. products: [],
  252. selectedProduct: null
  253. })
  254.  
  255. this.setSwappsValuesInStore()
  256. this.setSwappsFieldsForValidation()
  257.  
  258. if (this.isProductAvailableForCategory(this.state.swapps[index].categoryOptions)) {
  259. await this.loadProductsToState(value, index)
  260. }
  261. }
  262.  
  263. loadProductsToState = async (brand, index) => {
  264. await this.saveSwappsToState(index, {
  265. isProductsLoading: true
  266. })
  267. const api = new AdsProductsApi()
  268. const products = await api.fetchProductsByBrand(brand)
  269. await this.saveSwappsToState(index, {
  270. products: products.map(product => ({label: product.model, value: product.id})),
  271. isProductsLoading: false
  272. })
  273. }
  274.  
  275. onProductChange = async e => {
  276. const value = Number(e.target.value)
  277. const index = Number(e.target.dataset.index)
  278. await this.saveSwappsToState(index, {
  279. selectedProduct: value
  280. })
  281. this.setSwappsValuesInStore()
  282. this.setSwappsFieldsForValidation()
  283. }
  284.  
  285. onSpecificationChange1 = async e => {
  286. const value = e.target.value
  287. const index = Number(e.target.dataset.index)
  288. await this.saveSwappsToState(index, {
  289. selectedSpecification1: value
  290. })
  291. this.setSwappsValuesInStore()
  292. this.setSwappsFieldsForValidation()
  293. }
  294.  
  295. onSpecificationChange2 = async e => {
  296. const value = e.target.value
  297. const index = Number(e.target.dataset.index)
  298. await this.saveSwappsToState(index, {
  299. selectedSpecification2: value
  300. })
  301. this.setSwappsValuesInStore()
  302. this.setSwappsFieldsForValidation()
  303. }
  304.  
  305. loadSpecificationsToState = async (index) => {
  306. if (this.state.swapps[index] && this.state.swapps[index].categoryOptions) {
  307. if (
  308. this.state.swapps[index].categoryOptions.swappSpecification1 &&
  309. this.state.swapps[index].categoryOptions.swappSpecification1.options
  310. ) {
  311. const options = this.state.swapps[index].categoryOptions.swappSpecification1.options.map((item) => ({
  312. value: item,
  313. label: item
  314. }))
  315. await this.saveSwappsToState(index, {
  316. specificationValues1: options
  317. })
  318. }
  319. }
  320. if (
  321. this.state.swapps[index].categoryOptions.swappSpecification2 &&
  322. this.state.swapps[index].categoryOptions.swappSpecification2.options
  323. ) {
  324. const options = this.state.swapps[index].categoryOptions.swappSpecification2.options.map((item) => ({
  325. value: item,
  326. label: item
  327. }))
  328. await this.saveSwappsToState(index, {
  329. specificationValues2: options
  330. })
  331. }
  332. }
  333.  
  334. saveSwappsToState = async (index, fields) => {
  335. await this.setState(prevState => {
  336. const newSwapps = prevState.swapps
  337. newSwapps[index] = {...prevState.swapps[index], ...fields}
  338. return prevState
  339. })
  340. }
  341.  
  342. onAddSwappsClick = async () => {
  343. await this.setState(prevState => {
  344. prevState.swapps.push(this.getDefaultSwapState())
  345. return {
  346. ...prevState,
  347. swapCounter: prevState.swapCounter + 1
  348. }
  349. })
  350. this.setSwappsValuesInStore()
  351. this.setSwappsFieldsForValidation()
  352. }
  353.  
  354. onRemoveSwappsClick = async e => {
  355. const index = Number(e.target.dataset.index)
  356. await this.setState(prevState => {
  357. const newSwapps = prevState.swapps.filter((item, i) => index !== i)
  358. return {
  359. ...prevState,
  360. swapCounter: prevState.swapCounter - 1,
  361. swapps: newSwapps
  362. }
  363. })
  364. this.setSwappsValuesInStore()
  365. this.setSwappsFieldsForValidation()
  366. }
  367.  
  368. isShouldRenderAddButton = () =>
  369. this.state.swapCounter < this.maxSwapCount &&
  370. this.state.selectedSwap &&
  371. this.state.selectedSwap !== 'No'
  372.  
  373. setSwappsValuesInStore = () => {
  374. const swapps = []
  375. this.state.swapps.forEach(item => {
  376. const value = {}
  377. if (item.selectedCategory) {
  378. value.category = item.selectedCategory
  379. }
  380. if (item.selectedBrand) {
  381. value.brand = item.selectedBrand
  382. }
  383. if (item.selectedProduct) {
  384. value.product = item.selectedProduct
  385. }
  386. if (item.selectedSpecification1) {
  387. value.specificaton1 = item.categoryOptions.swappSpecification1.id
  388. value.specificatonValue1 = item.selectedSpecification1
  389. }
  390. if (item.selectedSpecification2) {
  391. value.specificaton2 = item.categoryOptions.swappSpecification2.id
  392. value.specificatonValue2 = item.selectedSpecification2
  393. }
  394. if (Object.keys(value).length) {
  395. swapps.push(value)
  396. }
  397. })
  398. if (swapps.length) {
  399. this.props.setFormField('swapps', swapps)
  400. }
  401. }
  402.  
  403. unsetSwappsValuesFromStore = () => {
  404. this.props.unsetFormField('swapps')
  405. }
  406.  
  407. setSwappsFieldsForValidation = () => {
  408. const swapps = this.getSwappsFieldForValidation()
  409. if (swapps.length) {
  410. this.props.setFormForValidationField('swapps', swapps)
  411. }
  412. }
  413.  
  414. getSwappsFieldForValidation = () => {
  415. const swapps = []
  416. this.state.swapps.forEach(item => {
  417. const value = {}
  418. value.category = null
  419. if (item.selectedCategory && this.isBrandAvailableForCategory(item.categoryOptions)) {
  420. value.brand = null
  421. }
  422. if (item.selectedBrand && this.isProductAvailableForCategory(item.categoryOptions)) {
  423. value.product = null
  424. }
  425. if (Object.keys(value).length) {
  426. swapps.push(value)
  427. }
  428. })
  429. return swapps
  430. }
  431.  
  432. unsetSwappsFieldsForValidation = () => {
  433. this.props.unsetFormForValidationField('swapps')
  434. }
  435.  
  436. validate = () => {
  437. const values = []
  438. const swapps = this.getSwappsFieldForValidation()
  439. swapps.map((swapItem, index) => {
  440. if (Object.keys(swapItem).length) {
  441. const value = {}
  442. for (let field in swapItem) {
  443. if (swapItem.hasOwnProperty(field)) {
  444. value[field] = requiredValidator(this.getSwappsValueFromState(index, field))
  445. ? validationStatuses.VALID : validationStatuses.INVALID
  446. }
  447. }
  448. values.push(value)
  449. }
  450. })
  451. return values
  452. }
  453.  
  454. getSwappsValueFromState = (index, field) => {
  455. if (field) {
  456. switch (field) {
  457. case 'category':
  458. return this.state.swapps[index].selectedCategory
  459. case 'brand':
  460. return this.state.swapps[index].selectedBrand
  461. case 'product':
  462. return this.state.swapps[index].selectedProduct
  463. default:
  464. return null
  465. }
  466. } else {
  467. return null
  468. }
  469. }
  470.  
  471. onFocus = e => {
  472. const name = e.target.name
  473. const index = Number(e.target.dataset.index)
  474. const swapps = [...this.props.validity]
  475. swapps[index] = {
  476. ...swapps[index],
  477. [name]: validationStatuses.VALID
  478. }
  479. this.props.setFormFieldValidity('swapps', swapps)
  480. }
  481.  
  482. onBlur = e => {
  483. const name = e.target.name
  484. const index = Number(e.target.dataset.index)
  485. const value = e.target.value
  486. const swapps = [...this.props.validity]
  487. swapps[index] = {
  488. ...swapps[index],
  489. [name]: requiredValidator(value) ? validationStatuses.VALID : validationStatuses.INVALID
  490. }
  491. this.props.setFormFieldValidity('swapps', swapps)
  492. }
  493.  
  494. render () {
  495. return [
  496. <Select {...this.getSwapField()} key='swapp' />,
  497. this.getSwappsArray().map(
  498. index => <div
  499. className={`ads-add__swap-row ${index === 0 ? `ads-add__swap-row_first` : ''}`}
  500. key={`swapps-row-${index}`}
  501. >
  502. {
  503. this.getSwapItem(index).map(item => {
  504. const isError = this.props.validity && this.props.validity[index] && this.props.validity[index][item.name]
  505. ? this.props.validity[index][item.name] === validationStatuses.INVALID
  506. : false
  507. return item.type === 'button'
  508. ? <RemoveButton index={index} onClick={this.onRemoveSwappsClick} key={`remove-swapps-${index}`} />
  509. : <Select {...item} key={`swapps-${item.id}`} isError={isError} />
  510. })
  511. }
  512. </div>
  513. ),
  514. this.isShouldRenderAddButton() ? <AddButton onClick={this.onAddSwappsClick} key='add-swapps' /> : null
  515. ]
  516. }
  517. }
  518.  
  519. const mapStateToProps = (state) => ({
  520. categories: getFlattenCategories(state),
  521. validity: getFieldValidity(state, 'swapps')
  522. })
  523.  
  524. Swap.propTypes = {
  525. categories: PropTypes.arrayOf(PropTypes.shape({
  526. title: PropTypes.string.isRequired,
  527. id: PropTypes.number.isRequired,
  528. swappPresence: PropTypes.bool.isRequired,
  529. requiredAdOptions: PropTypes.oneOf(['BrandModel', 'BrandOnly', 'Services', null]),
  530. swappSpecification1: PropTypes.shape({
  531. id: PropTypes.number.isRequired,
  532. title: PropTypes.string.isRequired,
  533. options: PropTypes.arrayOf(PropTypes.string)
  534. }),
  535. swappSpecification2: PropTypes.shape({
  536. id: PropTypes.number.isRequired,
  537. title: PropTypes.string.isRequired,
  538. options: PropTypes.arrayOf(PropTypes.string)
  539. })
  540. })).isRequired,
  541. setFormField: PropTypes.func.isRequired,
  542. unsetFormField: PropTypes.func.isRequired,
  543. setFormForValidationField: PropTypes.func.isRequired,
  544. unsetFormForValidationField: PropTypes.func.isRequired,
  545. setFormFieldValidity: PropTypes.func.isRequired,
  546. validity: PropTypes.any
  547. }
  548.  
  549. Swap.defaultProps = {
  550. categories: []
  551. }
  552.  
  553. export default connect(
  554. mapStateToProps,
  555. {setFormField, unsetFormField, setFormForValidationField, unsetFormForValidationField, setFormFieldValidity},
  556. null,
  557. {withRef: true}
  558. )(Swap)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement