@plusscommunities/pluss-maintenance-web 1.1.16 → 1.1.18-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,841 @@
1
+ import React, { Component } from 'react';
2
+ import { Table } from 'react-bootstrap';
3
+ import { withRouter } from 'react-router';
4
+ import _ from 'lodash';
5
+ import { connect } from 'react-redux';
6
+ import FontAwesome from 'react-fontawesome';
7
+ import { PlussCore } from '../feature.config';
8
+ import { jobTypesUpdate } from '../actions';
9
+ import { maintenanceActions } from '../apis';
10
+ import { values } from '../values.config';
11
+
12
+ const { Components, Session, Helper } = PlussCore;
13
+ const DEFAULT_FIELD = { type: 'text', label: '', mandatory: false, isTitle: false, values: [''] };
14
+
15
+ class AddJobType extends Component {
16
+ constructor(props) {
17
+ super(props);
18
+
19
+ this.fieldTypes = [
20
+ {
21
+ Title: 'Text Input',
22
+ Key: 'text',
23
+ },
24
+ {
25
+ Title: 'Email Input',
26
+ Key: 'email',
27
+ },
28
+ {
29
+ Title: 'Phone Input',
30
+ Key: 'phone',
31
+ },
32
+ {
33
+ Title: 'Date Input',
34
+ Key: 'date',
35
+ },
36
+ {
37
+ Title: 'Time Input',
38
+ Key: 'time',
39
+ },
40
+ {
41
+ Title: 'Image Input',
42
+ Key: 'image',
43
+ },
44
+ {
45
+ Title: 'Yes/No Question',
46
+ Key: 'yn',
47
+ },
48
+ {
49
+ Title: 'Multiple Choice',
50
+ Key: 'multichoice',
51
+ },
52
+ {
53
+ Title: 'Checkboxes',
54
+ Key: 'checkbox',
55
+ },
56
+ {
57
+ Title: 'Title Text',
58
+ Key: 'staticTitle',
59
+ },
60
+ {
61
+ Title: 'Paragraph Text',
62
+ Key: 'staticText',
63
+ },
64
+ ];
65
+
66
+ this.state = {
67
+ loading: false,
68
+ jobTypeId: Helper.safeReadParams(this.props, 'jobTypeId') ? this.props.match.params.jobTypeId : null,
69
+ jobTypeName: '',
70
+ jobTypeEmail: '',
71
+ jobTypeDescription: '',
72
+ hasCustomFields: values.forceCustomFields ? true : false,
73
+ customFields: [_.cloneDeep(DEFAULT_FIELD)],
74
+ jobTypeLevel: 1,
75
+ warnings: ['this is a test warning'],
76
+ showWarnings: false,
77
+ submitting: false,
78
+ success: false,
79
+ };
80
+ }
81
+
82
+ UNSAFE_componentWillMount() {
83
+ Session.checkLoggedIn(this, this.props.auth);
84
+ if (this.state.jobTypeId) this.getJobType();
85
+ }
86
+
87
+ getJobType = async () => {
88
+ try {
89
+ const res = await maintenanceActions.getJobType(this.props.auth.site, this.state.jobTypeId);
90
+ const { typeName, email, description, level, hasCustomFields, customFields } = res.data;
91
+ this.setState({
92
+ jobTypeName: typeName,
93
+ jobTypeEmail: email,
94
+ jobTypeDescription: description,
95
+ jobTypeLevel: level,
96
+ hasCustomFields,
97
+ customFields,
98
+ });
99
+ } catch (error) {
100
+ console.error('getJobType', error);
101
+ }
102
+ };
103
+
104
+ getFieldTypeTitle = (type) => {
105
+ const fieldType = this.fieldTypes.find((f) => f.Key === type);
106
+ return fieldType ? fieldType.Title : '';
107
+ };
108
+
109
+ validateEmail = () => {
110
+ const { jobTypeEmail } = this.state;
111
+ return !_.isEmpty(jobTypeEmail) && Helper.isEmail(jobTypeEmail);
112
+ };
113
+
114
+ isJobTypeValid = () => {
115
+ const { jobTypeName, jobTypeDescription } = this.state;
116
+
117
+ if (_.isEmpty(jobTypeName)) return false;
118
+ if (!this.validateEmail()) return false;
119
+ if (_.isEmpty(jobTypeDescription)) return false;
120
+ if (!this.validateCustomFields()) return false;
121
+
122
+ return true;
123
+ };
124
+
125
+ validateCustomFields() {
126
+ const { submitting, hasCustomFields, customFields } = this.state;
127
+ if (submitting) return false;
128
+
129
+ // Validate custom fields
130
+ const warnings = [];
131
+ if (hasCustomFields) {
132
+ let missingLabel = false;
133
+ let hasMandatoryField = false;
134
+ let titleFieldCount = 0;
135
+ customFields.forEach((field) => {
136
+ const { type, label, values, mandatory, isTitle } = field;
137
+ if (['staticTitle', 'staticText'].includes(type)) return;
138
+
139
+ if (_.isEmpty(label)) {
140
+ missingLabel = true;
141
+ } else if (
142
+ _.isEmpty(type) ||
143
+ ((type === 'multichoice' || type === 'checkbox') && (!values || values.length < 2 || !values.every((value) => !_.isEmpty(value))))
144
+ ) {
145
+ warnings.push(`'${label}' is incomplete`);
146
+ }
147
+ if (mandatory) hasMandatoryField = true;
148
+ if (isTitle) titleFieldCount += 1;
149
+ });
150
+ if (missingLabel) {
151
+ warnings.push('All inputs must have a label');
152
+ }
153
+ if (!hasMandatoryField) {
154
+ warnings.push('There must be at least one required input');
155
+ }
156
+ if (titleFieldCount === 0) {
157
+ warnings.push('One of the required inputs must be selected as title for the request');
158
+ } else if (titleFieldCount > 1) {
159
+ warnings.push('Only one required input can be selected as title for the request');
160
+ }
161
+ }
162
+
163
+ this.setState({ warnings });
164
+ return warnings.length === 0;
165
+ }
166
+
167
+ onHandleChange = (event) => {
168
+ var stateChange = {};
169
+ stateChange[event.target.getAttribute('id')] = event.target.value;
170
+ this.setState(stateChange);
171
+ };
172
+
173
+ onFieldTypeChanged = (fieldIndex, key) => {
174
+ const customFields = [...this.state.customFields];
175
+ if (customFields[fieldIndex].type === key) return;
176
+
177
+ customFields[fieldIndex] = _.cloneDeep(DEFAULT_FIELD);
178
+ customFields[fieldIndex].type = key;
179
+
180
+ this.setState({ customFields });
181
+ };
182
+
183
+ onFieldLabelChanged = (fieldIndex, event) => {
184
+ const customFields = [...this.state.customFields];
185
+ customFields[fieldIndex].label = event.target.value;
186
+
187
+ this.setState({ customFields });
188
+ };
189
+
190
+ onFieldPlaceHolderChanged = (fieldIndex, event) => {
191
+ const customFields = [...this.state.customFields];
192
+ customFields[fieldIndex].placeHolder = event.target.value;
193
+
194
+ this.setState({ customFields });
195
+ };
196
+
197
+ onFieldMandatoryChanged = (fieldIndex) => {
198
+ const customFields = [...this.state.customFields];
199
+ customFields[fieldIndex].mandatory = !customFields[fieldIndex].mandatory;
200
+ if (!customFields[fieldIndex].mandatory) {
201
+ // If a field is not mandatory, it cannot be a title field
202
+ customFields[fieldIndex].isTitle = false;
203
+ }
204
+
205
+ this.setState({ customFields });
206
+ };
207
+
208
+ onFieldIsTitleChanged = (fieldIndex) => {
209
+ const customFields = [...this.state.customFields];
210
+ customFields[fieldIndex].isTitle = !customFields[fieldIndex].isTitle;
211
+ if (customFields[fieldIndex].isTitle) {
212
+ // If a field is title field, force mandatory
213
+ customFields[fieldIndex].mandatory = true;
214
+ }
215
+
216
+ this.setState({ customFields });
217
+ };
218
+
219
+ onFieldOptionChanged = (fieldIndex, optionIndex, event) => {
220
+ const customFields = [...this.state.customFields];
221
+ const prevValue = customFields[fieldIndex].values[optionIndex];
222
+ customFields[fieldIndex].values[optionIndex] = event.target.value;
223
+ // Change corresponding validation if exists
224
+ const validations = customFields[fieldIndex].validation;
225
+ let validation = validations ? validations.find((val) => val.value === prevValue) : null;
226
+ if (validation) validation.value = event.target.value;
227
+
228
+ this.setState({ customFields });
229
+ };
230
+
231
+ onAddNewOption = (fieldIndex) => {
232
+ const customFields = [...this.state.customFields];
233
+ customFields[fieldIndex].values.push('');
234
+ this.setState({ customFields });
235
+ };
236
+
237
+ onRemoveOption = (fieldIndex, optionIndex) => {
238
+ const customFields = [...this.state.customFields];
239
+ customFields[fieldIndex].values.splice(optionIndex, 1);
240
+ this.setState({ customFields });
241
+ };
242
+
243
+ onRemoveField(fieldIndex) {
244
+ const customFields = [...this.state.customFields];
245
+ if (customFields.length < 2) return;
246
+
247
+ customFields.splice(fieldIndex, 1);
248
+ this.setState({ customFields });
249
+ }
250
+
251
+ onAddNewField = () => {
252
+ const customFields = [...this.state.customFields];
253
+ customFields.push(_.cloneDeep(DEFAULT_FIELD));
254
+ this.setState({ customFields });
255
+ };
256
+
257
+ onMoveFieldPrev = (fieldIndex) => {
258
+ if (fieldIndex === 0) return;
259
+ const customFields = [...this.state.customFields];
260
+ const item = customFields.splice(fieldIndex, 1)[0];
261
+ customFields.splice(fieldIndex - 1, 0, item);
262
+
263
+ this.setState({ customFields });
264
+ };
265
+
266
+ onMoveFieldNext = (fieldIndex) => {
267
+ const customFields = [...this.state.customFields];
268
+ if (fieldIndex > customFields.length - 1) return;
269
+ const item = customFields.splice(fieldIndex, 1)[0];
270
+ customFields.splice(fieldIndex + 1, 0, item);
271
+
272
+ this.setState({ customFields });
273
+ };
274
+
275
+ onBack = () => {
276
+ window.history.back();
277
+ };
278
+
279
+ onSave = () => {
280
+ const { site } = this.props.auth;
281
+ const { submitting, jobTypeId, jobTypeName, jobTypeEmail, jobTypeDescription, jobTypeLevel, hasCustomFields, customFields } =
282
+ this.state;
283
+
284
+ if (submitting) return;
285
+ if (!this.isJobTypeValid()) {
286
+ this.setState({ showWarnings: true });
287
+ return;
288
+ }
289
+
290
+ this.setState({ submitting: true }, async () => {
291
+ try {
292
+ if (jobTypeId) {
293
+ await maintenanceActions.editJobType(
294
+ site,
295
+ jobTypeId,
296
+ jobTypeName,
297
+ jobTypeEmail,
298
+ jobTypeDescription,
299
+ jobTypeLevel,
300
+ hasCustomFields,
301
+ customFields,
302
+ );
303
+ } else {
304
+ await maintenanceActions.addJobType(
305
+ site,
306
+ jobTypeName,
307
+ jobTypeEmail,
308
+ jobTypeDescription,
309
+ jobTypeLevel,
310
+ hasCustomFields,
311
+ customFields,
312
+ );
313
+ }
314
+ this.props.jobTypesUpdate(site);
315
+ this.setState({ submitting: false, success: true });
316
+ } catch (error) {
317
+ console.error('onSave', error);
318
+ this.setState({ submitting: false });
319
+ alert('Something went wrong with the request. Please try again.');
320
+ }
321
+ });
322
+ };
323
+
324
+ renderBaseForm() {
325
+ const { success, jobTypeId, showWarnings, jobTypeName, jobTypeEmail, jobTypeDescription, hasCustomFields } = this.state;
326
+ if (success) return null;
327
+
328
+ // TODO: Request Type should be configurable
329
+ return (
330
+ <div className="padding-60 paddingVertical-40 bottomDivideBorder">
331
+ <Components.Text type="formTitleLarge" className="marginBottom-24">
332
+ {!jobTypeId ? 'New' : 'Edit'} Request Type
333
+ </Components.Text>
334
+ <Components.GenericInput
335
+ id="jobTypeName"
336
+ type="text"
337
+ label="Request type title"
338
+ placeholder="Request type title"
339
+ value={jobTypeName}
340
+ onChange={this.onHandleChange}
341
+ isRequired
342
+ isValid={() => !_.isEmpty(jobTypeName)}
343
+ showError={() => showWarnings && _.isEmpty(jobTypeName)}
344
+ alwaysShowLabel
345
+ />
346
+ <Components.GenericInput
347
+ id="jobTypeEmail"
348
+ type="text"
349
+ label="Email"
350
+ placeholder="Request email"
351
+ help="This is the email address that'll receive service requests of this type"
352
+ value={jobTypeEmail}
353
+ onChange={this.onHandleChange}
354
+ isRequired
355
+ isValid={this.validateEmail}
356
+ showError={() => showWarnings && !this.validateEmail()}
357
+ alwaysShowLabel
358
+ />
359
+ <Components.GenericInput
360
+ id="jobTypeDescription"
361
+ type="text"
362
+ label="Description"
363
+ placeholder="Add a description. "
364
+ help="This description will be visible to the people to help them select the correct request type."
365
+ value={jobTypeDescription}
366
+ onChange={this.onHandleChange}
367
+ isRequired
368
+ isValid={() => !_.isEmpty(jobTypeDescription)}
369
+ showError={() => showWarnings && _.isEmpty(jobTypeDescription)}
370
+ alwaysShowLabel
371
+ />
372
+ {values.forceCustomFields ? null : (
373
+ <Components.RadioButton
374
+ label="Do you want to create a custom form for this request type?"
375
+ isActive={hasCustomFields}
376
+ options={[
377
+ {
378
+ Label: 'Yes',
379
+ Value: true,
380
+ onChange: () => this.setState({ hasCustomFields: true }),
381
+ },
382
+ {
383
+ Label: 'No',
384
+ Value: false,
385
+ onChange: () => this.setState({ hasCustomFields: false }),
386
+ },
387
+ ]}
388
+ />
389
+ )}
390
+ </div>
391
+ );
392
+ }
393
+
394
+ renderOptionalCheckBox(field, fieldIndex) {
395
+ return (
396
+ <Components.CheckBox
397
+ id={`fieldOptional${fieldIndex}`}
398
+ label="Set this field as optional"
399
+ isActive={!field.mandatory}
400
+ onChange={(e) => this.onFieldMandatoryChanged(fieldIndex, e)}
401
+ />
402
+ );
403
+ }
404
+
405
+ renderTitleCheckBox(field, fieldIndex) {
406
+ return (
407
+ <Components.CheckBox
408
+ id={`fieldTitle${fieldIndex}`}
409
+ label="Use this field as the title"
410
+ isActive={field.isTitle}
411
+ onChange={(e) => this.onFieldIsTitleChanged(fieldIndex, e)}
412
+ />
413
+ );
414
+ }
415
+
416
+ renderFieldText(field, fieldIndex) {
417
+ return (
418
+ <div className="fieldInner">
419
+ <Components.GenericInput
420
+ id={`fieldLabel${fieldIndex}`}
421
+ className={'textInput'}
422
+ placeholder={'Type your label here (required)'}
423
+ value={field.label}
424
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
425
+ />
426
+ <Components.GenericInput
427
+ id={`fieldPlaceHolder${fieldIndex}`}
428
+ className={'placeHolderInput'}
429
+ placeholder={'Insert placeholder (optional)'}
430
+ value={field.placeHolder}
431
+ onChange={(e) => this.onFieldPlaceHolderChanged(fieldIndex, e)}
432
+ />
433
+ {this.renderOptionalCheckBox(field, fieldIndex)}
434
+ {this.renderTitleCheckBox(field, fieldIndex)}
435
+ </div>
436
+ );
437
+ }
438
+
439
+ renderFieldDate(field, fieldIndex) {
440
+ return (
441
+ <div className="fieldInner">
442
+ <Components.GenericInput
443
+ id={`fieldLabel${fieldIndex}`}
444
+ className={'textInput'}
445
+ placeholder={'Type your label here (required)'}
446
+ value={field.label}
447
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
448
+ />
449
+ {this.renderOptionalCheckBox(field, fieldIndex)}
450
+ {this.renderTitleCheckBox(field, fieldIndex)}
451
+ </div>
452
+ );
453
+ }
454
+
455
+ renderFieldTime(field, fieldIndex) {
456
+ return (
457
+ <div className="fieldInner">
458
+ <Components.GenericInput
459
+ id={`fieldLabel${fieldIndex}`}
460
+ className={'textInput'}
461
+ placeholder={'Type your label here (required)'}
462
+ value={field.label}
463
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
464
+ />
465
+ {this.renderOptionalCheckBox(field, fieldIndex)}
466
+ {this.renderTitleCheckBox(field, fieldIndex)}
467
+ </div>
468
+ );
469
+ }
470
+
471
+ renderFieldImage(field, fieldIndex) {
472
+ return (
473
+ <div className="fieldInner">
474
+ <Components.GenericInput
475
+ id={`fieldLabel${fieldIndex}`}
476
+ className={'textInput'}
477
+ placeholder={'Type your label here (required)'}
478
+ value={field.label}
479
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
480
+ />
481
+ {this.renderOptionalCheckBox(field, fieldIndex)}
482
+ </div>
483
+ );
484
+ }
485
+
486
+ renderFieldYesNo(field, fieldIndex) {
487
+ return (
488
+ <div className="fieldInner">
489
+ <Components.GenericInput
490
+ id={`fieldLabel${fieldIndex}`}
491
+ className={'textInput'}
492
+ placeholder={'Type your label here (required)'}
493
+ value={field.label}
494
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
495
+ />
496
+ <Table className="optionsContainer">
497
+ <thead className="headings">
498
+ <tr>
499
+ <th className="icon" />
500
+ <th className="options">Options</th>
501
+ </tr>
502
+ </thead>
503
+ <tbody>
504
+ {['Yes', 'No'].map((value, optionIndex) => {
505
+ return (
506
+ <tr key={optionIndex} className="option">
507
+ <td>
508
+ <Components.RadioButton single disabled isActive={false} />
509
+ </td>
510
+ <td>
511
+ <Components.GenericInput id={`fieldOption${optionIndex}`} value={value} disabled />
512
+ </td>
513
+ </tr>
514
+ );
515
+ })}
516
+ </tbody>
517
+ </Table>
518
+ {this.renderOptionalCheckBox(field, fieldIndex)}
519
+ </div>
520
+ );
521
+ }
522
+
523
+ renderFieldMultiple(field, fieldIndex) {
524
+ const { customFields } = this.state;
525
+ return (
526
+ <div className="fieldInner">
527
+ <Components.GenericInput
528
+ id={`fieldLabel${fieldIndex}`}
529
+ className={'textInput'}
530
+ placeholder={'Type your label here (required)'}
531
+ value={field.label}
532
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
533
+ />
534
+ <Table className="optionsContainer">
535
+ <thead className="headings">
536
+ <tr>
537
+ <th className="icon" />
538
+ <th className="options-wide">Options</th>
539
+ <th className="remove" />
540
+ </tr>
541
+ </thead>
542
+ <tbody>
543
+ {field.values &&
544
+ field.values.map((value, optionIndex) => {
545
+ return (
546
+ <tr key={optionIndex} className="option">
547
+ <td>
548
+ <Components.RadioButton single disabled isActive={false} />
549
+ </td>
550
+ <td>
551
+ <Components.GenericInput
552
+ id={`fieldOption${optionIndex}`}
553
+ placeholder={'Enter option'}
554
+ value={value}
555
+ onChange={(e) => this.onFieldOptionChanged(fieldIndex, optionIndex, e)}
556
+ />
557
+ </td>
558
+ <td>
559
+ {customFields[fieldIndex].values.length > 1 ? (
560
+ <div onClick={() => this.onRemoveOption(fieldIndex, optionIndex)}>
561
+ <FontAwesome name="minus-circle" className="cornerCancelButton_icon" />
562
+ </div>
563
+ ) : null}
564
+ </td>
565
+ </tr>
566
+ );
567
+ })}
568
+ </tbody>
569
+ </Table>
570
+ <div className="clearfix addoption optionAdd marginBottom-10" onClick={() => this.onAddNewOption(fieldIndex)}>
571
+ <Components.P60Icon className="addoption_plus" icon="add-circle" />
572
+ <div className="fillSpace">
573
+ <p className="addoption_text">Add Another Option</p>
574
+ </div>
575
+ </div>
576
+ {this.renderOptionalCheckBox(field, fieldIndex)}
577
+ {this.renderTitleCheckBox(field, fieldIndex)}
578
+ </div>
579
+ );
580
+ }
581
+
582
+ renderFieldCheckbox(field, fieldIndex) {
583
+ const { customFields } = this.state;
584
+ return (
585
+ <div className="fieldInner">
586
+ <Components.GenericInput
587
+ id={`fieldLabel${fieldIndex}`}
588
+ className={'textInput'}
589
+ placeholder={'Type your label here (required)'}
590
+ value={field.label}
591
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
592
+ />
593
+ <Table className="optionsContainer">
594
+ <thead className="headings">
595
+ <tr>
596
+ <th className="icon" />
597
+ <th>Options</th>
598
+ <th className="remove" />
599
+ </tr>
600
+ </thead>
601
+ <tbody>
602
+ {field.values &&
603
+ field.values.map((value, optionIndex) => {
604
+ return (
605
+ <tr key={optionIndex} className="option">
606
+ <td>
607
+ <Components.RadioButton single disabled isActive={false} isSquare />
608
+ </td>
609
+ <td>
610
+ <Components.GenericInput
611
+ id={`fieldOption${optionIndex}`}
612
+ placeholder={'Enter option'}
613
+ value={value}
614
+ onChange={(e) => this.onFieldOptionChanged(fieldIndex, optionIndex, e)}
615
+ />
616
+ </td>
617
+ <td>
618
+ {customFields[fieldIndex].values.length > 1 ? (
619
+ <div onClick={() => this.onRemoveOption(fieldIndex, optionIndex)}>
620
+ <FontAwesome name="minus-circle" className="cornerCancelButton_icon" />
621
+ </div>
622
+ ) : null}
623
+ </td>
624
+ </tr>
625
+ );
626
+ })}
627
+ </tbody>
628
+ </Table>
629
+ <div className="clearfix addoption optionAdd marginBottom-10" onClick={() => this.onAddNewOption(fieldIndex)}>
630
+ <Components.P60Icon className="addoption_plus" icon="add-circle" />
631
+ <div className="fillSpace">
632
+ <p className="addoption_text">Add Another Option</p>
633
+ </div>
634
+ </div>
635
+ {this.renderOptionalCheckBox(field, fieldIndex)}
636
+ {this.renderTitleCheckBox(field, fieldIndex)}
637
+ </div>
638
+ );
639
+ }
640
+
641
+ renderFieldStaticTitle(field, fieldIndex) {
642
+ return (
643
+ <div className="fieldInner">
644
+ <Components.GenericInput
645
+ id={`fieldStatic${fieldIndex}`}
646
+ placeholder="Insert title here (required)"
647
+ value={field.label}
648
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
649
+ large
650
+ />
651
+ </div>
652
+ );
653
+ }
654
+
655
+ renderFieldStaticText(field, fieldIndex) {
656
+ return (
657
+ <div className="fieldInner">
658
+ <Components.GenericInput
659
+ id={`fieldStatic${fieldIndex}`}
660
+ placeholder="Insert your paragraph text here (required)"
661
+ value={field.label}
662
+ onChange={(e) => this.onFieldLabelChanged(fieldIndex, e)}
663
+ type="textarea"
664
+ />
665
+ </div>
666
+ );
667
+ }
668
+
669
+ renderField(field, fieldIndex) {
670
+ const { customFields } = this.state;
671
+
672
+ const renderFieldContent = () => {
673
+ switch (field.type) {
674
+ case 'text':
675
+ case 'email':
676
+ case 'phone':
677
+ return this.renderFieldText(field, fieldIndex);
678
+ case 'date':
679
+ return this.renderFieldDate(field, fieldIndex);
680
+ case 'time':
681
+ return this.renderFieldTime(field, fieldIndex);
682
+ case 'image':
683
+ return this.renderFieldImage(field, fieldIndex);
684
+ case 'yn':
685
+ return this.renderFieldYesNo(field, fieldIndex);
686
+ case 'multichoice':
687
+ return this.renderFieldMultiple(field, fieldIndex);
688
+ case 'checkbox':
689
+ return this.renderFieldCheckbox(field, fieldIndex);
690
+ case 'staticTitle':
691
+ return this.renderFieldStaticTitle(field, fieldIndex);
692
+ case 'staticText':
693
+ return this.renderFieldStaticText(field, fieldIndex);
694
+ default:
695
+ return null;
696
+ }
697
+ };
698
+
699
+ return (
700
+ <div className="fieldContainer" key={fieldIndex}>
701
+ <div className="fieldNumberContainer">
702
+ <p className="fieldNumber">{fieldIndex + 1}</p>
703
+ </div>
704
+ <div className="field">
705
+ <div className="fieldHeader">
706
+ <div className="group">
707
+ <div className="line" />
708
+ <div className="fieldType">{this.getFieldTypeTitle(field.type)}</div>
709
+ </div>
710
+ <div className="group">
711
+ <Components.DropdownInput
712
+ id={`fieldType${fieldIndex}`}
713
+ placeholder="Type"
714
+ value="Change Field Type"
715
+ options={this.fieldTypes}
716
+ onSelect={(key) => this.onFieldTypeChanged(fieldIndex, key)}
717
+ />
718
+ {customFields.length > 1 && (
719
+ <div className="delete" onClick={() => this.onRemoveField(fieldIndex)}>
720
+ Delete
721
+ </div>
722
+ )}
723
+ </div>
724
+ </div>
725
+ {renderFieldContent()}
726
+ </div>
727
+ {customFields.length > 1 && (
728
+ <div className="switchField">
729
+ {fieldIndex > 0 ? (
730
+ <div className="circle" onClick={() => this.onMoveFieldPrev(fieldIndex)}>
731
+ <FontAwesome name="angle-up" className="icon" />
732
+ </div>
733
+ ) : null}
734
+ {fieldIndex < customFields.length - 1 ? (
735
+ <div className="circle" onClick={() => this.onMoveFieldNext(fieldIndex)}>
736
+ <FontAwesome name="angle-down" className="icon" />
737
+ </div>
738
+ ) : null}
739
+ </div>
740
+ )}
741
+ </div>
742
+ );
743
+ }
744
+
745
+ renderCustomForm() {
746
+ const { success, hasCustomFields, customFields } = this.state;
747
+ if (success || !hasCustomFields) return null;
748
+
749
+ return (
750
+ <div className="padding-60 paddingTop-8 paddingLeft-20">
751
+ <div className="fields">
752
+ {customFields.map((field, fieldIndex) => this.renderField(field, fieldIndex))}
753
+ <div className="clearfix addoption addField" onClick={() => this.onAddNewField()}>
754
+ <Components.P60Icon className="addoption_plus" icon="add-circle" />
755
+ <div className="fillSpace">
756
+ <p className="addoption_text">Add New Field</p>
757
+ </div>
758
+ </div>
759
+ </div>
760
+ </div>
761
+ );
762
+ }
763
+
764
+ renderWarnings() {
765
+ const { showWarnings, warnings } = this.state;
766
+ if (!showWarnings || !warnings || warnings.length === 0) return null;
767
+
768
+ return (
769
+ <div className="padding-40 paddingBottom-8 text-help">
770
+ To save the form
771
+ <ul style={{ padding: 0, paddingLeft: 16 }}>
772
+ {warnings.map((warn, index) => (
773
+ <li key={index}>{warn}</li>
774
+ ))}
775
+ </ul>
776
+ </div>
777
+ );
778
+ }
779
+
780
+ renderSuccess() {
781
+ const { success, jobTypeId } = this.state;
782
+ if (!success) return null;
783
+
784
+ // TODO: Replace name with configuration
785
+ return (
786
+ <Components.SuccessPopup
787
+ text={`Request Type has been ${!jobTypeId ? 'added' : 'edited'}`}
788
+ buttons={[
789
+ {
790
+ type: 'outlined',
791
+ onClick: this.onBack,
792
+ text: 'Go to home',
793
+ },
794
+ ]}
795
+ />
796
+ );
797
+ }
798
+
799
+ renderSubmit() {
800
+ if (this.state.submitting) {
801
+ return <Components.Button buttonType="secondary">Saving...</Components.Button>;
802
+ }
803
+ return (
804
+ <div>
805
+ <Components.Button inline buttonType="tertiary" onClick={this.onBack} isActive style={{ marginRight: 8 }}>
806
+ Cancel
807
+ </Components.Button>
808
+ <Components.Button inline buttonType="primary" onClick={this.onSave} isActive>
809
+ Save
810
+ </Components.Button>
811
+ </div>
812
+ );
813
+ }
814
+
815
+ render() {
816
+ const { success } = this.state;
817
+
818
+ return (
819
+ <Components.OverlayPage>
820
+ <Components.OverlayPageContents noBottomButtons={success}>
821
+ <Components.OverlayPageSection className="pageSectionWrapper--newPopup">
822
+ <div className="addForm">
823
+ {this.renderBaseForm()}
824
+ {this.renderWarnings()}
825
+ {this.renderCustomForm()}
826
+ </div>
827
+ {this.renderSuccess()}
828
+ </Components.OverlayPageSection>
829
+ </Components.OverlayPageContents>
830
+ <Components.OverlayPageBottomButtons>{this.renderSubmit()}</Components.OverlayPageBottomButtons>
831
+ </Components.OverlayPage>
832
+ );
833
+ }
834
+ }
835
+
836
+ const mapStateToProps = (state) => {
837
+ const { auth } = state;
838
+ return { auth, strings: (state.strings && state.strings.config) || {} };
839
+ };
840
+
841
+ export default connect(mapStateToProps, { jobTypesUpdate })(withRouter(AddJobType));