Skip to content

Commit

Permalink
Add radio inputs to amount field
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Abban committed Sep 27, 2024
1 parent 4a287ee commit 9e77c07
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 17 deletions.
51 changes: 34 additions & 17 deletions src/components/shared/form_fields/AmountField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
<div class="form-field-amount-custom" :class="{ active: isCustomAmount }">
<label class="form-field-amount-help-text" for="amount-custom">{{ $t('donation_form_payment_amount_label') }}</label>
<div class="form-field-amount-custom-euro-symbol" :class="{ active: isCustomAmount }">
<div class="radio radio-form-input">
<input type="radio" class="form-field-amount-custom-radio" :checked="isCustomAmount" aria-hidden="true" tabindex="-1"/>
</div>

<TextFormInput
v-model="customAmount"
input-type="text"
Expand Down Expand Up @@ -149,6 +153,7 @@ watch( () => 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;
Expand All @@ -164,39 +169,33 @@ $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;
width: 100%;
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 {
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
}
}
</style>
16 changes: 16 additions & 0 deletions tests/unit/components/shared/form_fields/AmountField.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLInputElement>( '.form-field-amount-custom-radio' ).element.checked ).toBeFalsy();

await customAmountInput.setValue( '1998' );
await customAmountInput.trigger( 'blur' );

expect( wrapper.find<HTMLInputElement>( '.form-field-amount-custom-radio' ).element.checked ).toBeTruthy();

await wrapper.find( 'input[value="29900"]' ).trigger( 'change' );

expect( wrapper.find<HTMLInputElement>( '.form-field-amount-custom-radio' ).element.checked ).toBeFalsy();
} );

it( 'does not select amounts for choices that are below minimum amount', async () => {
const wrapper = getWrapper();

Expand Down

0 comments on commit 9e77c07

Please sign in to comment.