@thecb/components 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/.github/workflows/bump-version.yml +30 -0
  2. package/.github/workflows/create-release/build-body.sh +35 -0
  3. package/.github/workflows/create-release.yml +52 -0
  4. package/.github/workflows/publish-update.yml +73 -0
  5. package/README.md +68 -90
  6. package/dist/index.cjs.js +49122 -0
  7. package/package.json +17 -37
  8. package/rollup.config.js +43 -23
  9. package/src/components/atoms/button-with-action/ButtonWithAction.js +25 -4
  10. package/src/components/atoms/button-with-action/ButtonWithAction.theme.js +64 -234
  11. package/src/components/atoms/formatted-credit-card/FormattedCreditCard.js +53 -0
  12. package/src/components/atoms/formatted-credit-card/FormattedCreditCard.theme.js +9 -0
  13. package/src/components/atoms/formatted-credit-card/index.js +3 -0
  14. package/src/components/atoms/icons/AccountNumberImage.js +95 -0
  15. package/src/components/atoms/icons/BankIcon.js +82 -0
  16. package/src/components/atoms/icons/CheckmarkIcon.js +55 -0
  17. package/src/components/atoms/icons/GenericCard.js +39 -0
  18. package/src/components/atoms/icons/PaymentIcon.js +50 -0
  19. package/src/components/atoms/icons/RoutingNumberImage.js +95 -0
  20. package/src/components/atoms/icons/index.js +14 -1
  21. package/src/components/atoms/index.js +3 -0
  22. package/src/components/atoms/jumbo/Jumbo.js +76 -0
  23. package/src/components/atoms/jumbo/index.js +3 -0
  24. package/src/components/atoms/loading/Loading.js +17 -0
  25. package/src/components/atoms/loading/index.js +3 -0
  26. package/src/components/atoms/nav-header/NavHeader.js +1 -1
  27. package/src/components/index.js +1 -0
  28. package/src/components/molecules/account-and-routing-modal/AccountAndRoutingModal.js +75 -0
  29. package/src/components/molecules/account-and-routing-modal/AccountAndRoutingModal.theme.js +24 -0
  30. package/src/components/molecules/account-and-routing-modal/index.js +3 -0
  31. package/src/components/molecules/address-form/AddressForm.js +2 -1
  32. package/src/components/molecules/address-form/index.js +6 -6
  33. package/src/components/molecules/change-password-form/ChangePasswordForm.js +2 -1
  34. package/src/components/molecules/change-password-form/index.js +1 -1
  35. package/src/components/molecules/edit-name-form/EditNameForm.js +2 -1
  36. package/src/components/molecules/edit-name-form/index.js +1 -1
  37. package/src/components/molecules/editable-list/EditableList.js +139 -0
  38. package/src/components/molecules/editable-list/EditableList.styled.js +31 -0
  39. package/src/components/molecules/editable-list/index.js +3 -0
  40. package/src/components/molecules/editable-table/EditableTable.js +30 -0
  41. package/src/components/molecules/editable-table/EditableTable.styled.js +80 -0
  42. package/src/components/molecules/editable-table/TableListItem.js +64 -0
  43. package/src/components/molecules/editable-table/index.js +4 -0
  44. package/src/components/molecules/email-form/EmailForm.js +2 -1
  45. package/src/components/molecules/email-form/index.js +1 -1
  46. package/src/components/molecules/forgot-password-form/ForgotPasswordForm.js +2 -1
  47. package/src/components/molecules/forgot-password-form/index.js +1 -1
  48. package/src/components/molecules/index.js +5 -0
  49. package/src/components/molecules/login-form/LoginForm.js +2 -1
  50. package/src/components/molecules/login-form/index.js +1 -1
  51. package/src/components/molecules/module/Module.js +1 -3
  52. package/src/components/molecules/partial-amount-form/PartialAmountForm.js +73 -0
  53. package/src/components/molecules/partial-amount-form/PartialAmountForm.state.js +51 -0
  54. package/src/components/molecules/partial-amount-form/index.js +4 -0
  55. package/src/components/molecules/payment-form-ach/PaymentFormACH.js +189 -0
  56. package/src/components/molecules/payment-form-ach/PaymentFormACH.state.js +38 -0
  57. package/src/components/molecules/payment-form-ach/index.js +11 -0
  58. package/src/components/molecules/payment-form-card/PaymentFormCard.js +132 -0
  59. package/src/components/molecules/payment-form-card/PaymentFormCard.state.js +39 -0
  60. package/src/components/molecules/payment-form-card/index.js +11 -0
  61. package/src/components/molecules/phone-form/PhoneForm.js +2 -1
  62. package/src/components/molecules/phone-form/index.js +1 -1
  63. package/src/components/molecules/registration-form/RegistrationForm.js +2 -1
  64. package/src/components/molecules/registration-form/index.js +1 -1
  65. package/src/components/molecules/reset-password-form/ResetPasswordForm.js +3 -1
  66. package/src/components/molecules/reset-password-form/index.js +1 -1
  67. package/src/constants/index.js +4 -0
  68. package/src/index.js +3 -1
  69. package/src/util/formats.js +54 -2
  70. package/src/util/general.js +27 -4
  71. package/src/util/index.js +4 -0
  72. package/src/util/inputValidationUtils.js +0 -167
  73. package/.tool-versions +0 -1
  74. package/dist/cb-components.cjs.js +0 -77
  75. package/src/util/router-utils.js +0 -23
