@thecb/components 2.2.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 (308) hide show
  1. package/.eslintrc.json +29 -0
  2. package/.github/PULL_REQUEST_TEMPLATE.md +18 -0
  3. package/.github/stale.yml +17 -0
  4. package/.prettierignore +3 -0
  5. package/.tool-versions +1 -0
  6. package/README.md +149 -0
  7. package/dist/cb-components.cjs.js +77 -0
  8. package/package.json +96 -0
  9. package/rollup.config.js +35 -0
  10. package/src/components/atoms/alert/Alert.js +67 -0
  11. package/src/components/atoms/alert/Alert.theme.js +71 -0
  12. package/src/components/atoms/alert/index.js +3 -0
  13. package/src/components/atoms/amount-callout/AmountCallout.js +27 -0
  14. package/src/components/atoms/amount-callout/AmountCallout.theme.js +19 -0
  15. package/src/components/atoms/amount-callout/index.js +3 -0
  16. package/src/components/atoms/breadcrumb/Breadcrumb.js +50 -0
  17. package/src/components/atoms/breadcrumb/Breadcrumb.theme.js +25 -0
  18. package/src/components/atoms/breadcrumb/index.js +3 -0
  19. package/src/components/atoms/button-with-action/ButtonWithAction.js +128 -0
  20. package/src/components/atoms/button-with-action/ButtonWithAction.stories.js +125 -0
  21. package/src/components/atoms/button-with-action/ButtonWithAction.theme.js +360 -0
  22. package/src/components/atoms/button-with-action/index.js +3 -0
  23. package/src/components/atoms/button-with-link/ButtonWithLink.js +40 -0
  24. package/src/components/atoms/button-with-link/index.js +3 -0
  25. package/src/components/atoms/checkbox/Checkbox.js +143 -0
  26. package/src/components/atoms/checkbox/Checkbox.theme.js +54 -0
  27. package/src/components/atoms/checkbox/index.js +3 -0
  28. package/src/components/atoms/checkbox-list/CheckboxList.js +129 -0
  29. package/src/components/atoms/checkbox-list/CheckboxList.theme.js +42 -0
  30. package/src/components/atoms/checkbox-list/index.js +3 -0
  31. package/src/components/atoms/country-dropdown/CountryDropdown.js +24 -0
  32. package/src/components/atoms/country-dropdown/index.js +1 -0
  33. package/src/components/atoms/country-dropdown/options.js +249 -0
  34. package/src/components/atoms/display-box/DisplayBox.js +22 -0
  35. package/src/components/atoms/display-box/DisplayBox.theme.js +9 -0
  36. package/src/components/atoms/display-box/index.js +3 -0
  37. package/src/components/atoms/display-card/DisplayCard.js +65 -0
  38. package/src/components/atoms/display-card/index.js +3 -0
  39. package/src/components/atoms/dropdown/Dropdown.js +299 -0
  40. package/src/components/atoms/dropdown/Dropdown.theme.js +9 -0
  41. package/src/components/atoms/dropdown/DropdownIcon.js +31 -0
  42. package/src/components/atoms/dropdown/index.js +3 -0
  43. package/src/components/atoms/form-layouts/FormContainer.js +28 -0
  44. package/src/components/atoms/form-layouts/FormInput.js +218 -0
  45. package/src/components/atoms/form-layouts/FormInputColumn.js +15 -0
  46. package/src/components/atoms/form-layouts/FormInputRow.js +26 -0
  47. package/src/components/atoms/form-layouts/FormLayouts.theme.js +52 -0
  48. package/src/components/atoms/form-layouts/index.js +6 -0
  49. package/src/components/atoms/form-select/FormSelect.js +62 -0
  50. package/src/components/atoms/form-select/FormSelect.styled.js +65 -0
  51. package/src/components/atoms/form-select/index.js +3 -0
  52. package/src/components/atoms/formatted-address/FormattedAddress.js +53 -0
  53. package/src/components/atoms/formatted-address/FormattedAddress.theme.js +11 -0
  54. package/src/components/atoms/formatted-address/index.js +3 -0
  55. package/src/components/atoms/hamburger-button/HamburgerButton.js +113 -0
  56. package/src/components/atoms/hamburger-button/index.js +3 -0
  57. package/src/components/atoms/heading/Heading.js +37 -0
  58. package/src/components/atoms/heading/Heading.styled.js +14 -0
  59. package/src/components/atoms/heading/Heading.theme.js +18 -0
  60. package/src/components/atoms/heading/index.js +3 -0
  61. package/src/components/atoms/icons/AccountsAddIcon.js +42 -0
  62. package/src/components/atoms/icons/AccountsIcon.js +37 -0
  63. package/src/components/atoms/icons/AccountsIconSmall.js +63 -0
  64. package/src/components/atoms/icons/ChevronIcon.js +51 -0
  65. package/src/components/atoms/icons/ForgotPasswordIcon.js +46 -0
  66. package/src/components/atoms/icons/GoToEmailIcon.js +31 -0
  67. package/src/components/atoms/icons/Icons.theme.js +38 -0
  68. package/src/components/atoms/icons/PaymentMethodIcon.js +42 -0
  69. package/src/components/atoms/icons/PaymentsIconSmall.js +63 -0
  70. package/src/components/atoms/icons/ProfileIconSmall.js +44 -0
  71. package/src/components/atoms/icons/PropertiesAddIcon.js +70 -0
  72. package/src/components/atoms/icons/PropertiesIconSmall.js +32 -0
  73. package/src/components/atoms/icons/SettingsIconSmall.js +63 -0
  74. package/src/components/atoms/icons/VerifiedEmailIcon.js +53 -0
  75. package/src/components/atoms/icons/index.js +28 -0
  76. package/src/components/atoms/index.js +33 -0
  77. package/src/components/atoms/labeled-amount/LabeledAmount.js +35 -0
  78. package/src/components/atoms/labeled-amount/LabeledAmount.theme.js +10 -0
  79. package/src/components/atoms/labeled-amount/index.js +3 -0
  80. package/src/components/atoms/layouts/Box.js +83 -0
  81. package/src/components/atoms/layouts/Box.styled.js +131 -0
  82. package/src/components/atoms/layouts/Center.js +28 -0
  83. package/src/components/atoms/layouts/Center.styled.js +18 -0
  84. package/src/components/atoms/layouts/Cluster.js +37 -0
  85. package/src/components/atoms/layouts/Cluster.styled.js +21 -0
  86. package/src/components/atoms/layouts/Cover.js +49 -0
  87. package/src/components/atoms/layouts/Cover.styled.js +29 -0
  88. package/src/components/atoms/layouts/Frame.js +28 -0
  89. package/src/components/atoms/layouts/Frame.styled.js +27 -0
  90. package/src/components/atoms/layouts/Grid.js +38 -0
  91. package/src/components/atoms/layouts/Grid.styled.js +22 -0
  92. package/src/components/atoms/layouts/Imposter.js +52 -0
  93. package/src/components/atoms/layouts/Imposter.styled.js +19 -0
  94. package/src/components/atoms/layouts/Motion.js +51 -0
  95. package/src/components/atoms/layouts/Motion.styled.js +41 -0
  96. package/src/components/atoms/layouts/Reel.js +28 -0
  97. package/src/components/atoms/layouts/Reel.styled.js +17 -0
  98. package/src/components/atoms/layouts/Sidebar.js +42 -0
  99. package/src/components/atoms/layouts/Sidebar.styled.js +38 -0
  100. package/src/components/atoms/layouts/Stack.js +36 -0
  101. package/src/components/atoms/layouts/Stack.styled.js +30 -0
  102. package/src/components/atoms/layouts/Switcher.js +64 -0
  103. package/src/components/atoms/layouts/Switcher.styled.js +44 -0
  104. package/src/components/atoms/layouts/examples/FixedSizeContainer.js +22 -0
  105. package/src/components/atoms/layouts/examples/FixedSizeContainer.styled.js +20 -0
  106. package/src/components/atoms/layouts/examples/LayoutContentBlock.js +27 -0
  107. package/src/components/atoms/layouts/examples/LayoutContentBlock.styled.js +15 -0
  108. package/src/components/atoms/layouts/examples/ResizingContainer.js +49 -0
  109. package/src/components/atoms/layouts/examples/ResizingContainer.styled.js +39 -0
  110. package/src/components/atoms/layouts/examples/cluster-example/ClusterExample.js +10 -0
  111. package/src/components/atoms/layouts/examples/cluster-example/ClusterExample.stories.js +97 -0
  112. package/src/components/atoms/layouts/examples/grid-example/GridExample.js +49 -0
  113. package/src/components/atoms/layouts/examples/grid-example/GridExample.stories.js +44 -0
  114. package/src/components/atoms/layouts/examples/sidebar-example/SidebarExample.js +11 -0
  115. package/src/components/atoms/layouts/examples/sidebar-example/SidebarExample.stories.js +87 -0
  116. package/src/components/atoms/layouts/examples/stack-example/StackExample.js +27 -0
  117. package/src/components/atoms/layouts/examples/stack-example/StackExample.stories.js +69 -0
  118. package/src/components/atoms/layouts/examples/switcher-example/SwitcherExample.js +38 -0
  119. package/src/components/atoms/layouts/examples/switcher-example/SwitcherExample.stories.js +65 -0
  120. package/src/components/atoms/layouts/index.js +27 -0
  121. package/src/components/atoms/line-item/LineItem.js +30 -0
  122. package/src/components/atoms/line-item/LineItem.theme.js +7 -0
  123. package/src/components/atoms/line-item/index.js +3 -0
  124. package/src/components/atoms/link/ExternalLink.js +50 -0
  125. package/src/components/atoms/link/ExternalLink.styled.js +26 -0
  126. package/src/components/atoms/link/InternalLink.js +51 -0
  127. package/src/components/atoms/link/InternalLink.styled.js +39 -0
  128. package/src/components/atoms/link/Link.theme.js +8 -0
  129. package/src/components/atoms/link/index.js +4 -0
  130. package/src/components/atoms/nav-footer/NavFooter.js +57 -0
  131. package/src/components/atoms/nav-footer/index.js +3 -0
  132. package/src/components/atoms/nav-header/NavHeader.js +36 -0
  133. package/src/components/atoms/nav-header/index.js +3 -0
  134. package/src/components/atoms/paragraph/Paragraph.js +31 -0
  135. package/src/components/atoms/paragraph/Paragraph.styled.js +13 -0
  136. package/src/components/atoms/paragraph/Paragraph.theme.js +18 -0
  137. package/src/components/atoms/paragraph/index.js +3 -0
  138. package/src/components/atoms/password-requirements/PasswordRequirements.js +116 -0
  139. package/src/components/atoms/password-requirements/index.js +3 -0
  140. package/src/components/atoms/placeholder/Placeholder.js +122 -0
  141. package/src/components/atoms/placeholder/Placeholder.theme.js +9 -0
  142. package/src/components/atoms/placeholder/index.js +3 -0
  143. package/src/components/atoms/processing-fee/ProcessingFee.js +43 -0
  144. package/src/components/atoms/processing-fee/ProcessingFee.theme.js +7 -0
  145. package/src/components/atoms/processing-fee/index.js +3 -0
  146. package/src/components/atoms/radio-button/RadioButton.js +101 -0
  147. package/src/components/atoms/radio-button/RadioButton.theme.js +9 -0
  148. package/src/components/atoms/radio-button/index.js +3 -0
  149. package/src/components/atoms/solid-divider/SolidDivider.js +22 -0
  150. package/src/components/atoms/solid-divider/SolidDivider.theme.js +8 -0
  151. package/src/components/atoms/solid-divider/index.js +3 -0
  152. package/src/components/atoms/spinner/Spinner.js +61 -0
  153. package/src/components/atoms/spinner/Spinner.theme.js +5 -0
  154. package/src/components/atoms/spinner/index.js +3 -0
  155. package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.js +28 -0
  156. package/src/components/atoms/state-province-dropdown/index.js +3 -0
  157. package/src/components/atoms/state-province-dropdown/options.js +3837 -0
  158. package/src/components/atoms/text/Text.js +37 -0
  159. package/src/components/atoms/text/Text.styled.js +32 -0
  160. package/src/components/atoms/text/Text.theme.js +22 -0
  161. package/src/components/atoms/text/index.js +3 -0
  162. package/src/components/atoms/toggle-switch/ToggleSwitch.js +212 -0
  163. package/src/components/atoms/toggle-switch/ToggleSwitch.theme.js +36 -0
  164. package/src/components/atoms/toggle-switch/index.js +3 -0
  165. package/src/components/index.js +3 -0
  166. package/src/components/molecules/address-form/AddressForm.js +110 -0
  167. package/src/components/molecules/address-form/AddressForm.state.js +52 -0
  168. package/src/components/molecules/address-form/index.js +11 -0
  169. package/src/components/molecules/change-password-form/ChangePasswordForm.js +92 -0
  170. package/src/components/molecules/change-password-form/ChangePasswordForm.state.js +33 -0
  171. package/src/components/molecules/change-password-form/index.js +11 -0
  172. package/src/components/molecules/collapsible-section/CollapsibleSection.js +126 -0
  173. package/src/components/molecules/collapsible-section/CollapsibleSection.theme.js +11 -0
  174. package/src/components/molecules/collapsible-section/index.js +3 -0
  175. package/src/components/molecules/edit-name-form/EditNameForm.js +51 -0
  176. package/src/components/molecules/edit-name-form/EditNameForm.state.js +14 -0
  177. package/src/components/molecules/edit-name-form/index.js +11 -0
  178. package/src/components/molecules/email-form/EmailForm.js +55 -0
  179. package/src/components/molecules/email-form/EmailForm.state.js +19 -0
  180. package/src/components/molecules/email-form/index.js +11 -0
  181. package/src/components/molecules/forgot-password-form/ForgotPasswordForm.js +32 -0
  182. package/src/components/molecules/forgot-password-form/ForgotPasswordForm.state.js +11 -0
  183. package/src/components/molecules/forgot-password-form/index.js +11 -0
  184. package/src/components/molecules/highlight-tab-row/HighlightTabRow.js +62 -0
  185. package/src/components/molecules/highlight-tab-row/HighlightTabRow.theme.js +7 -0
  186. package/src/components/molecules/highlight-tab-row/index.js +8 -0
  187. package/src/components/molecules/index.js +24 -0
  188. package/src/components/molecules/login-form/LoginForm.js +46 -0
  189. package/src/components/molecules/login-form/LoginForm.state.js +14 -0
  190. package/src/components/molecules/login-form/index.js +11 -0
  191. package/src/components/molecules/modal/Modal.js +138 -0
  192. package/src/components/molecules/modal/index.js +3 -0
  193. package/src/components/molecules/module/Module.js +42 -0
  194. package/src/components/molecules/module/Module.theme.js +30 -0
  195. package/src/components/molecules/module/index.js +8 -0
  196. package/src/components/molecules/nav-menu/NavMenu.theme.js +5 -0
  197. package/src/components/molecules/nav-menu/NavMenuDesktop.js +39 -0
  198. package/src/components/molecules/nav-menu/NavMenuMobile.js +63 -0
  199. package/src/components/molecules/nav-menu/index.js +4 -0
  200. package/src/components/molecules/obligation/Obligation.js +69 -0
  201. package/src/components/molecules/obligation/icons/AccountBillIcon.js +89 -0
  202. package/src/components/molecules/obligation/icons/AccountConstructionIcon.js +99 -0
  203. package/src/components/molecules/obligation/icons/AccountDentalIcon.js +94 -0
  204. package/src/components/molecules/obligation/icons/AccountElectricIcon.js +99 -0
  205. package/src/components/molecules/obligation/icons/AccountGarbageIcon.js +94 -0
  206. package/src/components/molecules/obligation/icons/AccountGasIcon.js +94 -0
  207. package/src/components/molecules/obligation/icons/AccountGenericIcon.js +89 -0
  208. package/src/components/molecules/obligation/icons/AccountMedicalIcon.js +94 -0
  209. package/src/components/molecules/obligation/icons/AccountWaterIcon.js +94 -0
  210. package/src/components/molecules/obligation/icons/PropertyApartmentIcon.js +99 -0
  211. package/src/components/molecules/obligation/icons/PropertyBusinessIcon.js +94 -0
  212. package/src/components/molecules/obligation/icons/PropertyCarIcon.js +99 -0
  213. package/src/components/molecules/obligation/icons/PropertyCommercialVehicleIcon.js +100 -0
  214. package/src/components/molecules/obligation/icons/PropertyGarageIcon.js +96 -0
  215. package/src/components/molecules/obligation/icons/PropertyLandIcon.js +99 -0
  216. package/src/components/molecules/obligation/icons/PropertyMotorcycleIcon.js +99 -0
  217. package/src/components/molecules/obligation/icons/PropertyPersonalIcon.js +94 -0
  218. package/src/components/molecules/obligation/icons/PropertyStorefrontIcon.js +100 -0
  219. package/src/components/molecules/obligation/icons/index.js +60 -0
  220. package/src/components/molecules/obligation/index.js +3 -0
  221. package/src/components/molecules/obligation/modules/AmountModule.js +36 -0
  222. package/src/components/molecules/obligation/modules/IconModule.js +29 -0
  223. package/src/components/molecules/obligation/modules/PaymentDetailsActions.js +67 -0
  224. package/src/components/molecules/obligation/modules/TitleModule.js +25 -0
  225. package/src/components/molecules/obligation/modules/index.js +6 -0
  226. package/src/components/molecules/payment-button-bar/PaymentButtonBar.js +80 -0
  227. package/src/components/molecules/payment-button-bar/index.js +3 -0
  228. package/src/components/molecules/payment-details/PaymentDetails.js +158 -0
  229. package/src/components/molecules/payment-details/PaymentDetails.theme.js +11 -0
  230. package/src/components/molecules/payment-details/index.js +1 -0
  231. package/src/components/molecules/phone-form/PhoneForm.js +44 -0
  232. package/src/components/molecules/phone-form/PhoneForm.state.js +17 -0
  233. package/src/components/molecules/phone-form/index.js +11 -0
  234. package/src/components/molecules/radio-section/RadioSection.js +205 -0
  235. package/src/components/molecules/radio-section/RadioSection.theme.js +15 -0
  236. package/src/components/molecules/radio-section/index.js +3 -0
  237. package/src/components/molecules/registration-form/RegistrationForm.js +104 -0
  238. package/src/components/molecules/registration-form/RegistrationForm.state.js +40 -0
  239. package/src/components/molecules/registration-form/index.js +11 -0
  240. package/src/components/molecules/reset-confirmation-form/ResetConfirmationForm.js +56 -0
  241. package/src/components/molecules/reset-confirmation-form/index.js +3 -0
  242. package/src/components/molecules/reset-password-form/ResetPasswordForm.js +67 -0
  243. package/src/components/molecules/reset-password-form/ResetPasswordForm.state.js +30 -0
  244. package/src/components/molecules/reset-password-form/index.js +11 -0
  245. package/src/components/molecules/reset-password-success/ResetPasswordSuccess.js +55 -0
  246. package/src/components/molecules/reset-password-success/index.js +3 -0
  247. package/src/components/molecules/tab-sidebar/TabSidebar.js +92 -0
  248. package/src/components/molecules/tab-sidebar/TabSidebar.theme.js +9 -0
  249. package/src/components/molecules/tab-sidebar/index.js +3 -0
  250. package/src/components/molecules/terms-and-conditions/TermsAndConditions.js +73 -0
  251. package/src/components/molecules/terms-and-conditions/index.js +3 -0
  252. package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.js +64 -0
  253. package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.theme.js +28 -0
  254. package/src/components/molecules/terms-and-conditions-modal/index.js +3 -0
  255. package/src/components/molecules/workflow-tile/WorkflowTile.js +58 -0
  256. package/src/components/molecules/workflow-tile/index.js +3 -0
  257. package/src/components/templates/center-single/CenterSingle.js +61 -0
  258. package/src/components/templates/center-single/index.js +3 -0
  259. package/src/components/templates/center-stack/CenterStack.js +49 -0
  260. package/src/components/templates/center-stack/index.js +3 -0
  261. package/src/components/templates/default-page-template/DefaultPageTemplate.js +49 -0
  262. package/src/components/templates/default-page-template/index.js +3 -0
  263. package/src/components/templates/index.js +5 -0
  264. package/src/components/templates/sidebar-single-content/SidebarSingleContent.js +60 -0
  265. package/src/components/templates/sidebar-single-content/index.js +3 -0
  266. package/src/components/templates/sidebar-stack-content/SidebarStackContent.js +81 -0
  267. package/src/components/templates/sidebar-stack-content/index.js +3 -0
  268. package/src/components/templates/templates.theme.js +5 -0
  269. package/src/components/withWindowSize.js +50 -0
  270. package/src/constants/colors.js +178 -0
  271. package/src/constants/regex_constants.js +1 -0
  272. package/src/constants/style_constants.js +21 -0
  273. package/src/deprecated/colors.js +154 -0
  274. package/src/deprecated/components/radio-button/index.js +3 -0
  275. package/src/deprecated/components/radio-button/radio-button.js +44 -0
  276. package/src/deprecated/icons/AlertErrorIcon.js +42 -0
  277. package/src/deprecated/icons/AlertInfoIcon.js +42 -0
  278. package/src/deprecated/icons/AlertSuccessIcon.js +42 -0
  279. package/src/deprecated/icons/AlertWarningIcon.js +36 -0
  280. package/src/deprecated/icons/BankIcon.js +82 -0
  281. package/src/deprecated/icons/GenericCard.js +39 -0
  282. package/src/deprecated/icons/IconAdd.js +44 -0
  283. package/src/deprecated/icons/IconCheck.js +23 -0
  284. package/src/deprecated/icons/IconCheckEmail.js +46 -0
  285. package/src/deprecated/icons/IconChevron.js +35 -0
  286. package/src/deprecated/icons/IconEmailVerified.js +62 -0
  287. package/src/deprecated/icons/IconEye.js +32 -0
  288. package/src/deprecated/icons/IconEyeSlash.js +48 -0
  289. package/src/deprecated/icons/IconInvalid.js +69 -0
  290. package/src/deprecated/icons/IconNeutral.js +27 -0
  291. package/src/deprecated/icons/IconQuit.js +32 -0
  292. package/src/deprecated/icons/IconValid.js +72 -0
  293. package/src/deprecated/icons/IconWarn.js +28 -0
  294. package/src/deprecated/icons/index.js +40 -0
  295. package/src/deprecated/index.js +1 -0
  296. package/src/deprecated/spinner/Spinner.js +68 -0
  297. package/src/deprecated/spinner/index.js +1 -0
  298. package/src/deprecated/utility/__tests__/safeConcat.spec.js +59 -0
  299. package/src/deprecated/utility/__tests__/validateKeyType.spec.js +116 -0
  300. package/src/deprecated/utility/index.js +2 -0
  301. package/src/deprecated/utility/safeConcat.js +10 -0
  302. package/src/deprecated/utility/validateKeyType.js +19 -0
  303. package/src/index.js +2 -0
  304. package/src/util/formats.js +30 -0
  305. package/src/util/general.js +15 -0
  306. package/src/util/inputValidationUtils.js +257 -0
  307. package/src/util/router-utils.js +23 -0
  308. package/src/util/themeUtils.js +144 -0
