@seamlessdocs/payment-modals 1.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/.babelrc +13 -0
  2. package/.eslintrc.json +11 -0
  3. package/.idea/PaymentModals.iml +8 -0
  4. package/.idea/codeStyles/Project.xml +44 -0
  5. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/misc.xml +6 -0
  8. package/.idea/modules.xml +8 -0
  9. package/.idea/vcs.xml +6 -0
  10. package/.prettierrc +4 -0
  11. package/README.md +1 -0
  12. package/build/payment-modals.js +52 -0
  13. package/config/env.js +93 -0
  14. package/config/jest/cssTransform.js +14 -0
  15. package/config/jest/fileTransform.js +40 -0
  16. package/config/modules.js +88 -0
  17. package/config/paths.js +90 -0
  18. package/config/pnpTs.js +35 -0
  19. package/config/webpack.config.js +656 -0
  20. package/config/webpackDevServer.config.js +104 -0
  21. package/index.css +11 -0
  22. package/index.html +137 -0
  23. package/package.json +58 -0
  24. package/scripts/build.js +191 -0
  25. package/scripts/start.js +145 -0
  26. package/scripts/test.js +53 -0
  27. package/src/Components/ACHPaymentModal/ACHPaymentModal.module.css +118 -0
  28. package/src/Components/ACHPaymentModal/Form/FieldContainer/FieldContainer.module.css +40 -0
  29. package/src/Components/ACHPaymentModal/Form/FieldContainer/index.jsx +60 -0
  30. package/src/Components/ACHPaymentModal/Form/Form.module.css +81 -0
  31. package/src/Components/ACHPaymentModal/Form/index.jsx +189 -0
  32. package/src/Components/ACHPaymentModal/index.jsx +83 -0
  33. package/src/Components/ChooseModal/ChooseModal.module.css +114 -0
  34. package/src/Components/ChooseModal/index.jsx +34 -0
  35. package/src/Components/EmptyModal/index.jsx +7 -0
  36. package/src/Components/ErrorModal/ErrorModal.module.css +64 -0
  37. package/src/Components/ErrorModal/index.jsx +35 -0
  38. package/src/Components/ErrorOptionalModal/index.jsx +9 -0
  39. package/src/Components/Modal/Modal.module.css +29 -0
  40. package/src/Components/Modal/index.jsx +13 -0
  41. package/src/Components/PayNowModal/index.jsx +27 -0
  42. package/src/Components/ProcessingModal/ProcessingModal.module.css +50 -0
  43. package/src/Components/ProcessingModal/index.jsx +25 -0
  44. package/src/Components/SelectPaymentModal/SelectPaymentModal.module.css +212 -0
  45. package/src/Components/SelectPaymentModal/index.jsx +117 -0
  46. package/src/Components/SuccessModal/SuccessModal.module.css +34 -0
  47. package/src/Components/SuccessModal/index.jsx +23 -0
  48. package/src/OpenViewStyles.css +16 -0
  49. package/src/assets/img/back.svg +3 -0
  50. package/src/assets/img/bank-account.svg +7 -0
  51. package/src/assets/img/credit-card.svg +36 -0
  52. package/src/assets/img/error-icon.svg +1 -0
  53. package/src/assets/img/error.svg +3 -0
  54. package/src/assets/img/loader.svg +3 -0
  55. package/src/assets/img/lock-icon.svg +3 -0
  56. package/src/assets/img/logo.svg +6 -0
  57. package/src/assets/img/processing.gif +0 -0
  58. package/src/assets/img/success.svg +4 -0
  59. package/src/assets/img/valid-icon.svg +1 -0
  60. package/src/index.jsx +93 -0
  61. package/webpack.config.js +78 -0
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ // Do this as the first thing so that any code reading it knows the right env.
4
+ process.env.BABEL_ENV = 'test';
5
+ process.env.NODE_ENV = 'test';
6
+ process.env.PUBLIC_URL = '';
7
+
8
+ // Makes the script crash on unhandled rejections instead of silently
9
+ // ignoring them. In the future, promise rejections that are not handled will
10
+ // terminate the Node.js process with a non-zero exit code.
11
+ process.on('unhandledRejection', err => {
12
+ throw err;
13
+ });
14
+
15
+ // Ensure environment variables are read.
16
+ require('../config/env');
17
+
18
+
19
+ const jest = require('jest');
20
+ const execSync = require('child_process').execSync;
21
+ let argv = process.argv.slice(2);
22
+
23
+ function isInGitRepository() {
24
+ try {
25
+ execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
26
+ return true;
27
+ } catch (e) {
28
+ return false;
29
+ }
30
+ }
31
+
32
+ function isInMercurialRepository() {
33
+ try {
34
+ execSync('hg --cwd . root', { stdio: 'ignore' });
35
+ return true;
36
+ } catch (e) {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ // Watch unless on CI or explicitly running all tests
42
+ if (
43
+ !process.env.CI &&
44
+ argv.indexOf('--watchAll') === -1 &&
45
+ argv.indexOf('--watchAll=false') === -1
46
+ ) {
47
+ // https://github.com/facebook/create-react-app/issues/5210
48
+ const hasSourceControl = isInGitRepository() || isInMercurialRepository();
49
+ argv.push(hasSourceControl ? '--watch' : '--watchAll');
50
+ }
51
+
52
+
53
+ jest.run(argv);
@@ -0,0 +1,118 @@
1
+ .modalContainer {
2
+ overflow-y: auto;
3
+
4
+ box-sizing: border-box;
5
+ max-width: 600px;
6
+ height: 100%;
7
+ max-height: calc(100vh - 150px);
8
+
9
+ border-radius: none;
10
+ background: none;
11
+ }
12
+
13
+ .modal {
14
+ display: flex;
15
+
16
+ border-radius: 6px;
17
+ background: #fff;
18
+ }
19
+
20
+ .backIcon {
21
+ margin-right: 8px;
22
+ }
23
+
24
+ .backTextContainer {
25
+ display: flex;
26
+ align-items: center;
27
+
28
+ margin-bottom: 10px;
29
+
30
+ cursor: pointer;
31
+
32
+ color: white;
33
+
34
+ font-size: 13px;
35
+ line-height: 16px;
36
+ }
37
+
38
+ .paymentInfoContainer {
39
+ flex-shrink: 0;
40
+
41
+ box-sizing: border-box;
42
+ width: 165px;
43
+ padding: 10px;
44
+
45
+ border-radius: 6px 0px 0px 6px;
46
+ background: #e2e5ea;
47
+ }
48
+
49
+ .paymentFormContainer {
50
+ flex-grow: 1;
51
+
52
+ padding: 35px 45px 0px;
53
+ }
54
+
55
+ .paymentInfoWrapper {
56
+ display: flex;
57
+ align-items: center;
58
+
59
+ height: 100%;
60
+ }
61
+
62
+ .achTitle {
63
+ margin-bottom: 5px;
64
+
65
+ text-align: center;
66
+
67
+ color: #2c2f32;
68
+
69
+ font-size: 18px;
70
+ font-weight: bold;
71
+ line-height: 22px;
72
+ }
73
+
74
+ .descriptionContainer {
75
+ display: flex;
76
+ flex-direction: column;
77
+ }
78
+
79
+ .achDescription {
80
+ padding-bottom: 5px;
81
+
82
+ text-align: center;
83
+
84
+ color: #7e909f;
85
+ border-bottom: 2px solid white;
86
+
87
+ font-size: 13px;
88
+ font-weight: 500;
89
+ line-height: 16px;
90
+ }
91
+
92
+ .totalAmount {
93
+ margin: 25px 0 0;
94
+
95
+ text-align: center;
96
+
97
+ color: #1f53ac;
98
+
99
+ font-size: 23px;
100
+ font-weight: bold;
101
+ line-height: 28px;
102
+ }
103
+
104
+ .feeInfo {
105
+ margin: 13px 0 0;
106
+
107
+ text-align: center;
108
+
109
+ color: #7e909f;
110
+
111
+ font-size: 13px;
112
+ font-weight: 500;
113
+ line-height: 16px;
114
+ }
115
+
116
+ .moneyValue {
117
+ word-break: break-all;
118
+ }
@@ -0,0 +1,40 @@
1
+ .fieldContainer {
2
+ position: relative;
3
+
4
+ box-sizing: border-box;
5
+ padding: 10px;
6
+
7
+ border: 1px solid #d7e0e8;
8
+ border-radius: 5px;
9
+ background: #ffffff;
10
+ }
11
+
12
+ .fieldName {
13
+ margin: 0 0 5px;
14
+
15
+ text-align: left;
16
+
17
+ color: #081424;
18
+
19
+ font-size: 11px;
20
+ font-weight: bold;
21
+ line-height: 13px;
22
+ }
23
+
24
+ .validationIcon {
25
+ position: absolute;
26
+ top: 0;
27
+ right: 0;
28
+
29
+ margin: 8px;
30
+ }
31
+
32
+ .invalidField {
33
+ background: #fbf3f2;
34
+ }
35
+
36
+ .tooltip{
37
+ padding: 8px;
38
+
39
+ text-align: center;
40
+ }
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+ import classNames from 'classnames';
3
+ import PropTypes from 'prop-types';
4
+ import ReactTooltip from 'react-tooltip';
5
+
6
+ import { Field } from 'formik';
7
+
8
+ import errorIcon from '../../../../assets/img/error-icon.svg';
9
+ import validIcon from '../../../../assets/img/valid-icon.svg';
10
+
11
+ import styles from './FieldContainer.module.css';
12
+
13
+ const FieldContainer = ({ name, label, children }) => {
14
+ return (
15
+ <Field name={name}>
16
+ {({ field, meta }) => (
17
+ <div
18
+ className={classNames(styles.fieldContainer, {
19
+ [styles.invalidField]: meta.touched && meta.error
20
+ })}
21
+ >
22
+ <div className={styles.fieldName}>{label}</div>
23
+ {meta.touched && meta.error && (
24
+ <>
25
+ <img
26
+ data-tip
27
+ data-for={name}
28
+ className={styles.validationIcon}
29
+ src={errorIcon}
30
+ alt="error"
31
+ />
32
+ <ReactTooltip
33
+ className={styles.tooltip}
34
+ id={name}
35
+ place="top"
36
+ type="dark"
37
+ effect="solid"
38
+ >
39
+ <span>{meta.error}</span>
40
+ </ReactTooltip>
41
+ </>
42
+ )}
43
+ {meta.touched && !meta.error && (
44
+ <img className={styles.validationIcon} src={validIcon} alt="valid" />
45
+ )}
46
+
47
+ {children(field)}
48
+ </div>
49
+ )}
50
+ </Field>
51
+ );
52
+ };
53
+
54
+ FieldContainer.propTypes = {
55
+ name: PropTypes.string.isRequired,
56
+ label: PropTypes.string.isRequired,
57
+ children: PropTypes.func.isRequired
58
+ };
59
+
60
+ export default FieldContainer;
@@ -0,0 +1,81 @@
1
+ .fullNameContainer {
2
+ width: 100%;
3
+ margin-bottom: 13px;
4
+ }
5
+
6
+ .input {
7
+ width: 100%;
8
+ height: auto !important;
9
+ margin: 0 !important;
10
+ padding: 0 !important;
11
+
12
+ opacity: 0.7;
13
+ color: #081424 !important;
14
+ border: none !important;
15
+ outline: none !important;
16
+ background: transparent;
17
+ background-color: transparent !important;
18
+ box-shadow: none !important;
19
+
20
+ font-size: 16px !important;
21
+ line-height: 19px !important;
22
+ }
23
+
24
+ .routingNumberContainer {
25
+ margin-right: 7px;
26
+ }
27
+
28
+ .numberInfoContainer {
29
+ display: flex;
30
+
31
+ margin-bottom: 13px;
32
+ }
33
+
34
+ .submitBtn {
35
+ box-sizing: border-box;
36
+ width: 100%;
37
+ padding: 15px;
38
+
39
+ cursor: pointer;
40
+
41
+ color: #ffffff;
42
+ border: 1px solid #2c508d;
43
+ border-radius: 5px;
44
+ background: #1f53ac;
45
+
46
+ font-size: 16px;
47
+ font-weight: bold;
48
+ line-height: 19px;
49
+ }
50
+
51
+ .lockIcon {
52
+ margin-right: 10px;
53
+ }
54
+
55
+ .summaryError {
56
+ visibility: hidden;
57
+
58
+ margin: 0;
59
+ padding: 9px 30px 9px;
60
+
61
+ text-align: center;
62
+
63
+ color: #d0021b;
64
+
65
+ font-size: 16px;
66
+ line-height: 18px;
67
+ }
68
+
69
+ .summaryErrorVisible {
70
+ visibility: visible;
71
+ }
72
+
73
+ @media (max-width: 600px) {
74
+ .numberInfoContainer {
75
+ flex-direction: column;
76
+ }
77
+
78
+ .routingNumberContainer {
79
+ margin: 0 0 13px;
80
+ }
81
+ }
@@ -0,0 +1,189 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import classNames from 'classnames';
4
+ import Select from 'react-select';
5
+ import { Formik, Form } from 'formik';
6
+
7
+ import FieldContainer from './FieldContainer';
8
+
9
+ import lockIcon from '../../../assets/img/lock-icon.svg';
10
+
11
+ import styles from './Form.module.css';
12
+
13
+ const ACCOUNT_TYPES = [
14
+ { value: 'checkingPersonal', label: 'Checking (Personal)' },
15
+ { value: 'savingsPersonal', label: 'Savings (Personal)' },
16
+ { value: 'checkingBusiness', label: 'Checking (Business)' },
17
+ { value: 'savingBusiness', label: 'Saving (Business)' }
18
+ ];
19
+
20
+ const SELECT_CUSTOM_STYLES = {
21
+ control: provided => ({
22
+ ...provided,
23
+ minHeight: 'auto',
24
+ border: 'none',
25
+ fontsize: '16px',
26
+ lineHeight: '19px',
27
+ color: '#081424',
28
+ opacity: '0.7',
29
+ boxShadow: 'none',
30
+ backgroundColor: 'transparent',
31
+ '&:hover': {
32
+ border: 'none',
33
+ boxShadow: 'none'
34
+ }
35
+ }),
36
+ singleValue: provided => ({ ...provided, margin: '0' }),
37
+ placeholder: provided => ({ ...provided, margin: '0' }),
38
+ valueContainer: provided => ({ ...provided, padding: '0' }),
39
+ indicatorContainer: provided => ({ ...provided, padding: '0' }),
40
+ dropdownIndicator: provided => ({
41
+ ...provided,
42
+ padding: '0',
43
+ color: '#1F53AC',
44
+ '&:hover': {
45
+ color: '#1F53AC'
46
+ }
47
+ }),
48
+ menuList: provided => ({
49
+ ...provided,
50
+ fontsize: '16px',
51
+ lineHeight: '19px',
52
+ color: '#081424',
53
+ textAlign: 'left'
54
+ }),
55
+ input: provided => ({
56
+ ...provided,
57
+ '& input': {
58
+ height: 'auto !important',
59
+ lineHeight: 'normal !important'
60
+ }
61
+ })
62
+ };
63
+
64
+ const validate = values => {
65
+ const errors = {};
66
+
67
+ if (!values.firstName) {
68
+ errors.firstName = 'Required field';
69
+ }
70
+
71
+ if (!values.lastName) {
72
+ errors.lastName = 'Required field';
73
+ }
74
+
75
+ if (!values.accountType) {
76
+ errors.accountType = 'Required field';
77
+ }
78
+
79
+ if (!values.routingNumber) {
80
+ errors.routingNumber = 'Required field';
81
+ } else if (!/^\d+$/.test(values.routingNumber)) {
82
+ errors.routingNumber = 'Must be a number';
83
+ } else if (values.routingNumber.toString().length !== 9) {
84
+ errors.routingNumber = 'Routing number structure is not valid';
85
+ }
86
+
87
+ if (!values.accountNumber) {
88
+ errors.accountNumber = 'Required field';
89
+ } else if (!/^\d+$/.test(values.accountNumber)) {
90
+ errors.accountNumber = 'Must be a number';
91
+ } else if (
92
+ values.accountNumber.toString().length < 9 ||
93
+ values.accountNumber.toString().length > 12
94
+ ) {
95
+ errors.accountNumber = 'Account number structure is not valid';
96
+ }
97
+
98
+ return errors;
99
+ };
100
+
101
+ const ACHForm = ({ onPay }) => {
102
+ return (
103
+ <Formik
104
+ initialValues={{
105
+ firstName: '',
106
+ lastName: '',
107
+ accountNumber: '',
108
+ routingNumber: '',
109
+ accountType: null
110
+ }}
111
+ validate={validate}
112
+ onSubmit={values => {
113
+ onPay(
114
+ values.firstName,
115
+ values.lastName,
116
+ values.routingNumber,
117
+ values.accountNumber,
118
+ values.accountType.value
119
+ );
120
+ }}
121
+ >
122
+ {({ isValid, submitCount, setFieldValue, setFieldTouched }) => (
123
+ <Form>
124
+ <div className={styles.fullNameContainer}>
125
+ <FieldContainer name="firstName" label="First Name">
126
+ {field => <input className={styles.input} type="text" {...field} />}
127
+ </FieldContainer>
128
+ </div>
129
+ <div className={styles.fullNameContainer}>
130
+ <FieldContainer name="lastName" label="Last Name">
131
+ {field => <input className={styles.input} type="text" {...field} />}
132
+ </FieldContainer>
133
+ </div>
134
+ <div className={styles.numberInfoContainer}>
135
+ <div className={styles.routingNumberContainer}>
136
+ <FieldContainer name="routingNumber" label="Routing #">
137
+ {field => <input className={styles.input} type="text" {...field} />}
138
+ </FieldContainer>
139
+ </div>
140
+ <div className={styles.accountNumberContainer}>
141
+ <FieldContainer name="accountNumber" label="Account #">
142
+ {field => <input className={styles.input} type="text" {...field} />}
143
+ </FieldContainer>
144
+ </div>
145
+ </div>
146
+
147
+ <div className={styles.fullNameContainer}>
148
+ <FieldContainer name="accountType" label="Account Type">
149
+ {field => (
150
+ <Select
151
+ styles={SELECT_CUSTOM_STYLES}
152
+ value={field.value}
153
+ placeholder="Select Account Type ..."
154
+ onChange={option => {
155
+ setFieldTouched('accountType');
156
+ setFieldValue('accountType', option);
157
+ }}
158
+ options={ACCOUNT_TYPES}
159
+ components={{
160
+ IndicatorSeparator: () => null
161
+ }}
162
+ />
163
+ )}
164
+ </FieldContainer>
165
+ </div>
166
+
167
+ <button className={styles.submitBtn} type="submit">
168
+ <img className={styles.lockIcon} src={lockIcon} alt="lock payment" />
169
+ Authorize Payment
170
+ </button>
171
+
172
+ <div
173
+ className={classNames(styles.summaryError, {
174
+ [styles.summaryErrorVisible]: !!submitCount && !isValid
175
+ })}
176
+ >
177
+ Please correct invalid fields
178
+ </div>
179
+ </Form>
180
+ )}
181
+ </Formik>
182
+ );
183
+ };
184
+
185
+ ACHForm.propTypes = {
186
+ onPay: PropTypes.func.isRequired
187
+ };
188
+
189
+ export default ACHForm;
@@ -0,0 +1,83 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import Modal from '../Modal';
5
+ import ACHForm from './Form';
6
+
7
+ import backIcon from '../../assets/img/back.svg';
8
+
9
+ import styles from './ACHPaymentModal.module.css';
10
+
11
+ const ACHPaymentModal = ({
12
+ amount,
13
+ totalAmount,
14
+ feeAmount,
15
+ description,
16
+ feeName,
17
+ onPay,
18
+ onClose
19
+ }) => {
20
+ return (
21
+ <Modal className={styles.modalContainer}>
22
+ <div
23
+ className={styles.backTextContainer}
24
+ onClick={onClose}
25
+ onKeyDown={onClose}
26
+ role="button"
27
+ tabIndex="0"
28
+ >
29
+ <img className={styles.backIcon} src={backIcon} alt="back" />
30
+ Back to form
31
+ </div>
32
+ <div className={styles.modal}>
33
+ <div className={styles.paymentInfoContainer}>
34
+ <div className={styles.paymentInfoWrapper}>
35
+ <div>
36
+ <div className={styles.descriptionContainer}>
37
+ <span className={styles.achTitle}>ACH Payment</span>
38
+ <span className={styles.achDescription}>{description}</span>
39
+ </div>
40
+
41
+ <div className={styles.totalAmount}>
42
+ <currency>$</currency>
43
+ <money className={styles.moneyValue}>{Number(totalAmount).toFixed(2)}</money>
44
+ </div>
45
+
46
+ {!!feeAmount && (
47
+ <div className={styles.feeInfo}>
48
+ <currency>$</currency>
49
+ <money className={styles.moneyValue}>{Number(amount).toFixed(2)}</money>
50
+ {' submission + '}
51
+ <currency>$</currency>
52
+ <money>{Number(feeAmount).toFixed(2)}</money>
53
+ {` ${feeName || 'processing fee'}`}
54
+ </div>
55
+ )}
56
+ </div>
57
+ </div>
58
+ </div>
59
+ <div className={styles.paymentFormContainer}>
60
+ <ACHForm onPay={onPay} />
61
+ </div>
62
+ </div>
63
+ </Modal>
64
+ );
65
+ };
66
+
67
+ ACHPaymentModal.propTypes = {
68
+ onPay: PropTypes.func.isRequired,
69
+ onClose: PropTypes.func.isRequired,
70
+ amount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
71
+ totalAmount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
72
+ description: PropTypes.string,
73
+ feeName: PropTypes.string,
74
+ feeAmount: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
75
+ };
76
+
77
+ ACHPaymentModal.defaultProps = {
78
+ feeAmount: '',
79
+ description: '',
80
+ feeName: ''
81
+ };
82
+
83
+ export default ACHPaymentModal;