Skip to content

Commit

Permalink
fix issues with selects and polish stuff up
Browse files Browse the repository at this point in the history
  • Loading branch information
kylemh committed Jan 27, 2025
1 parent ef9c127 commit 9f0e1c1
Show file tree
Hide file tree
Showing 24 changed files with 126 additions and 170 deletions.
5 changes: 4 additions & 1 deletion components/Form/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ import Alert from 'components/Alert/Alert';
import styles from './Input.module.css';

/** @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Attributes_common_to_all_input_types */
interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'form'> {
interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'disabled' | 'form'> {
field: FieldInputProps<string>;
form: FormikState<Record<string, string>> & FormikHelpers<Record<string, string>>;
hasValidationStyling?: boolean;
isDisabled?: boolean;
isLabelHidden?: boolean;
label: string;
}

function Input({
className,
isDisabled = false,
field: { name, value, ...field },
form: { touched, errors },
hasValidationStyling = true,
Expand Down Expand Up @@ -47,6 +49,7 @@ function Input({
[styles.valid]: touched[name] && !hasErrors && hasValidationStyling,
[styles.invalid]: touched[name] && hasErrors && hasValidationStyling,
})}
disabled={isDisabled}
id={id || name}
name={name}
type={type}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ exports[`Input > should render with required props 1`] = `
>
<input
className="Input"
disabled={false}
id="someInputName"
name="someInputName"
onBlur={[MockFunction spy]}
Expand Down
44 changes: 0 additions & 44 deletions components/Form/MultiStepForm.module.css

This file was deleted.

30 changes: 21 additions & 9 deletions components/Form/MultiStepForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ import Button from 'components/Buttons/Button/Button';
import Form from 'components/Form/Form';
import Alert from 'components/Alert/Alert';
import ProgressIndicator from 'components/ProgressIndicator/ProgressIndicator';
import styles from './MultiStepForm.module.css';

const InlineLoadingSpinner = () => (
<span
aria-hidden
className="border-solid border-white border-4 !border-b-themePrimary rounded-[50%] h-5 w-5 box-border animate-spin group-hover:border-themeSecondary transition-colors"
/>
);

interface MultiStepFormProps<T> {
initialValues: T;
Expand Down Expand Up @@ -107,18 +113,16 @@ export function MultiStepForm<T extends Record<string, string | string[] | numbe
onSubmit={handleSubmit}
>
{formikBag => (
<Form className={styles.MultiStepForm} onSubmit={formikBag.handleSubmit}>
<h3 className={styles.centerAligned}>{CurrentStep.title}</h3>
<Form className="w-full max-w-prose-sm !m-0" onSubmit={formikBag.handleSubmit}>
<h3 className="text-center">{CurrentStep.title}</h3>

<ProgressIndicator stepNumber={stepNumber} totalSteps={steps.length} />

<CurrentStep {...formikBag} />

<div className={styles.errorMessage}>
{errorMessage && <Alert type="error">{errorMessage}</Alert>}
</div>
<div className="mt-8">{errorMessage && <Alert type="error">{errorMessage}</Alert>}</div>

<div className={styles.buttonGrouping}>
<div className="flex flex-nowrap justify-around items-center mx-auto mt-8 w-full gap-x-4 min-w-[7rem]">
{!isFirstStep && (
<Button
theme="secondary"
Expand All @@ -136,8 +140,12 @@ export function MultiStepForm<T extends Record<string, string | string[] | numbe
theme="secondary"
disabled={formikBag.isSubmitting}
data-testid={MULTI_STEP_SUBMIT_BUTTON}
className="group"
>
Submit ✓
<span className="flex items-center justify-center gap-x-2">
{formikBag.isSubmitting && <InlineLoadingSpinner />}
<span className="mt-[0.325rem]">Submit ✓</span>
</span>
</Button>
) : (
<Button
Expand All @@ -146,8 +154,12 @@ export function MultiStepForm<T extends Record<string, string | string[] | numbe
disabled={formikBag.isSubmitting}
fullWidth={isFirstStep}
data-testid={MULTI_STEP_STEP_BUTTON}
className="group"
>
Next →
<span className="flex items-center justify-center gap-x-2">
{formikBag.isSubmitting && <InlineLoadingSpinner />}
<span className="mt-[0.325rem]">Next →</span>
</span>
</Button>
)}
</div>
Expand Down
41 changes: 14 additions & 27 deletions components/Form/Select/SelectMulti.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import styles from './Select.module.css';
export interface SelectMultiProps
extends Pick<ThemedReactSelectProps<true>, 'id' | 'hasValidationStyling' | 'isSearchable'> {
className?: string;
field: FieldInputProps<string[]>;
field: FieldInputProps<{ label: string; value: string }[]>;
form: FormikState<Record<string, string[]>> & FormikHelpers<Record<string, string[]>>;
isLabelHidden?: boolean;
label: string;
Expand All @@ -29,22 +29,8 @@ export function SelectMulti({
options,
...props // disabled, placeholder, etc.
}: SelectMultiProps) {
const value = options.filter(option => fieldValue.includes(option.value));
const hasErrors = Boolean(errors[name]);

const sharedProps = {
...props,
id: id ? `${id}` : name,
hasErrors,
hasValidationStyling,
isTouched: Boolean(touched[name]),
isSearchable,
name,
onBlur: () => setFieldTouched(name),
options,
value,
};

return (
<div className={classNames(className, styles.field)}>
<Label for={name} isHidden={isLabelHidden}>
Expand All @@ -53,20 +39,21 @@ export function SelectMulti({

<div className={styles.selectFeedbackGrouping}>
<ThemedReactSelect<true>
{...sharedProps}
isMulti={true} // eslint-disable-line react/jsx-boolean-value
onChange={selectedArray => {
if (selectedArray) {
setFieldValue(
name,
selectedArray.map(item => item.value),
);
} else {
setFieldValue(name, []);
}
{...props}
id={id ? `${id}` : name}
name={name}
hasErrors={hasErrors}
hasValidationStyling={hasValidationStyling}
isMulti
isSearchable={isSearchable}
isTouched={Boolean(touched[name])}
onBlur={() => setFieldTouched(name)}
onChange={async selectedArray => {
await setFieldValue(name, selectedArray ?? []);
await setFieldTouched(name, true);
}}
options={options}
value={value ?? []}
value={fieldValue}
/>

<ErrorMessage name={name}>
Expand Down
10 changes: 3 additions & 7 deletions components/Form/Select/SelectSingle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { ErrorMessage } from 'formik';
import Alert from 'components/Alert/Alert';
import Label from 'components/Form/Label/Label';
import classNames from 'classnames';
import LogRocket from 'logrocket';
import type { ThemedReactSelectProps, OptionType } from './ThemedReactSelect';
import { ThemedReactSelect } from './ThemedReactSelect';
import styles from './Select.module.css';
Expand Down Expand Up @@ -56,12 +55,9 @@ export function SelectSingle({
<ThemedReactSelect<false>
{...sharedProps}
isMulti={false}
onChange={option => {
if (option) {
setFieldValue(name, option.value);
} else {
LogRocket.captureException(new Error('SelectSingle onChange received a null option'));
}
onChange={async option => {
await setFieldValue(name, option?.value ?? '');
await setFieldTouched(name, true);
}}
options={options}
value={value}
Expand Down
3 changes: 2 additions & 1 deletion components/Form/Select/ThemedReactSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ export function ThemedReactSelect<TMulti extends boolean>({
closeMenuOnSelect={!isMulti}
isMulti={isMulti}
isSearchable={isSearchable}
blurInputOnSelect={isMulti}
blurInputOnSelect={isMulti && !isTouched} // this is ideal UX for seeing-eye users
styles={{
control: base => {
return {
...base,
backgroundColor: isDisabled ? 'transparent' : 'white',
borderColor:
isTouched && hasValidationStyling ? outerColor : `rgba(${rgbValuesSecondary}, 0.5)`,
boxShadow: isTouched && hasValidationStyling ? `0 0 1px 1px ${outerColor}` : 'none',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ exports[`Select > should render with required props 1`] = `
className="css-1f43avz-a11yText-A11yText"
/>
<div
className=" css-1mgllov-control"
className=" css-1s1bmlz-control"
onMouseDown={[Function]}
onTouchEnd={[Function]}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ exports[`Select > should render with required props 1`] = `
className="css-1f43avz-a11yText-A11yText"
/>
<div
className=" css-1mgllov-control"
className=" css-1s1bmlz-control"
onMouseDown={[Function]}
onTouchEnd={[Function]}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exports[`ThemedReactSelect > should render (multi) with required props 1`] = `
className="css-1f43avz-a11yText-A11yText"
/>
<div
className=" css-1mgllov-control"
className=" css-1s1bmlz-control"
onMouseDown={[Function]}
onTouchEnd={[Function]}
>
Expand Down Expand Up @@ -192,7 +192,7 @@ exports[`ThemedReactSelect > should render (non-multi) with required props 1`] =
className="css-1f43avz-a11yText-A11yText"
/>
<div
className=" css-1mgllov-control"
className=" css-1s1bmlz-control"
onMouseDown={[Function]}
onTouchEnd={[Function]}
>
Expand Down
20 changes: 10 additions & 10 deletions components/Forms/RegistrationForm/RegistrationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function RegistrationForm({
name="email"
label="Email*"
component={Input}
disabled={isSubmitting}
isDisabled={isSubmitting}
autoComplete="username email"
/>

Expand All @@ -126,7 +126,7 @@ export function RegistrationForm({
name="confirm-email"
label="Confirm Email*"
component={Input}
disabled={isSubmitting}
isDisabled={isSubmitting}
autoComplete="username email"
/>

Expand All @@ -136,7 +136,7 @@ export function RegistrationForm({
name="password"
label="Password*"
component={Input}
disabled={isSubmitting}
isDisabled={isSubmitting}
autoComplete="new-password"
/>

Expand All @@ -146,7 +146,7 @@ export function RegistrationForm({
name="confirm-password"
label="Confirm Password*"
component={Input}
disabled={isSubmitting}
isDisabled={isSubmitting}
autoComplete="new-password"
/>

Expand All @@ -155,7 +155,7 @@ export function RegistrationForm({
name="firstName"
label="First Name*"
component={Input}
disabled={isSubmitting}
isDisabled={isSubmitting}
autoComplete="given-name"
/>

Expand All @@ -164,7 +164,7 @@ export function RegistrationForm({
name="lastName"
label="Last Name*"
component={Input}
disabled={isSubmitting}
isDisabled={isSubmitting}
autoComplete="family-name"
/>

Expand All @@ -173,7 +173,7 @@ export function RegistrationForm({
name="zipcode"
label="Zipcode*"
component={Input}
disabled={isSubmitting}
isDisabled={isSubmitting}
autoComplete="postal-code"
/>

Expand All @@ -194,7 +194,7 @@ export function RegistrationForm({
</span>
}
component={Checkbox}
disabled={isSubmitting}
isDisabled={isSubmitting}
/>

<Field
Expand All @@ -214,14 +214,14 @@ export function RegistrationForm({
</span>
}
component={Checkbox}
disabled={isSubmitting}
isDisabled={isSubmitting}
/>
</div>

{errorMessage && <Alert type="error">{errorMessage}</Alert>}

<div className="max-w-md px-3 mt-5">
<Button type="submit" theme="secondary" disabled={isSubmitting}>
<Button type="submit" theme="secondary" isDisabled={isSubmitting}>
Submit
</Button>
<p className="pt-5 text-xs">
Expand Down
4 changes: 2 additions & 2 deletions components/Forms/UpdateProfileForm/UpdateProfileForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function UpdateProfileForm({
return getServerErrorMessage(errorObject);
};

const onValueChange = async (values: UpdateProfileFormShape) => {
const onStepSubmit = async (values: UpdateProfileFormShape) => {
const hasMilitaryExperience = [
'Active Duty U.S. Military Service Member',
'U.S. Reserve or National Guard member',
Expand Down Expand Up @@ -91,7 +91,7 @@ function UpdateProfileForm({
<MultiStepForm
initialValues={initialValues}
getErrorMessage={generateError}
onEachStepSubmit={onValueChange}
onEachStepSubmit={onStepSubmit}
onFinalSubmit={goToProfile}
steps={steps}
/>
Expand Down
Loading

0 comments on commit 9f0e1c1

Please sign in to comment.