Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(EMI-2196): Consolidated global AddressFormFields component + usage in Auction/Invoice apps #14898

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

erikdstock
Copy link
Contributor

@erikdstock erikdstock commented Nov 22, 2024

The type of this PR is: feat

The changes are relatively small when viewed commit-by-commit, at least for the early ones.

Description

This PR relates to EMI-2196 and completes EMI-2205. It consolidates our Auction + Invoice address forms to use a single <AddressFormFields /> layout. This component includes its own validation schema and the utils files in the src/Components/Address has new helpers for working with and testing that. There are new tests to replace Because the phone number input is sometimes not required, it can be controlled with a prop.

Because we consolidate forms, we also get US address autocomplete in the invoice form for free (this could also be controlled with a prop if we wanted).

cc @artsy/emerald-devs

Invoice app, before and after.

image

Invoice form with autocomplete

image

Followup work

  • This opens the door to a lot of cleanup in our checkout flow, which includes several redundant types.
    • The checkout/shipping modal should be easy to migrate to this. The full-page version will be a little harder because of the extra instrumentation involved (for example in hiding shipping quotes)
    • We can also move off of the credit card payment form there which is extra complicated because it does not use formik.
    • The address form filling helper fillAddressFormFields() created for this specific layout might be more efficient than the multiple similar helpers called fillAddressForm(). This migration could therefore help address EMI-1685.
  • We can update the user settings page to use this layout as well, but first we'll want to integrate the rich phone input into this layout along with the rich phone validation.

cc @artsy/emerald-devs

Copy link

relativeci bot commented Nov 22, 2024

#1017 Bundle Size — 9.54MiB (-0.07%).

13be370(current) vs ffe4f84 main#484(baseline)

Important

Bundle introduced 1 and removed 4 duplicate packages – View changed duplicate packages

Warning

Bundle introduced 3 new packages: web-vitals, @sentry-internal/browser-utils, stylis – View changed packages

Bundle metrics  Change 9 changes Regression 1 regression Improvement 3 improvements
                 Current
#1017
     Baseline
#484
Improvement  Initial JS 3.69MiB(-6.58%) 3.95MiB
No change  Initial CSS 0B 0B
Change  Cache Invalidation 87.74% 2.04%
Change  Chunks 141(-1.4%) 143
Change  Assets 145(-0.68%) 146
Change  Modules 5690(+0.94%) 5637
Regression  Duplicate Modules 495(+8.79%) 455
Change  Duplicate Code 5.87%(-0.17%) 5.88%
Improvement  Packages 282(-3.09%) 291
Improvement  Duplicate Packages 39(-7.14%) 42
Bundle size by type  Change 2 changes Regression 1 regression Improvement 1 improvement
                 Current
#1017
     Baseline
#484
Regression  JS 9.33MiB (+0.2%) 9.31MiB
Improvement  Other 212.46KiB (-10.67%) 237.84KiB

Bundle analysis reportBranch erik.emi2196-invoice-address-for...Project dashboard


Generated by RelativeCIDocumentationReport issue

@@ -10,7 +11,7 @@ export const AddressFormWithCreditCard: React.FC<React.PropsWithChildren<unknown
setFieldError,
errors,
touched,
} = useFormContext()
} = useAuctionFormContext()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this changed because the name was coming up in searches in multiple places and caused me to confuse myself. Maybe not worth it though.

phoneNumber: string
}

export const AddressFormFields = <V extends FormikContextWithAddress>() => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type parameter here helps guarantee that the useFormikContext() call below will be able to service our fields.

@erikdstock
Copy link
Contributor Author

I'll re-open this when it's ready for merge.

Comment on lines +83 to +86
if (!values.address) {
helpers.setStatus("SUBMISSION_FAILED")
return
}
Copy link
Contributor Author

@erikdstock erikdstock Nov 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caused a bunch of test failures [fixed here] even though I don't think it would be an issue in real life due to form validations. I only did it to satisfy some ts complaints about using the ! so we could remove it.

@erikdstock erikdstock marked this pull request as ready for review November 23, 2024 05:15
@erikdstock
Copy link
Contributor Author

Hmm, I see some more validation schemas that I might need to reconcile:

OTOH maybe this is ok as long as the validations work - but it would be nice to keep it all consistent and in one place.

Copy link
Contributor Author

@erikdstock erikdstock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR tour.

