1 | import React, { Component } from 'react';
|
2 | import { connect } from 'react-redux';
|
3 | require('./array');
|
4 | import {
|
5 | Container,
|
6 | Header,
|
7 | List,
|
8 | ListItem,
|
9 | InputGroup,
|
10 | Input,
|
11 | Title,
|
12 | Content,
|
13 | Footer,
|
14 | FooterTab,
|
15 | Button,
|
16 | Picker,
|
17 | Icon,
|
18 | Text
|
19 | } from 'native-base';
|
20 | import * as Titles from './titles';
|
21 | import * as Common from './common';
|
22 | import * as UIA from './actions/uiActions';
|
23 | import { Colors } from './colors';
|
24 |
|
25 | export const FirstName = 'firstName';
|
26 | export const LastName = 'lastName';
|
27 | export const BusinessName = 'businessName';
|
28 | export const SupportEmail = 'supportEmail';
|
29 | export const StripeAccountLegalEntityOptions = () => {
|
30 | return {
|
31 |
|
32 | [FirstName]: validation(['notempty', 'alphanumericlike', 'maxlength22']),
|
33 | [LastName]: validation(['notempty', 'alphanumericlike', 'maxlength22']),
|
34 | 'maidenName': validation(['notempty', 'alphanumericlike', 'maxlength22']),
|
35 | 'personalIdNumber': validation(['notempty', 'length9']),
|
36 | 'accountNumber': validation(['notempty', 'maxlength22']),
|
37 | 'url': validation(['url_empty']),
|
38 | [BusinessName]: validation(['notempty', 'maxlength50']),
|
39 | 'businessUrl': validation(['url_empty']),
|
40 | [AddressCity]: validation(['notempty', 'maxlength50', 'alphanumericlike']),
|
41 | [AddressLine1]: validation(['notempty', 'maxlength50', 'alphanumericlike']),
|
42 | 'productDescription': validation(['maxlength50', 'alphanumericlike']),
|
43 | 'statementDescriptor': validation(['maxlength22', 'alphanumericlike']),
|
44 | [SupportEmail]: validation(['email_empty']),
|
45 | 'supportUrl': validation(['url_empty']),
|
46 | [AddressPostalCode]: validation(['numbers', 'length5']),
|
47 | 'endDate': validation(['pastdate']),
|
48 | };
|
49 | }
|
50 | export const AddressPostalCode = 'addressPostalCode';
|
51 | export const AddressCity = 'addressCity';
|
52 | export const AddressZip = 'addressZip';
|
53 | export const AddressLine1 = 'addressLine1';
|
54 | export function ValidatedCreditCard() {
|
55 | return {
|
56 | 'name': validation(['notempty', 'alphanumericlike', 'maxlength50']),
|
57 | 'email': validation(['email_empty']),
|
58 | 'number': validation(['notempty', 'length14t19', 'credit']),
|
59 | 'cvc': validation(['notempty', 'length3t4']),
|
60 | [AddressLine1]: validation(['maxlength50']),
|
61 | 'addressLine2': validation(['maxlength50']),
|
62 | [AddressCity]: validation(['alphanumericlike']),
|
63 | [AddressZip]: validation(['zipempty']),
|
64 | 'expirationYear': validation(['expirationYear'], {
|
65 | year: 'expirationYear',
|
66 | month: 'expirationMonth'
|
67 | }),
|
68 | 'expirationMonth': validation(['expirationMonth'], {
|
69 | year: 'expirationYear',
|
70 | month: 'expirationMonth'
|
71 | })
|
72 | }
|
73 | }
|
74 | export function ValidateCreditCard(me, state) {
|
75 | var _validation = ValidatedCreditCard();
|
76 | var valid = validate(me, _validation, state);
|
77 |
|
78 | me.props.UI(UIA.CREDIT_CARD_VALID, valid);
|
79 |
|
80 | return valid;
|
81 | }
|
82 |
|
83 | export const Email = 'email';
|
84 | export function ValidateStripeManagedAccount(me, stripeState) {
|
85 | var _validation = {
|
86 | [Email]: validation(['email_empty']),
|
87 | [BusinessName]: validation(['notempty', 'maxlength50', 'alphanumericlike']),
|
88 | 'businessUrl': validation(['url_empty']),
|
89 | 'productDescription': validation(['notempty', 'maxlength50']),
|
90 | 'statementDescriptor': validation(['notempty', 'maxlength22']),
|
91 | 'supportEmail': validation(['email_empty']),
|
92 | 'supportUrl': validation(['url_empty']),
|
93 | }
|
94 |
|
95 | var valid = validate(me, _validation, stripeState);
|
96 | me.props.UI(LA.ADD_BANK_ACCOUNT_STATE_VALID, valid, true);
|
97 | return valid;
|
98 | }
|
99 |
|
100 | export const PersonalAddressCity = 'personalAddressCity';
|
101 | export const PersonalAddressPostalCode = 'personalAddressPostalCode';
|
102 | export const PersonalAddressLine1 = 'personalAddressLine1';
|
103 | export function ValidateStripeAccountPersonalAddress(me, stripeState) {
|
104 |
|
105 | var _validation = {
|
106 | [PersonalAddressLine1]: validation(['notempty', 'maxlength50', 'alphanumericlike']),
|
107 | [PersonalAddressCity]: validation(['notempty', 'maxlength50', 'alphanumericlike']),
|
108 | [PersonalAddressPostalCode]: validation(['zip', 'notempty', 'numbers']),
|
109 | }
|
110 |
|
111 | var valid = validate(me, _validation, stripeState);
|
112 | me.props.UI(LA.ADD_STRIPE_ACCOUNT_LEGAL_ENTITY_OPTIONS_STATE_VALID, valid);
|
113 |
|
114 | me.props.UI(LA.ADD_STRIPE_ACCOUNT_LEGAL_ENTITY_OPTIONS_STATE, Object.assign({}, stripeState), true);
|
115 |
|
116 | }
|
117 | export function ValidateStripeAccountLegalEntityOptions(me, stripeState) {
|
118 | var _validation = StripeAccountLegalEntityOptions();
|
119 | var valid = validate(me, _validation, stripeState);
|
120 |
|
121 | me.props.UI(LA.ADD_STRIPE_ACCOUNT_LEGAL_ENTITY_OPTIONS_STATE_VALID, valid);
|
122 | me.props.UI(LA.ADD_STRIPE_ACCOUNT_LEGAL_ENTITY_OPTIONS_STATE, Object.assign({}, stripeState), true);
|
123 |
|
124 | return valid;
|
125 | }
|
126 |
|
127 | export function validateBank(me) {
|
128 |
|
129 | var { state } = me.props;
|
130 |
|
131 | var ADD_STRIPE_ACCOUNT_BANK_ACCOUNT_OPTIONS = UIA.Get(state, LA.ADD_STRIPE_ACCOUNT_BANK_ACCOUNT_OPTIONS) || {};
|
132 | var ADD_BANK_ACCOUNT_STATE = UIA.Get(state, LA.ADD_BANK_ACCOUNT_STATE);
|
133 | var ADD_STRIPE_ACCOUNT_LEGAL_ENTITY_OPTIONS_STATE = UIA.Get(state, LA.ADD_STRIPE_ACCOUNT_LEGAL_ENTITY_OPTIONS_STATE) || {};
|
134 |
|
135 | return ValidateStripeAccountBankAccountOptions(me, ADD_STRIPE_ACCOUNT_BANK_ACCOUNT_OPTIONS) &&
|
136 | ValidateStripeManagedAccount(me, ADD_BANK_ACCOUNT_STATE) &&
|
137 | ValidateStripeAccountLegalEntityOptions(me, ADD_STRIPE_ACCOUNT_LEGAL_ENTITY_OPTIONS_STATE);
|
138 | }
|
139 |
|
140 | export function ValidateStripeAccountBankAccountOptions(me, stripeState) {
|
141 | var _validation = {
|
142 | 'accountNumber': validation(['notempty', 'numbers', 'length9to17']),
|
143 | 'bankName': validation(['notempty', 'alphanumericlike']),
|
144 | 'accountHolderName': validation(['notempty', 'alphanumericlike']),
|
145 | 'routingNumber': validation(['notempty', 'numbers', 'length9']),
|
146 | }
|
147 |
|
148 | var valid = validate(me, _validation, stripeState);
|
149 | me.props.UI(LA.ADD_STRIPE_ACCOUNT_BANK_ACCOUNT_OPTIONS_VALID, valid);
|
150 | me.props.UI(LA.ADD_STRIPE_ACCOUNT_BANK_ACCOUNT_OPTIONS, stripeState, true);
|
151 | return valid;
|
152 | }
|
153 |
|
154 | function numbers(x) {
|
155 | return !(x || '').toString().split('').find(t => {
|
156 | return '0123456789'.indexOf(t) === -1;
|
157 | });
|
158 | }
|
159 |
|
160 | function isntDependentAndHidden(prop, ui, obj) {
|
161 |
|
162 | if (obj && ui.properties[prop].find(t => t.dependsOn)) {
|
163 | var res = true;
|
164 | ui.properties[prop].find(t => {
|
165 | Object.keys(t.extensions || {}).map(key => {
|
166 | if (t.extensions[key] &&
|
167 | t.extensions[key].dependsOn &&
|
168 | t.extensions[key].property &&
|
169 | t.extensions[key].match &&
|
170 | t.extensions[key].match.find(v => obj[t.extensions[key].property.lowercaseFirstLetter()] === v) === undefined) {
|
171 | res = false;
|
172 | }
|
173 | })
|
174 | });
|
175 | return res;
|
176 | }
|
177 | return true;
|
178 | }
|
179 |
|
180 | export function validateUI(ui, obj) {
|
181 | if (ui && ui.properties) {
|
182 | var _validation = {};
|
183 | for (var prop in ui.properties) {
|
184 | var vrules = [];
|
185 | (ui.properties[prop] || []).filter(t => {
|
186 | return isntDependentAndHidden(prop, ui, obj);
|
187 | }).map(t => {
|
188 | vrules = [...vrules, ...(t.validationRules || [])];
|
189 | })
|
190 | if (vrules && vrules.length) {
|
191 | var validationTexts = {};
|
192 | ui.properties[prop].map(t => {
|
193 | if (t) {
|
194 | validationTexts = { ...validationTexts, ...t.validationTexts };
|
195 | }
|
196 | })
|
197 | _validation[prop] = validation(vrules, { validationTexts });
|
198 | }
|
199 | }
|
200 |
|
201 | var stripeState = obj;
|
202 | var valid = validate(_validation, stripeState, (t, v) => {
|
203 | return t[v];
|
204 | });
|
205 | return valid;
|
206 | }
|
207 | }
|
208 | export function validation(args, opts) {
|
209 | var { validationTexts } = (opts || {})
|
210 | return args.map(x => {
|
211 | var temp = (function () {
|
212 | var validationText = (validationTexts || {})[x];
|
213 | switch (x) {
|
214 | case 'zipempty':
|
215 | return {
|
216 | func: x => !x || (x.length === 5 && numbers(x)),
|
217 | message: validationText || Titles.ZipCodeInvalid
|
218 | }
|
219 |
|
220 | case 'zip':
|
221 | return {
|
222 | func: x => x.length === 5 && numbers(x),
|
223 | message: validationText || Titles.ZipCodeInvalid
|
224 | }
|
225 | case 'pastdate':
|
226 | case 'beforenow':
|
227 | return {
|
228 | func: v => {
|
229 | try {
|
230 | var date = new Date(Date.parse(v));
|
231 | return Date.now() - date.getTime() > 0;
|
232 | }
|
233 | catch (e) { return false }
|
234 | },
|
235 | message: validationText || Titles.MustBeInThePast
|
236 | }
|
237 | case '18plus':
|
238 | return {
|
239 | func: v => {
|
240 | try {
|
241 | var date = new Date(Date.parse(v));
|
242 | return Date.now() - date.getTime() > 5.676e+11;
|
243 | }
|
244 | catch (e) { return false }
|
245 |
|
246 | },
|
247 | message: validationText || Titles.MustBeAtLeast18
|
248 | }
|
249 | case 'expirationYear':
|
250 | return {
|
251 | func: (v, obj) => {
|
252 | if (obj && opts && opts.month && opts.year) {
|
253 | var date = new Date();
|
254 | var month = date.getUTCMonth() + 1;
|
255 | var year = date.getUTCFullYear();
|
256 |
|
257 | if (year > parseFloat(obj[opts.year])) {
|
258 | return false;
|
259 | }
|
260 | }
|
261 | return true;
|
262 | },
|
263 | message: validationText || Titles.InvalidYear
|
264 | }
|
265 | case 'expirationMonth':
|
266 | return {
|
267 | func: (v, obj) => {
|
268 | if (obj && opts && opts.month && opts.year) {
|
269 | var date = new Date();
|
270 | var month = date.getUTCMonth() + 1;
|
271 | var year = date.getUTCFullYear();
|
272 | if ((month > parseFloat(obj[opts.month])) && year === parseFloat(obj[opts.year])) {
|
273 | return false;
|
274 | }
|
275 | if (year > parseFloat(obj[opts.year])) {
|
276 | return false;
|
277 | }
|
278 | }
|
279 | return true;
|
280 | },
|
281 | message: validationText || Titles.InvalidMonth
|
282 | }
|
283 | case 'email':
|
284 | return {
|
285 | func: v => validateEmail(v),
|
286 | message: validationText || Titles.EnterValidEmail,
|
287 | }
|
288 | case 'maxlength22':
|
289 | return {
|
290 | func: x => x.length <= 22,
|
291 | message: validationText || Titles.TooLong,
|
292 | }
|
293 | case 'length16':
|
294 | return {
|
295 | func: x => x.length === 16,
|
296 | message: validationText || Titles.IncorrectLength,
|
297 | }
|
298 | case 'length14t19':
|
299 | return {
|
300 | func: x => x.length >= 14 && x.length <= 19,
|
301 | message: validationText || Titles.IncorrectLength,
|
302 | }
|
303 | case 'credit':
|
304 | return {
|
305 | func: x => {
|
306 | return CredCardValidations.find(j => {
|
307 | return j.startsWith.find(t => x.startsWith(t)) && j.lengths.find(t => x.length == t);
|
308 | })
|
309 | },
|
310 | message: validationText || Titles.InvalidCard
|
311 | }
|
312 | case 'length3':
|
313 | return {
|
314 | func: x => x.length === 3,
|
315 | message: validationText || Titles.IncorrectLength,
|
316 | }
|
317 |
|
318 | case 'maxlength50':
|
319 | return {
|
320 | func: x => x.length <= 50,
|
321 | message: validationText || Titles.TooLong,
|
322 | }
|
323 | case 'email_empty':
|
324 | return {
|
325 | func: v => !v || validateEmail(v),
|
326 | message: validationText || Titles.EnterValidEmail,
|
327 | }
|
328 | case 'url':
|
329 | return {
|
330 | func: v => isUrlValid(v),
|
331 | message: validationText || Titles.ValidUrl
|
332 | }
|
333 | case 'url_empty':
|
334 | return {
|
335 | func: v => !(v || '').toString().trim() || isUrlValid(v),
|
336 | message: validationText || Titles.ValidUrl,
|
337 | }
|
338 | case 'notempty':
|
339 | return {
|
340 | func: v => {
|
341 | if (Array.isArray(v)) {
|
342 | return v.length;
|
343 | }
|
344 | return v
|
345 | },
|
346 | message: validationText || Titles.CantBeEmpty
|
347 | };
|
348 | case 'debit':
|
349 | return {
|
350 | func: v => {
|
351 | var tests = {
|
352 | 'name': validation(['notempty', 'alphanumericlike', 'maxlength50']),
|
353 | 'number': validation(['notempty', 'length14t19', 'credit']),
|
354 | 'cvc': validation(['notempty', 'length3t4']),
|
355 | 'expirationYear': validation(['expirationYear'], {
|
356 | year: 'expirationYear',
|
357 | month: 'expirationMonth'
|
358 | }),
|
359 | 'expirationMonth': validation(['expirationMonth'], {
|
360 | year: 'expirationYear',
|
361 | month: 'expirationMonth'
|
362 | })
|
363 | }
|
364 | var res = validate(tests, v || {}, (x, y) => { return x ? x[y] : null });
|
365 | return res.result;
|
366 | },
|
367 | message: validationText || Titles.DebitIncorrect
|
368 | }
|
369 | case 'year':
|
370 | return {
|
371 | func: x => !`${x}` || (x || '').length === 0 || (x.length === 4 && !(`${x}`.split('').findIndex(y => `0123456789`.indexOf(y) !== -1))),
|
372 | message: validationText || Titles.YearInvalid
|
373 | }
|
374 | case 'cvc':
|
375 | return {
|
376 | func: x => x.length >= 3 && x.length <= 4,
|
377 | message: validationText || Titles.Length3t4
|
378 | }
|
379 | case 'length3t4':
|
380 | return {
|
381 | func: x => x.length >= 3 && x.length <= 4,
|
382 | message: validationText || Titles.Length3t4
|
383 | }
|
384 |
|
385 | case 'length12':
|
386 | return {
|
387 | func: x => x.length === 12,
|
388 | message: validationText || Titles.Length12
|
389 | }
|
390 | case 'socialsecurity':
|
391 | return {
|
392 | func: x => x && x.length === 9,
|
393 | message: validationText || Titles.InvalidSS
|
394 | }
|
395 | case 'length9to17':
|
396 | return {
|
397 | func: x =>
|
398 | x.length === 12 ||
|
399 | x.length === 13 ||
|
400 | x.length === 14 ||
|
401 | x.length === 15 ||
|
402 | x.length === 16 ||
|
403 | x.length === 17 ||
|
404 | x.length === 11 ||
|
405 | x.length === 10 ||
|
406 | x.length === 9,
|
407 | message: validationText || Titles.Length9to17
|
408 | }
|
409 | case 'length8':
|
410 | return {
|
411 | func: x => x.length === 8,
|
412 | message: validationText || Titles.Length8
|
413 | }
|
414 | case 'length9':
|
415 | return {
|
416 | func: x => x.length === 9,
|
417 | message: validationText || Titles.Length9
|
418 | };
|
419 | case 'length4':
|
420 | return {
|
421 | func: x => x.length === 4,
|
422 | message: validationText || Titles.Length4
|
423 | }
|
424 | case 'length5':
|
425 | return {
|
426 | func: x => x.length === 5,
|
427 | message: validationText || Titles.Length5
|
428 | }
|
429 | case 'numeric':
|
430 | case 'numbers':
|
431 | return {
|
432 | func: numbers,
|
433 | message: validationText || Titles.OnlyNumbersAllowed
|
434 | };
|
435 | case 'alphanumericlike':
|
436 | return {
|
437 | func: x => !(x || '').toString().split('').find(t => {
|
438 | t = t.toLowerCase();
|
439 | return 'abcdefghijk lmnopqrstuvwxyz,.;\'0123456789'.indexOf(t) === -1;
|
440 | }),
|
441 | message: validationText || Titles.ValidCharacters
|
442 | };
|
443 | }
|
444 | })();
|
445 | if (temp) {
|
446 | Object.assign(temp, { name: x });
|
447 | }
|
448 | return temp;
|
449 | });
|
450 | }
|
451 | export function GetCardType(x) {
|
452 | return CredCardValidations.find(j => {
|
453 | return j.startsWith.find(t => x.startsWith(t)) && j.lengths.find(t => x.length == t);
|
454 | });
|
455 | }
|
456 |
|
457 | const CredCardValidations = [
|
458 | { name: 'American Express', startsWith: ['34', '37'], lengths: [15] },
|
459 | { name: 'Diners Club - Carte Blanche', startsWith: ['300', '301', '302', '303', '304', '305'], lengths: [14] },
|
460 | { name: 'Diners Club - International', startsWith: ['36'], lengths: [14] },
|
461 | { name: 'Diners Club - USA & Canada', startsWith: ['54'], lengths: [16] },
|
462 | { name: 'Discover', startsWith: [...[].interpolate(622126, 622925 + 1, x => x).map(x => x.toString()), ...['6011', '644', '645', '646', '647', '648', '649', '65']], lengths: [16, 17, 18, 19] },
|
463 | { name: 'InstaPayment', startsWith: [...[637, 638, 639].map(x => x.toString())], lengths: [16] },
|
464 | { name: 'JCB', startsWith: [...[].interpolate(3528, 3589 + 1, x => x).map(x => x.toString())], lengths: [16, 17, 18, 19] },
|
465 | { name: 'Maestro', startsWith: [...[5018, 5020, 5038, 5893, 6304, 6759, 6761, 6762, 6763].map(x => x.toString())], lengths: [16, 17, 18, 19] },
|
466 | { name: 'MasterCard', startsWith: [...[].interpolate(222100, 272099 + 1, x => x.toString()), ...[51, 52, 53, 54, 55].map(x => x.toString())], lengths: [16, 17, 18, 19] },
|
467 | { name: 'Visa', startsWith: [...[4].map(x => x.toString())], lengths: [16, 13, 19] },
|
468 | { name: 'Visa Electron', startsWith: [...[4026, 417500, 4508, 4844, 4913, 4917].map(x => x.toString())], lengths: [16] }];
|
469 |
|
470 | export function InputField(value, iconName, dark) {
|
471 | return {
|
472 | errorIcon: () => {
|
473 | if (value) {
|
474 | return <Icon name='md-flag' style={{ color: Colors.Color5 }} />
|
475 | }
|
476 | if (iconName)
|
477 | return <Icon name={iconName} style={{ color: Colors.Color5 }} />;
|
478 | return null;
|
479 | },
|
480 | errorText: () => {
|
481 | var text = value;
|
482 | if (text) {
|
483 | return Common.ErrorText(text);
|
484 | }
|
485 | return null;
|
486 | },
|
487 | };
|
488 | }
|
489 | function validateEmail(email) {
|
490 | var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
491 | return re.test(email);
|
492 | }
|
493 |
|
494 | function isUrlValid(userInput) {
|
495 | var res = userInput.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
|
496 | if (res == null)
|
497 | return false;
|
498 | else
|
499 | return true;
|
500 | }
|
501 | export function validate(validation, stripeState, getValue) {
|
502 | var result = { result: true };
|
503 | var validationState = {};
|
504 | for (var key in validation) {
|
505 | var rules = validation[key];
|
506 | var _rule = null;
|
507 | if (rules.find(rule => {
|
508 | if (!stripeState) {
|
509 | return true;
|
510 | }
|
511 | var _validationStateValue = getValue(stripeState, key);
|
512 | if (stripeState.hasOwnProperty(key) && !rule.func(_validationStateValue, stripeState)) {
|
513 | _rule = rule;
|
514 | return true;
|
515 | }
|
516 | return false;
|
517 | })) {
|
518 | validationState = Object.assign(validationState, { [key]: _rule ? _rule.message : Titles.Required })
|
519 | result.result = false;
|
520 | }
|
521 | else {
|
522 | validationState = Object.assign(validationState, { [key]: false })
|
523 | }
|
524 | }
|
525 | result.validationState = validationState;
|
526 | return result;
|
527 | } |
\ | No newline at end of file |