@@ -0,0 +1,80 @@
1
+ import React, { useContext, Fragment } from "react";
2
+ import { ThemeContext } from "styled-components";
3
+
4
+ import ButtonWithLink from "../../atoms/button-with-link";
5
+ import ButtonWithAction from "../../atoms/button-with-action";
6
+ import { Box, Cluster } from "../../atoms/layouts";
7
+ import SolidDivider from "../../atoms/solid-divider";
8
+
9
+ const PaymentButtonBar = ({
10
+ forwardButtonText = "Next",
11
+ forwardButtonAction,
12
+ forwardButtonLoading,
13
+ backButtonAction,
14
+ cancelURL,
15
+ cancelText = "Cancel",
16
+ redirectURL,
17
+ redirectText = "Return"
18
+ }) => {
19
+ const { isMobile } = useContext(ThemeContext);
20
+
21
+ const backButton = !!cancelURL ? (
22
+ <ButtonWithLink
23
+ text={cancelText}
24
+ url={cancelURL}
25
+ variant="secondary"
26
+ extraStyles={isMobile && "flex-grow: 1"}
27
+ dataQa={cancelText}
28
+ />
29
+ ) : (
30
+ backButtonAction && (
31
+ <ButtonWithAction
32
+ text="Back"
33
+ variant="secondary"
34
+ action={backButtonAction}
35
+ extraStyles={isMobile && "flex-grow: 1"}
36
+ dataQa="Back"
37
+ />
38
+ )
39
+ );
40
+
41
+ const forwardButton = !!redirectURL ? (
42
+ <ButtonWithLink
43
+ url={redirectURL}
44
+ text={redirectText}
45
+ variant="primary"
46
+ extraStyles={isMobile && "flex-grow: 1"}
47
+ dataQa={redirectText}
48
+ />
49
+ ) : (
50
+ forwardButtonAction && (
51
+ <ButtonWithAction
52
+ text={forwardButtonText}
53
+ variant="primary"
54
+ action={forwardButtonAction}
55
+ isLoading={forwardButtonLoading}
56
+ extraStyles={isMobile && "flex-grow: 1"}
57
+ dataQa={forwardButtonText}
58
+ />
59
+ )
60
+ );
61
+
62
+ return (
63
+ <Fragment>
64
+ <Box padding="1.25rem 0" />
65
+ <SolidDivider />
66
+ <Box padding="2.5rem 0 3.125rem 0">
67
+ <Cluster
68
+ justify={!!backButton ? "space-between" : "flex-end"}
69
+ align="center"
70
+ childGap="0.75rem"
71
+ >
72
+ {backButton}
73
+ {forwardButton}
74
+ </Cluster>
75
+ </Box>
76
+ </Fragment>
77
+ );
78
+ };
79
+
80
+ export default PaymentButtonBar;
@@ -0,0 +1,3 @@
1
+ import PaymentButtonBar from "./PaymentButtonBar";
2
+
3
+ export default PaymentButtonBar;
@@ -0,0 +1,158 @@
1
+ import React, { useState, Fragment } from "react";
2
+ import { Stack, Cluster, Box, Motion } from "../../atoms/layouts";
3
+ import { fallbackValues } from "./PaymentDetails.theme";
4
+
5
+ import { displayCurrency } from "../../../util/general";
6
+ import { themeComponent } from "../../../util/themeUtils";
7
+ import CollapsibleSection from "../collapsible-section";
8
+
9
+ import LabeledAmount from "../../atoms/labeled-amount";
10
+ import LineItem from "../../atoms/line-item";
11
+ import Heading from "../../atoms/heading";
12
+ import SolidDivider from "../../atoms/solid-divider";
13
+
14
+ const PaymentDetailsContent = ({
15
+ lineItemElems,
16
+ feeElems,
17
+ subtotal,
18
+ total,
19
+ themeValues
20
+ }) => (
21
+ <Stack>
22
+ {lineItemElems}
23
+ <SolidDivider />
24
+ <Box padding="0.5rem 0">
25
+ <LabeledAmount
26
+ variant={themeValues.labeledAmountSubtotal}
27
+ label="Subtotal"
28
+ amount={displayCurrency(subtotal)}
29
+ />
30
+ {feeElems}
31
+ </Box>
32
+ <SolidDivider />
33
+ <LabeledAmount
34
+ variant={themeValues.labeledAmountTotal}
35
+ label="Total"
36
+ amount={displayCurrency(total)}
37
+ />
38
+ </Stack>
39
+ );
40
+
41
+ const Collapsible = ({ content, title, supportsTouch, isOpen, setIsOpen }) => (
42
+ <CollapsibleSection
43
+ isMobile={true}
44
+ supportsTouch={supportsTouch}
45
+ isOpen={isOpen}
46
+ title={title}
47
+ initiallyOpen={false}
48
+ toggleSection={() => setIsOpen(!isOpen)}
49
+ customTitle={true}
50
+ >
51
+ <Motion
52
+ variants={{
53
+ open: { opacity: 1 },
54
+ closed: { opacity: 0 }
55
+ }}
56
+ positionTransition
57
+ initial={"closed"}
58
+ >
59
+ {content}
60
+ </Motion>
61
+ </CollapsibleSection>
62
+ );
63
+
64
+ const NonCollapsible = ({ title, content }) => (
65
+ <Stack>
66
+ {title}
67
+ {content}
68
+ </Stack>
69
+ );
70
+
71
+ const PaymentDetails = ({
72
+ lineItems: _lineItems,
73
+ fees: _fees,
74
+ subtotal,
75
+ total,
76
+ hideTitle = false,
77
+ titleText = "Payment Details",
78
+ initiallyOpen = false,
79
+ collapsibleOnMobile = true,
80
+ isMobile,
81
+ supportsTouch,
82
+ themeValues
83
+ }) => {
84
+ const [isOpen, setIsOpen] = useState(initiallyOpen);
85
+ const fees = _fees
86
+ .filter(fee => fee.amount > 0)
87
+ .map(({ amount, ...rest }) => ({
88
+ ...rest,
89
+ amount: displayCurrency(amount)
90
+ }));
91
+ const lineItems = _lineItems.map(({ amount, ...rest }) => ({
92
+ ...rest,
93
+ amount: displayCurrency(amount)
94
+ }));
95
+ const isCollapsible = isMobile && collapsibleOnMobile;
96
+ const lineItemElems = lineItems.map((item, id) => (
97
+ <LineItem key={id} variant={themeValues.lineItem} {...item} />
98
+ ));
99
+ const feeElems = fees.map(fee => (
100
+ <Fragment key={fee.label}>
101
+ <Box padding="0.25rem 0" />
102
+ <LabeledAmount
103
+ key={fee.label}
104
+ variant={themeValues.labeledAmountSubtotal}
105
+ {...fee}
106
+ />
107
+ </Fragment>
108
+ ));
109
+ const content = isCollapsible ? (
110
+ <Stack>
111
+ <SolidDivider />
112
+ <PaymentDetailsContent
113
+ {...{ lineItemElems, feeElems, subtotal, total, themeValues }}
114
+ />
115
+ </Stack>
116
+ ) : (
117
+ <PaymentDetailsContent
118
+ {...{ lineItemElems, feeElems, subtotal, total, themeValues }}
119
+ />
120
+ );
121
+ const title = hideTitle ? (
122
+ <Fragment />
123
+ ) : isCollapsible ? (
124
+ <Box width="100%" padding="none">
125
+ <Cluster justify="space-between" align="center">
126
+ <Heading variant="h6" weight="700">
127
+ {titleText}
128
+ </Heading>
129
+ {displayCurrency(total)}
130
+ </Cluster>
131
+ </Box>
132
+ ) : (
133
+ <Heading variant="h3" weight="700" margin="1rem 0 0 0">
134
+ {titleText}
135
+ </Heading>
136
+ );
137
+ return isCollapsible ? (
138
+ <Collapsible
139
+ {...{
140
+ title,
141
+ content,
142
+ isOpen,
143
+ setIsOpen,
144
+ isMobile,
145
+ supportsTouch
146
+ }}
147
+ />
148
+ ) : (
149
+ <NonCollapsible {...{ title, content }} />
150
+ );
151
+ };
152
+
153
+ export default themeComponent(
154
+ PaymentDetails,
155
+ "PaymentDetails",
156
+ fallbackValues,
157
+ "default"
158
+ );
@@ -0,0 +1,11 @@
1
+ const backgroundColor = { default: "transparent", small: "transparent" };
2
+ const lineItem = { default: "default", small: "small" };
3
+ const labeledAmountSubtotal = { default: "pL", small: "p" };
4
+ const labeledAmountTotal = { default: "h6", small: "pL" };
5
+
6
+ export const fallbackValues = {
7
+ backgroundColor,
8
+ lineItem,
9
+ labeledAmountSubtotal,
10
+ labeledAmountTotal
11
+ };
@@ -0,0 +1 @@
1
+ export { default } from "./PaymentDetails";
@@ -0,0 +1,44 @@
1
+ import React, { useEffect } from "react";
2
+ import { phoneFormats, formatDelimiter } from "../../../util/formats";
3
+ import { required, hasLength } from "redux-freeform";
4
+ import { createFormat } from "formatted-input";
5
+ import {
6
+ FormInput,
7
+ FormContainer,
8
+ FormInputColumn
9
+ } from "../../atoms/form-layouts";
10
+
11
+ const PhoneForm = ({
12
+ variant = "default",
13
+ fields,
14
+ actions,
15
+ clearOnDismount,
16
+ showErrors,
17
+ handleSubmit
18
+ }) => {
19
+ if (clearOnDismount) {
20
+ useEffect(() => () => actions.form.clear(), []);
21
+ }
22
+ const phoneErrorMessage = {
23
+ [required.error]: "Phone number is required",
24
+ [hasLength.error]: "Phone number must be 10 digits"
25
+ };
26
+
27
+ return (
28
+ <FormContainer variant={variant} role="form" aria-label="Phone number">
29
+ <FormInputColumn>
30
+ <FormInput
31
+ labelTextWhenNoError="Phone number"
32
+ errorMessages={phoneErrorMessage}
33
+ field={fields.phone}
34
+ fieldActions={actions.fields.phone}
35
+ showErrors={showErrors}
36
+ formatter={createFormat(phoneFormats, formatDelimiter)}
37
+ onKeyUp={e => e.key === "Enter" && handleSubmit(e)}
38
+ />
39
+ </FormInputColumn>
40
+ </FormContainer>
41
+ );
42
+ };
43
+
44
+ export default PhoneForm;
@@ -0,0 +1,17 @@
1
+ import {
2
+ createFormState,
3
+ required,
4
+ onlyIntegers,
5
+ hasLength
6
+ } from "redux-freeform";
7
+
8
+ const formConfig = {
9
+ phone: {
10
+ validators: [required(), hasLength(10, 10)],
11
+ constraints: [onlyIntegers(), hasLength(0, 10)]
12
+ }
13
+ };
14
+
15
+ export const { reducer, mapStateToProps, mapDispatchToProps } = createFormState(
16
+ formConfig
17
+ );
@@ -0,0 +1,11 @@
1
+ import PhoneForm from "./PhoneForm";
2
+ import {
3
+ reducer,
4
+ mapStateToProps,
5
+ mapDispatchToProps,
6
+ } from "./PhoneForm.state";
7
+
8
+ PhoneForm.reducer = reducer;
9
+ PhoneForm.mapStateToProps = mapStateToProps;
10
+ PhoneForm.mapDispatchToProps = mapDispatchToProps;
11
+ export default PhoneForm;
@@ -0,0 +1,205 @@
1
+ import React, { useState } from "react";
2
+ import styled from "styled-components";
3
+ import { themeComponent } from "../../../util/themeUtils";
4
+ import { fallbackValues } from "./RadioSection.theme";
5
+ import { AnimatePresence } from "framer-motion";
6
+ import RadioButton from "../../atoms/radio-button";
7
+ import { Box, Cluster, Stack, Motion } from "../../atoms/layouts";
8
+ import { noop } from "../../../util/general";
9
+ import Text from "../../atoms/text";
10
+ import { CHARADE_GREY } from "../../../constants/colors";
11
+ /*
12
+ Takes an array of section objects, each object should look like:
13
+ {
14
+ title: <React Component(s)>,
15
+ id: <String> "identifier of section",
16
+ disabled: boolean,
17
+ dataQa: string,
18
+ content: <React Component(s)> e.g.: <Box><Stack>cool content stuff</Stack></Box> (any collection of components will work)
19
+ }
20
+
21
+ Also takes an "openSection" which should equal the id of the section that should be open
22
+ And a toggleOpenSection. RadioSection will call this function with the id of the section
23
+ that it is in. It is up to the user to store the open section value in state up from the component
24
+ using a useState() hook, or reducer.
25
+
26
+ The section itself comes with some motion to open/close. To add more motion to the content,
27
+ wrap your content with a Motion layout primitive and provide appropriate props.
28
+
29
+ */
30
+
31
+ const RadioSection = ({
32
+ themeValues,
33
+ isMobile,
34
+ supportsTouch,
35
+ sections = [],
36
+ openSection = "",
37
+ toggleOpenSection,
38
+ staggeredAnimation = false,
39
+ initiallyOpen = true,
40
+ openHeight = "auto"
41
+ }) => {
42
+ const handleKeyDown = (id, e) => {
43
+ if (e?.keyCode === 13) {
44
+ toggleOpenSection(id);
45
+ }
46
+ };
47
+
48
+ const wrapper = {
49
+ open: {
50
+ height: openHeight,
51
+ opacity: 1,
52
+ transition: {
53
+ duration: 0.3,
54
+ ease: [0.04, 0.62, 0.23, 0.98],
55
+ staggerChildren: staggeredAnimation ? 0.15 : 0
56
+ }
57
+ },
58
+ closed: {
59
+ height: 0,
60
+ opacity: 0,
61
+ transition: {
62
+ duration: 0.3,
63
+ ease: [0.04, 0.62, 0.23, 0.98],
64
+ staggerChildren: staggeredAnimation ? 0.15 : 0,
65
+ staggerDirection: -1
66
+ }
67
+ }
68
+ };
69
+
70
+ const borderStyles = `
71
+ border-width: 0 0 1px 0;
72
+ border-color: ${themeValues.borderColor};
73
+ border-style: solid;
74
+ border-radius: 0px;
75
+ transform-origin: 100% 0;
76
+
77
+ &:last-child {
78
+ border-width: 0;
79
+ }
80
+ `;
81
+
82
+ const RightIcon = styled.img`
83
+ height: ${({ isMobile }) => (isMobile ? "14px" : "18px")};
84
+ width: ${({ isMobile }) => (isMobile ? "22px" : "28px")};
85
+ ${({ fade }) => fade && "opacity: 0.4;"}
86
+ transition: opacity 0.3s ease;
87
+ `;
88
+
89
+ const [focused, setFocused] = useState(null);
90
+
91
+ return (
92
+ <Box
93
+ padding="1px"
94
+ border={`1px solid ${themeValues.borderColor}`}
95
+ borderRadius="4px"
96
+ >
97
+ <Stack childGap="0">
98
+ {sections
99
+ .filter(section => !section.hidden)
100
+ .map(section => (
101
+ <Motion
102
+ tabIndex="0"
103
+ onKeyDown={e => handleKeyDown(section.id, e)}
104
+ onFocus={() => setFocused(section.id)}
105
+ onBlur={() => setFocused(null)}
106
+ focusStyles={themeValues.focusStyles}
107
+ animate={openSection === section.id ? "open" : "closed"}
108
+ initial={initiallyOpen ? "open" : "closed"}
109
+ key={`item-${section.id}`}
110
+ extraStyles={borderStyles}
111
+ >
112
+ <Stack childGap="0">
113
+ <Box
114
+ padding={
115
+ section.hideRadioButton
116
+ ? "1.5rem"
117
+ : "1.25rem 1.5rem 1.25rem 1.25rem"
118
+ }
119
+ background={
120
+ section.disabled
121
+ ? themeValues.headingDisabledColor
122
+ : themeValues.headingBackgroundColor
123
+ }
124
+ onClick={
125
+ isMobile && supportsTouch
126
+ ? noop
127
+ : () => toggleOpenSection(section.id)
128
+ }
129
+ onTouchEnd={
130
+ isMobile && supportsTouch
131
+ ? () => toggleOpenSection(section.id)
132
+ : noop
133
+ }
134
+ key={`header-${section.id}`}
135
+ borderSize="0px"
136
+ borderColor={themeValues.borderColor}
137
+ borderWidthOverride={
138
+ openSection === section.id && !!section.content
139
+ ? `0px 0px 1px 0px`
140
+ : ``
141
+ }
142
+ extraStyles={!section.disabled ? "cursor: pointer;" : ""}
143
+ dataQa={section.dataQa ? section.dataQa : section.id}
144
+ >
145
+ <Cluster
146
+ justify="space-between"
147
+ align="center"
148
+ childGap="0.5rem"
149
+ >
150
+ <Cluster justify="flex-start" align="center">
151
+ {!section.hideRadioButton && (
152
+ <Box padding="0">
153
+ <RadioButton
154
+ name={section.id}
155
+ radioOn={openSection === section.id}
156
+ radioFocused={focused === section.id}
157
+ toggleRadio={() => toggleOpenSection(section.id)}
158
+ tabIndex="-1"
159
+ />
160
+ </Box>
161
+ )}
162
+ <Text variant="p" color={CHARADE_GREY} aria-level="3">
163
+ {section.title}
164
+ </Text>
165
+ </Cluster>
166
+ {section.rightIcons && (
167
+ <Cluster childGap="0.5rem">
168
+ {section.rightIcons.map(icon => (
169
+ <RightIcon
170
+ src={icon.img}
171
+ key={icon.img}
172
+ fade={!icon.enabled}
173
+ isMobile={isMobile}
174
+ />
175
+ ))}
176
+ </Cluster>
177
+ )}
178
+ </Cluster>
179
+ </Box>
180
+ <AnimatePresence initial={false}>
181
+ {openSection === section.id && (
182
+ <Motion
183
+ key={`content-${section.id}`}
184
+ padding="0"
185
+ background={themeValues.bodyBackgroundColor}
186
+ layoutTransition
187
+ initial="closed"
188
+ animate="open"
189
+ exit="closed"
190
+ variants={wrapper}
191
+ extraStyles={`transform-origin: 100% 0;`}
192
+ >
193
+ {section.content}
194
+ </Motion>
195
+ )}
196
+ </AnimatePresence>
197
+ </Stack>
198
+ </Motion>
199
+ ))}
200
+ </Stack>
201
+ </Box>
202
+ );
203
+ };
204
+
205
+ export default themeComponent(RadioSection, "RadioSection", fallbackValues);
@@ -0,0 +1,15 @@
1
+ import { WHITE, GREY_CHATEAU, ATHENS_GREY } from "../../../constants/colors";
2
+
3
+ const headingBackgroundColor = `${WHITE}`;
4
+ const headingDisabledColor = `${ATHENS_GREY}`;
5
+ const bodyBackgroundColor = "#eeeeee";
6
+ const borderColor = `${GREY_CHATEAU}`;
7
+ const focusStyles = `outline: none;`;
8
+
9
+ export const fallbackValues = {
10
+ headingBackgroundColor,
11
+ headingDisabledColor,
12
+ bodyBackgroundColor,
13
+ borderColor,
14
+ focusStyles
15
+ };
@@ -0,0 +1,3 @@
1
+ import RadioSection from "./RadioSection";
2
+
3
+ export default RadioSection;
@@ -0,0 +1,104 @@
1
+ import React, { useEffect } from "react";
2
+ import {
3
+ required,
4
+ hasLength,
5
+ matchesField,
6
+ hasNumber,
7
+ hasLowercaseLetter,
8
+ hasUppercaseLetter,
9
+ hasSpecialCharacter,
10
+ isProbablyEmail
11
+ } from "redux-freeform";
12
+ import PasswordRequirements from "../../atoms/password-requirements";
13
+ import { Box } from "../../atoms/layouts";
14
+ import { FormInput, FormInputColumn } from "../../atoms/form-layouts";
15
+
16
+ const RegistrationForm = ({
17
+ clearOnDismount,
18
+ fields,
19
+ actions,
20
+ handleSubmit,
21
+ showErrors,
22
+ isMobile
23
+ }) => {
24
+ if (clearOnDismount) {
25
+ useEffect(() => () => actions.form.clear(), []);
26
+ }
27
+ const firstNameErrorMessages = {
28
+ [required.error]: "First name is required"
29
+ };
30
+ const lastNameErrorMessages = {
31
+ [required.error]: "Last name is required"
32
+ };
33
+ const emailErrorMessages = {
34
+ [required.error]: "Email is required",
35
+ [isProbablyEmail.error]: "Invalid email address"
36
+ };
37
+ const passwordErrorMessages = {
38
+ [required.error]: "Password is required",
39
+ [hasLength.error]: "Password must have at least 8 characters",
40
+ [hasNumber.error]: "Password must contain at least one number",
41
+ [hasLowercaseLetter.error]:
42
+ "Password must contain at least one lowercase letter",
43
+ [hasUppercaseLetter.error]:
44
+ "Password must contain at least one uppercase letter",
45
+ [hasSpecialCharacter.error]:
46
+ "Password must contain at least one special character (!@#$%^&*.?)"
47
+ };
48
+ const confirmPasswordErrorMessages = {
49
+ [matchesField.error]: "Confirm password must match password"
50
+ };
51
+
52
+ return (
53
+ <FormInputColumn role="form" aria-label="Registration">
54
+ <FormInput
55
+ labelTextWhenNoError="First name"
56
+ errorMessages={firstNameErrorMessages}
57
+ field={fields.firstName}
58
+ fieldActions={actions.fields.firstName}
59
+ showErrors={showErrors}
60
+ onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
61
+ />
62
+ <FormInput
63
+ labelTextWhenNoError="Last name"
64
+ errorMessages={lastNameErrorMessages}
65
+ field={fields.lastName}
66
+ fieldActions={actions.fields.lastName}
67
+ showErrors={showErrors}
68
+ onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
69
+ />
70
+ <FormInput
71
+ labelTextWhenNoError="Email address"
72
+ errorMessages={emailErrorMessages}
73
+ field={fields.email}
74
+ fieldActions={actions.fields.email}
75
+ showErrors={showErrors}
76
+ onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
77
+ type="email"
78
+ />
79
+ <FormInput
80
+ labelTextWhenNoError="Password"
81
+ errorMessages={passwordErrorMessages}
82
+ field={fields.password}
83
+ fieldActions={actions.fields.password}
84
+ showErrors={showErrors}
85
+ onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
86
+ type="password"
87
+ />
88
+ <FormInput
89
+ labelTextWhenNoError="Confirm password"
90
+ errorMessages={confirmPasswordErrorMessages}
91
+ field={fields.confirmPassword}
92
+ fieldActions={actions.fields.confirmPassword}
93
+ showErrors={showErrors}
94
+ onKeyDown={e => e.key === "Enter" && handleSubmit(e)}
95
+ type="password"
96
+ />
97
+ <Box padding={isMobile ? "0" : "0.5rem 0 0"}>
98
+ <PasswordRequirements password={fields.password} isMobile={isMobile} />
99
+ </Box>
100
+ </FormInputColumn>
101
+ );
102
+ };
103
+
104
+ export default RegistrationForm;