Guest User

Untitled

a guest
Jul 20th, 2018
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.97 KB | None | 0 0
  1. import PropTypes from 'prop-types';
  2. import React, { Component } from 'react';
  3. import { Platform, View, Text, TextInput, TouchableHighlight, AsyncStorage, Image, ScrollView, Modal } from "react-native";
  4. import Numeral from 'numeral';
  5. import { NetworkInfo } from 'react-native-network-info';
  6. import SmsListener from 'react-native-android-sms-listener';
  7. import axios from 'axios';
  8. import { Icon } from 'react-native-elements';
  9.  
  10. import t from 'tcomb-form-native';
  11. import * as css from '../styles/Styles';
  12. import { NativeModules } from 'react-native';
  13.  
  14. import {SCREEN_WIDTH, SCREEN_HEIGHT} from '../utility/Constants';
  15. import { Header } from 'react-navigation';
  16.  
  17. const HEADER_HEIGHT = Header.HEIGHT;
  18.  
  19.  
  20. const CallLogs = NativeModules.CallLogs;
  21. const Form = t.form.Form;
  22.  
  23.  
  24.  
  25.  
  26. export const req = async (args) => {
  27. console.log('req args:')
  28. console.log(args)
  29. try {
  30. const response = await axios(args.url, {
  31. method: args.method,
  32. headers: args.headers,
  33. data: JSON.stringify(args.body)
  34. });
  35. return response.data
  36. } catch (e) {
  37. console.log('error object', Object.keys(e));
  38. if (typeof e != 'object') console.log('error: ', e);
  39. }
  40. };
  41.  
  42.  
  43.  
  44.  
  45.  
  46. export const formStyles = {
  47. ...Form.stylesheet,
  48. formGroup: {
  49. normal: css.styles.textInputWithTitleContainer,
  50. error: css.styles.textInputWithTitleContainer
  51. },
  52. controlLabel: {
  53. normal: css.styles.textInputWithTitleLabelStyle,
  54. error: {
  55. fontWeight: '500',
  56. fontFamily: 'sans-serif-light',
  57. fontSize: 13,
  58. color: 'red',
  59. paddingBottom: 5,
  60. letterSpacing: 5
  61. }
  62. },
  63. textbox: {
  64. normal: {
  65. backgroundColor: '#e6e8e8',
  66. fontSize: 17,
  67. padding: 7,
  68. marginBottom: 5,
  69. color: 'black'
  70. },
  71. error: {
  72. backgroundColor: '#e6e8e8',
  73. fontSize: 17,
  74. padding: 7,
  75. marginBottom: 5,
  76. color: 'red'
  77. }
  78. },
  79. pickerContainer: {
  80. normal: {
  81. backgroundColor: '#e6e8e8',
  82. color: 'black'
  83. },
  84. open: {},
  85. error: {
  86. backgroundColor: '#e6e8e8',
  87. color: 'red'
  88. }
  89. },
  90. dateValue: {
  91. normal: {
  92. backgroundColor: '#e6e8e8',
  93. color: 'black',
  94. fontSize: 17,
  95. padding: 7,
  96. marginBottom: 5
  97. },
  98. error: {}
  99. },
  100. };
  101.  
  102. function currencyTextBox(locals) {
  103. if (locals.hidden) {
  104. return null;
  105. }
  106.  
  107. var stylesheet = locals.stylesheet;
  108. var formGroupStyle = stylesheet.formGroup.normal;
  109. var controlLabelStyle = stylesheet.controlLabel.normal;
  110. var textboxStyle = stylesheet.textbox.normal;
  111. var textboxViewStyle = stylesheet.textboxView.normal;
  112. var helpBlockStyle = stylesheet.helpBlock.normal;
  113. var errorBlockStyle = stylesheet.errorBlock;
  114.  
  115. if (locals.hasError) {
  116. formGroupStyle = stylesheet.formGroup.error;
  117. controlLabelStyle = stylesheet.controlLabel.error;
  118. textboxStyle = stylesheet.textbox.error;
  119. textboxViewStyle = stylesheet.textboxView.error;
  120. helpBlockStyle = stylesheet.helpBlock.error;
  121. }
  122.  
  123. if (locals.editable === false) {
  124. textboxStyle = stylesheet.textbox.notEditable;
  125. textboxViewStyle = stylesheet.textboxView.notEditable;
  126. }
  127.  
  128. var label = locals.label ? (
  129. <Text style={controlLabelStyle}>{locals.label}</Text>
  130. ) : null;
  131.  
  132. var help = locals.help ? (
  133. <Text style={helpBlockStyle}>{locals.help}</Text>
  134. ) : null;
  135.  
  136. var error =
  137. locals.hasError && locals.error ? (
  138. <Text accessibilityLiveRegion="polite" style={errorBlockStyle}>
  139. {locals.error}
  140. </Text>
  141. ) : null;
  142.  
  143. let customStyle = {
  144. searchSection: {
  145. flex: 1,
  146. flexDirection: 'row',
  147. justifyContent: 'center',
  148. alignItems: 'center',
  149. backgroundColor: '#fff',
  150. },
  151. searchIcon: {
  152. paddingTop: 7,
  153. paddingRight: 0,
  154. paddingBottom: 7,
  155. paddingLeft: 7,
  156. marginBottom: 5,
  157. backgroundColor: '#e6e8e8',
  158. fontSize: 17,
  159. color: 'black',
  160. },
  161. input: {
  162. flex: 1,
  163. },
  164. }
  165.  
  166. return (
  167. <View style={formGroupStyle}>
  168. {label}
  169. <View style={[customStyle.searchSection, textboxViewStyle]}>
  170. <TextInput
  171. style={customStyle.searchIcon}
  172. value='₦'
  173. editable={false}
  174. />
  175. <TextInput
  176. accessibilityLabel={locals.label}
  177. ref="input"
  178. autoCapitalize={locals.autoCapitalize}
  179. autoCorrect={locals.autoCorrect}
  180. autoFocus={locals.autoFocus}
  181. blurOnSubmit={locals.blurOnSubmit}
  182. editable={locals.editable}
  183. keyboardType={locals.keyboardType}
  184. maxLength={locals.maxLength}
  185. multiline={locals.multiline}
  186. onBlur={locals.onBlur}
  187. onEndEditing={locals.onEndEditing}
  188. onFocus={locals.onFocus}
  189. onLayout={locals.onLayout}
  190. onSelectionChange={locals.onSelectionChange}
  191. onSubmitEditing={locals.onSubmitEditing}
  192. onContentSizeChange={locals.onContentSizeChange}
  193. placeholderTextColor={locals.placeholderTextColor}
  194. secureTextEntry={locals.secureTextEntry}
  195. selectTextOnFocus={locals.selectTextOnFocus}
  196. selectionColor={locals.selectionColor}
  197. numberOfLines={locals.numberOfLines}
  198. underlineColorAndroid={locals.underlineColorAndroid}
  199. clearButtonMode={locals.clearButtonMode}
  200. clearTextOnFocus={locals.clearTextOnFocus}
  201. enablesReturnKeyAutomatically={locals.enablesReturnKeyAutomatically}
  202. keyboardAppearance={locals.keyboardAppearance}
  203. onKeyPress={locals.onKeyPress}
  204. returnKeyType={locals.returnKeyType}
  205. selectionState={locals.selectionState}
  206. onChangeText={value => locals.onChange(value)}
  207. onChange={locals.onChangeNative}
  208. placeholder={locals.placeholder}
  209. style={[customStyle.input, textboxStyle]}
  210. value={locals.value}
  211. />
  212. </View>
  213. {help}
  214. {error}
  215. </View>
  216. );
  217. }
  218.  
  219. export const getFieldsFromArray = (fields, text) => {
  220. let found_fields = []
  221. let find_fields = (arr) => {
  222. arr.forEach( (f) => {
  223. if (Array.isArray(f)) {
  224. find_fields(f)
  225. } else {
  226. if (f.indexOf(text) !== -1) {
  227. found_fields.push(f)
  228. }
  229. }
  230. })
  231. }
  232. find_fields(fields)
  233. return found_fields
  234. };
  235.  
  236. export const getFieldsOfType = (form_structure, fieldType) => {
  237. let found_fields = []
  238. let find_fields = (arr) => {
  239. arr.forEach((f) => {
  240. if (Array.isArray(f)) {
  241. find_fields(f)
  242. }
  243. if (f.fieldType == fieldType) {
  244. found_fields.push(f.fieldName)
  245. }
  246. })
  247. }
  248. find_fields(form_structure)
  249. return found_fields
  250. }
  251.  
  252. export const NumberType = (frm)=>{
  253. var max,min;
  254.  
  255. if (frm.limit){
  256. max = frm.limit.hasOwnProperty('max') ? frm.limit.max : Infinity
  257. min = frm.limit.hasOwnProperty('min') ? frm.limit.min : -Infinity
  258. }
  259.  
  260. var NumberType = t.refinement(t.Number, function (n) {
  261. if (frm.limit){
  262. return ( (n >= min) && (n <= max) )
  263. }
  264. return n;
  265. });
  266.  
  267. return NumberType;
  268. }
  269.  
  270. export const NumberTypeError = (frm)=>{
  271. var max, min, max_str, min_str;
  272.  
  273. if (frm.limit) {
  274. max = frm.limit.hasOwnProperty('max') ? frm.limit.max : Infinity
  275. min = frm.limit.hasOwnProperty('min') ? frm.limit.min : -Infinity
  276. max_str = max
  277. min_str = min
  278. if (frm.fieldType == 'currency') {
  279. if (!(max == Infinity)) max_str = '₦ ' + Numeral(max).format('0,0');
  280. if (!(min == -Infinity)) min_str = '₦ ' + Numeral(min).format('0,0');
  281. }
  282. }
  283.  
  284. return function (value, path, context) {
  285. var msg;
  286. if ( !((value === '') || (value === null)) ) {
  287. if (value > max) {
  288. msg = 'Maximum is ' + max_str
  289. } else if (value < min) {
  290. msg = 'Minimum is ' + min_str
  291. }
  292. } else {
  293. msg = 'This field is required'
  294. }
  295. return msg;
  296. };
  297. }
  298.  
  299. export const makeForm = (formStructure, dropDownOption, app_form_read_only=false) => {
  300.  
  301. if (app_form_read_only) {
  302. return makeReadOnlyForm(formStructure)
  303. }
  304.  
  305. t.refinement(t.Number, function (n) {
  306. return n >= 0;
  307. });
  308.  
  309. let formObj = {};
  310.  
  311. formStructure.forEach((frm) => {
  312. if (frm.fieldType == 'date' && !app_form_read_only) {
  313. formObj[frm.fieldName] = t.Date
  314. } else if (frm.fieldType == 'data'){
  315. formObj[frm.fieldName] = (frm.mandatory ? t.String : t.maybe(t.String))
  316. } else if (frm.fieldType == 'select' && !app_form_read_only){
  317. formObj[frm.fieldName] = (frm.mandatory ? t.enums( dropDownOption[frm.fieldName] || {} ) : t.maybe(t.enums( dropDownOption[frm.fieldName] || {} )))
  318. } else if (frm.fieldType == 'number' || frm.fieldType == 'currency'){
  319. formObj[frm.fieldName] = (frm.mandatory ? NumberType(frm) : t.maybe(t.Number))
  320. } else if (frm.fieldType == 'list' && !app_form_read_only) {
  321. formObj[frm.fieldName] = (frm.mandatory ? t.list(t.String) : t.maybe(t.list(t.String)))
  322. } else {
  323. formObj[frm.fieldName] = (frm.mandatory ? t.String : t.maybe(t.String))
  324. }
  325. })
  326.  
  327. return t.struct(formObj);
  328. }
  329.  
  330. export const makeFormOptions = (formStructure, formProps=null, app_form_read_only=false, customStyles=null) => {
  331.  
  332. if (app_form_read_only) {
  333. return makeReadOnlyFormOptions(formStructure)
  334. }
  335.  
  336. let optionsObj = {};
  337.  
  338. for(let idx=0; idx < formStructure.length; idx++) {
  339.  
  340. optionsObj[formStructure[idx].fieldName] = {
  341. label:formStructure[idx].label
  342. }
  343.  
  344. if (formProps){
  345. optionsObj[formStructure[idx].fieldName]['onSubmitEditing'] = (event) => {
  346. let current_field = formStructure[idx].fieldName,
  347. next_field = idx+1 < formStructure.length ? formStructure[idx+1].fieldName : null ;
  348. formProps.prepareForm(current_field, next_field, event, formProps.onSubmitEditing)
  349. }
  350. }
  351.  
  352. if (formStructure[idx].placeholder) {
  353. optionsObj[formStructure[idx].fieldName]['placeholder'] = formStructure[idx].placeholder
  354. }
  355.  
  356. if (formStructure[idx].mandatory) {
  357. optionsObj[formStructure[idx].fieldName]['error'] = formStructure[idx].errorMessage || 'this field is required.'
  358. }
  359.  
  360. if (formStructure[idx].fieldType == 'date') {
  361. optionsObj[formStructure[idx].fieldName]['mode'] = 'date'
  362. optionsObj[formStructure[idx].fieldName]['config'] = {
  363. format: (date) => formatDate(date),
  364. dialogMode: 'spinner'
  365. }
  366. } else if (formStructure[idx].fieldType == 'currency') {
  367. optionsObj[formStructure[idx].fieldName]['error'] = NumberTypeError(formStructure[idx])
  368. optionsObj[formStructure[idx].fieldName]['template'] = currencyTextBox
  369. optionsObj[formStructure[idx].fieldName]['transformer'] = {
  370. format: value => {
  371. if (parseFloat(value)) {
  372. return Numeral(value).format('0,0')
  373. } else {
  374. return null
  375. }
  376. },
  377. parse: value => {
  378. if (parseFloat((value || '').replace(',',''))) {
  379. return parseFloat(value.replace(/,/g,''));
  380. } else {
  381. return null;
  382. }
  383. }
  384. };
  385.  
  386. } else if (formStructure[idx].fieldType == 'number') {
  387. optionsObj[formStructure[idx].fieldName]['error'] = NumberTypeError(formStructure[idx])
  388. } else if (formStructure[idx].fieldType == 'list') {
  389. optionsObj[formStructure[idx].fieldName]['item'] = {
  390. label: 'My tag'
  391. }
  392. }
  393.  
  394. if (idx == formStructure.length-1) {
  395. optionsObj[formStructure[idx].fieldName]['returnKeyType'] = 'done'
  396. } else {
  397. optionsObj[formStructure[idx].fieldName]['returnKeyType'] = 'go'
  398. }
  399. }
  400.  
  401. optionsObj = {
  402. stylesheet: customStyles || formStyles,
  403. auto:'placeholders',
  404. fields:optionsObj
  405. }
  406.  
  407. return optionsObj
  408. }
  409.  
  410. export const isFormEmpty = (form_obj) => {
  411. let is_empty = true;
  412. Object.keys(form_obj).forEach((key) => {
  413. if (key.indexOf('date') !== -1) {
  414. return false;
  415. }
  416. if (form_obj[key]) {
  417. is_empty = false;
  418. }
  419. })
  420. return is_empty
  421. }
  422.  
  423.  
  424. export const makeReadOnlyForm = (formStructure) => {
  425.  
  426. let formObj = {};
  427.  
  428. formStructure.forEach((frm) => {
  429. if (frm.fieldType == 'number' || frm.fieldType == 'currency'){
  430. formObj[frm.fieldName] = t.maybe(t.Number)
  431. } else {
  432. formObj[frm.fieldName] = t.maybe(t.String)
  433. }
  434. })
  435.  
  436. return t.struct(formObj);
  437. }
  438.  
  439. const readonlyFormStyles = {
  440. ...Form.stylesheet,
  441. formGroup: {
  442. normal: css.styles.textInputWithTitleContainer,
  443. error: css.styles.textInputWithTitleContainer
  444. },
  445. controlLabel: {
  446. normal: css.styles.textInputWithTitleLabelStyle,
  447. error: css.styles.textInputWithTitleLabelStyle
  448. },
  449. textbox: {
  450. normal: {
  451. backgroundColor: '#e6e8e8',
  452. fontSize: 17,
  453. padding: 7,
  454. marginBottom: 5,
  455. color: 'black'
  456. },
  457. error: {
  458. backgroundColor: '#e6e8e8',
  459. fontSize: 17,
  460. padding: 7,
  461. marginBottom: 5,
  462. color: 'red'
  463. },
  464. notEditable: {
  465. backgroundColor: '#e6e8e8',
  466. fontSize: 17,
  467. padding: 7,
  468. marginBottom: 5,
  469. color: 'black'
  470. }
  471. },
  472. pickerContainer: {
  473. normal: {
  474. backgroundColor: '#e6e8e8',
  475. color: 'black'
  476. },
  477. open: {},
  478. error: {
  479. backgroundColor: '#e6e8e8',
  480. color: 'red'
  481. }
  482. },
  483. dateValue: {
  484. normal: {
  485. backgroundColor: '#e6e8e8',
  486. color: 'black',
  487. fontSize: 17,
  488. padding: 7,
  489. marginBottom: 5
  490. },
  491. error: {}
  492. },
  493. textboxView: {
  494. normal: {
  495. flex: 1,
  496. backgroundColor: '#e6e8e8',
  497. },
  498. error: {
  499. flex: 1,
  500. backgroundColor: '#e6e8e8',
  501. },
  502. notEditable: {
  503. flex: 1,
  504. backgroundColor: '#e6e8e8',
  505. }
  506. },
  507. };
  508.  
  509. export const makeReadOnlyFormOptions = (formStructure) => {
  510.  
  511. let optionsObj = {};
  512.  
  513. for(let idx=0; idx < formStructure.length; idx++) {
  514. optionsObj[formStructure[idx].fieldName] = {
  515. label: formStructure[idx].label,
  516. placeholder: formStructure[idx].placeholder,
  517. editable: false
  518. }
  519. if (formStructure[idx].fieldType == 'currency') {
  520. optionsObj[formStructure[idx].fieldName]['template'] = currencyTextBox
  521. }
  522. }
  523.  
  524. optionsObj = {
  525. stylesheet:readonlyFormStyles,
  526. auto:'placeholders',
  527. fields:optionsObj
  528. }
  529.  
  530. return optionsObj
  531. }
  532.  
  533. export const fixDateFormat = (date) => {
  534. if (typeof date === 'string' || date instanceof String){
  535. let sep = (date.indexOf('/') !== -1) ? '/' : '-';
  536. if (date.indexOf(sep) !== -1){
  537. nd = date.split(sep);
  538. if (nd.length == 3 && nd[0] < 32) {
  539. return [nd[1], nd[0], nd[2]].join('/');
  540. } else if (nd[0].length == 4) {
  541. return [nd[1], nd[2], nd[0]].join('/');
  542. }
  543. }
  544. }
  545. return date
  546. }
  547.  
  548. export const formatDate = (date) => {
  549.  
  550. date_ = fixDateFormat(date)
  551. let d = new Date(date);
  552.  
  553. if (d == 'Invalid Date'){
  554. throw 'Invalid Date';
  555. }
  556.  
  557. var month = '' + (d.getMonth() + 1),
  558. day = '' + d.getDate(),
  559. year = d.getFullYear();
  560.  
  561. if (month.length < 2) month = '0' + month;
  562. if (day.length < 2) day = '0' + day;
  563.  
  564. return [day, month, year].join('/');
  565. }
  566.  
  567. const InfoGrid = ({data,rowStyle,labelStyle,valueStyle, valStyle,labStyle,showAll,invertLabelPosition}) => {
  568. var data_lst = [];
  569. var tmp_value;
  570. for (var i=0; i<data.length; i++){
  571. if (data[i].grid_view || showAll) {
  572. if (data[i].value_type == 'currency') {
  573. tmp_value = Numeral(data[i].value).format('0,0.00') + ' NGN'
  574. } else {
  575. tmp_value = data[i].value
  576. }
  577. let topComponent = <Text style={valueStyle}>{tmp_value}</Text>
  578. let bottomComponent = <Text style={labelStyle}>{data[i].label}</Text>
  579. if (invertLabelPosition) {
  580. [topComponent,bottomComponent] = [bottomComponent,topComponent]
  581. }
  582. data_lst.push(
  583. <View style={rowStyle} key={i}>
  584. {topComponent}
  585. {bottomComponent}
  586. </View>
  587. )
  588. }
  589. };
  590. return (
  591. [...data_lst]
  592. );
  593. };
  594.  
  595. const MakeLinks = ({ onPress,data,baseStyle,labelStyle,valueStyle,
  596. colorData, underlayColor}) => {
  597. var data_lst = []
  598. for (var i=0; i<data.length; i++){
  599. let tmp_data = data[i],
  600. tmp_baseStyle;
  601. if (i == 0){
  602. tmp_baseStyle = [baseStyle, {marginTop:0}]
  603. } else {
  604. tmp_baseStyle = baseStyle
  605. }
  606. tmp_data = [
  607. {label:'Date Requested:', value:formatDate(tmp_data.date_requested)},
  608. {label:'Date Approved:', value:tmp_data.date_approved && formatDate(tmp_data.date_approved)},
  609. {label:'Loan Amount:', value:'₦ ' + Numeral(tmp_data.principal).format('0,0.00')},
  610. {label:'Tenor:', value:tmp_data.tenor},
  611. {label:'Interest Rate:', value:tmp_data.interest_rate||'-' + '%'},
  612. {label:'Amount Repaid:', value:'₦ ' + Numeral(tmp_data.amount_repaid).format('0,0.00')},
  613. {label:'Amount Due:', value:'₦ ' + Numeral(tmp_data.outstanding_amount).format('0,0.00')},
  614. {label:'Loan Product:', value:tmp_data.loan_product},
  615. {label:'Bank Paid To:', value:tmp_data.bank_paid_to},
  616. {label:'Account Paid To:', value:tmp_data.account_paid_to},
  617. {label:'Reason for Loan:', value:tmp_data.reason_for_loan},
  618. {label:'Loan Status:', value:tmp_data.loan_status},
  619. {label:'Installments Paid:', value:tmp_data.installments_paid}
  620. ]
  621. let installments = data[i].installments;
  622. let next_repayment = installments.find(i=>i.total_due > 1); // undefined if none found
  623. let statusCode = '01'; // assume fully paid by default
  624. if (next_repayment) {
  625. // check if next repayment due date is past
  626. statusCode = ((new Date(fixDateFormat(next_repayment.due_date)) > Date.now()) && '02')||'03'
  627. }
  628. data[i]['statusCode'] = statusCode;
  629.  
  630. data_lst.push(
  631. <View key={100+i}>
  632. <InfoGridLink
  633. colorData={colorData}
  634. data={data[i]}
  635. baseStyle={tmp_baseStyle}
  636. labelStyle={labelStyle}
  637. valueStyle={valueStyle}
  638. underlayColor={underlayColor}
  639. onPress={ ()=>onPress("LoanHistoryItem", {data:tmp_data, installments}) }
  640. />
  641. </View>
  642. )
  643. };
  644. return data_lst;
  645. };
  646.  
  647. const InfoGridLink = ({ onPress,data,baseStyle,labelStyle,valueStyle,
  648. colorData,underlayColor }) => {
  649.  
  650. let color = colorData[data.statusCode];
  651. let amtValue = Numeral(data.outstanding_amount).format('0,0.00') + ' NGN';
  652. if (data.statusCode == '01') amtValue = '';
  653.  
  654. return (
  655. <TouchableHighlight
  656. style={baseStyle}
  657. onPress={ onPress }
  658. underlayColor={underlayColor}
  659. >
  660. <View>
  661. <View style={{flexDirection:'row'}}>
  662. <View style={{flex:0.5}}>
  663. <Text style={valueStyle[0]}>{Numeral(data.principal).format('0,0.00') + ' NGN'}</Text>
  664. <Text style={labelStyle[0]}>Amount Obtained</Text>
  665. </View>
  666. <View style={{flex:0.5, alignItems:'flex-end'}}>
  667. <Text style={valueStyle[1]}>{formatDate(data.date_requested)}</Text>
  668. <Text style={labelStyle[1]}>Date Taken</Text>
  669. </View>
  670. </View>
  671. <View style={{flexDirection:'row'}}>
  672. <View style={{flex:0.5}}>
  673. <Text style={valueStyle[2]}>{data.reason_for_loan}</Text>
  674. <Text style={labelStyle[2]}>Loan Reason</Text>
  675. </View>
  676. <View style={{flex:0.5, alignItems:'flex-end'}}>
  677. <View style={{flex:0.73}}>
  678. <Text style={valueStyle[3]}>{amtValue}</Text>
  679. </View>
  680. <View style={{flex:0.27}}>
  681. <Text style={[labelStyle[3], {color:color.color}]}>{color.text}</Text>
  682. </View>
  683. </View>
  684. </View>
  685. </View>
  686. </TouchableHighlight>
  687. );
  688. };
  689.  
  690. InfoGridLink.PropTypes = {
  691. onPress: PropTypes.func,
  692. title: PropTypes.string
  693. };
  694.  
  695. export {InfoGridLink, InfoGrid, MakeLinks};
  696.  
  697.  
  698.  
  699. export const sendLocation = async (taskKey, userObject, location, user_event, source) => {
  700.  
  701. let location_data = JSON.stringify({...location, source}, null, 2),
  702. prev_location,
  703. event_type;
  704.  
  705. prev_location = await AsyncStorage.getItem('@user:user_location')
  706. prev_location = prev_location ? JSON.parse(prev_location) : {...location, source}
  707. await AsyncStorage.setItem('@user:user_location', location_data);
  708.  
  709. if (prev_location.source == source == 'location') {
  710. event_type = 'moving'
  711. } else if (prev_location.source == source == 'stationary') {
  712. event_type = 'stationary'
  713. } else if (prev_location.source != source == 'location') {
  714. event_type = 'started moving'
  715. } else if (prev_location.source != source == 'stationary') {
  716. event_type = 'stopped moving'
  717. } else {
  718. event_type = user_event
  719. }
  720.  
  721.  
  722. NetworkInfo.getIPV4Address(async ipv4 => {
  723. const requestPayload = {
  724. cmd: 'softcash.utils.add_tracking',
  725. mobileNumber: userObject.phonenos,
  726. ip: ipv4,
  727. gps: `${location.latitude}, ${location.longitude}`,
  728. date: moment().format('DD/MM/YYYY'),
  729. time: moment().format('HH:mm:ss'),
  730. imei: IMEI.getImei(),
  731. event: user_event,
  732. event_type: event_type,
  733. location_data: location_data
  734. };
  735. console.log(requestPayload)
  736. const response = await sendToFrappe(requestPayload);
  737. // IMPORTANT: task has to be ended by endTask
  738. if (!(taskKey == null)) BackgroundGeolocation.endTask(taskKey);
  739. });
  740. }
  741.  
  742. export const formatCurrency = (amt) => {
  743. return '₦ ' + Numeral(amt).format('0,0.00')
  744. }
  745.  
  746.  
  747. export const listenToSMS = (callback) => {
  748.  
  749. let subscription = SmsListener.addListener(message => {
  750. let verificationCodeRegex = /Your authentication token is ([\d]{6,})/im
  751. console.log('message object')
  752. console.log(message)
  753.  
  754. if (verificationCodeRegex.test(message.body)) {
  755. let verificationCode = message.body.match(verificationCodeRegex)[1]
  756. console.log('verification matched')
  757. console.log(verificationCode)
  758. callback(verificationCode);
  759. }
  760. })
  761. return subscription;
  762. }
  763.  
  764.  
  765. export function getPastDate(days,weeks, months){
  766. var today = new Date();
  767. var t_days = (parseInt(days) * 24 * 60 * 60 * 1000) || 0;
  768. var t_weeks = (parseInt(weeks) * 7 * 24 * 60 * 60 * 1000) || 0;
  769. var t_months = parseInt(months) || 0;
  770. var year = today.getFullYear();
  771. var n_date = new Date(Date.now() - t_days - t_weeks);
  772. var month = n_date.getMonth() + 1
  773. var day = n_date.getDate()
  774. while ((month - t_months) < 1){
  775. t_months = t_months - month;
  776. month = 12;
  777. year = year - 1;
  778. }
  779. var n_month = month - t_months;
  780. if (n_month.toString().length < 2) n_month = '0' + n_month;
  781. if (day.toString().length < 2) day = '0' + day;
  782. var s_date = [year, n_month, day].join('-');
  783. return new Date(s_date);
  784. }
  785.  
  786.  
  787. export const getCallLogs = ()=>{
  788. return new Promise((resolve)=>{
  789. CallLogs.show((logs)=>{
  790. resolve(logs)
  791. })
  792. })
  793. }
  794.  
  795.  
  796.  
  797. export const appStateListener = {
  798. add: async function(event, handler) {
  799. AppState.addEventListener(event, handler);
  800. },
  801. remove: function(event, handler) {
  802. AppState.removeEventListener(event, handler);
  803. }
  804. }
  805.  
  806.  
  807.  
  808. export const cardIcon = (cardBrand)=>{
  809. cardBrand = cardBrand.toLowerCase();
  810.  
  811. if (cardBrand.indexOf('visa') != -1) {
  812. cardBrand = 'visa';
  813. } else if (cardBrand.indexOf('mastercard') != -1) {
  814. cardBrand = 'mastercard';
  815. } else if (cardBrand.indexOf('verve') != -1) {
  816. cardBrand = 'verve';
  817. }
  818.  
  819. let icons = {
  820. visa: require('../img/visa-icon.png'),
  821. mastercard: require('../img/mastercard-icon.png'),
  822. verve: require('../img/verve-icon.png')
  823. }
  824. return (
  825. <Image
  826. source={icons[cardBrand]}
  827. style={{height:30, width:60, resizeMode:'contain'}}
  828. />
  829. )
  830. }
  831.  
  832.  
  833. export const cardsPicker = (cards, pickCard=false, onPress, onLongPress)=>{
  834. let retList = [];
  835. onPress = onPress ? onPress : ()=>{};
  836. onLongPress = onLongPress ? onLongPress : ()=>{};
  837. for(let i=0; i<cards.length; i++){
  838. let cardMask = '**** **** **** ' + cards[i].card_last4;
  839. let card_expiry = 'EXP: ' + cards[i].card_expiry;
  840. let card_brand = cards[i].card_brand.trim();
  841. let card_bank = cards[i].card_bank || 'NULL';
  842. let defaultCard = cards[i].default;
  843. if (defaultCard) {
  844. defaultCard = (
  845. <View>
  846. <Icon name="ios-checkmark-circle-outline" type="ionicon" color="white" size={30}/>
  847. </View>
  848. );
  849. } else {
  850. defaultCard = null;
  851. }
  852. retList.push(
  853. <View key={10+i} style={{
  854. marginVertical:5,
  855. marginHorizontal:10,
  856. }}>
  857. <TouchableHighlight onPress={()=>onPress(i)} onLongPress={()=>onLongPress(i)} underlayColor="#e3e3e3">
  858. <View>
  859. <View style={{
  860. backgroundColor:'#5816ae',
  861. borderRadius:5,
  862. paddingVertical: 10
  863. }}>
  864. <View style={{
  865. flexDirection:'row',
  866. justifyContent:'space-between',
  867. minHeight:1,
  868. paddingHorizontal:10,
  869. height:30
  870. }}>
  871. <View style={{flex:0.73, marginRight:10, flexDirection:'row', justifyContent:'space-between'}}>
  872. <Text style={{fontSize:18, color:'#fff', textAlignVertical:'center', fontWeight:'bold'}}>{card_brand.toUpperCase()}</Text>
  873. {defaultCard}
  874. </View>
  875. <View style={{flex:0.27, alignItems:'flex-end'}}>
  876. {cardIcon(card_brand)}
  877. </View>
  878. </View>
  879. <View style={{height:30, marginHorizontal:10}}>
  880. <Text style={{fontSize:18, color:'#fff', textAlignVertical:'center'}}>{card_bank.toUpperCase()}</Text>
  881. </View>
  882. <View style={{
  883. flexDirection:'row',
  884. justifyContent:'space-between',
  885. minHeight:1,
  886. paddingHorizontal:10,
  887. height:30
  888. }}>
  889. <Text style={{fontSize:20, color:'#fff'}}>{cardMask}</Text>
  890. <Text style={{fontSize:16, textAlignVertical:'center', color:'#fff'}}>{card_expiry}</Text>
  891. </View>
  892. </View>
  893. </View>
  894. </TouchableHighlight>
  895. </View>
  896. )
  897. }
  898. return retList;
  899. }
  900.  
  901.  
  902. export const showOverlay = (show, closeStatus=true, closeFn)=>(
  903. <View>
  904. <View style={{
  905. flex: 1,
  906. position: 'absolute',
  907. left: 0,
  908. top: 0,
  909. opacity: 0.5,
  910. backgroundColor: 'black',
  911. width: SCREEN_WIDTH,
  912. height:SCREEN_HEIGHT - HEADER_HEIGHT,
  913. zIndex:9
  914. }}/>
  915. <View style={{
  916. position: 'absolute',
  917. left: SCREEN_WIDTH * 0.05,
  918. top: SCREEN_HEIGHT * 0.1,
  919. height:SCREEN_HEIGHT * 0.65,
  920. width:SCREEN_WIDTH * 0.9,
  921. backgroundColor:'#fff',
  922. borderRadius:5,
  923. zIndex:10,
  924. alignItems: 'center'
  925. }}>
  926. <ScrollView>
  927. {show}
  928. </ScrollView>
  929. {
  930. closeStatus &&
  931. <TouchableHighlight onPress={closeFn} style={{margin:10, padding:5}}>
  932. <Text style={{textAlign: 'center', fontSize:20}}>Close</Text>
  933. </TouchableHighlight>
  934. }
  935. </View>
  936. </View>
  937. );
  938.  
  939.  
  940. export const freeze = (freezeMsg)=>(
  941. <View style={{
  942. flex: 1,
  943. position: 'absolute',
  944. left: 0,
  945. top: 0,
  946. opacity: 0.5,
  947. backgroundColor: 'black',
  948. width: SCREEN_WIDTH,
  949. height:SCREEN_HEIGHT - HEADER_HEIGHT,
  950. zIndex:9
  951. }}>
  952. <Text style={{
  953. marginVertical: SCREEN_HEIGHT * 0.65 * 0.5,
  954. marginHorizontal: SCREEN_WIDTH * 0.125,
  955. fontSize: 27,
  956. fontWeight: '100',
  957. color:'#f0f0f0',
  958. textAlign:'center'
  959. }}>{freezeMsg}</Text>
  960. </View>
  961. );
  962.  
  963.  
  964.  
  965.  
  966. export const MyModal = ({ view, onComplete, modalVisible}) => {
  967. return (
  968. <Modal
  969. animationType="slide"
  970. transparent={true}
  971. visible={modalVisible}
  972. onRequestClose={() => {
  973. alert('Modal has been closed.');
  974. }}>
  975. <View style={{marginVertical:0.2*SCREEN_HEIGHT, marginHorizontal:'17%', height:'52%', borderWidth:3, borderColor:'green', backgroundColor:'white', borderRadius:10}}>
  976. {view}
  977. </View>
  978. </Modal>
  979. )
  980. }
  981.  
  982. export const RenderPeriods = (data, extended) => {
  983. var data_lst = [];
  984. for (var i=0; i<data.length; i++){
  985. data_lst.push(
  986. <View style={{marginBottom:10, paddingBottom:5, marginHorizontal:10, backgroundColor:'#f3f3f3'}} key={i}>
  987. <View style={{
  988. flexDirection:'row',
  989. justifyContent:'space-between',
  990. borderBottomWidth:1,
  991. borderBottomColor:'brown'
  992. }}>
  993. <Icon name="event" size={20}/>
  994. <Text style={{fontSize:17, fontWeight:'500', color:'#000'}}>{formatDate(data[i].due_date)}</Text>
  995. </View>
  996. {
  997. extended &&
  998. <View style={{flexDirection:'row', justifyContent:'space-between'}}>
  999. <Text style={{fontSize:17}}>Principal Paid:</Text>
  1000. <Text style={{fontSize:17}}>{'₦ ' + Numeral(data[i].principal_paid).format('0,0.00')}</Text>
  1001. </View>
  1002. }
  1003. <View style={{flexDirection:'row', justifyContent:'space-between'}}>
  1004. <Text style={{fontSize:17}}>Principal Due:</Text>
  1005. <Text style={{fontSize:17}}>{'₦ ' + Numeral(data[i].principal_due).format('0,0.00')}</Text>
  1006. </View>
  1007. {
  1008. extended &&
  1009. <View style={{flexDirection:'row', justifyContent:'space-between'}}>
  1010. <Text style={{fontSize:17}}>Interest Paid:</Text>
  1011. <Text style={{fontSize:17}}>{'₦ ' + Numeral(data[i].interest_paid).format('0,0.00')}</Text>
  1012. </View>
  1013. }
  1014. <View style={{flexDirection:'row', justifyContent:'space-between'}}>
  1015. <Text style={{fontSize:17}}>Interest Due:</Text>
  1016. <Text style={{fontSize:17}}>{'₦ ' + Numeral(data[i].interest_due).format('0,0.00')}</Text>
  1017. </View>
  1018. <View style={{flexDirection:'row', justifyContent:'space-between'}}>
  1019. <Text style={{fontSize:17, color:'#0f0f0f'}}>Total:</Text>
  1020. <Text style={{fontSize:17, color:'#0f0f0f'}}>{'₦ ' + Numeral(data[i].total_due).format('0,0.00')}</Text>
  1021. </View>
  1022. </View>
  1023. );
  1024. };
  1025. return data_lst;
  1026. };
Add Comment
Please, Sign In to add comment