Comment on lines -29 to -38
export interface Address {
name: string
country: string
postalCode: string
addressLine1: string
addressLine2: string
city: string
region: string
phoneNumber?: string
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Tour start: This file contains a non-formik address form layout which is only used on the checkout>payment route. I'm considering it deprecated so moved most utility types and constants to a nearby file.

Comment on lines +13 to +16
interface FormikContextWithAddress {
address: Address
phoneNumber?: string
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the PR is here: I promoted the Apps/Auction/Components/Form/AddressForm.tsx file to live in Components/Address/AddressFormFields.tsx. It is now used by both the auction and invoice apps for their credit card forms, and is named with Fields because it is only the fields.

  • This file also exports a non-Component helper for generating the yup form validations. Both the helper and the component have a prop/arg for whether to include the phone number.
  • The type argument of the AddressFormFields component helps guarantee that it will be used in within a formik context that matches those fields

@@ -312,6 +312,7 @@ export const AddressAutocompleteInput = ({
onChange={onChange}
error={error}
data-testid={dataTestId}
required={!!autocompleteProps.required}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The address autocomplete input is incorrectly not passing the required prop to its fallback input - likely a bug in the existing shipping route where this input is used, but not likely one many people hit since they generally have an address.

Comment on lines +17 to +23
describe("AddressForm", () => {
const mockOnSubmit = jest.fn()
beforeEach(() => {
mockOnSubmit.mockClear()
})

describe("without phone number input", () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A port of the Auction AddressForm.jest.enzyme.tsx file, now with more assertions.

Comment on lines +38 to +39
export const fillAddressFormFields = async (address: Partial<Address>) => {
const { country, phoneNumber, ...defaultTextInputs } = address
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hopeful this can replace our multiple other fillAddressForm() helpers and do so in a fast way since we have several test suites completely disable in CI due to timeouts specifically tied to these helpers (see EMI-1685).

Comment on lines +73 to +85
export const yupAddressValidator = Yup.object().shape({
name: Yup.string().required("Full name is required"),
addressLine1: Yup.string().required("Street address is required"),
addressLine2: Yup.string().nullable(),
city: Yup.string().required("City is required"),
postalCode: postalCodeValidator,
region: Yup.string().when("country", {
is: country => ["US", "CA"].includes(country),
then: Yup.string().required("State is required"),
otherwise: Yup.string(),
}),
country: Yup.string().required("Country is required"),
})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from our refactored checkout shipping route validations- between this and the user settings>shipping address validations (worth a comparison maybe) I think we can get a single validation schema.

@@ -28,6 +32,9 @@ export const InvoicePaymentForm: React.FC<React.PropsWithChildren<InvoicePayment
<Formik<AddressFormValues>
onSubmit={handleSubmit}
initialValues={{ address: emptyAddress, creditCard: false }}
validationSchema={Yup.object().shape({
...addressFormFieldsValidator({ withPhoneNumber: false }),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using our address form fields validator in a yup schema. strangely this formik context didn't seem to have any validation... maybe because it relied on stripe and we don't actually store any address?

@@ -36,7 +43,7 @@ export const AddressFormWithCreditCard: React.FC<React.PropsWithChildren<unknown
required
/>

<AddressForm />
<AddressFormFields<AddressFormValues> />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using our new AddressFormFields component with the formik type param to mostly guarantee that our context will satisfy those fields*

I say mostly because if you aren't including a phone number then you shouldn't pass the withPhoneNumber prop. I think we could get fancier with our function component type to give it multiple signatures (if your type doesn't have a phone number, then your withPhoneNumber prop can't be true. But then you get into the validation schema constructor function which is its own separate thing in a different file and I thought this is too much magic. Maybe a happy medium would be better doc comments in the file.

@@ -44,7 +47,7 @@ export const AddressFormWithCreditCard: React.FC<React.PropsWithChildren<unknown
required
/>

<AddressForm />
<AddressFormFields<AuctionFormValues> withPhoneNumber />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here as well is the auction registration route using our new form withPhoneNumber. I wondered if i should use the schema constructor helper mentioned earlier in this tour on the formik context here but haven't done it yet.

}

export const addressFormFieldsValidator = (args: {
withPhoneNumber: boolean
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be typed with Props right up above?

Copy link
Member

@damassi damassi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR looks great @erikdstock 💯

Only feedback is: The PR title seems a bit misleading considering everything that's going on in here. If we can perhaps summarize it there (for search) that'd be ideal, but otherwise 🍏

@erikdstock erikdstock changed the title feat(EMI-2196): Invoice address form layout feat(EMI-2196): Consolidated global AddressFormFields component + usage in Auction/Invoice apps Nov 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants