UNPKG

115 kBJavaScriptView Raw
1import React, { Component } from 'react';
2// import { connect } from 'react-redux';
3import * as Titles from './titles';
4// import DatePicker from 'react-native-datepicker';
5import * as Formatter from './telephoneinput';
6
7import * as Globals from './globals';
8import * as Validation from './validation';
9import LeftView from './components/leftview';
10import CountryData from './country_data';
11// import {
12// CardIOModule
13// } from 'react-native-awesome-card-io';
14import FastImage from 'react-native-fast-image';
15import {
16 Card,
17 CardItem,
18 Spinner,
19 List,
20 SwipeRow,
21 ListItem,
22 Item,
23 Radio,
24 Container,
25 Header,
26 ActionSheet,
27 Title,
28 Content,
29 Footer,
30 Input,
31 FooterTab,
32 Tab,
33 TabHeading,
34 Tabs,
35 ScrollableTab,
36 Button,
37 Icon,
38 Badge,
39 Picker,
40 CheckBox,
41 Body,
42 Left,
43 Right,
44 DatePicker,
45 Text,
46 InputGroup,
47 H3,
48 H2,
49 H1,
50} from 'native-base';
51import InfiniteListSelect from './components/inifinitelistselect';
52import Switch from './components/switch';
53import HR from './components/hr';
54// import MapView from 'react-native-maps';
55var { GooglePlacesAutocomplete } = require('react-native-google-places-autocomplete');
56
57import * as UIA from './actions/uiActions';
58// import * as Common from '../../customer/common';
59import { View } from 'native-base';
60import * as utils from './redutil';
61import { Colors } from './colors';
62import { Actions } from 'react-native-router-flux';
63
64import {
65 Image,
66 StyleSheet, PixelRatio,
67 Dimensions,
68 InteractionManager,
69 Platform,
70 Slider,
71 TextInput,
72 KeyboardAvoidingView,
73 Animated,
74 Alert,
75} from 'react-native';
76const { width, height } = Dimensions.get('window');
77
78let MapView = null;
79export const SetMapView = (v) => {
80 MapView = v;
81}
82export const HeaderRight = (callback, value, title) => {
83 return (
84 <Right>
85 {InputField({
86 value: (value || (() => false)),
87 title: title || '',
88 type: 'switch',
89 onValueChange: (callback || ((val) => {
90 })),
91 placeHolder: title || ''
92 })}
93 </Right>
94 );
95}
96
97export const EmptyList = (emptyTitle) => {
98 return (
99 <ListItem>
100 <Text>{emptyTitle || Titles.EmptyList}</Text>
101 </ListItem>
102 )
103}
104export const HeaderTitle = (text, style) => {
105 style = style || {};
106 return (
107 <Body>
108 <Title style={style}>
109 {text || Titles.HeroCarCare}
110 </Title>
111 </Body>
112 );
113}
114
115
116export const BOOLEAN_BUTTONS = (off, on) => {
117 return [Titles.Cancel, on || Titles.On, off || Titles.Off];
118}
119export const BOOLEAN_BUTTONS_VALUE = (index) => {
120 return BOOLEAN_BUTTONS()[index] === Titles.On;
121}
122export const displayMonth = (month) => {
123 if (!isNaN(month))
124 if (parseInt(month) < 10) {
125 return '0' + month;
126 }
127 return month;
128}
129
130const useTabs = (ui) => {
131 if (ui && ui.properties) {
132 for (var i in ui.properties) {
133 if (ui.properties[i] && ui.properties[i].length && ui.properties[i].some(t => !t.singular)) {
134 return true;
135 }
136 }
137 }
138 return false;
139}
140const IsIOS = Platform.OS === 'ios';
141const HEADER = '$ HEADER';
142const SINGULAR = '$ singular';
143const TITLE = '$ title';
144const ICON = '$ icon';
145const getTabSections = (ui) => {
146 var result = [];
147 var singular = {};
148 var addedsingular = false;
149 if (ui && ui.properties) {
150 for (var i in ui.properties) {
151 if (ui.properties[i] && ui.properties[i].length && ui.properties[i].some(t => !t.singular)) {
152 var title = ui.properties[i].find(t => t.groupTitle) || {};
153 var icon = ui.properties[i].find(t => t.groupIcon) || {};
154
155 result.push({
156
157 [ICON]: icon.groupIcon,
158 [HEADER]: i,
159 [TITLE]: title.groupTitle,
160 [i]: ui.properties[i]
161 });
162 }
163 else if (ui.properties[i] && ui.properties[i].length) {
164 singular = Object.assign(singular, {
165
166 [TITLE]: Titles.General,
167 [HEADER]: SINGULAR,
168 [i]: ui.properties[i]
169 });
170 addedsingular = true;
171 }
172 }
173 if (addedsingular) {
174 result.unshift(singular);
175 }
176 }
177 return result;
178}
179
180const getSingularSection = (ui) => {
181 var result = [];
182 var singular = {};
183 var addedsingular = false;
184 if (ui && ui.properties) {
185 for (var i in ui.properties) {
186 if (ui.properties[i] && ui.properties[i].length && ui.properties[i].some(t => t.singular)) {
187 singular = Object.assign(singular, { [i]: ui.properties[i] });
188 addedsingular = true;
189 }
190 }
191 if (addedsingular) {
192 result.push(singular);
193 }
194 }
195 return result;
196}
197var _ui = null;
198// const setUi = (ui) => {
199// _ui = ui;
200// }
201// const getUi = () => {
202// return _ui;
203// }
204export const CommonUi = (ui, getState, setState, readonly, validation) => {
205 /// setUi(ui);
206 if (ui) {
207 var sections = null;
208 if (useTabs(ui)) {
209 sections = getTabSections(ui);
210 }
211 else {
212 sections = getSingularSection(ui);
213 }
214 validation.$ui = ui;
215 return getCommonUi(sections, getState, setState, readonly, validation);
216 }
217 return null;
218}
219const getCommonUi = (sections, getState, setState, readonly, validation) => {
220 if (sections && sections.length > 1) {
221 var ops = {};
222 if (sections.length > 3) {
223 ops.renderTabBar = (() => <ScrollableTab />);
224 }
225 return (
226 <Tabs {...ops}>
227 {sections.map((section, i) => getSection(section, i, getState, setState, readonly, validation, { sections }))}
228 </Tabs>
229 )
230 }
231 else if (sections && sections.length) {
232 return renderSection(sections[0], getState, setState, readonly, validation, ops)
233 }
234 return null;
235}
236const getTabHeading = (section, i, ops) => {
237 if (ops && ops.sections && ops.sections.length > 3) {
238 return (
239 <TabHeading key={'header' + i}><Text>{section[TITLE] || section[HEADER]}</Text></TabHeading>
240 );
241 }
242 return (
243 <TabHeading key={'header' + i}>{section[ICON] ? <Icon name={section[ICON]} /> : null}{section[ICON] ? null : <Text>{section[TITLE] || section[HEADER]}</Text>}</TabHeading>
244 );
245};
246
247const getSection = (section, i, getState, setState, readonly, validation, ops) => {
248 if (validation && validation.noCard) {
249 return renderSection(section, getState, setState, readonly, validation);
250 }
251 return (
252 <Tab heading={getTabHeading(section, i, ops)}>
253 {renderSection(section, getState, setState, readonly, validation)}
254 </Tab>
255 );
256}
257
258const renderSection = (section, getState, setState, readonly, validation) => {
259 var _sects = [];
260 for (var i in section) {
261 if (Array.isArray(section[i])) {
262 section[i].map(t => t.$key = i);
263 _sects = [..._sects, ...section[i]];
264 }
265 }
266
267 var cardItems = (
268
269 [(<CardItem key={'sects-item' + section[TITLE]} header>
270 <Text>{section[TITLE]}</Text>
271 </CardItem>),
272 ..._sects.map(s => {
273 return (
274 <CardItem key={'sects ' + s.$key + s.key}>
275 {_renderSection(s, getState, setState, readonly, validation)}
276 </CardItem>
277 )
278 })]
279 );
280 if (validation && validation.noCard) {
281 return cardItems;
282 }
283 return (<Card>{cardItems}</Card>)
284}
285const getValue = (state, path) => {
286 var result;
287 if (path === '') {
288 return state;
289 }
290 if (state) {
291 path.split('.').map((t, i) => {
292 if (state && t) {
293 state = state[t];
294 }
295 });
296 result = state;
297 }
298 return result;
299}
300export const _commonReadonlyField = (opts) => {
301 var { getValue, getState, value_path, title, useCapFirst, writeReadonlyBody } = opts;
302 if (writeReadonlyBody) {
303 return writeReadonlyBody(opts);
304 }
305 var text = getValue(getState(), value_path) || '';
306 if (useCapFirst && text) {
307 text = utils.capitalizeFirstLetter(text);
308 }
309 return (
310 <Left>
311 <Body>
312 <Text>{text}</Text>
313 <Text note>{title}</Text>
314 </Body>
315 </Left>
316 )
317}
318const findKey = (obj, value) => {
319 if (obj)
320 for (var i in obj) {
321 if (obj[i] === value) {
322 return i;
323 }
324 }
325 return null;
326}
327const deleteIcon = () => { return 'md-trash' };
328const getEditIcon = () => { return 'md-hammer' };
329export const _renderSection = (section, getState, setState, readonly, validation) => {
330 var sectionkey = section.key;
331 var path = section.$key;
332 sectionkey = sectionkey.lowercaseFirstLetter();
333 var title = section.title || sectionkey;
334 if (section.dependsOn) {
335 var show = section.extensions ? false : true;
336 var dependValue = getValue(getState(), `${section.dependsOn.lowercaseFirstLetter()}`);
337 Object.keys(section.extensions || {}).filter(t => {
338 return section.extensions[t].dependsOn && section.dependsOn === section.extensions[t].property;
339 }).map(t => {
340 show = show || !!section.extensions[t].match.find(y => y === dependValue);
341 })
342 if (!dependValue || !show) {
343 return null;
344 }
345 }
346 var value_path = !section.singular ? `${path}.${sectionkey}` : sectionkey;
347 if (section.singular && !section.usePath) {
348 path = '';
349 }
350 var defaultSetValue = (value) => {
351 if (!readonly) {
352 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
353 setState(path, update, (updatedState) => {
354 executeValidation({
355 validation,
356 value_path,
357 getValue,
358 updatedState,
359 validationrules: section.validationRules
360 });
361 });
362
363 }
364 };
365 var useCapFirst = false;
366 if (section && section.options) {
367 if (section.options.indexOf('CAPITALIZE_FIRST_LETTER') !== -1) {
368 useCapFirst = true;
369 }
370 }
371 switch (section.type) {
372 case 'COLLECTION':
373 case 'OBJECT':
374 if (readonly) {
375
376 }
377 var isSingularObject = section.type === 'OBJECT';
378 var {
379 isEditing,
380 getCurrentMode,
381 getTitle,
382 getSubTitle,
383 getBody,
384 getThumbnail
385 } = validation;
386 getTitle = getTitle || ((t) => { return t && t.title ? t.title : Titles.Unknown });
387 getSubTitle = getSubTitle || ((t) => { return t && t.title ? t.title : Titles.Unknown })
388 getBody = getBody || ((t) => { return null });
389 getThumbnail = getThumbnail || ((t) => { return null; });
390 var mode = getCurrentMode();
391 var edit = isEditing();
392
393 var showAddBtn = false;
394 var showEditDeleteBtns = false;
395 var value = getValue(getState(), path) || [];
396 if (mode === UIA.MODE.CREATE || edit) {
397 showAddBtn = true;
398 showEditDeleteBtns = true;
399 }
400
401 var renderItem = ((item, i) => {
402 var body = getBody(item, i);
403 var t_transp = {}
404 if (section.singular) {
405 t_transp.transparent = true;
406 }
407 var hideCardItem = !(showEditDeleteBtns && !section.disableEdit) && !(showEditDeleteBtns && !section.disableRemove) && !section.displayTimeSince
408 return (
409 <Card {...t_transp} key={`item-${item.id || i}`}>
410 <CardItem>
411 <Left>
412 {getThumbnail(item)}
413 <Body>
414 <Text>{getTitle(item)}</Text>
415 <Text note>{getSubTitle(item)}</Text>
416 </Body>
417 </Left>
418 </CardItem>
419 {hideCardItem ? <CardItem>
420 {showEditDeleteBtns && !section.disableEdit ? (<Left>
421 <Button transparent onPress={() => {
422 var { $ui } = validation;// getUi();
423 var collection = ($ui.collections[section.$key]);
424 if (collection && collection.typeName && validation.updateObject) {
425 validation.updateObject(collection.typeName, item, (res) => {
426 if (res) {
427 var value_ = [...value]
428 value_[i] = res;
429 // var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
430 setState(path, value_, () => {
431 if (validation.onUpdatedObject) {
432 validation.onUpdatedObject(collection.typeName, res, i);
433 }
434 });
435 }
436 });
437 }
438 else if (isSingularObject) {
439 validation.updateObject(section.key, item, (res) => {
440 if (res) {
441 setState(path, res, () => {
442 if (validation.onUpdatedObject) {
443 validation.onUpdatedObject(section.key, res, null);
444 }
445 });
446 }
447 });
448 }
449 }}><LeftView>
450 <Icon style={{ padding: 3, color: Colors.Active }} active name={getEditIcon()} />
451 <Text style={{ padding: 3, color: Colors.Active }}>{Titles.Edit}</Text>
452 </LeftView>
453 </Button>
454 </Left>) : null}
455 {showEditDeleteBtns && !section.disableRemove ? (<Body>
456 <Button transparent onPress={OkCancel(Titles.AreYouSure, '', (() => {
457 var value_ = [...value.filter((t, index) => {
458 if (i === index) {
459 return false;
460 }
461 return true;
462 })];
463 setState(path, value_, () => {
464 if (validation.onDeletedObject) {
465 var { $ui } = validation;// getUi();
466 var collection = ($ui.collections[section.$key]);
467 validation.onDeletedObject(collection.typeName, value[i], i);
468 }
469 });
470 }))}>
471 <LeftView>
472 <Icon style={{ padding: 3, color: Colors.Active }} active name={deleteIcon()} />
473 <Text style={{ padding: 3, color: Colors.Active }}>{Titles.Delete}</Text>
474 </LeftView>
475 </Button>
476 </Body>) : null}
477 {section.displayTimeSince ? (<Right>
478 <Text>{timeSinceDate(item.updated || item.created)}</Text>
479 </Right>) : null}
480 </CardItem> : null}
481
482 {body ? (Array.isArray(body) ? body : (<CardItem cardBody>
483 {body}
484 </CardItem>)) : null}
485 </Card>
486 );
487 });
488
489 if (section.singular) {
490 path = value_path;
491 }
492 var collectionVl = Validation.InputField(getValue(validation.get(), value_path));
493 var _errorText = collectionVl ? collectionVl.errorText() : null;
494 return (<View style={{ marginTop: 3, flex: 1, flexDirection: 'column' }}>
495 {_errorText ? <ListItem>
496 <Left>
497 {collectionVl.errorIcon()}
498 {_errorText}
499 </Left>
500 </ListItem> : null}
501 {showAddBtn && !section.disableAdd ? (<Button transparent key={'collection-add' + section.title}
502 onPress={() => {
503 var { $ui } = validation;// getUi();
504 var collection = ($ui.collections[section.$key]);
505 if (collection && collection.typeName) {
506 validation.newObject(collection.typeName, (res) => {
507 if (res) {
508 var value_ = [...value, res]
509 // var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
510 setState(path, value_, (updatedState) => {
511 executeValidation({
512 validation,
513 value_path,
514 getValue,
515 updatedState,
516 validationrules: section.validationRules,
517 callback: () => {
518 if (validation.onCreatedObject) {
519 validation.onCreatedObject(collection.typeName, res);
520 }
521 }
522 });
523 });
524
525 }
526 });
527 }
528 }}>
529 <Icon name="md-add" />
530 <Text>{Titles.Add} {title}</Text>
531 </Button>) : (<View><Text>{section.singular ? title : null}</Text></View>)}
532 {isSingularObject && value ? [value].map(renderItem) : (section.singular ? (((<View><Text note>{section.singular ? null : null}</Text></View>))) : null)}
533 {!isSingularObject && value && value.length ? value.map(renderItem) : (!section.singular ? (((<View><Text note>{section.singular ? Titles.None : null}</Text></View>))) : null)}
534 </View>)
535 break;
536 case 'DATE':
537 if (readonly) {
538 return _commonReadonlyField({
539 getValue: (state, vp) => {
540 var value = getValue(getState(), value_path) || undefined;
541 try {
542 var date = new Date(Date.parse(value));
543 console.log(date);
544 return date.toLocaleDateString();
545 } catch (e) { }
546 return value;
547 }, getState, value_path, title, useCapFirst, ...section.ui
548 });
549 }
550 return InputField({
551 value: () => {
552 var _res = getValue(getState(), value_path) || undefined;
553 // if (typeof _res === 'string') {
554 // try {
555 // return new Date(Date.parse(_res));
556 // } catch (e) { }
557 // }
558 return _res;
559 },
560 title: section.title,
561 inputProps: () => { return { keyboardType: "numeric" } },
562 type: 'date',
563 format: () => { return "MM-DD-YYYY" },
564 onValueChange: (value) => {
565 var date = new Date(Date.parse(value));
566 console.log(date);
567 // if (isValidDate(date)) {
568 // value = date;
569 // }
570 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
571 setState(path, update, (updatedState) => {
572 executeValidation({
573 validation,
574 value_path,
575 getValue,
576 updatedState,
577 validationrules: section.validationRules
578 });
579 });
580 },
581 required: () => section.required,
582 placeHolder: `${Titles.Select} ${section.title}`,
583 ...(section.ui || {})
584 }, Validation.InputField(getValue(validation.get(), value_path)));
585 break;
586 case 'CHOICE':
587 if (readonly) {
588 return _commonReadonlyField({
589 getValue: (state, vp) => {
590 var value = getValue(getState(), value_path) || undefined;
591 if (section.useKeyAsValue && section.useValueAsLabel) {
592 return section.choices[value];
593 }
594
595 var res = findKey(section.choices, value);
596 if (useCapFirst) {
597 return utils.capitalizeFirstLetter(res);
598 }
599
600 return res;
601 }, getState, value_path, title, useCapFirst, ...section.ui
602 });
603 }
604 var items = () => {
605 var choiceResults = [];
606 // choiceResults.push((<Picker.Item key={'SELECT_ONE'} label={Titles.Select} value={undefined} />));
607 for (var choice in section.choices) {
608 var label = section.useValueAsLabel ? section.choices[choice] : choice;
609 var _valchoice = section.useKeyAsValue ? choice : section.choices[choice];
610 choiceResults.push((<Picker.Item key={'choice_' + choice} label={utils.capitalizeFirstLetter(label)} value={_valchoice} />));
611 }
612 return choiceResults;
613 };
614 var _type = 'picker';
615 if (section && section.options) {
616 if (section.options.indexOf('CHOICELIST') !== -1) {
617 _type = 'choicelist';
618 items = () => {
619 return section.choices;
620 };
621 }
622
623 }
624 return InputField({
625 value: () => {
626 return getValue(getState(), value_path) || undefined;
627 },
628 title: section.title,
629 type: _type,
630 useCapFirst,
631 section,
632 onValueChange: (value) => {
633 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
634 setState(path, update, (updatedState) => {
635 executeValidation({
636 validation,
637 value_path,
638 getValue,
639 updatedState,
640 validationrules: section.validationRules
641 });
642 });
643
644 },
645 ...(section.ui || {}),
646 required: () => section.required,
647 placeHolder: `${Titles.Select} ${section.title}`,
648 items: items
649 }, Validation.InputField(getValue(validation.get(), value_path)));
650 break;
651 case 'ACCOUNTNUMBER':
652 if (readonly) {
653 return _commonReadonlyField({ getValue, getState, value_path, title, useCapFirst, ...section.ui });
654 }
655 return ValidatedInputField({
656 validationrules: ['notempty', 'numbers', 'length9to17', ...(section.validationRules || [])],
657 value_path,
658 path,
659 getState,
660 inputProps: () => { return { keyboardType: "numeric" } },
661 required: () => section.required,
662 sectionkey,
663 setState,
664 readonly,
665 title,
666 ...(section.ui || {}),
667 validation
668 }, Validation.InputField(getValue(validation.get(), value_path)));
669 break;
670 case 'EMAIL':
671 if (readonly) {
672 return _commonReadonlyField({ getValue, getState, value_path, title, useCapFirst, ...section.ui });
673 }
674 return ValidatedInputField({
675 validationrules: ['email', ...(section.validationRules || [])],
676 value_path,
677 path,
678 required: () => section.required,
679 getState,
680 sectionkey,
681 setState,
682 readonly,
683 title,
684 validation,
685 ...(section.ui || {})
686 }, Validation.InputField(getValue(validation.get(), value_path)));
687 break;
688 case 'VIN':
689 if (readonly) {
690 return _commonReadonlyField({
691 getValue: (state, vp) => {
692 var value = getValue(getState(), value_path) || undefined;
693 if (value) {
694 return value;
695 }
696 return Titles.Vin;
697 }, getState, value_path, title, useCapFirst, ...section.ui
698 });
699 }
700 var { vin } = validation;
701 vin = vin || (() => { });
702 return InputField({
703 value: () => {
704 return getValue(getState(), value_path) || undefined;
705 },
706 required: () => section.required,
707 title: Titles.Vin,
708 onChangeText: (value) => {
709 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
710 setState(path, update);
711 if (value && value.length > 10)
712 return vin(value, res => {
713 var model = res.find(x => x.Variable === 'Model');
714 if (model && section.vinModel) {
715 model = { [section.vinModel.lowercaseFirstLetter()]: model.Value };
716 }
717 else { model = {} };
718 var make = res.find(x => x.Variable === 'Make');
719 if (make && section.vinMake) {
720 make = { [section.vinMake.lowercaseFirstLetter()]: make.Value };
721 }
722 else { make = {} };
723 var _year = res.find(x => x.Variable === "Model Year");
724 if (_year && section.vinYear) {
725 _year = { [section.vinYear.lowercaseFirstLetter()]: _year.Value };
726 }
727 else { _year = {} }
728 var update = Object.assign({}, getValue(getState(), path), _year, model, make, {
729 [sectionkey]: value
730 });
731
732 setState(path, update, (updatedState) => {
733 executeValidation({
734 validation,
735 value_path,
736 getValue,
737 updatedState,
738 validationrules: section.validationRules
739 });
740 });
741
742 });
743 },
744 placeHolder: Titles.EnterVin,
745 ...(section.ui || {})
746 }, Validation.InputField(getValue(validation.get(), value_path)));
747 break;
748 case 'CARYEAR':
749 if (readonly) {
750 return _commonReadonlyField({
751 getValue: (state, vp) => {
752 var value = getValue(getState(), value_path) || undefined;
753 if (value) {
754 return value;
755 }
756 return Titles.SelectCarYear;
757 }, getState, value_path, title, useCapFirst, ...section.ui
758 });
759 }
760 var d = new Date();
761 var year = d.getFullYear();
762 var years = [];
763 for (var i = 0; i < 30; i++) {
764 years.push((year - i + 2).toString());
765 }
766 return InputField({
767 value: () => {
768 return getValue(getState(), value_path) || undefined;
769 },
770 required: () => section.required,
771 title: Titles.CarYear,
772 type: 'picker',
773 onValueChange: (value) => {
774 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
775 setState(path, update);
776 },
777 placeHolder: Titles.SelectCarYear,
778 items: () => {
779 return years.map(d => {
780 return (
781 <Picker.Item key={d} label={d.toString()} value={d.toString()} />
782 );
783 })
784 },
785 ...(section.ui || {})
786 }, Validation.InputField(getValue(validation.get(), value_path)));
787 break;
788 case 'CARMODEL':
789 if (readonly) {
790 return _commonReadonlyField({
791 getValue: (state, vp) => {
792 var value = getValue(getState(), value_path) || undefined;
793 if (value) {
794 return value;
795 }
796 return Titles.SelectCarModel;
797 }, getState, value_path, title, useCapFirst, ...section.ui
798 });
799 }
800 var { carmodels } = validation;
801 carmodels = carmodels || (() => { return [] });
802 function getModelItems(make) {
803 var makeid = make.Model_ID.toString();
804 var makename = make.Model_Name;
805 // return <Picker.Item key={makeid} label={makename} value={makeid} />;
806 return { id: makeid, name: makename };
807 }
808 return InputField({
809 value: () => {
810 return getValue(getState(), value_path) || undefined;
811 },
812 required: () => section.required,
813 title: Titles.CarModel,
814 type: 'infinite-picker',
815 onValueChange: (value) => {
816 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value ? value.name : null });
817 setState(path, update);
818 },
819 placeHolder: Titles.SelectCarModel,
820 items: () => {
821 var vp = `${section.dependsOn.lowercaseFirstLetter()}`;
822 return carmodels(getValue(getState(), vp) || undefined).map(getModelItems);
823 },
824 ...(section.ui || {})
825 }, Validation.InputField(getValue(validation.get(), value_path)));
826 break;
827 case 'CARMAKE':
828 if (readonly) {
829 return _commonReadonlyField({
830 getValue: (state, vp) => {
831 var value = getValue(getState(), value_path) || undefined;
832 if (value) {
833 return value;
834 }
835 return Titles.SelectCarMake;
836 }, getState, value_path, title, useCapFirst, ...section.ui
837 });
838 }
839 var { carmakes } = validation;
840 carmakes = carmakes || (() => { return [] });
841 function getMakeItems(make) {
842 var makeid = make.Make_ID.toString();
843 var makename = make.Make_Name;
844 // return <Picker.Item key={makeid} label={makename} value={makeid} />;
845 return { id: makeid, name: makename };
846 }
847 return InputField({
848 value: () => {
849 return getValue(getState(), value_path) || undefined;
850 },
851 title: Titles.CarMake,
852 type: 'infinite-picker',
853 onValueChange: (value) => {
854 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value ? value.name : null });
855 setState(path, update, (updatedState) => {
856 executeValidation({
857 validation,
858 value_path,
859 getValue,
860 updatedState,
861 validationrules: section.validationRules
862 });
863 });
864 },
865 errorText: () => {
866
867 },
868 required: () => section.required,
869 placeHolder: Titles.SelectCarMake,
870 items: () => {
871 return carmakes().map(getMakeItems)
872 },
873 ...(section.ui || {})
874 }, Validation.InputField(getValue(validation.get(), value_path)));
875 break;
876 case 'STATE':
877 if (readonly) {
878 return _commonReadonlyField({
879 getValue: (state, vp) => {
880 var value = getValue(getState(), value_path) || undefined;
881 var cod = CountryData.states.find(d => d.abbreviation == value)
882 if (cod) {
883 return cod.name;
884 }
885 return Titles.SelectState;
886 }, getState, value_path, title, useCapFirst, ...section.ui
887 });
888 }
889 return InputField({
890 value: () => {
891 return getValue(getState(), value_path) || undefined;
892 },
893 title: Titles.StateProvince,
894 type: 'picker',
895 onValueChange: defaultSetValue,
896 required: () => section.required,
897 placeHolder: Titles.SelectState,
898 items: () => {
899 return CountryData.states.map(d => {
900 return (
901 <Picker.Item key={d.abbreviation} label={d.name} value={d.abbreviation} />
902 );
903 })
904 }
905 }, Validation.InputField(getValue(validation.get(), value_path)))
906 break;
907 case 'COUNTRY':
908 if (readonly) {
909 return _commonReadonlyField({
910 getValue: (state, vp) => {
911 var value = getValue(getState(), value_path) || undefined;
912 var cod = CountryData.allCountriesObject.find(d => d.ISO2.toUpperCase() == value)
913 if (cod) {
914 return cod.name;
915 }
916 return Titles.SelectCountry;
917 }, getState, value_path, title, useCapFirst, ...section.ui
918 });
919 }
920 return InputField({
921 value: () => {
922 return getValue(getState(), value_path) || undefined;
923 },
924 title: Titles.Country,
925 type: 'picker',
926 onValueChange: (value) => {
927 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
928 setState(path, update, (updatedState) => {
929 executeValidation({
930 validation,
931 value_path,
932 getValue,
933 updatedState,
934 validationrules: section.validationRules
935 });
936 });
937 },
938 required: () => section.required,
939 placeHolder: Titles.SelectCountry,
940 items: () => {
941 return CountryData.allCountriesObject.map(d => {
942 return (
943 <Picker.Item key={d.name} label={d.name} value={d.ISO2.toUpperCase()} />
944 );
945 })
946 }
947 }, Validation.InputField(getValue(validation.get(), value_path)));
948 break;
949 case 'CURRENCY':
950 if (readonly) {
951 return _commonReadonlyField({
952 getValue: (state, vp) => {
953 var value = getValue(getState(), value_path) || undefined;
954 var cod = value;
955 if (cod) {
956 return value;
957 }
958 return Titles.SelectCurrency;
959 }, getState, value_path, title, useCapFirst, ...section.ui
960 });
961 }
962 return InputField({
963 value: () => {
964 return getValue(getState(), value_path) || undefined;
965 },
966 title: Titles.Currency,
967 type: 'picker',
968 required: () => section.required,
969 onValueChange: defaultSetValue,
970 placeHolder: Titles.SelectCurrency,
971 items: () => {
972 return CountryData.currencies.map(d => {
973 return (
974 <Picker.Item key={d} label={d} value={d} />
975 );
976 })
977 }
978 }, Validation.InputField(getValue(validation.get(), value_path)));
979 break;
980 case 'DEBIT':
981 case 'DEBITCARD':
982 if (readonly) {
983 var val = getValue(getState(), value_path) || {};
984 var name = val.name || '';
985 var z = Formatter.default.creditCard((val.card || '').toString());
986 var expYear = val.expirationMonth;
987 var cvv = val.cVV;
988 var expMonth = val.expirationMonth;
989 return (
990 <View style={{ flex: 1 }}>
991 <View style={{ flexDirection: 'column' }}>
992 <Text>{name}</Text>
993 <Text>{z} {cvv}</Text>
994 <Text>{expMonth}/{expYear}</Text>
995 <Text note>{title}</Text>
996 </View>
997 </View>
998 )
999 }
1000 var debit_margin = 2;
1001 return (
1002 <View style={{ flex: 1 }}>
1003 <View style={{ flex: 1, margin: debit_margin }}>
1004 {InputField({
1005 value: () => {
1006 var val = (getValue(getState(), path) || {})[sectionkey] || {};
1007 var name = val.name || '';
1008 return name;
1009 },
1010 onChangeText: (value) => {
1011 var _updatevalue = (getValue(getState(), path) || {})[sectionkey] || {};
1012
1013 _updatevalue = Object.assign({}, _updatevalue, {
1014 name: ((value))
1015 });
1016
1017 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: _updatevalue });
1018 setState(path, update, (updatedState) => {
1019 executeValidation({
1020 validation,
1021 value_path,
1022 getValue,
1023 updatedState,
1024 validationrules: section.validationRules
1025 });
1026 });
1027 },
1028 title: Titles.Name,
1029 type: 'string',
1030 required: () => section.required,
1031 editable: () => true,
1032 ...(section.ui || {}),
1033 placeHolder: Titles.Name
1034 }, Validation.InputField(getValue(validation.get(), value_path)))}
1035 </View>
1036 <View style={{ flexDirection: 'row' }}>
1037 <View style={{ flex: 1, margin: debit_margin }}>
1038 {InputField({
1039 value: () => {
1040 var val = (getValue(getState(), path) || {})[sectionkey] || {};
1041 var card = val.card || '';
1042 return Formatter.default.creditCard(card.toString());
1043 },
1044 onChangeText: (value) => {
1045 var _updatevalue = (getValue(getState(), path) || {})[sectionkey] || {};
1046 //(Formatter.default.removeNonNumbers(value, '+()'))
1047 _updatevalue = Object.assign({}, _updatevalue, {
1048 card: (Formatter.default.removeNonNumbers(value, '+()'))
1049 })
1050 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: _updatevalue });
1051 setState(path, update, (updatedState) => {
1052 executeValidation({
1053 validation,
1054 value_path,
1055 getValue,
1056 updatedState,
1057 validationrules: section.validationRules
1058 });
1059 });
1060 },
1061 required: () => section.required,
1062 title: title,
1063 inputProps: () => { return { keyboardType: "numeric" } },
1064 type: 'string',
1065 editable: () => true,
1066 placeHolder: title,
1067 ...(section.ui || {}),
1068 }, Validation.InputField(getValue(validation.get(), value_path)))}</View>
1069 <View style={{ width: 80, margin: debit_margin }}>
1070 {InputField({
1071 value: () => {
1072 var val = (getValue(getState(), path) || {})[sectionkey] || {};
1073 var card = val.cVV || '';
1074 return Formatter.default.creditCard(card.toString());
1075 },
1076 onChangeText: (value) => {
1077 var _updatevalue = (getValue(getState(), path) || {})[sectionkey] || {};
1078 //(Formatter.default.removeNonNumbers(value, '+()'))
1079 _updatevalue = Object.assign({}, _updatevalue, {
1080 cVV: (Formatter.default.removeNonNumbers(value, '+()'))
1081 })
1082 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: _updatevalue });
1083 setState(path, update, (updatedState) => {
1084 executeValidation({
1085 validation,
1086 value_path,
1087 getValue,
1088 updatedState,
1089 validationrules: section.validationRules
1090 });
1091 });
1092 },
1093 required: () => section.required,
1094 title: Titles.CardNumber,
1095 inputProps: () => { return { keyboardType: "numeric" } },
1096 type: 'string',
1097 editable: () => true,
1098 ...(section.ui || {}),
1099 placeHolder: Titles.CardNumber
1100 }, Validation.InputField(getValue(validation.get(), value_path)))}</View>
1101 </View>
1102 <View style={{ flexDirection: 'row' }}>
1103 <View style={{ flex: 1, margin: debit_margin }}>
1104 {InputField({
1105 value: () => {
1106 var val = (getValue(getState(), path) || {})[sectionkey] || {};
1107 var month = val.expirationMonth || '';
1108 return month;
1109 },
1110 title: Titles.ExpirationMonth,
1111 type: 'picker',
1112 required: () => section.required,
1113 onValueChange: (value) => {
1114 var _updatevalue = (getValue(getState(), path) || {})[sectionkey] || {};
1115 //(Formatter.default.removeNonNumbers(value, '+()'))
1116 _updatevalue = Object.assign({}, _updatevalue, {
1117 expirationMonth: (Formatter.default.removeNonNumbers(value, '+()'))
1118 })
1119 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: _updatevalue });
1120 setState(path, update, (updatedState) => {
1121 executeValidation({
1122 validation,
1123 value_path,
1124 getValue,
1125 updatedState,
1126 validationrules: section.validationRules
1127 });
1128 });
1129 },
1130 placeHolder: Titles.SelectMonth,
1131 ...(section.ui || {}),
1132 items: () => {
1133 return [].interpolate(0, 12, t => ({ month: Titles.Month(`${t + 1}`), id: `${t}` })).map(t => {
1134 return (<Picker.Item key={t.id} label={t.month} value={t.id} />);
1135 });
1136 }
1137 }, Validation.InputField(getValue(validation.get(), value_path)))}</View>
1138 <View style={{ flex: 1, margin: debit_margin }}>
1139 {InputField({
1140 value: () => {
1141 var val = (getValue(getState(), path) || {})[sectionkey] || {};
1142 var year = val.expirationYear || '';
1143 return year;
1144 },
1145 title: Titles.ExpirationYear,
1146 type: 'picker',
1147 required: () => section.required,
1148 onValueChange: (value) => {
1149 var _updatevalue = (getValue(getState(), path) || {})[sectionkey] || {};
1150 //(Formatter.default.removeNonNumbers(value, '+()'))
1151 _updatevalue = Object.assign({}, _updatevalue, {
1152 expirationYear: (Formatter.default.removeNonNumbers(value, '+()'))
1153 })
1154 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: _updatevalue });
1155 setState(path, update, (updatedState) => {
1156 executeValidation({
1157 validation,
1158 value_path,
1159 getValue,
1160 updatedState,
1161 validationrules: section.validationRules
1162 });
1163 });
1164 },
1165 placeHolder: Titles.ExpirationYear,
1166 ...(section.ui || {}),
1167 items: () => {
1168 var currentYear = new Date(Date.now()).getUTCFullYear();
1169 return [].interpolate(0, 12, t => ({ year: (`${currentYear + t}`), id: `${currentYear + t}` })).map(t => {
1170 return (<Picker.Item key={t.id} label={t.year} value={t.id} />);
1171 });
1172 }
1173 }, Validation.InputField(getValue(validation.get(), value_path)))}</View>
1174 </View>
1175 </View>
1176 )
1177 case 'CREDITCARD':
1178 if (readonly) {
1179 var val = getValue(getState(), value_path) || '';
1180 var z = Formatter.default.creditCard(val.toString());
1181 return (
1182 <Left>
1183 <Body>
1184 <Text>{z}</Text>
1185 <Text note>{title}</Text>
1186 </Body>
1187 </Left>
1188 )
1189 }
1190 return InputField({
1191 value: () => {
1192 var val = getValue(getState(), value_path) || '';
1193 return Formatter.default.creditCard(val.toString());
1194 },
1195 onChangeText: (value) => {
1196 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: (Formatter.default.removeNonNumbers(value, '+()')) });
1197 setState(path, update, (updatedState) => {
1198 executeValidation({
1199 validation,
1200 value_path,
1201 getValue,
1202 updatedState,
1203 validationrules: section.validationRules
1204 });
1205 });
1206 },
1207 required: () => section.required,
1208 title: title,
1209 inputProps: () => { return { keyboardType: "numeric" } },
1210 type: 'string',
1211 editable: () => true,
1212 placeHolder: title
1213 }, Validation.InputField(getValue(validation.get(), value_path)));
1214 case 'ROUTINGNUMBER':
1215 if (readonly) {
1216 return (
1217 <Left>
1218 <Body>
1219 <Text>{getValue(getState(), value_path) || ''}</Text>
1220 <Text note>{title}</Text>
1221 </Body>
1222 </Left>
1223 )
1224 }
1225 return ValidatedInputField({
1226 validationrules: ['notempty', 'numbers', 'length9', ...(section.validationRules || [])],
1227 value_path,
1228 path,
1229 required: () => section.required,
1230 getState,
1231 sectionkey,
1232 inputProps: () => { return { keyboardType: "numeric" } },
1233 setState,
1234 readonly,
1235 title,
1236 ...(section.ui || {}),
1237 validation
1238 }, Validation.InputField(getValue(validation.get(), value_path)));
1239 break;
1240 case 'GEOLOCATION':
1241 var coordinate = getValue(getState(), value_path);
1242 if (!coordinate) {
1243 return null;
1244 }
1245 if (coordinate.latitude === 0 && coordinate.longitude === 0) {
1246 coordinate.latitude = 34;
1247 coordinate.longitude = 34;
1248 }
1249 if (!coordinate.latitudeDelta || !coordinate.longitudeDelta) {
1250 coordinate.latitudeDelta = 5;
1251 coordinate.longitudeDelta = 5;
1252 }
1253 return (
1254 InputField({
1255 type: 'loc_rad',
1256 value: () => (coordinate),
1257 title: section.title || Titles.Location,
1258 required: () => section.required,
1259 viewProps: () => { return { flex: 1 } },
1260 onValueChange: (val) => {
1261 },
1262 extra: () => {
1263 return (
1264 //[
1265 coordinate ? (readonly ? (<MapView.Marker
1266 coordinate={coordinate}
1267 />) : (<MapView.Marker draggable
1268 coordinate={coordinate}
1269 onDragEnd={(e) => {
1270 if (!readonly) {
1271 var update = Object.assign({}, getValue(getState(), path), {
1272 [sectionkey]: e.nativeEvent.coordinate
1273 });
1274 setState(path, update, (updatedState) => {
1275 executeValidation({
1276 validation,
1277 value_path,
1278 getValue,
1279 updatedState,
1280 validationrules: section.validationRules
1281 });
1282 });
1283 }
1284 }}
1285 />)) : null
1286 // , <MapView.Circle
1287 // key={(promoCode.radius) + JSON.stringify(promoCode.point)}
1288 // fillColor={Colors.HeroBlue + '55'}
1289 // center={promoCode.point}
1290 // radius={1000 * ((promoCode.radius) || .1)} />
1291 //]
1292 )
1293 },
1294 placeHolder: section.title || Titles.Location
1295 }, Validation.InputField(getValue(validation.get(), value_path)))
1296 )
1297 break;
1298 case 'ADDRESS':
1299 var googlePlacesApi = Globals.getGooglePlacesApi();
1300 if (readonly || !googlePlacesApi) {
1301 return _commonReadonlyField({
1302 getValue: (state, vp) => {
1303 var value = getValue(getState(), value_path) || undefined;
1304 if (value) {
1305 return value.formatted_address;
1306 }
1307 return Titles.SelectAddress;
1308 }, getState, value_path, title, useCapFirst, ...section.ui
1309 });
1310 }
1311 var $$_value;
1312 var $$_placeholder = title;
1313 try {
1314 $$_value = getValue(getState(), value_path);
1315 $$_placeholder = $$_value ? $$_value.formatted_address : title;
1316 }
1317 catch (e) {
1318 console.log(e);
1319 }
1320 return (
1321 InputField({
1322 // errorIcon: () => { return (field.icon ? <Icon name={field.icon} /> : null); },
1323 getAddress: () => GetAddressInput({
1324 placeHolder: $$_placeholder,
1325 value_path,
1326 title,
1327 googlePlacesApi,
1328 getValue,
1329 getState,
1330 path, sectionkey, setState,
1331 ...(section.ui || {})
1332 }),
1333 required: () => section.required,
1334 type: 'address',
1335 // viewProps: () => { return {key: field.key || ('field.name' + field.name) } },
1336 value: () => {
1337 var res_ = getValue(getState(), value_path) || undefined;
1338 if (res_ && res_.addressComponents) {
1339 res_.addressLine1 = getStreetAddress(res_.addressComponents);
1340 res_.city = getCity(res_.addressComponents);
1341 res_.state = getStateOrProvince(res_.addressComponents);
1342 res_.zipCode = getZipCode(res_.addressComponents);
1343 }
1344 return res_;
1345 },
1346 placeholder: $$_placeholder,
1347 title: title,
1348 inputProps: () => { return { autoCapitalize: 'none' } },
1349 //onChangeText: field.onValueChange.bind(me, field.name),
1350 placeHolder: title,
1351 ...(section.ui || {})
1352 }, Validation.InputField(getValue(validation.get(), value_path)))
1353 );
1354 break;
1355 case 'LONGSTRING':
1356 if (readonly) {
1357 return (
1358 <Left>
1359 <Body>
1360 <Text>{getValue(getState(), value_path) || ''}</Text>
1361 <Text note>{title}</Text>
1362 </Body>
1363 </Left>
1364 )
1365 }
1366 return InputField({
1367 value: () => {
1368 return getValue(getState(), value_path) || '';
1369 },
1370 onChangeText: defaultSetValue,
1371 title: title,
1372 required: () => section.required,
1373 type: 'autotext',
1374 editable: () => !readonly,
1375 placeHolder: title
1376 }, Validation.InputField(getValue(validation.get(), value_path)));
1377 case 'NUMBER':
1378 case 'STRING':
1379 if (readonly || section.readOnly) {
1380
1381 return _commonReadonlyField({ getValue, getState, value_path, title, useCapFirst, ...section.ui });
1382 return (
1383 <Left>
1384 <Body>
1385 <Text>{getValue(getState(), value_path) || ''}</Text>
1386 <Text note>{title}</Text>
1387 </Body>
1388 </Left>
1389 )
1390 }
1391
1392 return ValidatedInputField({
1393 validationrules: [...(section.validationRules || []), (section.type === 'NUMBER' ? 'numeric' : (section.validationRules && section.validationRules.length ? null : 'alphanumericlike'))].filter(x => x),
1394 value_path,
1395 path,
1396 getState,
1397 inputProps: () => {
1398 return {
1399 keyboardType: section.type === 'NUMBER' ? 'numeric' : "default"
1400 }
1401 },
1402 required: () => section.required,
1403 sectionkey,
1404 setState,
1405 readonly,
1406 title,
1407 validation,
1408 ...(section.ui || {})
1409 }, Validation.InputField(getValue(validation.get(), value_path)));
1410 case 'RADIO':
1411 return (<Card>
1412 <CardItem>{InputField({
1413 value: () => {
1414 return (getValue(getState(), value_path));
1415 },
1416 items: () => {
1417 return section.choices;
1418 },
1419 onValueChange: defaultSetValue,
1420 title: title,
1421 required: () => section.required,
1422 extra: () => { return (<View><Text>{getValue(getState(), value_path)}</Text></View>) },
1423 type: 'radio',
1424 editable: () => !readonly,
1425 placeHolder: title
1426 }, Validation.InputField(getValue(validation.get(), value_path)))}</CardItem></Card>);
1427 case 'CHECKLIST':
1428 return (InputField({
1429 value: () => {
1430 return (getValue(getState(), value_path));
1431 },
1432 items: () => {
1433 return section.choices;
1434 },
1435 useCapFirst,
1436 onValueChange: defaultSetValue,
1437 title: title,
1438 section,
1439 required: () => section.required,
1440 extra: () => { return (<View><Text>{getValue(getState(), value_path)}</Text></View>) },
1441 type: 'checklist',
1442 editable: () => !readonly,
1443 placeHolder: title,
1444 ...(section.ui || {})
1445 }, Validation.InputField(getValue(validation.get(), value_path))));
1446 case 'SLIDER':
1447 return (
1448 <Card>
1449 <CardItem>{InputField({
1450 value: () => {
1451 return parseFloat(getValue(getState(), value_path) || section.min);
1452 },
1453 onValueChange: defaultSetValue,
1454 title: title,
1455 required: () => section.required,
1456 max: () => section.max,
1457 min: () => section.min,
1458 step: () => section.step,
1459 extra: () => { return (<View><Text>{getValue(getState(), value_path)}</Text></View>) },
1460 type: 'slider',
1461 editable: () => !readonly,
1462 placeHolder: title
1463 }, Validation.InputField(getValue(validation.get(), value_path)))}
1464 </CardItem>
1465 </Card>)
1466 break;
1467 case 'MONEY':
1468 if (readonly) {
1469 var val = getValue(getState(), value_path) || '';
1470 return (
1471 <Left>
1472 <Body>
1473 <Text>{Formatter.default.currency(val.toString())}</Text>
1474 <Text note>{title}</Text>
1475 </Body>
1476 </Left>
1477 )
1478 }
1479 return InputField({
1480 value: () => {
1481 var val = getValue(getState(), value_path) || '';
1482 return Formatter.default.currency(val.toString());
1483 },
1484 onChangeText: defaultSetValue,
1485 title: title,
1486 inputProps: () => { return { keyboardType: "numeric" } },
1487 type: 'string',
1488 required: () => section.required,
1489 editable: () => true,
1490 placeHolder: title
1491 }, Validation.InputField(getValue(validation.get(), value_path)));
1492 case 'PHONE':
1493 if (readonly) {
1494 var val = getValue(getState(), value_path) || '';
1495 return (
1496 <Left>
1497 <Body>
1498 <Text>{z}</Text>
1499 <Text note>{title}</Text>
1500 </Body>
1501 </Left>
1502 )
1503 }
1504 return InputField({
1505 value: () => {
1506 var val = getValue(getState(), value_path) || '';
1507 return Formatter.default.getFormattedPhoneNumber(val.toString());
1508 },
1509 onChangeText: (value) => {
1510 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: (Formatter.default.removeNonNumbers(value, '+()')) });
1511 setState(path, update, (updatedState) => {
1512 executeValidation({
1513 validation,
1514 value_path,
1515 getValue,
1516 updatedState,
1517 validationrules: section.validationRules
1518 });
1519 });
1520 },
1521 required: () => section.required,
1522 title: title,
1523 inputProps: () => { return { keyboardType: "numeric" } },
1524 type: 'string',
1525 editable: () => true,
1526 placeHolder: title
1527 }, Validation.InputField(getValue(validation.get(), value_path)));
1528 case 'SOCIALSECURITY':
1529 if (readonly) {
1530 var val = getValue(getState(), value_path) || '';
1531 return (
1532 <Left>
1533 <Body>
1534 <Text>{Formatter.default.socialSecurity(val.toString())}</Text>
1535 <Text note>{title}</Text>
1536 </Body>
1537 </Left>
1538 )
1539 }
1540 return ValidatedInputField({
1541 validationrules: ['notempty', 'numbers', 'length9', ...(section.validationRules || [])],
1542 value_path,
1543 path,
1544 required: () => section.required,
1545 getState,
1546 formatter: Formatter.default.socialSecurity,
1547 unformatter: Formatter.default.removeNonNumbers,
1548 inputProps: () => { return { keyboardType: "numeric" } },
1549 sectionkey,
1550 setState,
1551 readonly,
1552 title,
1553 validation
1554 }, Validation.InputField(getValue(validation.get(), value_path)));
1555
1556 case 'BOOLEAN':
1557 return (InputField({
1558 value: () => {
1559 return getValue(getState(), value_path) || false;
1560 },
1561 onValueChange: (value) => {
1562 if (!readonly) {
1563 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: value });
1564 setState(path, update, (updatedState) => {
1565 executeValidation({
1566 validation,
1567 value_path,
1568 getValue,
1569 updatedState,
1570 validationrules: section.validationRules
1571 })
1572 });
1573 }
1574 },
1575 title: title,
1576 type: 'check',
1577 required: () => section.required,
1578 editable: () => !readonly,
1579 placeHolder: title
1580 }, Validation.InputField(getValue(validation.get(), value_path))));
1581 }
1582}
1583
1584export const GetAddressInput = (opts) => {
1585 var { value_path, title, placeHolder, googlePlacesApi, getValue, getState, path, sectionkey, setState, inputStyle, placeholderTextColor } = opts;
1586 inputStyle = inputStyle || (() => { return {}; });
1587 var $path = ` $ ${path}`;
1588 var $value = getValue(getState(), $path);
1589 return (
1590 <GooglePlacesAutocomplete
1591 placeholder={placeHolder || title}
1592 minLength={2}
1593 autoFocus={false}
1594 placeholderTextColor={placeholderTextColor}
1595 listViewDisplayed={$value && $value[sectionkey] ? $value[sectionkey].listViewDisplayed : false}
1596 fetchDetails={true}
1597 renderDescription={(row) => {
1598 if (row && row.terms && row.terms.length) {
1599 return row.terms.map(x => x.value).join(', ');
1600 }
1601 return null;
1602 }}
1603 onFocus={() => {
1604 var $_update = Object.assign({}, getValue(getState(), $path), {
1605 [sectionkey]: {
1606 listViewDisplayed: true
1607 }
1608 });
1609 setState($path, $_update);
1610 }}
1611 onPress={(data, details = null) => {
1612 var update = { addressComponents: details.address_components.map(x => x) };
1613 if (details && details.geometry && details.geometry.location) {
1614 var loc = details.geometry.location;
1615 update = Object.assign({}, update, {
1616 latitude: loc.lat,
1617 longitude: loc.lng
1618 });
1619 }
1620 if (details && details.geometry && details.geometry.viewport) {
1621 var viewport = details.geometry.viewport;
1622 if (viewport.northeast && viewport.southwest) {
1623 update = Object.assign({}, update,
1624 {
1625 latitudeDelta: viewport.northeast.lat - viewport.southwest.lat,
1626 longitudeDelta: viewport.northeast.lng - viewport.southwest.lng,
1627 });
1628 }
1629 }
1630 else {
1631 update = Object.assign({}, update,
1632 {
1633 latitudeDelta: 0.015,
1634 longitudeDelta: 0.0121,
1635 })
1636 }
1637 if (update) {
1638 update = Object.assign(update, {
1639 formatted_address: details.formatted_address
1640 });
1641 }
1642
1643 var $value = getValue(getState(), $path);
1644 var $_update = Object.assign({}, getValue(getState(), $path), {
1645 [sectionkey]: {
1646 listViewDisplayed: false
1647 }
1648 });
1649 setState($path, $_update);
1650 var _update = Object.assign({}, getValue(getState(), path), { [sectionkey]: update });
1651 setState(path, _update);
1652 }}
1653 getDefaultValue={() => {
1654 var value = getValue(getState(), value_path) || undefined;
1655 if (value) {
1656 return value.formatted_address;
1657 }
1658 return ''; // text input default value
1659 }}
1660 query={{
1661 key: googlePlacesApi,
1662 language: 'en', // language of the results
1663 }}
1664 enablePoweredByContainer={false}
1665 styles={{
1666 description: {
1667 fontWeight: 'bold',
1668 },
1669 listView: {
1670 backgroundColor: 'transparent',
1671 },
1672
1673 predefinedPlacesDescription: {
1674
1675 },
1676 textInput: {
1677 backgroundColor: 'transparent',
1678 ...(inputStyle())
1679 },
1680 textInputContainer: {
1681 borderLeftWidth: 0,
1682 borderRightWidth: 0,
1683 backgroundColor: 'transparent',
1684 height: 44,
1685 borderTopColor: 'transparent',
1686 borderBottomColor: 'transparent',
1687 }
1688 }}
1689 currentLocationLabel={Titles.CurrentLocation}
1690 nearbyPlacesAPI='GooglePlacesSearch'
1691 GoogleReverseGeocodingQuery={{
1692 }}
1693
1694 filterReverseGeocodingByTypes={['locality', 'administrative_area_level_3']}
1695 // filter
1696 />
1697 )
1698}
1699
1700export const BackButton = (ops) => {
1701 ops = Object.assign({ action: () => { }, style: {} }, ops)
1702 return (
1703
1704 <Button transparent onPress={() => {
1705 ops.action();
1706 if (!ops.cancel)
1707 Actions.pop();
1708 }}>
1709 <Icon name='md-arrow-round-back' style={ops.style} />
1710 </Button>
1711 );
1712}
1713const executeValidation = (opts) => {
1714 var { validation, value_path, callback, getValue, updatedState, validationrules } = opts;
1715 validationrules = validationrules || [];
1716 var validationResult = Validation.validate({
1717 [value_path]: Validation.validation(validationrules)
1718 }, updatedState, getValue);
1719 if (validationResult) {
1720 validation.set(null, validationResult.validationState, callback)
1721 }
1722}
1723export const ValidatedInputField = (opts) => {
1724 var { formatter, unformatter, required, title, validationrules, inputProps, value_path, path, getState, sectionkey, setState, readonly, validation } = opts;
1725 inputProps = inputProps || (() => { return {}; });
1726 unformatter = unformatter || (t => { return t; });
1727 formatter = formatter || (t => { return `${t}`; });
1728 required = required || (() => { return false; })
1729 return InputField({
1730 inputProps,
1731 ...opts,
1732 value: () => {
1733 return formatter(getValue(getState(), value_path) || '');
1734 },
1735 onChangeText: (value) => {
1736 // if (value) {
1737 // value = value.trim();
1738 // }
1739 var update = Object.assign({}, getValue(getState(), path), { [sectionkey]: unformatter(value) });
1740 setState(path, update, (updatedState) => {
1741 executeValidation({
1742 validation,
1743 value_path,
1744 getValue,
1745 updatedState,
1746 validationrules
1747 });
1748 });
1749 ;
1750 },
1751 required,
1752 title: title,
1753 // type: 'string',
1754 editable: () => true,
1755 placeHolder: title
1756 }, Validation.InputField(getValue(validation.get(), value_path)));
1757}
1758export const ListButtonItem = (icon, title, action, extras, right, key, note) => {
1759 var _right = null;
1760 var _extras = null;
1761 if (extras) {
1762 extras = <Body>{extras}</Body>
1763 }
1764 if (right) {
1765 _right = <Right>{right}</Right>
1766 }
1767 return (
1768 <ListItem button key={key} icon onPress={action}>
1769 {icon ? (<Left>
1770 <Icon name={icon} />
1771 </Left>) : null}
1772 <Body><Text>{title}</Text>{note}</Body>
1773 {_extras}
1774 {_right}
1775 </ListItem>
1776 )
1777}
1778
1779export const ErrorText = (text) => {
1780 return (
1781 <Text style={{ fontSize: 12, color: Colors.Danger }}>{text}</Text>
1782 );
1783}
1784
1785export const InputProps = (value, onChangeText, placeHolderText, label, keyboardType) => {
1786 return {
1787 value: value,
1788 keyboardType: keyboardType || 'default',
1789 onChangeText: onChangeText,
1790 label: label || '',
1791 placeholder: placeHolderText
1792 }
1793}
1794export const runAfter = (me, callback) => {
1795 me.setState({ busy: true })
1796 InteractionManager.runAfterInteractions(() => {
1797 if (callback)
1798 callback();
1799 me.setState({ busy: false });
1800 });
1801}
1802
1803export const whileNotBusy = (callback) => {
1804 return new Promise((resolve, fail) => {
1805 InteractionManager.runAfterInteractions(() => {
1806 try {
1807 if (callback)
1808 callback();
1809 resolve();
1810 } catch (e) {
1811 fail(e);
1812 }
1813 });
1814 });
1815}
1816
1817
1818export const getStreetAddress = addressComponents => {
1819 return getPartOfComponents(['street_number', 'route'], addressComponents);
1820};
1821export const getCity = addressComponents => {
1822 return getPartOfComponents(['locality'], addressComponents);
1823}
1824export const getStateOrProvince = addressComponents => {
1825 return getPartOfComponents(["administrative_area_level_1"], addressComponents);
1826}
1827export const getZipCode = addressComponents => {
1828 return getPartOfComponents(["postal_code"], addressComponents);
1829}
1830const getPartOfComponents = (types, addressComponents) => {
1831 return addressComponents ? addressComponents.filter(x =>
1832 types.find(t => x.types.indexOf(t) !== -1))
1833 .map(t => t.shortName || t.short_name)
1834 .join(' ') : null;
1835}
1836export const Circle = (children, style) => {
1837 return (
1838 <View style={style}>
1839 <View
1840 style={{
1841 flex: 1,
1842 alignItems: 'center',
1843 flexDirection: 'column'
1844 }}>
1845 <View style={{
1846 flex: 1,
1847 alignItems: 'center',
1848 flexDirection: 'row'
1849 }}>
1850 {children}
1851 </View>
1852 </View>
1853 </View>
1854 )
1855}
1856export const ProcessCircle = (children, style) => {
1857 return Circle(children, Object.assign({
1858 height: 19,
1859 width: 19,
1860 borderRadius: 19,
1861 backgroundColor: Colors.HeroBlue
1862 }, style));
1863}
1864export const DblCircle = (child, rad, rad2) => {
1865 return (
1866 Circle(
1867 Circle(child, {
1868 height: rad - rad2,
1869 width: rad - rad2,
1870 borderRadius: rad - rad2,
1871 backgroundColor: Colors.White
1872 }), {
1873 height: rad,
1874 borderRadius: rad,
1875 width: rad,
1876 backgroundColor: Colors.HeroBlue
1877 })
1878 )
1879}
1880export const dateTime = (datetimestring) => {
1881 var date = new Date(datetimestring);
1882 if (isNaN(date.getTime())) {
1883 return '';
1884 }
1885 return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
1886}
1887export const localDate = (datetimestring) => {
1888 var date = new Date(datetimestring);
1889 if (isNaN(date.getTime())) {
1890 return '';
1891 }
1892 return date.toLocaleDateString();
1893}
1894
1895export function timeSinceDate(dateString) {
1896 if (!dateString) {
1897 return null;
1898 }
1899 var date = new Date(dateString);
1900 return timeSince(date);
1901}
1902
1903export function timeSince(date) {
1904 if (!date.getTime || isNaN(date.getTime())) {
1905 return '';
1906 }
1907 var seconds = Math.floor((new Date() - date) / 1000);
1908
1909 var interval = Math.floor(seconds / 31536000);
1910
1911 if (interval > 1) {
1912 return date.toLocaleDateString();
1913 }
1914 interval = Math.floor(seconds / 2592000);
1915 if (interval > 1) {
1916 return interval + Titles.Ago(` ${Titles.Months}`);
1917 }
1918 interval = Math.floor(seconds / 86400);
1919 if (interval > 1) {
1920 return interval + Titles.Ago(` ${Titles.Days}`);
1921 }
1922 interval = Math.floor(seconds / 3600);
1923 if (interval > 1) {
1924 return interval + Titles.Ago(` ${Titles.Hours}`);
1925 }
1926 interval = Math.floor(seconds / 60);
1927 if (interval > 1) {
1928 return interval + Titles.Ago(` ${Titles.Minut}`);
1929 }
1930 return Math.floor(seconds) + Titles.Seconds;
1931}
1932
1933export const writeLocation = point => {
1934 if (point && point.latitude && point.longitude) {
1935 return point.latitude + '°, ' + point.longitude + '°';
1936 }
1937 return '';
1938}
1939export const InformationCardItem = (text, note, icon, key) => {
1940 icon = icon || null;
1941 if (typeof (icon) == 'string') {
1942 icon = <Icon name={icon} />;
1943 }
1944 var extras = {};
1945 if (key) {
1946 extras = { key };
1947 }
1948 return (
1949 <CardItem {...extras} >
1950 {icon}
1951 <Body>
1952 <Text>{text}</Text>
1953 <Text note>{note}</Text>
1954 </Body>
1955 </CardItem>
1956 );
1957}
1958
1959export const sortByCreated = (asc) => {
1960 if (asc)
1961 return (a, b) => { return Date.parse(a.created) - Date.parse(b.created) };
1962 return (b, a) => { return Date.parse(a.created) - Date.parse(b.created) };
1963}
1964
1965export const getText = (key, obj) => {
1966 if (obj && obj[key] && obj[key].toFixed)
1967 return obj[key].toFixed(2);
1968 if (obj && obj[key]) {
1969 return obj[key];
1970 }
1971 return '0.00';
1972}
1973export const percentage = num => {
1974 if (isNaN(num)) {
1975 return '';
1976 }
1977 return (Math.floor(num * 100));
1978}
1979
1980export const flex = () => {
1981 return { flex: 1 };
1982}
1983
1984export const image = (profileImage, imagesize) => {
1985 var pimage = profileImage ? profileImage.replace('sz=50', `sz=${imagesize}`) : '';
1986 if (pimage.indexOf('facebook') !== -1) {
1987 pimage += "?type=large"
1988 }
1989 return pimage;
1990}
1991
1992export const profileImage = (profileImage, imagesize, icon) => {
1993 if (!profileImage) {
1994 icon = icon || 'md-person';
1995 return (<Icon name={icon} style={{ color: Colors.Laborer }} />)
1996 }
1997 imagesize = imagesize || 41;
1998 var pimage = image(profileImage, imagesize);
1999 return (
2000 <View>
2001 {pimage ? <FastImage style={{
2002 width: imagesize,
2003 height: imagesize,
2004 borderRadius: imagesize / 2,
2005 }} source={{ uri: pimage }} /> : null}
2006 </View>
2007 );
2008}
2009
2010export const profileImg = (profileImage, imagesize, borderRadius, style) => {
2011 if (!profileImage) {
2012 return (<Icon name='md-person' style={{ color: Colors.Laborer }} />)
2013 }
2014 style = style || {};
2015 imagesize = imagesize || 41;
2016 var pimage = image(profileImage, imagesize);
2017 return (
2018 pimage ? <FastImage style={Object.assign({
2019 width: imagesize,
2020 height: imagesize,
2021 borderRadius: borderRadius || imagesize / 2,
2022 }, style)} source={{ uri: pimage }} /> : null
2023 );
2024}
2025
2026export const ErrorStateProp = name => {
2027 return name + '_$_error';
2028}
2029
2030export const InputGroupView = () => {
2031 return {
2032 flex: 1,
2033 flexDirection: 'column',
2034 borderBottomWidth: 1,
2035 borderColor: TextColor() + '00'
2036 }
2037}
2038export const PickerText = (dark) => {
2039 return { color: TextColor(dark), fontSize: 13, lineHeight: 16 };
2040}
2041
2042
2043export const TextColor = (dark) => {
2044 return Colors.Dark;
2045}
2046export const InputField = (options, errorStuff) => {
2047 options = options || {};
2048 var keyboardavoidingbehavior = 'height';
2049 options = Object.assign({}, errorStuff, options);
2050 options = Object.assign({
2051 relativePosStyle: InputGroupView(),
2052 titleStyle: Object.assign(PickerText(options.lightMode), flex(), options.required && options.required() ? { fontWeight: '900' } : {}, {}),
2053 title: '',
2054 value: () => { },
2055 onChangeText: () => { },
2056 onchange: () => { },
2057 noHR: () => true,
2058 errorIcon: () => { return null },
2059 placeHolder: '',
2060 inputStyle: () => {
2061 return {};
2062 },
2063 required: () => false,
2064 inputProps: () => { return {}; },
2065 errorGroupState: () => { { } },
2066 onBlur: () => { },
2067 editable: () => true,
2068 key: () => undefined,
2069 errorText: () => { },
2070 style: () => { return {}; },
2071 lightMode: false,
2072 format: () => { return "YYYY-MM-DD" },
2073 min: () => 0,
2074 max: () => 1,
2075 step: () => 0,
2076 hrOptions: () => { return {} },
2077 getAddress: () => { return null },
2078 viewProps: () => { return {} },
2079 extra: () => { return null },
2080 onSubmitEditing: () => {
2081 return () => { }
2082 }
2083 }, options)
2084 var inputprops = Object.assign({
2085 onSubmitEditing: options.onSubmitEditing(),
2086 onBlur: options.onBlur(),
2087 autoCapitalize: 'none'
2088 }, options.inputProps());
2089 var input_field = null;
2090 var hr_ = (options.lightMode && !options.noHR()) ? <HR lineColor={Colors.Dark} {...options.hrOptions()} /> : null;
2091 var alwaysshowtitle = false;
2092 var nevershowtitle = false;
2093 if (options.type === 'address') {
2094 input_field = (
2095 <View underline={false} style={{ flexDirection: 'row', ...(options.viewStyle || {}) }}>
2096 {options.errorIcon()}
2097 {options.errorText()}
2098 {options.getAddress()}
2099 </View>
2100 );
2101
2102 if (options.inputBody) {
2103 return options.inputBody(options.getAddress(), options);
2104 }
2105 }
2106 else if (options.type === 'switch') {
2107 alwaysshowtitle = true;
2108 input_field = (
2109 <View style={{ flexDirection: 'column' }}>
2110 <View style={{ flexDirection: 'row' }}>
2111 <Right>
2112 <Switch value={options.value()}
2113 disabled={!options.editable()}
2114 onValueChange={options.onValueChange} />
2115 </Right>
2116 </View>
2117 {options.errorText()}
2118 </View>
2119 );
2120 }
2121 else if (options.type === 'infinite-picker') {
2122 input_field = (
2123 <View style={{ flexDirection: 'column' }}>
2124 <InfiniteListSelect options={Object.assign({ hr_, flex }, options)} inputprops={inputprops}>
2125 </InfiniteListSelect>
2126 {options.errorText()}
2127 </View>
2128 );
2129
2130 if (options.inputBody) {
2131 return options.inputBody(input_field, options);
2132 }
2133 }
2134 else if (options.type === 'check') {
2135 nevershowtitle = true;
2136 input_field = (
2137 <View style={{ flex: 1, flexDirection: 'column' }}>
2138 <ListItem noBorder={true} onPress={() => {
2139 if (options.onValueChange && options.editable())
2140 options.onValueChange(!options.value());
2141 }}>
2142 <CheckBox
2143 onPress={() => {
2144 if (options.onValueChange && options.editable())
2145 options.onValueChange(!options.value());
2146 }}
2147 checked={options.value()}
2148 disabled={!options.editable()}
2149 onValueChange={options.onValueChange} />
2150 <Body>
2151 <Text>{options.title}</Text>
2152 </Body>
2153 </ListItem>
2154 {options.errorText()}
2155 {hr_}
2156 </View>
2157 );
2158 }
2159 else if (options.type === 'actionsheet') {
2160 var action_sheet_options = options.destructiveButtonIndex ? {
2161 destructiveButtonIndex: options.destructiveButtonIndex()
2162 } : {};
2163 input_field = (
2164 <Button transparent onPress={() => ActionSheet.show(
2165 Object.assign({
2166 options: options.buttons(),
2167 cancelButtonIndex: options.cancelindex(),
2168 title: options.title
2169 }, action_sheet_options),
2170 (buttonIndex) => options.onValueChange(buttonIndex)
2171 )}><Text>{options.title}</Text></Button>
2172 );
2173 }
2174 else if (options.type === 'slider') {
2175 alwaysshowtitle = true;
2176 input_field = (
2177 <View style={{ flexDirection: 'column' }}>
2178 <View style={{ flexDirection: 'row' }}>
2179 {options.errorIcon()}
2180 <Slider
2181 style={{ flex: 3 }}
2182 step={options.step()}
2183 maximumValue={options.max()}
2184 minimumValue={options.min()}
2185 value={options.value()}
2186 disabled={!options.editable()}
2187 onSlidingComplete={options.onValueChange}
2188 onValueChange={options.onchange} />
2189 </View>
2190 {options.extra()}
2191 {options.errorText()}
2192 {hr_}
2193 </View>
2194 )
2195 }
2196 else if (options.type === 'loc_rad') {
2197 var map_options = {};
2198 if (options.width) {
2199 map_options = { width: options.width() };
2200 }
2201 var key_st = options.key() ? { key: options.key() } : null;
2202 input_field = (
2203 <View style={{ flexDirection: 'column', backgroundColor: 'red' }}>
2204 <View style={{ flexDirection: 'row', backgroundColor: 'red' }}>
2205 {options.errorIcon()}
2206 <MapView
2207 {...key_st}
2208 style={Object.assign({ flex: 1, height: 300, backgroundColor: 'blue', })}
2209 onRegionChange={options.onValueChange}
2210 initialRegion={options.value()} >
2211 {options.extra()}
2212 </MapView>
2213 </View>
2214 {options.errorText()}
2215 {hr_}
2216 </View>
2217 )
2218 }
2219 else if (false && options.type === 'date') {
2220
2221 var val = options.value() || '';
2222 var prevalue = val;
2223 var _date_val = null;
2224 var format = 'YYYY-MM-DD';
2225 if (!val) {
2226 _date_val = format;
2227 }
2228 _date_val = Formatter.default.date(Formatter.default.removeNonNumbers(val, null, true));
2229 _date_val = _date_val.substring(0, format.length);
2230
2231 _date_val = _date_val + format.split('').subset(_date_val.length).join('');
2232 _date_val = _date_val.substring(0, format.length);
2233 var cursor_position = Platform.OS === "android" ? _date_val.length - 1 : _date_val.length;
2234 var selection = Platform.OS === 'android' ? null : { start: cursor_position, end: cursor_position };
2235 var selectionprops = {};
2236 if (selection) {
2237 selectionprops.selection = selection;
2238 }
2239 input_field = (
2240 <KeyboardAvoidingView behavior={keyboardavoidingbehavior}>
2241 <View style={{ flexDirection: 'column' }}>
2242 <View {...options.errorGroupState()}>
2243 {options.errorIcon()}
2244 <Input
2245 {...inputprops}
2246 {...selectionprops}
2247 style={Object.assign(flex(), options.lightMode ? { color: Colors.Dark } : null, options.inputStyle())}
2248 value={_date_val}
2249 onChangeText={(value) => {
2250 var _val = value || '';// (Formatter.default.removeNonNumbers(value))
2251
2252 _val = Formatter.default.removeNonNumbers(_val, null, true);
2253 if (format.length > value.length) {
2254 _val = _val.split('').subset(0, _val.length - (format.length - value.length)).join('');
2255 }
2256 _date_val = Formatter.default.date((_val));
2257 options.onValueChange(_date_val);
2258 }}
2259 placeholderTextColor={options.required() ? Colors.Danger : Colors.LighterDark}
2260 placeholder={options.placeHolder + (options.required() ? '*' : '')} />
2261
2262 </View>
2263 {hr_}
2264 {options.errorText()}
2265 </View>
2266 </KeyboardAvoidingView>
2267 );
2268 }
2269 else if (options.type === 'date') {
2270 var fi_fi = (<DatePicker
2271 defaultDate={new Date(Date.now())}
2272 mode="date"
2273 timeZoneOffsetInMinutes={undefined}
2274 modalTransparent={false}
2275 animationType={"fade"}
2276 androidMode={"default"}
2277 placeHolderText={((new Date(options.value() || Date.now()).toLocaleDateString()))}
2278 format={options.format()}
2279 disabled={!options.editable()}
2280 confirmBtnText="Confirm"
2281 cancelBtnText="Cancel"
2282 {...(options.datePicker || {})}
2283 customStyles={{
2284 dateIcon: {
2285 position: 'absolute',
2286 left: 0,
2287 top: 4,
2288 marginLeft: 0,
2289 height: 0,
2290 width: 0
2291 },
2292 dateText: {
2293 color: TextColor(),
2294 },
2295 dateInput: {
2296 borderWidth: 0,
2297 },
2298 disabled: {
2299 backgroundColor: 'transparent',
2300 }
2301 }}
2302 onOpenModal={() => {
2303
2304 }}
2305 onDateChange={options.onValueChange}
2306 />);
2307 input_field = (
2308 <View style={{ flexDirection: 'column', ...(options.viewStyle || {}) }}>
2309 <Text>{options.title}</Text>
2310 <View style={{ flexDirection: 'row' }}>
2311 {options.errorIcon()}
2312 {fi_fi}
2313 </View>
2314 {options.errorText()}
2315 {hr_}
2316 </View>
2317 );
2318
2319 if (options.inputBody) {
2320 return options.inputBody(fi_fi, options);
2321 }
2322 }
2323 else if (options.type === 'picker') {
2324 var pickerops = options.pickerStyle || {};//{theme: PickerTheme(), textStyle: PickerText(options.lightMode) };
2325 input_field = (
2326 <Picker
2327 placeholder={options.placeHolder}
2328 {...pickerops}
2329 selectedValue={options.value()}
2330 onValueChange={options.onValueChange}>
2331 {options.items()}
2332 </Picker>
2333 );
2334 if (options.inputBody) {
2335 return options.inputBody(input_field, options);
2336 }
2337 }
2338 else if (options.type === 'choicelist') {
2339 var radios = [];
2340 // radios.push((<ListItem noBorder={true} key={"checklist" + options.title} itemHeader first>
2341 // <Left><Text>{options.title}</Text></Left>
2342 // </ListItem>));
2343 var _choices = options.items();
2344
2345 Object.keys(_choices || {}).map(choice => {
2346 var choiceTitle = choice;
2347 if (options.useCapFirst && choiceTitle) {
2348 choiceTitle = utils.capitalizeFirstLetter(choiceTitle);
2349 }
2350 var onPress = ((choice) => {
2351 if (!options.editable()) {
2352 return;
2353 }
2354 var values = choice;
2355 options.onValueChange(values);
2356 }).bind(null, _choices[choice]);
2357 var selected = (options.value() || null) === _choices[choice];
2358
2359 if (options.createRadio) {
2360 radios.push(options.createRadio({
2361 title: choiceTitle,
2362 key: 'checklist' + choice,
2363 onPress,
2364 selected,
2365 section: options.section,
2366 value: _choices[choice]
2367 }));
2368 }
2369 else {
2370 radios.push((<ListItem noBorder={true} key={'checklist' + choice} button onPress={onPress}>
2371 <Left>
2372 <Text>{choiceTitle}</Text>
2373 </Left>
2374 <Right>
2375 {selected ? <Icon name="md-checkmark" /> : null}
2376 </Right>
2377 </ListItem>));
2378 }
2379 });
2380 var radio_list = options.createRadioList ? options.createRadioList(radios, options) : (<List>
2381 {radios}
2382 </List>);
2383 var choice_body;
2384 if (options.createRadioBody) {
2385 return options.createRadioBody({
2386 errorText: options.errorText(),
2387 radio_list,
2388 title: options.title,
2389 section: options.section,
2390 value: options.value(),
2391 required: options.required()
2392 })
2393 }
2394 else {
2395 choice_body = (
2396 <View style={{ flexDirection: 'column' }}>
2397 {options.errorText()}
2398 {radio_list}
2399 </View>
2400 )
2401 }
2402
2403 input_field = (
2404 <KeyboardAvoidingView behavior={keyboardavoidingbehavior}>
2405 {choice_body}
2406 </KeyboardAvoidingView>
2407 );
2408 }
2409 else if (options.type === 'checklist') {
2410 var radios = [];
2411 // radios.push((<ListItem noBorder={true} key={"checklist" + options.title} itemHeader first>
2412 // <Left><Text>{options.title}</Text></Left>
2413 // </ListItem>));
2414 var choices = options.items() || {};
2415 // for (var choice in choices) {
2416 Object.keys(choices).map(c => {
2417 var choice = choices[c];
2418 var choiceTitle = choice;
2419 if (options.useCapFirst && choiceTitle) {
2420 choiceTitle = utils.capitalizeFirstLetter(choiceTitle);
2421 }
2422 var onPress = ((choice) => {
2423 if (!options.editable()) {
2424 return;
2425 }
2426 var values = options.value() || [];
2427 if (!values.some(t => t === choice)) {
2428 values.push(choice)
2429 }
2430 else {
2431 values = [...values.filter(t => t !== choice)];
2432 }
2433
2434 options.onValueChange(values);
2435 }).bind(null, choices[choice]);
2436 var selected = (options.value() || []).some(t => t === choices[choice]);
2437
2438 if (options.createRadio) {
2439 radios.push(options.createRadio({
2440 title: choiceTitle,
2441 key: 'checklist' + choice,
2442 onPress,
2443 selected,
2444 value: choices[choice]
2445 }));
2446 }
2447 else {
2448 radios.push((<ListItem noBorder={true} key={'checklist' + choice} button onPress={onPress}>
2449 <Left>
2450 <Text>{choiceTitle}</Text>
2451 </Left>
2452 <Right>
2453 {selected ? <Icon name="md-checkmark" /> : null}
2454 </Right>
2455 </ListItem>));
2456 }
2457 });
2458 var radio_list = options.createRadioList ? options.createRadioList(radios, options) : (<List>
2459 {radios}
2460 </List>);
2461 var choice_body;
2462 if (options.createRadioBody) {
2463 return options.createRadioBody({
2464 errorText: options.errorText(),
2465 radio_list,
2466 title: options.title,
2467 value: options.value(),
2468 section: options.section,
2469 required: options.required()
2470 })
2471 }
2472
2473 input_field = (
2474 <KeyboardAvoidingView behavior={keyboardavoidingbehavior}>
2475 <View style={{ flexDirection: 'column' }}>
2476 {options.errorText()}
2477 {radio_list}
2478 </View>
2479 </KeyboardAvoidingView>
2480 );
2481 }
2482 else if (options.type === 'radio') {
2483 var radios = [];
2484 radios.push((<ListItem noBorder={true} key={"radio" + options.title} itemHeader first>
2485 <Left><Text>{options.title}</Text></Left>
2486 </ListItem>));
2487 var choices = options.items();
2488 for (var choice in choices) {
2489 radios.push((<ListItem noBorder={true} key={'radio' + choice} style={{ flex: 1 }} button onPress={((choice) => {
2490 var value = choice;
2491 if (options.editable())
2492 options.onValueChange(value);
2493 }).bind(null, choices[choice])}>
2494 <Left>
2495 <Text>{choice}</Text>
2496 </Left>
2497 <Right>
2498 {options.value() === choices[choice] ? <Icon name="md-checkmark" /> : null}
2499 </Right>
2500 </ListItem>));
2501 }
2502 input_field = (
2503 <KeyboardAvoidingView behavior={keyboardavoidingbehavior}>
2504 <View style={{ flexDirection: 'column' }}>
2505 {options.errorText()}
2506 <List style={{ flex: 1 }}>
2507 {radios}
2508 </List>
2509 </View>
2510 </KeyboardAvoidingView>
2511 );
2512
2513 }
2514 else if (options.type === 'autotext') {
2515 input_field = (
2516 <KeyboardAvoidingView behavior={keyboardavoidingbehavior}>
2517 <View style={{ flexDirection: 'column' }}>
2518 <View {...options.errorGroupState()}>
2519 {options.errorIcon()}
2520 <TextInput
2521 autoGrow={true}
2522 {...inputprops}
2523
2524 value={options.value()}
2525 maxHeight={200}
2526 onChangeText={options.onChangeText}
2527 placeholder={options.placeHolder} />
2528 </View>
2529 {hr_}
2530 {options.errorText()}
2531 </View>
2532 </KeyboardAvoidingView>
2533 );
2534 }
2535 else {
2536 var fi_fi = (
2537 <Item>
2538 <Input
2539 placeholderTextColor={options.required() ? Colors.Danger : Colors.LighterDark}
2540 {...inputprops}
2541 style={Object.assign({}, options.lightMode ? { color: Colors.Dark } : null, options.inputStyle())}
2542 value={options.value()}
2543 onChangeText={options.onChangeText}
2544 placeholder={options.placeHolder + (options.required() ? '*' : '')} />
2545 </Item>
2546 );
2547 input_field = (
2548 <KeyboardAvoidingView behavior={keyboardavoidingbehavior} style={{ ...(options.viewStyle || {}) }}>
2549 <View style={{ flexDirection: 'column', paddingBottom: 5 }}>
2550 <View style={{ alignItems: 'flex-start', flexDirection: 'row', justifyContent: 'center' }} {...options.errorGroupState()}>
2551 {options.errorIcon()}
2552 {fi_fi}
2553 </View>
2554 {hr_}
2555 {options.errorText()}
2556 </View>
2557 </KeyboardAvoidingView>
2558 );
2559
2560 if (options.inputBody) {
2561 return options.inputBody(fi_fi, options);
2562 }
2563 }
2564 return (
2565 <View {...options.viewProps()} style={options.relativePosStyle}>
2566 <Text style={options.titleStyle}>
2567 {(options.value() || alwaysshowtitle) && !nevershowtitle ? options.title : ''} {options.value() && options.required() ? '*' : ''}
2568 </Text>
2569 {input_field}
2570 </View>
2571 )
2572}
2573
2574export const WaitingFooter = (me) => {
2575 return (
2576 <Footer>
2577 {SpinnerFooter()}
2578 </Footer>
2579 );
2580}
2581
2582
2583export const ErrorProps = (state, key, dark) => {
2584 if (key === undefined) {
2585 return state ? { style: Object.assign({ color: Colors.Danger }, ListIconStyle(dark)) } : { style: ListIconStyle(dark) }
2586 }
2587 else {
2588 var error = UIA.Get(state, key) ? { style: Object.assign({ color: Colors.Danger }, ListIconStyle(dark)) } : { style: ListIconStyle(dark) };
2589 return error;
2590 }
2591
2592}
2593
2594
2595export const MediaListItems = (me, resource, candelete, opts) => {
2596 var name_icon = null;
2597 var pimage = image(resource.url);
2598 opts = Object.assign({ onPress: () => { }, hideDate: false, imagesize: 30 }, opts);
2599 var { imagesize } = opts;
2600 if (resource.type === 'IMAGE') {
2601 name_icon = (
2602 <FastImage style={{
2603 width: imagesize,
2604 height: imagesize,
2605 }} source={{ uri: pimage }} />
2606 );
2607 }
2608 return (
2609 <ListItem key={resource.id} onPress={() => {
2610 opts.onPress();
2611 }}>
2612 <Left>{name_icon}
2613 {opts.hideDate ? null : <Text note>{dateTime(resource.created)}</Text>}
2614 </Left>
2615 {candelete ? <Right>
2616 <Button transparent onPress={() => {
2617 me.props.deleteResource(resource.id);
2618 }}>
2619 <Icon name="md-close" />
2620 </Button>
2621 </Right> : null}
2622 </ListItem>
2623 );
2624};
2625export const MediaViewItem = (me, resource, candelete, opts) => {
2626 var name_icon = null;
2627 opts = Object.assign({ hideDate: true, imagesize: 30 }, opts);
2628 var { imagesize } = opts;
2629 var pimage = image(resource.url);
2630 if (resource.type === 'IMAGE') {
2631 name_icon = (
2632 <FastImage style={{
2633 width: imagesize,
2634 height: imagesize,
2635 }} source={{ uri: pimage }} />
2636 );
2637 }
2638 return (
2639 <View key={resource.id}>
2640 <Left>{name_icon}
2641 {opts.hideDate ? null : <Text>{dateTime(resource.created)}</Text>}
2642 </Left>
2643 {candelete ? <Right>
2644 <Button transparent onPress={() => {
2645 me.props.deleteResource(resource.id);
2646 }}>
2647 <Icon name="md-close" />
2648 </Button>
2649 </Right> : null}
2650 </View>
2651 );
2652};
2653
2654
2655export function SpinnerFooter(style) {
2656 return (
2657 <View style={Object.assign({}, style)}>
2658 <Spinner size="small" color={TextColor()} />
2659 </View>
2660 );
2661}
2662
2663export const percentageFormatted = (val) => {
2664 val = Math.round(val * 100);
2665 return (val).toFixed(2).toString();
2666}
2667export const convertToCurrency = (val) => {
2668 if (isNaN(val)) {
2669 val = 0;
2670 }
2671 val = Math.round(val);
2672 return (val / 100).toFixed(2).toString();
2673}
2674
2675export const showConvertMeterToMile = val => {
2676 var res = 0;
2677
2678 if (!res) {
2679 res = Math.round(1000 * (val)) / 1000;
2680 }
2681
2682 return res;
2683}
2684const mtom = 0.000621371;
2685const metomi = 1609.344;
2686export const convertMeterToMile = val => {
2687 return val / metomi;
2688}
2689export const convertPriceMeterToMile = val => {
2690 return val / mtom;
2691}
2692
2693export const _getDistance = (directions) => {
2694 var result = Titles.Unknown;
2695 if (directions && directions.routes) {
2696 var distances = directions.routes.map(route => {
2697 var dist = 0;
2698 if (route.legs) {
2699 route.legs.forEach(leg => {
2700 if (leg.distance && leg.distance.value) {
2701 dist += leg.distance.value;
2702 }
2703 });
2704 }
2705 return dist;
2706 });
2707 if (distances.length) {
2708 result = distances[0];
2709 }
2710 }
2711 return result;
2712}
2713
2714export const SomethingWentWrong = (callback, alternateError) => {
2715 return () => {
2716 Alert.alert(Titles.Error, alternateError || Titles.SomethingWentWrong, [{
2717 text: Titles.Ok, onPress: () => {
2718 if (callback) {
2719 callback();
2720 }
2721 }
2722 }])
2723 };
2724}
2725export const Ok = (title, message, callback) => {
2726 return () => {
2727 Alert.alert(title, message, [{
2728 text: Titles.Ok, onPress: callback || (() => { })
2729 }])
2730 };
2731}
2732
2733export const OkCancel = (title, message, callback, cancel) => {
2734 return () => {
2735 Alert.alert(title, message, [{
2736 text: Titles.Ok, onPress: callback || (() => { })
2737 }, { text: Titles.Cancel, onPress: cancel || (() => { }) }])
2738 };
2739}
2740
2741export const GetAddressSelect = (me, field) => {
2742 var api = me.state.apiKey;
2743 if (!api) {
2744 return null;
2745 }
2746 if (field.onload && !me.state.loaded) {
2747 return null;
2748 }
2749 return (
2750 <GooglePlacesAutocomplete
2751 key={field.name + '#field'}
2752 placeholder={field.placeholder}
2753 minLength={2}
2754 autoFocus={false}
2755 listViewDisplayed='auto'
2756 fetchDetails={true}
2757 renderDescription={(row) => {
2758 if (row && row.terms && row.terms.length) {
2759 return row.terms.map(x => x.value).join(', ');
2760 }
2761 return null;
2762 }}
2763 onPress={(data, details = null) => {
2764 var update = { addressComponents: details.address_components.map(x => x) };
2765 if (details && details.geometry && details.geometry.location) {
2766 var loc = details.geometry.location;
2767 update = Object.assign({}, update, {
2768 latitude: loc.lat,
2769 longitude: loc.lng
2770 });
2771 }
2772 if (details && details.geometry && details.geometry.viewport) {
2773 var viewport = details.geometry.viewport;
2774 if (viewport.northeast && viewport.southwest) {
2775 update = Object.assign({}, update,
2776 {
2777 latitudeDelta: viewport.northeast.lat - viewport.southwest.lat,
2778 longitudeDelta: viewport.northeast.lng - viewport.southwest.lng,
2779 });
2780 }
2781 }
2782 else {
2783 update = Object.assign({}, update,
2784 {
2785 latitudeDelta: 0.015,
2786 longitudeDelta: 0.0121,
2787 })
2788 }
2789 if (update) {
2790 update = Object.assign(update, { formatted_address: details.formatted_address });
2791 if (me.mounted)
2792 me.setState({ updated: true, [field.name]: update });
2793 }
2794 }}
2795 getDefaultValue={() => {
2796 return me.state[field.name] || ''; // text input default value
2797 }}
2798 query={{
2799 key: api,
2800 language: 'en', // language of the results
2801
2802 }}
2803 enablePoweredByContainer={false}
2804 styles={{
2805 description: {
2806 fontWeight: 'bold',
2807 },
2808 listView: {
2809 backgroundColor: 'transparent',
2810 },
2811
2812 predefinedPlacesDescription: {
2813
2814 },
2815 textInput: {
2816
2817 backgroundColor: 'transparent',
2818 },
2819 textInputContainer: {
2820 borderLeftWidth: 0,
2821 borderRightWidth: 0,
2822 backgroundColor: 'transparent',
2823 height: 44,
2824 borderTopColor: 'transparent',
2825 borderBottomColor: 'transparent',
2826 }
2827 }}
2828 currentLocationLabel={Titles.CurrentLocation}
2829 nearbyPlacesAPI='GooglePlacesSearch'
2830 GoogleReverseGeocodingQuery={{
2831 }}
2832
2833 filterReverseGeocodingByTypes={['locality', 'administrative_area_level_3']}
2834 // filter
2835 />
2836 );
2837}
2838export const Waiting = () => {
2839 return (
2840 <View style={{
2841 flex: 1,
2842 alignItems: 'center',
2843 justifyContent: 'center',
2844 backgroundColor: 'black'
2845 }}>
2846 <View style={{
2847 flex: 1,
2848 alignItems: 'center',
2849 justifyContent: 'center',
2850 flexDirection: 'column'
2851 }}>
2852 {Banner({})}
2853 <Spinner color={Colors.White} />
2854 </View>
2855 </View>
2856 );
2857}
2858var CardIOModule = null;
2859export const setScanCardService = (cardIOModule) => {
2860 CardIOModule = cardIOModule;
2861}
2862export const scanCard = (callback, error) => {
2863 error = error || (() => { });
2864 callback = callback || (function () { });
2865 CardIOModule
2866 .scanCard({
2867 hideCardIOLogo: true,
2868 requireCardholderName: true
2869 })
2870 .then(callback)
2871 .catch(error)
2872}
2873export const Banner = (style, logo) => {
2874 style = style || {};
2875 return (
2876 <View style={Object.assign({}, {
2877 flex: 1,
2878 flexDirection: 'column',
2879 justifyContent: 'center',
2880 alignItems: 'center',
2881 }, style)}>
2882 <Image style={{
2883 resizeMode: 'contain',
2884 height: 100,
2885 width: Math.max(100, width - 200)
2886 }} source={logo} />
2887 </View>
2888 );
2889}
2890
2891export const CreateFields = (me, fields) => {
2892 return (fields || []).map(field => {
2893 // if (field.type === 'address') {
2894 // return GetAddressSelect(me, field);
2895 // }
2896 return (
2897 InputField({
2898 errorIcon: (style) => {
2899 style = style || {};
2900 return (field.icon ? <Icon name={field.icon} style={style} /> : null);
2901 },
2902 getAddress: () => { return GetAddressSelect(me, field) },
2903 type: field.type,
2904 viewProps: () => { return { key: field.key || ('field.name' + field.name) } },
2905 value: () => me.state[field.name] || '',
2906 title: field.placeholder,
2907 inputProps: () => { return { autoCapitalize: 'none' } },
2908 onChangeText: field.onValueChange.bind(me, field.name),
2909 placeHolder: field.placeholder
2910 })
2911 );
2912 });
2913}
2914
2915function isValidDate(d) {
2916 if (Object.prototype.toString.call(d) === "[object Date]") {
2917 // it is a date
2918 if (isNaN(d.getTime())) { // d.valueOf() could also work
2919 // date is not valid
2920 return false;
2921 }
2922 else {
2923 // date is valid
2924 return true;
2925 }
2926 }
2927 else {
2928 // not a date
2929 }
2930 return false
2931}
\No newline at end of file