@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.
- package/.eslintrc.json +29 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +18 -0
- package/.github/stale.yml +17 -0
- package/.prettierignore +3 -0
- package/.tool-versions +1 -0
- package/README.md +149 -0
- package/dist/cb-components.cjs.js +77 -0
- package/package.json +96 -0
- package/rollup.config.js +35 -0
- package/src/components/atoms/alert/Alert.js +67 -0
- package/src/components/atoms/alert/Alert.theme.js +71 -0
- package/src/components/atoms/alert/index.js +3 -0
- package/src/components/atoms/amount-callout/AmountCallout.js +27 -0
- package/src/components/atoms/amount-callout/AmountCallout.theme.js +19 -0
- package/src/components/atoms/amount-callout/index.js +3 -0
- package/src/components/atoms/breadcrumb/Breadcrumb.js +50 -0
- package/src/components/atoms/breadcrumb/Breadcrumb.theme.js +25 -0
- package/src/components/atoms/breadcrumb/index.js +3 -0
- package/src/components/atoms/button-with-action/ButtonWithAction.js +128 -0
- package/src/components/atoms/button-with-action/ButtonWithAction.stories.js +125 -0
- package/src/components/atoms/button-with-action/ButtonWithAction.theme.js +360 -0
- package/src/components/atoms/button-with-action/index.js +3 -0
- package/src/components/atoms/button-with-link/ButtonWithLink.js +40 -0
- package/src/components/atoms/button-with-link/index.js +3 -0
- package/src/components/atoms/checkbox/Checkbox.js +143 -0
- package/src/components/atoms/checkbox/Checkbox.theme.js +54 -0
- package/src/components/atoms/checkbox/index.js +3 -0
- package/src/components/atoms/checkbox-list/CheckboxList.js +129 -0
- package/src/components/atoms/checkbox-list/CheckboxList.theme.js +42 -0
- package/src/components/atoms/checkbox-list/index.js +3 -0
- package/src/components/atoms/country-dropdown/CountryDropdown.js +24 -0
- package/src/components/atoms/country-dropdown/index.js +1 -0
- package/src/components/atoms/country-dropdown/options.js +249 -0
- package/src/components/atoms/display-box/DisplayBox.js +22 -0
- package/src/components/atoms/display-box/DisplayBox.theme.js +9 -0
- package/src/components/atoms/display-box/index.js +3 -0
- package/src/components/atoms/display-card/DisplayCard.js +65 -0
- package/src/components/atoms/display-card/index.js +3 -0
- package/src/components/atoms/dropdown/Dropdown.js +299 -0
- package/src/components/atoms/dropdown/Dropdown.theme.js +9 -0
- package/src/components/atoms/dropdown/DropdownIcon.js +31 -0
- package/src/components/atoms/dropdown/index.js +3 -0
- package/src/components/atoms/form-layouts/FormContainer.js +28 -0
- package/src/components/atoms/form-layouts/FormInput.js +218 -0
- package/src/components/atoms/form-layouts/FormInputColumn.js +15 -0
- package/src/components/atoms/form-layouts/FormInputRow.js +26 -0
- package/src/components/atoms/form-layouts/FormLayouts.theme.js +52 -0
- package/src/components/atoms/form-layouts/index.js +6 -0
- package/src/components/atoms/form-select/FormSelect.js +62 -0
- package/src/components/atoms/form-select/FormSelect.styled.js +65 -0
- package/src/components/atoms/form-select/index.js +3 -0
- package/src/components/atoms/formatted-address/FormattedAddress.js +53 -0
- package/src/components/atoms/formatted-address/FormattedAddress.theme.js +11 -0
- package/src/components/atoms/formatted-address/index.js +3 -0
- package/src/components/atoms/hamburger-button/HamburgerButton.js +113 -0
- package/src/components/atoms/hamburger-button/index.js +3 -0
- package/src/components/atoms/heading/Heading.js +37 -0
- package/src/components/atoms/heading/Heading.styled.js +14 -0
- package/src/components/atoms/heading/Heading.theme.js +18 -0
- package/src/components/atoms/heading/index.js +3 -0
- package/src/components/atoms/icons/AccountsAddIcon.js +42 -0
- package/src/components/atoms/icons/AccountsIcon.js +37 -0
- package/src/components/atoms/icons/AccountsIconSmall.js +63 -0
- package/src/components/atoms/icons/ChevronIcon.js +51 -0
- package/src/components/atoms/icons/ForgotPasswordIcon.js +46 -0
- package/src/components/atoms/icons/GoToEmailIcon.js +31 -0
- package/src/components/atoms/icons/Icons.theme.js +38 -0
- package/src/components/atoms/icons/PaymentMethodIcon.js +42 -0
- package/src/components/atoms/icons/PaymentsIconSmall.js +63 -0
- package/src/components/atoms/icons/ProfileIconSmall.js +44 -0
- package/src/components/atoms/icons/PropertiesAddIcon.js +70 -0
- package/src/components/atoms/icons/PropertiesIconSmall.js +32 -0
- package/src/components/atoms/icons/SettingsIconSmall.js +63 -0
- package/src/components/atoms/icons/VerifiedEmailIcon.js +53 -0
- package/src/components/atoms/icons/index.js +28 -0
- package/src/components/atoms/index.js +33 -0
- package/src/components/atoms/labeled-amount/LabeledAmount.js +35 -0
- package/src/components/atoms/labeled-amount/LabeledAmount.theme.js +10 -0
- package/src/components/atoms/labeled-amount/index.js +3 -0
- package/src/components/atoms/layouts/Box.js +83 -0
- package/src/components/atoms/layouts/Box.styled.js +131 -0
- package/src/components/atoms/layouts/Center.js +28 -0
- package/src/components/atoms/layouts/Center.styled.js +18 -0
- package/src/components/atoms/layouts/Cluster.js +37 -0
- package/src/components/atoms/layouts/Cluster.styled.js +21 -0
- package/src/components/atoms/layouts/Cover.js +49 -0
- package/src/components/atoms/layouts/Cover.styled.js +29 -0
- package/src/components/atoms/layouts/Frame.js +28 -0
- package/src/components/atoms/layouts/Frame.styled.js +27 -0
- package/src/components/atoms/layouts/Grid.js +38 -0
- package/src/components/atoms/layouts/Grid.styled.js +22 -0
- package/src/components/atoms/layouts/Imposter.js +52 -0
- package/src/components/atoms/layouts/Imposter.styled.js +19 -0
- package/src/components/atoms/layouts/Motion.js +51 -0
- package/src/components/atoms/layouts/Motion.styled.js +41 -0
- package/src/components/atoms/layouts/Reel.js +28 -0
- package/src/components/atoms/layouts/Reel.styled.js +17 -0
- package/src/components/atoms/layouts/Sidebar.js +42 -0
- package/src/components/atoms/layouts/Sidebar.styled.js +38 -0
- package/src/components/atoms/layouts/Stack.js +36 -0
- package/src/components/atoms/layouts/Stack.styled.js +30 -0
- package/src/components/atoms/layouts/Switcher.js +64 -0
- package/src/components/atoms/layouts/Switcher.styled.js +44 -0
- package/src/components/atoms/layouts/examples/FixedSizeContainer.js +22 -0
- package/src/components/atoms/layouts/examples/FixedSizeContainer.styled.js +20 -0
- package/src/components/atoms/layouts/examples/LayoutContentBlock.js +27 -0
- package/src/components/atoms/layouts/examples/LayoutContentBlock.styled.js +15 -0
- package/src/components/atoms/layouts/examples/ResizingContainer.js +49 -0
- package/src/components/atoms/layouts/examples/ResizingContainer.styled.js +39 -0
- package/src/components/atoms/layouts/examples/cluster-example/ClusterExample.js +10 -0
- package/src/components/atoms/layouts/examples/cluster-example/ClusterExample.stories.js +97 -0
- package/src/components/atoms/layouts/examples/grid-example/GridExample.js +49 -0
- package/src/components/atoms/layouts/examples/grid-example/GridExample.stories.js +44 -0
- package/src/components/atoms/layouts/examples/sidebar-example/SidebarExample.js +11 -0
- package/src/components/atoms/layouts/examples/sidebar-example/SidebarExample.stories.js +87 -0
- package/src/components/atoms/layouts/examples/stack-example/StackExample.js +27 -0
- package/src/components/atoms/layouts/examples/stack-example/StackExample.stories.js +69 -0
- package/src/components/atoms/layouts/examples/switcher-example/SwitcherExample.js +38 -0
- package/src/components/atoms/layouts/examples/switcher-example/SwitcherExample.stories.js +65 -0
- package/src/components/atoms/layouts/index.js +27 -0
- package/src/components/atoms/line-item/LineItem.js +30 -0
- package/src/components/atoms/line-item/LineItem.theme.js +7 -0
- package/src/components/atoms/line-item/index.js +3 -0
- package/src/components/atoms/link/ExternalLink.js +50 -0
- package/src/components/atoms/link/ExternalLink.styled.js +26 -0
- package/src/components/atoms/link/InternalLink.js +51 -0
- package/src/components/atoms/link/InternalLink.styled.js +39 -0
- package/src/components/atoms/link/Link.theme.js +8 -0
- package/src/components/atoms/link/index.js +4 -0
- package/src/components/atoms/nav-footer/NavFooter.js +57 -0
- package/src/components/atoms/nav-footer/index.js +3 -0
- package/src/components/atoms/nav-header/NavHeader.js +36 -0
- package/src/components/atoms/nav-header/index.js +3 -0
- package/src/components/atoms/paragraph/Paragraph.js +31 -0
- package/src/components/atoms/paragraph/Paragraph.styled.js +13 -0
- package/src/components/atoms/paragraph/Paragraph.theme.js +18 -0
- package/src/components/atoms/paragraph/index.js +3 -0
- package/src/components/atoms/password-requirements/PasswordRequirements.js +116 -0
- package/src/components/atoms/password-requirements/index.js +3 -0
- package/src/components/atoms/placeholder/Placeholder.js +122 -0
- package/src/components/atoms/placeholder/Placeholder.theme.js +9 -0
- package/src/components/atoms/placeholder/index.js +3 -0
- package/src/components/atoms/processing-fee/ProcessingFee.js +43 -0
- package/src/components/atoms/processing-fee/ProcessingFee.theme.js +7 -0
- package/src/components/atoms/processing-fee/index.js +3 -0
- package/src/components/atoms/radio-button/RadioButton.js +101 -0
- package/src/components/atoms/radio-button/RadioButton.theme.js +9 -0
- package/src/components/atoms/radio-button/index.js +3 -0
- package/src/components/atoms/solid-divider/SolidDivider.js +22 -0
- package/src/components/atoms/solid-divider/SolidDivider.theme.js +8 -0
- package/src/components/atoms/solid-divider/index.js +3 -0
- package/src/components/atoms/spinner/Spinner.js +61 -0
- package/src/components/atoms/spinner/Spinner.theme.js +5 -0
- package/src/components/atoms/spinner/index.js +3 -0
- package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.js +28 -0
- package/src/components/atoms/state-province-dropdown/index.js +3 -0
- package/src/components/atoms/state-province-dropdown/options.js +3837 -0
- package/src/components/atoms/text/Text.js +37 -0
- package/src/components/atoms/text/Text.styled.js +32 -0
- package/src/components/atoms/text/Text.theme.js +22 -0
- package/src/components/atoms/text/index.js +3 -0
- package/src/components/atoms/toggle-switch/ToggleSwitch.js +212 -0
- package/src/components/atoms/toggle-switch/ToggleSwitch.theme.js +36 -0
- package/src/components/atoms/toggle-switch/index.js +3 -0
- package/src/components/index.js +3 -0
- package/src/components/molecules/address-form/AddressForm.js +110 -0
- package/src/components/molecules/address-form/AddressForm.state.js +52 -0
- package/src/components/molecules/address-form/index.js +11 -0
- package/src/components/molecules/change-password-form/ChangePasswordForm.js +92 -0
- package/src/components/molecules/change-password-form/ChangePasswordForm.state.js +33 -0
- package/src/components/molecules/change-password-form/index.js +11 -0
- package/src/components/molecules/collapsible-section/CollapsibleSection.js +126 -0
- package/src/components/molecules/collapsible-section/CollapsibleSection.theme.js +11 -0
- package/src/components/molecules/collapsible-section/index.js +3 -0
- package/src/components/molecules/edit-name-form/EditNameForm.js +51 -0
- package/src/components/molecules/edit-name-form/EditNameForm.state.js +14 -0
- package/src/components/molecules/edit-name-form/index.js +11 -0
- package/src/components/molecules/email-form/EmailForm.js +55 -0
- package/src/components/molecules/email-form/EmailForm.state.js +19 -0
- package/src/components/molecules/email-form/index.js +11 -0
- package/src/components/molecules/forgot-password-form/ForgotPasswordForm.js +32 -0
- package/src/components/molecules/forgot-password-form/ForgotPasswordForm.state.js +11 -0
- package/src/components/molecules/forgot-password-form/index.js +11 -0
- package/src/components/molecules/highlight-tab-row/HighlightTabRow.js +62 -0
- package/src/components/molecules/highlight-tab-row/HighlightTabRow.theme.js +7 -0
- package/src/components/molecules/highlight-tab-row/index.js +8 -0
- package/src/components/molecules/index.js +24 -0
- package/src/components/molecules/login-form/LoginForm.js +46 -0
- package/src/components/molecules/login-form/LoginForm.state.js +14 -0
- package/src/components/molecules/login-form/index.js +11 -0
- package/src/components/molecules/modal/Modal.js +138 -0
- package/src/components/molecules/modal/index.js +3 -0
- package/src/components/molecules/module/Module.js +42 -0
- package/src/components/molecules/module/Module.theme.js +30 -0
- package/src/components/molecules/module/index.js +8 -0
- package/src/components/molecules/nav-menu/NavMenu.theme.js +5 -0
- package/src/components/molecules/nav-menu/NavMenuDesktop.js +39 -0
- package/src/components/molecules/nav-menu/NavMenuMobile.js +63 -0
- package/src/components/molecules/nav-menu/index.js +4 -0
- package/src/components/molecules/obligation/Obligation.js +69 -0
- package/src/components/molecules/obligation/icons/AccountBillIcon.js +89 -0
- package/src/components/molecules/obligation/icons/AccountConstructionIcon.js +99 -0
- package/src/components/molecules/obligation/icons/AccountDentalIcon.js +94 -0
- package/src/components/molecules/obligation/icons/AccountElectricIcon.js +99 -0
- package/src/components/molecules/obligation/icons/AccountGarbageIcon.js +94 -0
- package/src/components/molecules/obligation/icons/AccountGasIcon.js +94 -0
- package/src/components/molecules/obligation/icons/AccountGenericIcon.js +89 -0
- package/src/components/molecules/obligation/icons/AccountMedicalIcon.js +94 -0
- package/src/components/molecules/obligation/icons/AccountWaterIcon.js +94 -0
- package/src/components/molecules/obligation/icons/PropertyApartmentIcon.js +99 -0
- package/src/components/molecules/obligation/icons/PropertyBusinessIcon.js +94 -0
- package/src/components/molecules/obligation/icons/PropertyCarIcon.js +99 -0
- package/src/components/molecules/obligation/icons/PropertyCommercialVehicleIcon.js +100 -0
- package/src/components/molecules/obligation/icons/PropertyGarageIcon.js +96 -0
- package/src/components/molecules/obligation/icons/PropertyLandIcon.js +99 -0
- package/src/components/molecules/obligation/icons/PropertyMotorcycleIcon.js +99 -0
- package/src/components/molecules/obligation/icons/PropertyPersonalIcon.js +94 -0
- package/src/components/molecules/obligation/icons/PropertyStorefrontIcon.js +100 -0
- package/src/components/molecules/obligation/icons/index.js +60 -0
- package/src/components/molecules/obligation/index.js +3 -0
- package/src/components/molecules/obligation/modules/AmountModule.js +36 -0
- package/src/components/molecules/obligation/modules/IconModule.js +29 -0
- package/src/components/molecules/obligation/modules/PaymentDetailsActions.js +67 -0
- package/src/components/molecules/obligation/modules/TitleModule.js +25 -0
- package/src/components/molecules/obligation/modules/index.js +6 -0
- package/src/components/molecules/payment-button-bar/PaymentButtonBar.js +80 -0
- package/src/components/molecules/payment-button-bar/index.js +3 -0
- package/src/components/molecules/payment-details/PaymentDetails.js +158 -0
- package/src/components/molecules/payment-details/PaymentDetails.theme.js +11 -0
- package/src/components/molecules/payment-details/index.js +1 -0
- package/src/components/molecules/phone-form/PhoneForm.js +44 -0
- package/src/components/molecules/phone-form/PhoneForm.state.js +17 -0
- package/src/components/molecules/phone-form/index.js +11 -0
- package/src/components/molecules/radio-section/RadioSection.js +205 -0
- package/src/components/molecules/radio-section/RadioSection.theme.js +15 -0
- package/src/components/molecules/radio-section/index.js +3 -0
- package/src/components/molecules/registration-form/RegistrationForm.js +104 -0
- package/src/components/molecules/registration-form/RegistrationForm.state.js +40 -0
- package/src/components/molecules/registration-form/index.js +11 -0
- package/src/components/molecules/reset-confirmation-form/ResetConfirmationForm.js +56 -0
- package/src/components/molecules/reset-confirmation-form/index.js +3 -0
- package/src/components/molecules/reset-password-form/ResetPasswordForm.js +67 -0
- package/src/components/molecules/reset-password-form/ResetPasswordForm.state.js +30 -0
- package/src/components/molecules/reset-password-form/index.js +11 -0
- package/src/components/molecules/reset-password-success/ResetPasswordSuccess.js +55 -0
- package/src/components/molecules/reset-password-success/index.js +3 -0
- package/src/components/molecules/tab-sidebar/TabSidebar.js +92 -0
- package/src/components/molecules/tab-sidebar/TabSidebar.theme.js +9 -0
- package/src/components/molecules/tab-sidebar/index.js +3 -0
- package/src/components/molecules/terms-and-conditions/TermsAndConditions.js +73 -0
- package/src/components/molecules/terms-and-conditions/index.js +3 -0
- package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.js +64 -0
- package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.theme.js +28 -0
- package/src/components/molecules/terms-and-conditions-modal/index.js +3 -0
- package/src/components/molecules/workflow-tile/WorkflowTile.js +58 -0
- package/src/components/molecules/workflow-tile/index.js +3 -0
- package/src/components/templates/center-single/CenterSingle.js +61 -0
- package/src/components/templates/center-single/index.js +3 -0
- package/src/components/templates/center-stack/CenterStack.js +49 -0
- package/src/components/templates/center-stack/index.js +3 -0
- package/src/components/templates/default-page-template/DefaultPageTemplate.js +49 -0
- package/src/components/templates/default-page-template/index.js +3 -0
- package/src/components/templates/index.js +5 -0
- package/src/components/templates/sidebar-single-content/SidebarSingleContent.js +60 -0
- package/src/components/templates/sidebar-single-content/index.js +3 -0
- package/src/components/templates/sidebar-stack-content/SidebarStackContent.js +81 -0
- package/src/components/templates/sidebar-stack-content/index.js +3 -0
- package/src/components/templates/templates.theme.js +5 -0
- package/src/components/withWindowSize.js +50 -0
- package/src/constants/colors.js +178 -0
- package/src/constants/regex_constants.js +1 -0
- package/src/constants/style_constants.js +21 -0
- package/src/deprecated/colors.js +154 -0
- package/src/deprecated/components/radio-button/index.js +3 -0
- package/src/deprecated/components/radio-button/radio-button.js +44 -0
- package/src/deprecated/icons/AlertErrorIcon.js +42 -0
- package/src/deprecated/icons/AlertInfoIcon.js +42 -0
- package/src/deprecated/icons/AlertSuccessIcon.js +42 -0
- package/src/deprecated/icons/AlertWarningIcon.js +36 -0
- package/src/deprecated/icons/BankIcon.js +82 -0
- package/src/deprecated/icons/GenericCard.js +39 -0
- package/src/deprecated/icons/IconAdd.js +44 -0
- package/src/deprecated/icons/IconCheck.js +23 -0
- package/src/deprecated/icons/IconCheckEmail.js +46 -0
- package/src/deprecated/icons/IconChevron.js +35 -0
- package/src/deprecated/icons/IconEmailVerified.js +62 -0
- package/src/deprecated/icons/IconEye.js +32 -0
- package/src/deprecated/icons/IconEyeSlash.js +48 -0
- package/src/deprecated/icons/IconInvalid.js +69 -0
- package/src/deprecated/icons/IconNeutral.js +27 -0
- package/src/deprecated/icons/IconQuit.js +32 -0
- package/src/deprecated/icons/IconValid.js +72 -0
- package/src/deprecated/icons/IconWarn.js +28 -0
- package/src/deprecated/icons/index.js +40 -0
- package/src/deprecated/index.js +1 -0
- package/src/deprecated/spinner/Spinner.js +68 -0
- package/src/deprecated/spinner/index.js +1 -0
- package/src/deprecated/utility/__tests__/safeConcat.spec.js +59 -0
- package/src/deprecated/utility/__tests__/validateKeyType.spec.js +116 -0
- package/src/deprecated/utility/index.js +2 -0
- package/src/deprecated/utility/safeConcat.js +10 -0
- package/src/deprecated/utility/validateKeyType.js +19 -0
- package/src/index.js +2 -0
- package/src/util/formats.js +30 -0
- package/src/util/general.js +15 -0
- package/src/util/inputValidationUtils.js +257 -0
- package/src/util/router-utils.js +23 -0
- 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,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,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;
|