· 6 years ago · Dec 05, 2019, 04:41 PM
1import React, { Component } from 'react'
2import classify from 'src/classify'
3import defaultClasses from './clientDetails.scss'
4import Tabs from '@material-ui/core/Tabs'
5import Tab from '@material-ui/core/Tab'
6import PropTypes from 'prop-types'
7import { withStyles } from '@material-ui/core/styles'
8import FormFieldset from '../../../components/FormFieldset/FormFieldset'
9import Button from '@material-ui/core/Button'
10import ActivityLogGrid from '../ActivityLogGrid'
11import { createMuiTheme, MuiThemeProvider } from '@material-ui/core/styles'
12import SnackbarContent from '@material-ui/core/SnackbarContent'
13import IconButton from '@material-ui/core/IconButton'
14import CloseIcon from '@material-ui/icons/Close'
15
16const styles = theme => ({
17 indicator: {
18 backgroundColor: 'white'
19 },
20 tab: {
21 '@media (max-width: 1123px)': {
22 minWidth: '100px'
23 }
24 },
25 root: {},
26 formContentWrapper: {},
27 mainContentWrapper: {},
28 form: {},
29 formDetails: {},
30 middleBoxWrapper: {},
31 smallButton: {},
32 box: {},
33 dottedBox: {},
34 formAction: {},
35 currentPage: {},
36 button: {},
37 header: {},
38 headerDate: {},
39 map: {}
40})
41class ClientDetails extends Component {
42 constructor() {
43 super()
44 this.saveDetails = this.saveDetails.bind(this)
45 this.changeValue = this.changeValue.bind(this)
46 this.state = {
47 currentTab: 0,
48 clientData: [],
49 deepPropsUpdate: 0,
50 showResponse: false,
51 responseStatus: false
52 }
53 }
54
55 componentWillMount() {
56 const { getClientDetails } = this.props
57 const { id } = this.props.match.params
58 getClientDetails(id)
59 }
60
61 componentDidMount() {
62 const { isLinked, currentTab } = this.props.history.location
63 isLinked && this.props.toggleDashboardSecondNav()
64 currentTab &&
65 this.setState({
66 currentTab
67 })
68
69 if (this.props.saveClientError && !this.props.saveClientSuccess){
70 this.setState({
71 showResponse: false,
72 responseStatus: false
73 })
74 }else if (this.props.saveClientSuccess){
75 this.setState({
76 responseStatus: true,
77 showResponse: true
78 })
79 }
80
81 }
82 handleClose = () => {
83 this.setState({
84 showResponse: false
85 })
86 }
87
88 componentWillReceiveProps(prevProps ,newProps) {
89 const { clientData, location, saveClientError, saveClientSuccess } = this.props
90 const newClientData = newProps.clientData
91 this.setState({
92 clientData: newProps.clientData,
93 deepPropsUpdate: this.state.deepPropsUpdate + 1
94 })
95
96 if (clientData !== newClientData && newClientData) {
97 this.setState({
98 firstname: newClientData.firstname || '',
99 lastname: newClientData.lastname || '',
100 email: newClientData.email || '',
101 phone: newClientData.extension_attributes.leads.length
102 ? newClientData.extension_attributes.leads.find(x => x !== undefined).phone || ''
103 : ''
104 })
105
106 newClientData.extension_attributes.leads.map(lead => {
107 let type = lead.customer_type === 'personal' ? 'private' : lead.customer_type
108
109 this.setState({
110 extension_attributes: {
111 leads: {
112 [type]: {
113 ...lead,
114 city: lead.city || '',
115 street: `${lead.street || ''}`,
116 demand_type: lead.demand_type || '',
117 demand_value: lead.demand_value || '',
118 roofAngle: lead.roof_angle || '',
119 latitude: lead.latitude || null,
120 longitude: lead.longitude || null
121 }
122 }
123 }
124 })
125 })
126 }
127 }
128
129 /**
130 * Functions handles changes on form input
131 * and save changed data to state
132 * @param ev
133 * @param type
134 * @param prefix - stirng - exist if value in input has some prefix, as zl or kW
135 */
136
137 changeValue(ev, type, prefix) {
138 const target = ev.currentTarget.name ? ev.currentTarget : ev.target
139 if (target.name === '') return
140 if (type && target) {
141 let value = prefix ? target.value.replace(prefix, '') : target.value
142 this.setState(prevState => ({
143 ...prevState,
144 extension_attributes: {
145 leads: {
146 [type]: {
147 ...prevState.extension_attributes.leads[type],
148 [target.name]: value
149 }
150 }
151 }
152 }))
153 } else {
154 if (target.name === 'firstname') {
155 let valArr = target.value.split(' ')
156 this.setState(prevState => ({
157 ...prevState,
158 [target.name]: valArr[0],
159 lastname: valArr[1] || ''
160 }))
161 return
162 }
163 this.setState(prevState => ({
164 ...prevState,
165 [target.name]: target.value
166 }))
167 }
168 }
169
170 /**
171 * Function prepares data to saving and call action to post it
172 * @param ev
173 */
174 saveDetails(ev) {
175 ev.preventDefault()
176 const { postClient } = this.props
177 const { state } = this
178 const formData = {}
179
180 let stateObj = JSON.parse(JSON.stringify(state))
181
182 Object.keys(stateObj).map(field => {
183 if (field === 'phone') return
184 formData[field] = stateObj[field]
185 })
186 let leadsArr = []
187 Object.keys(formData.extension_attributes.leads).map(type => {
188 /////////Temporary changes/////////////////////////////////
189 delete formData.extension_attributes.leads[type].identities
190 ////////Should be deleted, when API will be changed////////
191
192 leadsArr.push(formData.extension_attributes.leads[type])
193 })
194 formData.extension_attributes.leads = leadsArr
195 delete formData.clientData
196 delete formData.currentTab
197 delete formData.deepPropsUpdate
198 delete formData.showResponse
199 delete formData.responseStatus
200
201 Object.keys(formData.extension_attributes.leads[0]).map(key => {
202 Object.keys(stateObj).map(stateKey => {
203 stateObj[stateKey] && stateKey == key
204 ? (formData.extension_attributes.leads[0][key] = stateObj[stateKey])
205 : null
206 })
207 Object.keys(this.props.clientData).map(shouldBeKey => {
208 shouldBeKey !== key && delete formData[key]
209 if (!formData[shouldBeKey]) {
210 formData[shouldBeKey] = this.props.clientData[shouldBeKey]
211 }
212 })
213 })
214 delete formData.extension_attributes.leads[0].initial_quote
215
216 postClient(this.props.match.params, {
217 ...formData
218 })
219 }
220
221 /**
222 * Function saves data to state when marker on map was moved
223 * @param type
224 */
225 mapMarkerHandler = (type, data) => {
226 this.setState(prevState => ({
227 ...prevState,
228 extension_attributes: {
229 leads: {
230 [type]: {
231 ...prevState.extension_attributes.leads[type],
232 latitude: data.lat,
233 longitude: data.lng
234 }
235 }
236 }
237 }))
238 }
239
240 handleChange = (event, newValue) => {
241 this.setState({ currentTab: newValue })
242 }
243
244 currentPage = currentTab => {
245 const { classes } = this.props
246 const { clientData } = this.state
247 const { saveFilter } = this
248 return (
249 <ActivityLogGrid
250 key={this.state.deepPropsUpdate}
251 data={clientData}
252 saveFilter={saveFilter}
253 currentTab={currentTab}
254 order={this.state[currentTab] ? this.state[currentTab][0] : null}
255 orderBy={this.state[currentTab] ? this.state[currentTab][1] : null}
256 />
257 )
258 }
259
260 saveFilter = (order, orderBy, currentTab) => {
261 this.setState({ [currentTab]: [order, orderBy] })
262 }
263
264 render() {
265 const { clientData, classes } = this.props
266 const { changeValue, handleChange, currentPage, mapMarkerHandler } = this
267 const { firstname, lastname, email, phone, currentTab, customer_type } = this.state
268 const theme = createMuiTheme({
269 palette: {
270 primary: {
271 main: '#54B049',
272 contrastText: 'rgb(255, 255, 255)'
273 },
274 secondary: {
275 main: '#FD6A02',
276 contrastText: 'rgb(255, 255, 255)'
277 }
278 },
279 typography: {
280 useNextVariants: true
281 },
282 overrides: {
283 MuiButton: {
284 root: {
285 fontSize: 14,
286 letterSpacing: 0.75,
287 color: '#A0A6A4',
288 paddingLeft: 40,
289 paddingRight: 40,
290 marginRight: 10
291 }
292 }
293 }
294 })
295
296 let leadTypeData = {
297 private: { name: 'DOM', data: null },
298 company: { name: 'FIRMA', data: null },
299 farm: { name: 'ROLNIK', data: null }
300 }
301
302 let data = null
303
304 const roofTypes = [
305 { key: 'roof_less_10', title: 'Płaski dach (0°-10°)' },
306 { key: 'roof_more_10', title: 'Skośny dach (>10°)' },
307 { key: 'ground', title: 'Naziemna' }
308 ]
309
310 const demandTypes = [
311 {
312 key: 'average_electricity_bill',
313 title: 'Average Electricity Bill'
314 },
315 { key: 'persons', title: 'Persons' },
316 { key: 'kw_installation_power', title: 'kW Installation Power' },
317 { key: 'monthly_cost', title: 'Monthly Cost' }
318 ]
319
320 const customerType = [
321 { title: 'DOM', key: 'private' },
322 { title: 'FIRMA', key: 'company' },
323 { title: 'ROLNIK', key: 'rolnik' }
324 ]
325
326 const sideRoof = [{ title: 'Tak', key: true }, { title: 'Nie', key: false }]
327
328 const building = [{ title: 'W budowie', key: 'w_budowie' }, { title: 'Istniejący', key: 'istniejący' }]
329
330 const roofCoverage = [
331 { title: 'Blachodachówka', key: 'blachodachowka' },
332 { title: 'Blachotrapez', key: 'blachotrapez' },
333 { title: 'Dachówka ceramiczna', key: 'dachówka_ceramiczna' },
334 { title: 'Dachówka betonowa', key: 'dachówka_betonowa' },
335 { title: 'Dachówka karpiówka', key: 'dachówka_karpiówka' },
336 { title: 'Dachówka łupkowa', key: 'dachówka_łupkowa' }
337 ]
338
339 if (clientData) {
340 var mocInfo = null
341 var buildingInfo = null
342 // Saves the first one occurring by each type of lead to array
343 // in necessary format
344 clientData.extension_attributes.leads.map(lead => {
345 let type = lead.customer_type === 'personal' ? 'private' : lead.customer_type
346
347 if (
348 leadTypeData[type] &&
349 !leadTypeData[type].data &&
350 this.state.extension_attributes &&
351 this.state.extension_attributes.leads[type]
352 ) {
353 const {
354 city,
355 street,
356 street2,
357 demand_type,
358 demand_value,
359 latitude,
360 longitude,
361 zipcode,
362 message,
363 average_monthly_bill,
364 number_of_people,
365 roof_angle,
366 roof_coverage,
367 details_building,
368 details_annual_energy_consumption,
369 details_roof_area,
370 details_roof_pitch,
371 details_roof_south_side,
372 details_lightning_protection,
373 details_floors,
374 details_electrical_connection_power,
375 customer_type
376 } = this.state.extension_attributes.leads[type]
377
378 data = {
379 title: 'DANE',
380 fields: [
381 {
382 label: 'Typ klienta',
383 variant: 'outlined',
384 type: '',
385 name: 'customer_type',
386 select: true,
387 selectItems: customerType,
388 value: this.state.customer_type || customer_type,
389 wide: true
390 },
391 {
392 label: 'Imię/Nazwa',
393 variant: 'outlined',
394 name: 'firstname',
395 type: 'text',
396 value: `${firstname}`
397 },
398 {
399 label: 'Nazwisko/Nazwa',
400 variant: 'outlined',
401 name: 'firstname',
402 type: 'text',
403 value: `${lastname}`
404 },
405 {
406 label: 'Adres Email',
407 variant: 'outlined',
408 name: 'email',
409 type: 'email',
410 value: email,
411 wide: true
412 },
413 {
414 label: 'Telefon',
415 variant: 'outlined',
416 name: 'phone',
417 type: 'phone',
418 value: phone,
419 wide: true
420 }
421 ]
422 }
423
424 let instalationData = {
425 variant: 'outlined',
426 type: 'text',
427 value: demand_value
428 },
429 fieldData = {}
430
431 switch (demand_type) {
432 case 'average_electricity_bill':
433 fieldData = {
434 label: 'Sredni rachunek za prąd',
435 prefix: 'zł'
436 }
437 break
438 case 'persons':
439 fieldData = {
440 label: 'Liczba osób w domu'
441 }
442 break
443 case 'monthly_cost':
444 fieldData = {
445 label: 'Rachunek za miesiąc',
446 prefix: 'zł'
447 }
448 break
449 case 'kw_installation_power':
450 fieldData = {
451 label: 'Moc instalacji',
452 prefix: ' kW'
453 }
454 break
455 }
456 mocInfo = {
457 title: 'MOC INSTALACJI',
458 width: 'small',
459 fieldsGroup: [
460 {
461 fields: [
462 {
463 label: 'Sredni rachunek za prad',
464 variant: 'outlined',
465 name: 'average_monthly_bill',
466 type: 'number',
467 value: `${+average_monthly_bill}`
468 },
469 {
470 label: 'Ilosc osob w domu',
471 variant: 'outlined',
472 type: 'number',
473 name: 'number_of_people',
474 value: `${+number_of_people}`
475 },
476 instalationData
477 ]
478 }
479 ],
480 latitude: latitude,
481 longitude: longitude
482 }
483
484 buildingInfo = {
485 title: 'SZCZEGOLY BUDYNKU',
486 width: 'large',
487 fieldsGroup: [
488 {
489 fields: [
490 {
491 label: 'Budynek',
492 variant: 'outlined',
493 type: '',
494 name: 'details_building',
495 select: true,
496 selectItems: building,
497 value: this.state.details_building || details_building,
498 wide: false
499 },
500 {
501 label: 'Ilosc kondygnacji',
502 variant: 'outlined',
503 type: 'number',
504 name: 'details_floors',
505 value: details_floors ? details_floors : '',
506 wide: false
507 },
508 {
509 label: 'Ilosc spadow',
510 variant: 'outlined',
511 type: 'number',
512 name: 'details_roof_pitch',
513 value: details_roof_pitch ? details_roof_pitch : '',
514 wide: false
515 },
516 {
517 label: 'Typ instalacji',
518 variant: 'outlined',
519 type: '',
520 name: 'roof_angle',
521 select: true,
522 selectItems: roofTypes,
523 value: roof_angle ? roof_angle : '',
524 wide: false
525 },
526 {
527 label: 'Pokrycie dachu',
528 variant: 'outlined',
529 type: '',
530 name: 'roof_coverage',
531 select: true,
532 selectItems: roofCoverage,
533 value: this.state.roof_coverage || roof_coverage,
534 wide: true
535 },
536 {
537 label: 'Polac poludniowa',
538 variant: 'outlined',
539 type: '',
540 name: 'details_roof_south_side',
541 selectItems: sideRoof,
542 value: details_roof_south_side ? details_roof_south_side : '',
543 wide: false
544 },
545 {
546 label: 'Instalacja odgromowa',
547 variant: 'outlined',
548 type: 'number',
549 name: 'details_lightning_protection',
550 value: details_lightning_protection ? details_lightning_protection : '',
551 wide: false
552 },
553 {
554 label: 'Powierzchnia',
555 variant: 'outlined',
556 name: 'details_roof_area',
557 type: 'number',
558 value: details_roof_area ? details_roof_area : ''
559 },
560 {
561 label: 'Actualna moc przylacz',
562 variant: 'outlined',
563 name: 'details_electrical_connection_power',
564 type: 'number',
565 value: details_electrical_connection_power ? details_electrical_connection_power : ''
566 },
567 {
568 label: 'Roczne zuzycie energii',
569 variant: 'outlined',
570 name: 'details_annual_energy_consumption',
571 type: 'number',
572 value: details_annual_energy_consumption ? details_annual_energy_consumption : ''
573 },
574 {
575 wide: true,
576 label: 'Dodatkowy opis',
577 variant: 'outlined',
578 name: 'message',
579 type: 'text',
580 value: (this.state.message || this.state.message == '') ? this.state.message : message,
581 multiline: true
582 }
583 ]
584 }
585 ],
586 latitude: latitude,
587 longitude: longitude
588 }
589 Object.assign(instalationData, fieldData)
590
591 let leadInfo = {
592 title: leadTypeData[type].name,
593 fieldsGroup: [
594 {
595 fields: [
596 {
597 label: 'Województwo',
598 variant: 'outlined',
599 type: 'text',
600 name: 'city',
601 value: city,
602 wide: true
603 },
604 {
605 label: 'Kod pozctowy',
606 variant: 'outlined',
607 name: 'zipcode',
608 type: 'number',
609 value: zipcode
610 },
611 {
612 label: 'Ulica',
613 variant: 'outlined',
614 name: 'street',
615 type: 'text',
616 value: street
617 },
618 {
619 label: 'Miasto',
620 variant: 'outlined',
621 name: 'city',
622 type: 'text',
623 value: city
624 },
625
626 {
627 label: 'nr domu',
628 variant: 'outlined',
629 name: 'street2',
630 type: 'number',
631 value: street2
632 }
633 ]
634 }
635 ],
636 latitude: latitude,
637 longitude: longitude
638 }
639
640 leadTypeData[type].data = leadInfo
641 }
642 })
643 }
644 return (
645 <div className={defaultClasses.root}>
646 <Tabs
647 value={currentTab}
648 onChange={handleChange}
649 classes={{
650 indicator: classes.indicator
651 }}
652 >
653 <Tab
654 classes={{ root: classes.tab }}
655 label={<span style={currentTab == 0 ? { color: 'green' } : {}}>AKTYWNOSC</span>}
656 />
657 <Tab
658 classes={{ root: classes.tab }}
659 label={<span style={currentTab == 1 ? { color: 'green' } : {}}>DANE</span>}
660 />
661 <Tab
662 classes={{ root: classes.tab }}
663 label={<span style={currentTab == 2 ? { color: 'green' } : {}}>NOTATKI</span>}
664 />
665 <Tab
666 classes={{ root: classes.tab }}
667 label={<span style={currentTab == 3 ? { color: 'green' } : {}}>WYCENY</span>}
668 />
669 <Tab
670 classes={{ root: classes.tab }}
671 label={<span style={currentTab == 4 ? { color: 'green' } : {}}>WIADOMOSCI</span>}
672 />
673 </Tabs>
674 <div className={currentTab == 1 ? defaultClasses.formContentWrapper : defaultClasses.mainContentWrapper}>
675 {currentTab == 1 ? (
676 <MuiThemeProvider theme={theme}>
677 <form onSubmit={this.saveDetails} className={defaultClasses.form}>
678 <div className={defaultClasses.formDetails}>
679 <FormFieldset data={data} handler={changeValue} />
680 {Object.keys(leadTypeData).map((lead, index) => {
681 const leadContent = (
682 <React.Fragment key={`leadGroup${index}`}>
683 <FormFieldset
684 title={lead}
685 mapMarkerHandler={mapMarkerHandler}
686 leads={leadTypeData}
687 data={leadTypeData[lead].data}
688 handler={ev => changeValue(ev, lead, leadTypeData[lead].data.prefix)}
689 />
690 </React.Fragment>
691 )
692 return leadContent
693 })}
694 <FormFieldset data={mocInfo} handler={changeValue} />
695 <FormFieldset data={buildingInfo} handler={changeValue} />
696 </div>
697 <div className={defaultClasses.middleBoxWrapper}>
698 <h2>ZDJECIA</h2>
699 <div>
700 <div className={defaultClasses.box} />
701 <div className={defaultClasses.dottedBox}>
702 <p>Przeciagnij plik jpg/pdf</p>
703 <p>lub</p>
704 <Button type="submit" variant="contained" color="primary" className={defaultClasses.smallButton}>
705 WYBIERZ PLIK
706 </Button>
707 </div>
708 </div>
709 </div>
710 <div className={defaultClasses.formAction}>
711 <Button type="submit" variant="contained" color="secondary" className={defaultClasses.button}>
712 ZAPISZ ZMIANY
713 </Button>
714 </div>
715 </form>
716 </MuiThemeProvider>
717 ) : (
718 currentPage(currentTab)
719 )}
720 {this.state.showResponse ? (
721 <SnackbarContent
722 className={[classes.messegeBody, this.state.responseStatus ? classes.successMessage : classes.errorMessage]}
723 aria-describedby="client-snackbar"
724 message={
725 <span id="client-snackbar" className={classes.message}>
726 {this.state.responseStatus ? 'Pomyślnie zaktualizowano' : 'Błąd'}
727 </span>
728 }
729 action={[
730 <IconButton key="close" aria-label="close" color="inherit" onClick={this.handleClose}>
731 <CloseIcon className={classes.icon} />
732 </IconButton>
733 ]}
734 />
735 ) : null}
736 </div>
737 </div>
738 )
739 }
740}
741
742ClientDetails.propTypes = {
743 classes: PropTypes.object.isRequired
744}
745export default classify(defaultClasses)(withStyles(styles)(ClientDetails))