From 1c638026f39c7b91a76079e806892c3f331b19f7 Mon Sep 17 00:00:00 2001 From: antoniof Date: Tue, 14 Jan 2025 17:30:59 +0100 Subject: [PATCH] bsb input component --- packages/lib/src/components/PayTo/PayTo.tsx | 32 +++-- .../components/PayTo/components/BSBInput.tsx | 134 ++++++++++++++++-- .../PayTo/components/PayIDInput.scss | 12 +- .../PayTo/components/PayToComponent.tsx | 76 ++++++++++ .../PayTo/components/PayToInput.tsx | 62 -------- .../components/PayTo/components/validate.ts | 31 ++++ packages/server/translations/en-US.json | 6 +- 7 files changed, 262 insertions(+), 91 deletions(-) create mode 100644 packages/lib/src/components/PayTo/components/PayToComponent.tsx delete mode 100644 packages/lib/src/components/PayTo/components/PayToInput.tsx diff --git a/packages/lib/src/components/PayTo/PayTo.tsx b/packages/lib/src/components/PayTo/PayTo.tsx index abcb11e237..bf4bf4465c 100644 --- a/packages/lib/src/components/PayTo/PayTo.tsx +++ b/packages/lib/src/components/PayTo/PayTo.tsx @@ -9,9 +9,10 @@ Types (previously in their own file) */ import { UIElementProps } from '../internal/UIElement/types'; import { TxVariants } from '../tx-variants'; -import PayToInput from './components/PayToInput'; import { PayIdFormData } from './components/PayIDInput'; import { PayToIdentifierEnum } from './components/IdentifierSelector'; +import PayToComponent, { PayToComponentData } from './components/PayToComponent'; +import { BSBFormData } from './components/BSBInput'; export interface PayToConfiguration extends UIElementProps { paymentData?: any; @@ -19,7 +20,7 @@ export interface PayToConfiguration extends UIElementProps { placeholders?: any; //TODO } -export interface PayToData extends PayIdFormData { +export interface PayToData extends PayIdFormData, BSBFormData, PayToComponentData { shopperAccountIdentifier: string; } @@ -38,15 +39,22 @@ const config = { }; const getAccountIdentifier = (state: PayToData) => { - switch (state.selectedIdentifier) { - case PayToIdentifierEnum.email: - return state.email; - case PayToIdentifierEnum.abn: - return state.abn; - case PayToIdentifierEnum.orgid: - return state.orgid; - case PayToIdentifierEnum.phone: - return `${state.phonePrefix}-${state.phoneNumber}`; + // if it's BSB Input type merge bankAccount with BSB + if (state.selectedInput === 'bsb-option') { + return `${state.bsb}-${state.bankAccountNumber}`; + } else if (state.selectedInput === 'payid-option') { + // otherwise use the option in the dropdown + switch (state.selectedIdentifier) { + case PayToIdentifierEnum.email: + return state.email; + case PayToIdentifierEnum.abn: + return state.abn; + case PayToIdentifierEnum.orgid: + return state.orgid; + case PayToIdentifierEnum.phone: + // merge the phone prefix and number - see comment in ticket + return `${state.phonePrefix}-${state.phoneNumber}`; + } } }; /** @@ -118,7 +126,7 @@ export class PayToElement extends UIElement { return ( - void; + setComponentRef: (ref: ComponentMethodsRef) => void; +} + +const BASE_SCHEMA = ['bankAccountNumber', 'bsb', 'firstName', 'lastName']; + +export default function BSBInput({ setComponentRef, defaultData, placeholders, onChange }: BSBInputProps) { + const { i18n } = useCoreContext(); + + const form = useForm({ + schema: BASE_SCHEMA, + defaultData: defaultData, + rules: bsbValidationRules, + formatters: phoneFormatters + }); + const { handleChangeFor, triggerValidation, data, errors, valid, isValid } = form; + + // standard onChange propagate to parent state + useEffect(() => { + onChange({ data, valid, errors, isValid }); + }, [data, valid, errors, isValid]); + + const payToRef = useRef({ + showValidation: triggerValidation + }); + + useEffect(() => { + setComponentRef(payToRef.current); + }, [setComponentRef]); + + return ( +
+ + + - // TODO type this - // const { handleChangeFor, triggerValidation, data, valid, errors } = useForm({ - // schema: ['beneficiaryId'] - // }); - // - // const [status, setStatus] = useState('ready'); + + + - // this.setStatus = setStatus; - // this.showValidation = triggerValidation; + + + - return

BSBInput.tsx

; + + + +
+ ); } diff --git a/packages/lib/src/components/PayTo/components/PayIDInput.scss b/packages/lib/src/components/PayTo/components/PayIDInput.scss index 5c2cada5d3..4fc2bd9c00 100644 --- a/packages/lib/src/components/PayTo/components/PayIDInput.scss +++ b/packages/lib/src/components/PayTo/components/PayIDInput.scss @@ -1,10 +1,12 @@ @import 'styles/variable-generator'; -.adyen-checkout__fieldset--payto__payid_input { - margin-top: token(spacer-070); - - .adyen-checkout__fieldset__fields { +.adyen-checkout__payto-component { + .adyen-checkout__fieldset { margin-top: token(spacer-070); - gap: 0 token(spacer-060); + + .adyen-checkout__fieldset__fields { + margin-top: token(spacer-070); + gap: 0 token(spacer-060); + } } } diff --git a/packages/lib/src/components/PayTo/components/PayToComponent.tsx b/packages/lib/src/components/PayTo/components/PayToComponent.tsx new file mode 100644 index 0000000000..703722a63a --- /dev/null +++ b/packages/lib/src/components/PayTo/components/PayToComponent.tsx @@ -0,0 +1,76 @@ +import { h } from 'preact'; +import LoadingWrapper from '../../internal/LoadingWrapper'; +import SegmentedControl from '../../internal/SegmentedControl'; +import { useState } from 'preact/hooks'; +import { SegmentedControlOptions } from '../../internal/SegmentedControl/SegmentedControl'; +import PayIDInput from './PayIDInput'; +import BSBInput from './BSBInput'; +import { useCoreContext } from '../../../core/Context/CoreProvider'; + +export type PayToInputOption = 'payid-option' | 'bsb-option'; + +export type PayToComponentData = { selectedInput: PayToInputOption }; + +const inputOptions: SegmentedControlOptions = [ + { + value: 'payid-option', + label: 'PayID', + htmlProps: { + id: 'payid-option', // TODO move this to i18n + 'aria-controls': 'payid-input', + 'aria-expanded': true // TODO move this logic to segmented controller + } + }, + { + value: 'bsb-option', + label: 'BSB and account number', // TODO move this to i18n + htmlProps: { + id: 'bsb-option', + 'aria-controls': 'bsb-input', + 'aria-expanded': false // TODO move this logic to segmented controller + } + } +]; + +export default function PayToComponent(props) { + const { i18n } = useCoreContext(); + + const [status, setStatus] = useState('ready'); + + this.setStatus = setStatus; + + const defaultOption = inputOptions[0].value; + const [selectedInput, setSelectedInput] = useState(defaultOption); + + const onChange = ({ data, valid, errors, isValid }) => { + // merge selected input to as data, this keep the input layers untouched + props.onChange({ data: { selectedInput: selectedInput, ...data }, valid, errors, isValid }); + }; + + return ( + +
+ + {selectedInput === 'payid-option' && ( + + )} + {selectedInput === 'bsb-option' && ( + + )} + + {props.showPayButton && props.payButton({ status, label: i18n.get('confirmPurchase') })} +
+
+ ); +} diff --git a/packages/lib/src/components/PayTo/components/PayToInput.tsx b/packages/lib/src/components/PayTo/components/PayToInput.tsx deleted file mode 100644 index 7a0c2839f7..0000000000 --- a/packages/lib/src/components/PayTo/components/PayToInput.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { h } from 'preact'; -import LoadingWrapper from '../../internal/LoadingWrapper'; -import SegmentedControl from '../../internal/SegmentedControl'; -import { useState } from 'preact/hooks'; -import { SegmentedControlOptions } from '../../internal/SegmentedControl/SegmentedControl'; -import PayIDInput from './PayIDInput'; -import BSBInput from './BSBInput'; -import { useCoreContext } from '../../../core/Context/CoreProvider'; - -const inputOptions: SegmentedControlOptions = [ - { - value: 'payid-option', - label: 'PayID', - htmlProps: { - id: 'payid-option', // TODO move this to i18n - 'aria-controls': 'payid-input', - 'aria-expanded': true // TODO move this logic to segmented controller - } - }, - { - value: 'bsb-option', - label: 'BSB and account number', // TODO move this to i18n - htmlProps: { - id: 'bsb-option', - 'aria-controls': 'bsb-input', - 'aria-expanded': false // TODO move this logic to segmented controller - } - } -]; - -export default function PayToInput(props) { - const { i18n } = useCoreContext(); - - const [status, setStatus] = useState('ready'); - - this.setStatus = setStatus; - - const defaultOption = inputOptions[0].value; - const [selectedInput, setSelectedInput] = useState(defaultOption); - - const onChange = ({ data, valid, errors, isValid }) => { - props.onChange({ data, valid, errors, isValid }); - }; - - return ( - - - {selectedInput === 'payid-option' && ( - - )} - {selectedInput === 'bsb-option' && } - - {props.showPayButton && props.payButton({ status, label: i18n.get('confirmPurchase') })} - - ); -} diff --git a/packages/lib/src/components/PayTo/components/validate.ts b/packages/lib/src/components/PayTo/components/validate.ts index 6666f96afd..fb81089d24 100644 --- a/packages/lib/src/components/PayTo/components/validate.ts +++ b/packages/lib/src/components/PayTo/components/validate.ts @@ -74,3 +74,34 @@ export const payIdValidationRules: ValidatorRules = { errorMessage: 'mobileNumber.invalid' } }; + +//original regex /^\d{6}-[ -~]{1,28}$/ +const bsbRegex = /^\d{6}$/; +const bankAccountNumberRegex = /^[ -~]{1,28}$/; + +const bsbValidatorRule: ValidatorRule = { + validate: value => validationFromRegex(value, bsbRegex, bsbValidatorRule), + errorMessage: 'bsb.invalid', + modes: ['blur'] +}; + +const bankAccountNumberValidatorRule: ValidatorRule = { + validate: value => validationFromRegex(value, bankAccountNumberRegex, bankAccountNumberValidatorRule), + errorMessage: 'bankAccountNumber.invalid', + modes: ['blur'] +}; + +export const bsbValidationRules: ValidatorRules = { + bsb: bsbValidatorRule, + bankAccountNumber: bankAccountNumberValidatorRule, + firstName: { + validate: value => (isEmpty(value) ? null : true), // valid, if there are chars other than spaces, + errorMessage: 'firstName.invalid', + modes: ['blur'] + }, + lastName: { + validate: value => (isEmpty(value) ? null : true), + errorMessage: 'lastName.invalid', + modes: ['blur'] + } +}; diff --git a/packages/server/translations/en-US.json b/packages/server/translations/en-US.json index 0daa27cb21..d8a14a46e5 100644 --- a/packages/server/translations/en-US.json +++ b/packages/server/translations/en-US.json @@ -333,5 +333,9 @@ "payto.payid.option.phone": "Mobile", "payto.payid.option.email": "Email", "payto.payid.option.abn": "ABN", - "payto.payid.option.orgid": "Organization ID" + "payto.payid.option.orgid": "Organization ID", + "payto.bsb.header": "BSB", + "payto.bsb.description" : "Enter the bank account number and the Bank State Branch that is connected to your account to continue", + "payto.bsb.label.bankAccountNumber": "Bank account number", + "payto.bsb.label.bsb": "Bank State Branch" } \ No newline at end of file