@@ -12,7 +12,7 @@ export const phoneFormats = [
12
12
  "(___) ___-_",
13
13
  "(___) ___-__",
14
14
  "(___) ___-___",
15
- "(___) ___-____",
15
+ "(___) ___-____"
16
16
  ];
17
17
 
18
18
  const zipFormats = [
@@ -25,6 +25,58 @@ const zipFormats = [
25
25
  "______",
26
26
  "_____-__",
27
27
  "_____-___",
28
- "_____-____",
28
+ "_____-____"
29
29
  ];
30
+
31
+ const creditCardFormats = [
32
+ "",
33
+ "_",
34
+ "__",
35
+ "___",
36
+ "____",
37
+ "____ _",
38
+ "____ __",
39
+ "____ ___",
40
+ "____ ____",
41
+ "____ ____ _",
42
+ "____ ____ __",
43
+ "____ ____ ___",
44
+ "____ ____ ____",
45
+ "____ ____ ____ _",
46
+ "____ ____ ____ __",
47
+ "____ ____ ____ ___",
48
+ "____ ____ ____ ____"
49
+ ];
50
+
51
+ export const moneyFormats = [
52
+ "",
53
+ "$0.0_",
54
+ "$0.__",
55
+ "$_.__",
56
+ "$__.__",
57
+ "$___.__",
58
+ "$_,___.__",
59
+ "$__,___.__",
60
+ "$___,___.__",
61
+ "$_,___,___.__",
62
+ "$__,___,___.__",
63
+ "$___,___,___.__",
64
+ "$_,___,___,___.__",
65
+ "$__,___,___,___.__",
66
+ "$___,___,___,___.__",
67
+ "$_,___,___,___,___.__"
68
+ ];
69
+
70
+ export const expirationDateFormats = ["", "_", "__/", "__/_", "__/__"];
71
+
30
72
  export const zipFormat = createFormat(zipFormats, formatDelimiter);
73
+ export const creditCardFormat = createFormat(
74
+ creditCardFormats,
75
+ formatDelimiter
76
+ );
77
+ export const expirationDateFormat = createFormat(
78
+ expirationDateFormats,
79
+ formatDelimiter
80
+ );
81
+ export const phoneFormat = createFormat(phoneFormats, formatDelimiter);
82
+ export const moneyFormat = createFormat(moneyFormats, formatDelimiter);
@@ -2,14 +2,37 @@ import numeral from "numeral";
2
2
 
3
3
  export const noop = () => {};
4
4
 
5
- const formatMoneyString = (s) => numeral(s).format("$0,0.00");
6
- const convertCentsToMoneyDecimal = (n) => (n / 100).toFixed(2);
7
- export const displayCurrency = (cents) =>
5
+ const formatMoneyString = s => numeral(s).format("$0,0.00");
6
+ const convertCentsToMoneyDecimal = n => (n / 100).toFixed(2);
7
+ export const displayCurrency = cents =>
8
8
  formatMoneyString(convertCentsToMoneyDecimal(cents));
9
9
 
10
+ export const convertCentsToMoneyInt = n => (n / 100).toFixed(0);
11
+
10
12
  export const safeChildren = (children, replacement = []) => {
11
13
  if (children && children instanceof Array) {
12
- return children.map((child) => (!child ? replacement : child));
14
+ return children.map(child => (!child ? replacement : child));
13
15
  }
14
16
  return !children ? replacement : children;
15
17
  };
18
+
19
+ export const generateClickHandler = (form, handleErrors, submitForm) => e => {
20
+ e.preventDefault();
21
+ const formHasError = Object.values(form.fields).reduce(
22
+ (acc, curr) => acc || curr.hasErrors,
23
+ false
24
+ );
25
+ return formHasError ? handleErrors() : submitForm();
26
+ };
27
+
28
+ export const checkCardBrand = number => {
29
+ if (/^6011/.test(number)) {
30
+ return "DISCOVER";
31
+ } else if (/^5[1-5]/.test(number)) {
32
+ return "MASTERCARD";
33
+ } else if (/^4/.test(number)) {
34
+ return "VISA";
35
+ } else if (/^3[4,7]/.test(number)) {
36
+ return "AMEX";
37
+ } else return "UNKNOWN";
38
+ };
@@ -0,0 +1,4 @@
1
+ import * as formats from "./formats";
2
+ import * as general from "./general";
3
+
4
+ export { formats, general };
@@ -1,22 +1,5 @@
1
- import * as S from "sanctuary";
2
- import * as $ from "sanctuary-def";
3
1
  import * as R from "ramda";
4
2
 
5
- // FormInput :: { form :: Object String any, keyName :: String }
6
-
7
- // String -> Maybe String
8
- const getsMaybeString = keyName => S.gets(S.is($.String))([keyName, "value"]);
9
-
10
- // String, String, Regex -> FormInput -> Either String String
11
- const regexTest = (keyName, errorMsg, regex) =>
12
- S.pipe([
13
- getsMaybeString(keyName),
14
- S.maybeToEither("Invalid string entered"),
15
- S.chain(string =>
16
- S.test(regex)(string) ? S.Right(string) : S.Left(errorMsg)
17
- )
18
- ]);
19
-
20
3
  // Constants to reprsent input error types
21
4
  export const MIN_LENGTH_ERROR = "error/HAS_LENGTH";
22
5
  export const MAX_LENGTH_ERROR = "max_length_error";
@@ -105,153 +88,3 @@ export const getInputState = (
105
88
  }
106
89
  return INPUT_STATE_VALID;
107
90
  };
