-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is drop in replacement for the PaymentBankData component that is more accessible and integrated with our form fields components. ## Refactored the bankdata store - Added accountNumber and bankCode fields, as the direct debit field will accept both IBAN and account numbers making the naming confusing. - Added getters actions and mutations for the new fields. - Updated the typescript interfaces to reflect the new structure. ## Added an API resource This makes the API calls that validate the bank data more consistent with our other API resources ## Added a BankFields component The pattern for our form fields is that they take in model values and do not access the store directly, We then use wrapper components to manage store access. That's what this component is for. ## Added a DirectDebitField This handles visibility of labels, and formatting values when fields receive input. ## Added TextValueField As we're formatting the value in the input box we need a field similar to TextField that uses a prop as the value rather than take in a model. Ticket: https://phabricator.wikimedia.org/T364953
- Loading branch information
Showing
27 changed files
with
1,334 additions
and
297 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { BankAccountNumberRequest, BankAccountResponse, BankIbanRequest } from '@src/view_models/BankAccount'; | ||
import axios from 'axios'; | ||
|
||
export interface BankValidationResource { | ||
validateIban: ( data: BankIbanRequest ) => Promise<BankAccountResponse>; | ||
validateBankNumber: ( data: BankAccountNumberRequest ) => Promise<BankAccountResponse>; | ||
} | ||
|
||
export interface APIResponse { | ||
status: string; | ||
iban: string; | ||
bic: string; | ||
account: string; | ||
bankCode: string; | ||
bankName?: string; | ||
} | ||
|
||
export class ApiBankValidationResource implements BankValidationResource { | ||
validateIbanEndpoint: string; | ||
validateBankNumberEndpoint: string; | ||
|
||
constructor( validateIbanEndpoint: string, validateBankNumberEndpoint: string ) { | ||
this.validateIbanEndpoint = validateIbanEndpoint; | ||
this.validateBankNumberEndpoint = validateBankNumberEndpoint; | ||
} | ||
|
||
async validateIban( data: BankIbanRequest ): Promise<BankAccountResponse> { | ||
return this.validateBankData( this.validateIbanEndpoint, data ).then( ( response: APIResponse ) => { | ||
return { | ||
accountNumber: response.account, | ||
bankCode: response.bankCode, | ||
bankName: response.bankName, | ||
iban: response.iban, | ||
bic: response.bic, | ||
}; | ||
} ); | ||
} | ||
|
||
async validateBankNumber( data: BankAccountNumberRequest ): Promise<BankAccountResponse> { | ||
return this.validateBankData( this.validateBankNumberEndpoint, data ).then( ( response: APIResponse ) => { | ||
return { | ||
accountNumber: response.account, | ||
bankCode: response.bankCode, | ||
bankName: response.bankName, | ||
iban: response.iban, | ||
bic: response.bic, | ||
}; | ||
} ); | ||
} | ||
|
||
async validateBankData( endpoint: string, data: BankAccountNumberRequest | BankIbanRequest ): Promise<APIResponse> { | ||
let validationResult = await axios( endpoint, { | ||
method: 'get', | ||
headers: { 'Content-Type': 'multipart/form-data' }, | ||
params: data, | ||
} ); | ||
|
||
if ( validationResult.data.status === 'ERR' ) { | ||
return Promise.reject( 'ERR' ); | ||
} | ||
|
||
return Promise.resolve( validationResult.data ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<template> | ||
<div class="payment-bank-data-section"> | ||
<ScrollTarget target-id="iban-scroll-target"/> | ||
<DirectDebitField | ||
v-model:account-number="accountNumber" | ||
v-model:bank-code="bankCode" | ||
:bank-name="bankName" | ||
:bic="bic" | ||
:account-number-type="accountNumberType" | ||
:show-account-number-error="showError" | ||
:show-bank-code-error="showError" | ||
:bank-validation-resource="bankValidationResource" | ||
@field-changed="validateFields" | ||
/> | ||
</div> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import DirectDebitField from '@src/components/shared/form_fields/DirectDebitField.vue'; | ||
import { computed, inject, ref } from 'vue'; | ||
import ScrollTarget from '@src/components/shared/ScrollTarget.vue'; | ||
import { useStore } from 'vuex'; | ||
import { BankValidationResource } from '@src/api/BankValidationResource'; | ||
import { action } from '@src/store/util'; | ||
import { looksLikeBankAccountNumber, looksLikeIban } from '@src/util/bank_account_number_helpers'; | ||
import { AccountNumberType, BankAccountResponse } from '@src/view_models/BankAccount'; | ||
import { Validity } from '@src/view_models/Validity'; | ||
const store = useStore(); | ||
const bankValidationResource = inject<BankValidationResource>( 'bankValidationResource' ); | ||
const accountNumber = ref<string>( store.getters[ 'bankdata/accountNumber' ] ); | ||
const bankCode = ref<string>( store.getters[ 'bankdata/bankCode' ] ); | ||
const bankName = computed<string>( () => store.getters[ 'bankdata/bankName' ] ); | ||
const bic = computed<string>( () => store.getters[ 'bankdata/bic' ] ); | ||
const showError = computed<boolean>( () => store.getters[ 'bankdata/bankDataIsInvalid' ] ); | ||
const accountNumberType = computed<AccountNumberType>( () => { | ||
if ( looksLikeIban( accountNumber.value ) ) { | ||
return AccountNumberType.IBAN; | ||
} | ||
if ( looksLikeBankAccountNumber( accountNumber.value ) ) { | ||
return AccountNumberType.Account; | ||
} | ||
return AccountNumberType.None; | ||
} ); | ||
const validateFields = async ( fieldName: 'account-number' | 'bank-code' ): Promise<void> => { | ||
if ( fieldName === 'account-number' ) { | ||
await store.dispatch( action( 'bankdata', 'setAccountNumber' ), accountNumber.value ); | ||
} | ||
if ( fieldName === 'bank-code' ) { | ||
await store.dispatch( action( 'bankdata', 'setBankCode' ), bankCode.value ); | ||
} | ||
if ( accountNumberType.value !== AccountNumberType.Account || fieldName === 'bank-code' ) { | ||
await store.dispatch( action( 'bankdata', 'markEmptyFieldsAsInvalid' ) ); | ||
} | ||
if ( !store.getters[ 'bankdata/bankDataIsValid' ] ) { | ||
return Promise.resolve(); | ||
} | ||
let response: BankAccountResponse; | ||
await store.dispatch( action( 'bankdata', 'setValidating' ), true ); | ||
try { | ||
if ( accountNumberType.value === AccountNumberType.IBAN ) { | ||
response = await bankValidationResource.validateIban( { | ||
iban: accountNumber.value.toUpperCase(), | ||
} ); | ||
await store.dispatch( action( 'bankdata', 'setAccountNumber' ), response.iban ); | ||
await store.dispatch( action( 'bankdata', 'setBankCode' ), '' ); | ||
} else { | ||
response = await bankValidationResource.validateBankNumber( { | ||
accountNumber: accountNumber.value, | ||
bankCode: bankCode.value, | ||
} ); | ||
await store.dispatch( action( 'bankdata', 'setAccountNumber' ), response.accountNumber ); | ||
await store.dispatch( action( 'bankdata', 'setBankCode' ), response.bankCode ); | ||
} | ||
await store.dispatch( action( 'bankdata', 'setBankDataValidity' ), Validity.VALID ); | ||
await store.dispatch( action( 'bankdata', 'setBankName' ), response.bankName ); | ||
await store.dispatch( action( 'bankdata', 'setIban' ), response.iban ); | ||
await store.dispatch( action( 'bankdata', 'setBic' ), response.bic ); | ||
} catch ( e ) { | ||
await store.dispatch( action( 'bankdata', 'setBankDataValidity' ), Validity.INVALID ); | ||
await store.dispatch( action( 'bankdata', 'setBankName' ), '' ); | ||
await store.dispatch( action( 'bankdata', 'setIban' ), '' ); | ||
await store.dispatch( action( 'bankdata', 'setBic' ), '' ); | ||
} | ||
await store.dispatch( action( 'bankdata', 'setValidating' ), false ); | ||
}; | ||
store.watch( ( state, getters ) => getters[ 'bankdata/accountNumber' ], ( newAccountNumber: string ) => { | ||
accountNumber.value = newAccountNumber; | ||
} ); | ||
store.watch( ( state, getters ) => getters[ 'bankdata/bankCode' ], ( newBankCode: string ) => { | ||
bankCode.value = newBankCode; | ||
} ); | ||
</script> |
Oops, something went wrong.