Skip to content

Commit

Permalink
Add DirectDebitField component
Browse files Browse the repository at this point in the history
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
Abban committed Aug 27, 2024
1 parent b25ae5e commit 4f8c58c
Show file tree
Hide file tree
Showing 31 changed files with 1,358 additions and 323 deletions.
64 changes: 64 additions & 0 deletions src/api/BankValidationResource.ts
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 );
}
}
17 changes: 9 additions & 8 deletions src/components/pages/donation_form/AddressFormErrorSummaries.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
:is-visible="showErrorSummary"
:items="[
{
validity: store.state.bankdata.validity.bankdata,
validity: store.getters[ 'bankdata/bankDataIsInvalid' ] ? Validity.INVALID : Validity.VALID,
message: $t( 'donation_form_payment_bankdata_error' ),
focusElement: 'iban',
focusElement: 'account-number',
scrollElement: 'iban-scroll-target'
},
{
Expand Down Expand Up @@ -70,9 +70,9 @@
:is-visible="showErrorSummary"
:items="[
{
validity: store.state.bankdata.validity.bankdata,
validity: store.getters[ 'bankdata/bankDataIsInvalid' ] ? Validity.INVALID : Validity.VALID,
message: $t( 'donation_form_payment_bankdata_error' ),
focusElement: 'iban',
focusElement: 'account-number',
scrollElement: 'iban-scroll-target'
},
{
Expand Down Expand Up @@ -118,10 +118,10 @@
:is-visible="showErrorSummary"
:items="[
{
validity: store.state.address.validity.salutation,
message: $t( 'donation_form_salutation_error' ),
focusElement: 'email-salutation-0',
scrollElement: 'email-salutation-scroll-target'
validity: store.getters[ 'bankdata/bankDataIsInvalid' ] ? Validity.INVALID : Validity.VALID,
message: $t( 'donation_form_payment_bankdata_error' ),
focusElement: 'account-number',
scrollElement: 'iban-scroll-target'
},
{
validity: store.state.address.validity.firstName,
Expand Down Expand Up @@ -150,6 +150,7 @@
import ErrorSummary from '@src/components/shared/validation_summary/ErrorSummary.vue';
import { useStore } from 'vuex';
import { AddressTypeModel } from '@src/view_models/AddressTypeModel';
import { Validity } from '@src/view_models/Validity';
interface Props {
showErrorSummary: boolean;
Expand Down
5 changes: 2 additions & 3 deletions src/components/pages/donation_form/AddressForms.vue
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,13 @@ import { useAddressFunctions } from './AddressFunctions';
import { Salutation } from '@src/view_models/Salutation';
import { TrackingData } from '@src/view_models/TrackingData';
import { CampaignValues } from '@src/view_models/CampaignValues';
import { StoreKey } from '@src/store/donation_store';
import { injectStrict } from '@src/util/injectStrict';
import { AddressTypeIds } from '@src/components/pages/donation_form/AddressTypeIds';
import { Validity } from '@src/view_models/Validity';
import ValueEqualsPlaceholderWarning from '@src/components/shared/ValueEqualsPlaceholderWarning.vue';
import { useReceiptModel } from '@src/components/pages/donation_form/useReceiptModel';
import { useMailingListModel } from '@src/components/shared/form_fields/useMailingListModel';
import ScrollTarget from '@src/components/shared/ScrollTarget.vue';
import { useStore } from 'vuex';
interface Props {
countries: Country[],
Expand All @@ -183,7 +182,7 @@ const props = withDefaults( defineProps<Props>(), {
} );
const { addressType, isFullSelected, addressValidationPatterns } = toRefs( props );
const store = injectStrict( StoreKey );
const store = useStore();
const {
formData,
fieldErrors,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@
import RadioField from '@src/components/shared/form_fields/RadioField.vue';
import { AddressTypeModel } from '@src/view_models/AddressTypeModel';
import { useStore } from 'vuex';
import { StoreKey } from '@src/store/donation_store';
import { useAddressTypeModel } from '@src/components/pages/donation_form/DonationReceipt/useAddressTypeModel';
import { AddressFormData, AddressValidity } from '@src/view_models/Address';
import TextField from '@src/components/shared/form_fields/TextField.vue';
Expand All @@ -129,7 +128,7 @@ interface Props {
const props = defineProps<Props>();
const emit = defineEmits( [ 'field-changed' ] );
const store = useStore( StoreKey );
const store = useStore();
const addressType = useAddressTypeModel( store );
const showStreetWarning = computed<boolean>( () => /^\D+$/.test( props.formData.street.value ) );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
:is-visible="showErrorSummary"
:items="[
{
validity: store.state.bankdata.validity.bankdata,
validity: store.getters[ 'bankdata/bankDataIsInvalid' ] ? Validity.INVALID : Validity.VALID,
message: $t( 'donation_form_payment_bankdata_error' ),
focusElement: 'iban',
focusElement: 'account-number',
scrollElement: 'iban-scroll-target'
},
{
Expand Down Expand Up @@ -46,9 +46,9 @@
:is-visible="showErrorSummary"
:items="[
{
validity: store.state.bankdata.validity.bankdata,
validity: store.getters[ 'bankdata/bankDataIsInvalid' ] ? Validity.INVALID : Validity.VALID,
message: $t( 'donation_form_payment_bankdata_error' ),
focusElement: 'iban',
focusElement: 'account-number',
scrollElement: 'iban-scroll-target'
},
{
Expand Down Expand Up @@ -112,9 +112,9 @@
:is-visible="showErrorSummary"
:items="[
{
validity: store.state.bankdata.validity.bankdata,
validity: store.getters[ 'bankdata/bankDataIsInvalid' ] ? Validity.INVALID : Validity.VALID,
message: $t( 'donation_form_payment_bankdata_error' ),
focusElement: 'iban',
focusElement: 'account-number',
scrollElement: 'iban-scroll-target'
},
{
Expand Down
12 changes: 5 additions & 7 deletions src/components/pages/donation_form/subpages/AddressPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
ref="pageRef"
>
<h1 id="donation-form-heading" class="form-title">{{ $t( 'donation_form_heading' ) }}</h1>
<h2 id="donation-form-subheading" class="form-subtitle">{{ $t( 'donation_form_address_subheading' ) }}</h2>
<p id="donation-form-tagline">{{ $t( 'donation_form_section_address_tagline' ) }}</p>

<PaymentSummary
Expand All @@ -19,13 +18,12 @@
</PaymentSummary>

<form v-if="isDirectDebitPayment" id="bank-data-details" @submit="evt => evt.preventDefault()">
<ScrollTarget target-id="iban-scroll-target"/>
<PaymentBankData
:validateBankDataUrl="validateBankDataUrl"
:validateLegacyBankDataUrl="validateLegacyBankDataUrl"
/>
<h2 v-if="isDirectDebitPayment" id="donation-form-subheading" class="form-subtitle">{{ $t( 'donation_form_payment_bankdata_title' ) }}</h2>
<BankFields/>
</form>

<h2 v-if="isDirectDebitPayment" id="donation-form-subheading" class="form-subtitle">{{ $t( 'donation_form_address_subheading' ) }}</h2>

<form id="address-type-selection" @submit="evt => evt.preventDefault()">
<ScrollTarget target-id="address-type-scroll-target"/>
<AddressTypeBasic
Expand Down Expand Up @@ -96,7 +94,6 @@ import AddressTypeBasic from '@src/components/pages/donation_form/AddressTypeBas
import DonationSummary from '@src/components/pages/donation_form/DonationSummary.vue';
import PaymentSummary from '@src/components/pages/donation_form/PaymentSummary.vue';
import SubmitValues from '@src/components/pages/donation_form/SubmitValues.vue';
import PaymentBankData from '@src/components/shared/PaymentBankData.vue';
import PaymentTextFormButton from '@src/components/shared/form_elements/PaymentTextFormButton.vue';
import FormButton from '@src/components/shared/form_elements/FormButton.vue';
import FormSummary from '@src/components/shared/FormSummary.vue';
Expand All @@ -114,6 +111,7 @@ import { QUERY_STRING_INJECTION_KEY } from '@src/util/createCampaignQueryString'
import { useStore } from 'vuex';
import ScrollTarget from '@src/components/shared/ScrollTarget.vue';
import AddressFormErrorSummaries from '@src/components/pages/donation_form/AddressFormErrorSummaries.vue';
import BankFields from '@src/components/shared/BankFields.vue';
interface Props {
assetsPath: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
ref="pageRef"
>
<h1 id="donation-form-heading" class="form-title">{{ $t( 'donation_form_heading' ) }}</h1>
<h2 id="donation-form-subheading" class="form-subtitle">{{ $t( 'donation_form_address_subheading' ) }}</h2>
<p id="donation-form-tagline">{{ $t( 'donation_form_section_address_tagline' ) }}</p>

<PaymentSummary
Expand All @@ -18,14 +17,15 @@
@previous-page="previousPage">
</PaymentSummary>

<form v-if="isDirectDebitPayment" id="bank-data-details" @submit="evt => evt.preventDefault()">
<h2 v-if="isDirectDebitPayment" id="donation-form-subheading" class="form-subtitle">{{ $t( 'donation_form_payment_bankdata_title' ) }}</h2>
<BankFields/>
</form>

<h2 v-if="isDirectDebitPayment" id="donation-form-subheading" class="form-subtitle">{{ $t( 'donation_form_address_subheading' ) }}</h2>

<form @submit.prevent="submit" id="donation-form" action="/donation/add" method="post">
<AutofillHandler @autofill="onAutofill">
<ScrollTarget target-id="iban-scroll-target"/>
<PaymentBankData
v-if="isDirectDebitPayment"
:validateBankDataUrl="validateBankDataUrl"
:validateLegacyBankDataUrl="validateLegacyBankDataUrl"
/>

<NameFields
:show-error="fieldErrors"
Expand Down Expand Up @@ -133,15 +133,13 @@ import EmailField from '@src/components/shared/form_fields/EmailField.vue';
import FormButton from '@src/components/shared/form_elements/FormButton.vue';
import MailingListField from '@src/components/shared/form_fields/MailingListField.vue';
import NameFields from '@src/components/pages/donation_form/DonationReceipt/NameFields.vue';
import PaymentBankData from '@src/components/shared/PaymentBankData.vue';
import PaymentSummary from '@src/components/pages/donation_form/PaymentSummary.vue';
import RadioField from '@src/components/shared/form_fields/RadioField.vue';
import ValueEqualsPlaceholderWarning from '@src/components/shared/ValueEqualsPlaceholderWarning.vue';
import { AddressValidation } from '@src/view_models/Validation';
import { CampaignValues } from '@src/view_models/CampaignValues';
import { Country } from '@src/view_models/Country';
import { Salutation } from '@src/view_models/Salutation';
import { StoreKey } from '@src/store/donation_store';
import { TrackingData } from '@src/view_models/TrackingData';
import { Validity } from '@src/view_models/Validity';
import { adjustSalutationLocaleIfNeeded } from '@src/components/shared/SalutationLocaleAdjuster';
Expand All @@ -160,6 +158,7 @@ import FormSummary from '@src/components/shared/FormSummary.vue';
import SubmitValues from '@src/components/pages/donation_form/SubmitValues.vue';
import AddressFormErrorSummaries from '@src/components/pages/donation_form/DonationReceipt/AddressFormErrorSummaries.vue';
import ScrollTarget from '@src/components/shared/ScrollTarget.vue';
import BankFields from '@src/components/shared/BankFields.vue';
interface Props {
assetsPath: string;
Expand All @@ -176,7 +175,7 @@ interface Props {
const props = defineProps<Props>();
const emit = defineEmits( [ 'previous-page' ] );
const store = useStore( StoreKey );
const store = useStore();
const { addressType, addressTypeName } = useAddressType( store );
const { addressSummary, inlineSummaryLanguageItem } = useAddressSummary( store );
Expand Down
4 changes: 2 additions & 2 deletions src/components/pages/membership_form/SubmitValues.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<input type="hidden" name="payment_type" :value="fee.type">
<input type="hidden" name="membership_fee_interval" :value="fee.interval">
<input type="hidden" name="membership_fee" :value="fee.fee">
<input type="hidden" name="iban" :value="bankdata.iban">
<input type="hidden" name="bic" :value="bankdata.bic">
<input type="hidden" name="iban" :value="bankdata.accountNumber">
<input type="hidden" name="bic" :value="bankdata.bankCode">

<input type="hidden" name="adresstyp" :value="addressType">

Expand Down
Loading

0 comments on commit 4f8c58c

Please sign in to comment.