From 9e77c07b3a3972e84b22e27f1e41b8ea73bf25a6 Mon Sep 17 00:00:00 2001 From: Abban Dunne Date: Fri, 27 Sep 2024 14:11:20 +0200 Subject: [PATCH] Add radio inputs to amount field The amount field consisted of a group of hidden radio inputs and a text field. The problems with this are: - It's not clear to the donor what type of field they're interacting with. - When the donor has filled out the custom amount or has come from a banner or email with a value that isn't covered by one of the radio fields it's hard to see that the amount they want to donate is in the custom amount. This commit changes the following: - Make the radio inputs visible, making it clearer to the donor that the field group they're interacting with is a radio field. - Add a visual only radio input over the text field to make it more visually consistent with the other inputs in the field group and make it more clear when the inputted amount is custom. Ticket: https://phabricator.wikimedia.org/T375380 --- .../shared/form_fields/AmountField.vue | 51 ++++++++++++------- .../shared/form_fields/AmountField.spec.ts | 16 ++++++ 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/components/shared/form_fields/AmountField.vue b/src/components/shared/form_fields/AmountField.vue index ceebdc806..8712e7818 100644 --- a/src/components/shared/form_fields/AmountField.vue +++ b/src/components/shared/form_fields/AmountField.vue @@ -30,6 +30,10 @@
+
+ +
+ props.modelValue, ( newValue: string ) => { @use '@src/scss/settings/colors'; @use '@src/scss/settings/forms'; @use '@src/scss/mixins/visibility'; +@use '@src/scss/settings/breakpoints'; @use 'sass:map'; $max-width: 384px; @@ -164,14 +169,18 @@ $input-height: 50px; &-radio-container { display: flex; flex-wrap: wrap; - margin: 0 ( -( map.get( units.$spacing, 'small' ) ) ); + margin: 0 ( -( map.get( units.$spacing, 'xx-small' ) ) ); } &-radio { - width: 25%; - padding: 0 map.get( units.$spacing, 'small' ) map.get( units.$spacing, 'small' ); + width: 50%; + padding: 0 map.get( units.$spacing, 'xx-small' ) map.get( units.$spacing, 'small' ); font-size: 16px; + @include breakpoints.tablet-up { + width: 25%; + } + .radio-form-input { padding: 0; margin: 0; @@ -179,24 +188,14 @@ $input-height: 50px; min-width: auto; height: $input-height; line-height: $input-height; - text-align: center; + text-align: left; transition: background 100ms global.$easing, color 100ms global.$easing; - input { - @include visibility.screen-reader-only; - } - label { - padding: 0; + padding: 0 0 0 36px; } &.is-active { - label { - background: colors.$primary; - color: colors.$white; - font-weight: bold; - } - label:hover, input:focus + label, input:hover + label { @@ -231,7 +230,7 @@ $input-height: 50px; } input { - padding: 0 map.get( units.$spacing, 'medium' ); + padding: 0 map.get( units.$spacing, 'medium' ) 0 map.get( units.$spacing, 'xx-large' ); text-align: right; } @@ -253,9 +252,27 @@ $input-height: 50px; } &:after { right: auto; - left: 10px; + left: 44px; } } } + + &-custom .radio-form-input { + position: absolute; + z-index: 1; + height: 16px; + width: 16px; + min-width: 16px; + top: 50%; + transform: translateY( -50% ); + left: 16px; + + input { + padding: 0; + top: 0; + margin-top: 0; + left: 0; + } + } } diff --git a/tests/unit/components/shared/form_fields/AmountField.spec.ts b/tests/unit/components/shared/form_fields/AmountField.spec.ts index 4c3e387a9..05a51456d 100644 --- a/tests/unit/components/shared/form_fields/AmountField.spec.ts +++ b/tests/unit/components/shared/form_fields/AmountField.spec.ts @@ -135,6 +135,22 @@ describe( 'AmountField.vue', () => { expect( wrapper.find( '.form-field-amount-custom.active' ).exists() ).toBeFalsy(); } ); + it( 'Checks the custom amount radio when value is custom', async () => { + const wrapper = getWrapper(); + const customAmountInput = wrapper.find( '#amount-custom' ); + + expect( wrapper.find( '.form-field-amount-custom-radio' ).element.checked ).toBeFalsy(); + + await customAmountInput.setValue( '1998' ); + await customAmountInput.trigger( 'blur' ); + + expect( wrapper.find( '.form-field-amount-custom-radio' ).element.checked ).toBeTruthy(); + + await wrapper.find( 'input[value="29900"]' ).trigger( 'change' ); + + expect( wrapper.find( '.form-field-amount-custom-radio' ).element.checked ).toBeFalsy(); + } ); + it( 'does not select amounts for choices that are below minimum amount', async () => { const wrapper = getWrapper();