108
-
109
- // Number -> FormInput -> Either String String
110
- export const stringHasMinLength = minLength => ({ form, keyName }) =>
111
- S.pipe([
112
- getsMaybeString(keyName),
113
- S.maybeToEither("Invalid string entered"),
114
- S.chain(string =>
115
- string.length >= minLength ? S.Right(string) : S.Left(MIN_LENGTH_ERROR)
116
- )
117
- ])(form);
118
-
119
- // Number -> FormInput -> Either String String
120
- // This function is INCLUSIVE of the maxLength arg supplied to it
121
- export const stringHasMaxLength = maxLength => ({ form, keyName }) =>
122
- S.pipe([
123
- getsMaybeString(keyName),
124
- S.maybeToEither("Invalid string entered"),
125
- S.chain(string =>
126
- string.length <= maxLength ? S.Right(string) : S.Left(MAX_LENGTH_ERROR)
127
- )
128
- ])(form);
129
-
130
- // Number -> FormInput -> Either String String
131
- export const stringHasExactLength = exactLength => ({ form, keyName }) =>
132
- S.pipe([
133
- getsMaybeString(keyName),
134
- S.maybeToEither("Invalid string entered"),
135
- S.chain(string =>
136
- string.length == exactLength
137
- ? S.Right(string)
138
- : S.Left(EXACT_LENGTH_ERROR)
139
- )
140
- ])(form);
141
-
142
- // Array(Number) -> FormInput -> Either String String
143
- export const stringHasMultipleValidLengths = validLengths => ({
144
- form,
145
- keyName
146
- }) =>
147
- S.pipe([
148
- getsMaybeString(keyName),
149
- S.maybeToEither("Form is missing key or value is not a string"),
150
- S.chain(string =>
151
- R.contains(string.length, validLengths)
152
- ? S.Right(string)
153
- : S.Left(MULTIPLE_LENGTHS_ERROR)
154
- )
155
- ])(form);
156
-
157
- // FormInput -> Either String String
158
- /* NOTE: this is not a foolproof email validation check
159
- It will likely fail on edge cases such as " "@foo.com
160
- It also cannot tell you if the particular email entered is valid for the given domain
161
- Or if the email account actually exists
162
- Only use this to help indicate to a user that they may have entered their email incorrectly
163
- Real validation should be accomplished on the server by sending an email to
164
- the provided email address
165
- */
166
- export const isProbablyAnEmail = ({ form, keyName }) =>
167
- regexTest(keyName, EMAIL_ERROR, /^[^\s@]+@[^\s@]+\.[^\s@]+$/)(form);
168
-
169
- // FormInput -> Either String String
170
- export const stringHasNumber = ({ form, keyName }) =>
171
- regexTest(keyName, HAS_NUMBER_ERROR, /[0-9]/)(form);
172
-
173
- // FormInput -> Either String String
174
- export const stringHasUppercaseLetter = ({ form, keyName }) =>
175
- regexTest(keyName, HAS_UPPERCASE_LETTER_ERROR, /[A-Z]/)(form);
176
-
177
- // FormInput -> Either String String
178
- export const stringHasLowercaseLetter = ({ form, keyName }) =>
179
- regexTest(keyName, HAS_LOWERCASE_LETTER_ERROR, /[a-z]/)(form);
180
-
181
- // FormInput -> Either String String
182
- export const stringHasSpecialCharacter = ({ form, keyName }) =>
183
- regexTest(keyName, HAS_SPECIAL_CHARACTER_ERROR, /[!@#$%^&*.?]/)(form);
184
-
185
- // FormInput -> Either String String
186
- export const stringIsOnlyNumbers = ({ form, keyName }) =>
187
- regexTest(keyName, ONLY_NUMBERS_ERROR, /^[0-9]+$/)(form);
188
-
189
- // FormInput -> Either String String
190
- export const stringIsOnlyLetters = ({ form, keyName }) =>
191
- regexTest(keyName, ONLY_LETTERS_ERROR, /^[a-zA-Z]+$/)(form);
192
-
193
- // fieldIsRequired asks for only one character,
194
- // which can be a letter (a-z) or (A-Z), a digit (0-9), or one of the special characters (!@#$%^&*.?)
195
- // If you need only letters or numbers use one of the more specific string checks above
196
- // If you need the string to exceed a specificed length, use stringHasMinLength
197
- // FormInput -> Either String String
198
- export const fieldIsRequired = ({ form, keyName }) =>
199
- S.pipe([
200
- getsMaybeString(keyName),
201
- S.maybeToEither("Invalid string entered"),
202
- S.chain(string =>
203
- string.replace(/\s/g, "").length === 0
204
- ? S.Left(REQUIRED_FIELD_ERROR)
205
- : S.Right(string)
206
- )
207
- ])(form);
208
-
209
- // Number -> FormInput -> Either String String
210
- export const numberIsGreaterThan = minValue => ({ form, keyName }) =>
211
- S.pipe([
212
- getsMaybeString(keyName),
213
- S.maybeToEither("Invalid string entered"),
214
- S.chain(n =>
215
- parseInt(n, 10) > minValue
216
- ? S.Right(n.toString())
217
- : S.Left(NUM_GREATER_THAN_ERROR)
218
- )
219
- ])(form);
220
-
221
- // Number -> FormInput -> Either String String
222
- export const numberIsLessThan = maxValue => ({ form, keyName }) =>
223
- S.pipe([
224
- getsMaybeString(keyName),
225
- S.maybeToEither("Invalid string entered"),
226
- S.chain(n =>
227
- parseInt(n, 10) < maxValue
228
- ? S.Right(n.toString())
229
- : S.Left(NUM_LESS_THAN_ERROR)
230
- )
231
- ])(form);
232
-
233
- // Error message splits the keyname on capital letters, joins with a space, and lower cases, so "accountNumber" becomes "account number"
234
- // Eq a => FormInput -> String -> Either String a
235
- export const matchesOtherField = matchKey => ({ form, keyName }) =>
236
- S.equals(S.props([keyName, "value"])(form))(
237
- S.props([matchKey, "value"])(form)
238
- )
239
- ? S.Right(S.props([keyName, "value"])(form))
240
- : S.Left(MATCHES_FIELD_ERROR);
241
-
242
- // Array(String) -> FormInput -> Either String String
243
- export const selectIsValid = validOptions => ({ form, keyName }) =>
244
- S.pipe([
245
- getsMaybeString(keyName),
246
- S.maybeToEither("Invalid string entered"),
247
- S.chain(string =>
248
- R.contains(S.toUpper(string), validOptions)
249
- ? S.Right(string)
250
- : S.Left(VALID_SELECT_OPTION_ERROR)
251
- )
252
- ])(form);
253
-
254
- export const isInputInvalid = input => input.error && input.showError;
255
-
256
- export const inputErrorMessage = input =>
257
- input.showError ? input.errorMsg : "";
package/.tool-versions DELETED
@@ -1 +0,0 @@
1
- nodejs 10.15.3
@@ -1,77 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
-
7
- var React = _interopDefault(require('react'));
8
- var styled = _interopDefault(require('styled-components'));
9
-
10
- function _taggedTemplateLiteral(strings, raw) {
11
- if (!raw) {
12
- raw = strings.slice(0);
13
- }
14
-
15
- return Object.freeze(Object.defineProperties(strings, {
16
- raw: {
17
- value: Object.freeze(raw)
18
- }
19
- }));
20
- }
21
-
22
- /*
23
- Need to add a new color? Visit http://chir.ag/projects/name-that-color to generate a color name.
24
-
25
- Name already taken? If you can't use the existing color, then use thesaurus.com to pick a similar name
26
- to the one generated by name-that-color.
27
- */
28
- var PEWTER_GREY = "#DFE1E4";
29
- var MARINER_BLUE = "#2E75D2";
30
-
31
- function _templateObject2() {
32
- var data = _taggedTemplateLiteral(["\n height: 16px;\n width: 16px;\n background-color: ", ";\n border-radius: 8px;\n"]);
33
-
34
- _templateObject2 = function _templateObject2() {
35
- return data;
36
- };
37
-
38
- return data;
39
- }
40
-
41
- function _templateObject() {
42
- var data = _taggedTemplateLiteral(["\n height: 24px;\n width: 24px;\n border: 1px solid\n ", ";\n border-radius: 12px;\n display: flex;\n justify-content: center;\n align-items: center;\n margin: 10px;\n min-width: 24px;\n min-height: 24px;\n"]);
43
-
44
- _templateObject = function _templateObject() {
45
- return data;
46
- };
47
-
48
- return data;
49
- }
50
- var defaultTheme = {
51
- theme: {
52
- accentColor: MARINER_BLUE,
53
- inactiveColor: PEWTER_GREY
54
- }
55
- };
56
- var RadioButtonBorder = styled.div(_templateObject(), function (_ref) {
57
- var isSelected = _ref.isSelected,
58
- theme = _ref.theme;
59
- return isSelected ? theme.accentColor : theme.inactiveColor;
60
- });
61
- RadioButtonBorder.defaultProps = defaultTheme;
62
- var RadioButtonCenter = styled.div(_templateObject2(), function (_ref2) {
63
- var theme = _ref2.theme;
64
- return theme.accentColor;
65
- });
66
- RadioButtonCenter.defaultProps = defaultTheme;
67
-
68
- var RadioButton = function RadioButton(_ref3) {
69
- var isSelected = _ref3.isSelected,
70
- name = _ref3.name;
71
- return React.createElement(RadioButtonBorder, {
72
- isSelected: isSelected,
73
- name: name
74
- }, isSelected && React.createElement(RadioButtonCenter, null));
75
- };
76
-
77
- exports.RadioButton = RadioButton;
@@ -1,23 +0,0 @@
1
- import * as R from "ramda";
2
-
3
- // todo: remove ramda dep
4
- // maybe move logic to Header as that's the only component using this
5
- const getTabs = R.anyPass([
6
- R.equals("settings"),
7
- R.equals("accounts"),
8
- R.equals("properties")
9
- ]);
10
- const configureTabNavigation = subRoute =>
11
- subRoute.split("/").filter(route => getTabs(route));
12
- const getSubRoute = route => route.topLevel;
13
- const buildTabNavigation = R.compose(
14
- R.map(configureTabNavigation),
15
- R.map(getSubRoute)
16
- );
17
- const sortRoutes = R.compose(R.sortBy(R.toLower), R.flatten);
18
- const configureRoutes = R.compose(
19
- sortRoutes,
20
- R.compose(buildTabNavigation, R.flatten)
21
- );
22
-
23
- export { configureRoutes };