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

Add FormProviders to forms used so they can be more easily used (GCOM-1234) #2109

Draft
wants to merge 10 commits into
base: canary
Choose a base branch
from
4 changes: 1 addition & 3 deletions examples/magento-graphcms/pages/checkout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,7 @@ function ShippingPage() {
<Trans id='Next' />
</ComposedSubmitButton>
</FormActions>
<ApolloCartErrorAlert
error={renderProps.buttonState.isSubmitting ? undefined : renderProps.error}
/>
<ApolloCartErrorAlert />
</>
)}
/>
Expand Down
3 changes: 2 additions & 1 deletion examples/magento-graphcms/plugins/EnableCrosssellsPlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { AddProductsToCartFormProps } from '@graphcommerce/magento-product'
import { IfConfig, PluginProps } from '@graphcommerce/next-config'

export const component = 'AddProductsToCartForm'
export const exported = '@graphcommerce/magento-product'
export const exported =
'@graphcommerce/magento-product/components/AddProductsToCart/AddProductsToCartForm'
export const ifConfig: IfConfig = 'demoMode'

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { AddressFieldsProps } from '@graphcommerce/magento-customer'
import type { PluginProps } from '@graphcommerce/next-config'
import { PostcodeNLAddressFields } from '../components/PostcodeNLAddressFields'
import { useFormContext, useWatch } from '@graphcommerce/ecommerce-ui'

export const component = 'AddressFields'

export const exported = '@graphcommerce/magento-customer/components/AddressFields/AddressFields'

function AddPostcodeNLAddressFields(props: PluginProps<AddressFieldsProps>) {
const { form, Prev } = props
const country = form.watch('countryCode')
const { Prev, countryFirst } = props
const methods = useFormContext()
const country = useWatch({ control: methods.control, name: 'country' })
return country === 'NL' ? (
<PostcodeNLAddressFields countryFirst {...props} />
) : (
<Prev countryFirst {...props} />
<Prev countryFirst={countryFirst} {...props} />
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,19 @@ import {
AddressFields,
ApolloCustomerErrorAlert,
NameFields,
TelephoneField,
} from '@graphcommerce/magento-customer'
import { CountryRegionsDocument } from '@graphcommerce/magento-store'
import {
Button,
Form,
FormActions,
FormDivider,
FormRow,
InputCheckmark,
} from '@graphcommerce/next-ui'
import { phonePattern } from '@graphcommerce/react-hook-form'
import { i18n } from '@lingui/core'
import { Button, Form, FormActions, FormDivider } from '@graphcommerce/next-ui'
import { FormProvider } from '@graphcommerce/react-hook-form'
import { Trans } from '@lingui/react'
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { SxProps, TextField, Theme } from '@mui/material'
import { SxProps, Theme } from '@mui/material'
import { GetBillingAddressDocument } from './GetBillingAddress.gql'

export type EditBillingAddressFormProps = { sx?: SxProps<Theme> }
export type EditBillingAddressFormProps = { sx?: SxProps<Theme>; children?: React.ReactNode }

export function EditBillingAddressForm(props: EditBillingAddressFormProps) {
const { sx } = props
const { sx, children } = props
const countryQuery = useQuery(CountryRegionsDocument, { fetchPolicy: 'cache-and-network' })
const countries = countryQuery.data?.countries ?? countryQuery.previousData?.countries
const address = useCartQuery(GetBillingAddressDocument)?.data?.cart?.billing_address
Expand Down Expand Up @@ -62,48 +54,34 @@ export function EditBillingAddressForm(props: EditBillingAddressFormProps) {
},
})

const { handleSubmit, formState, required, error, muiRegister, valid } = form
const { handleSubmit, formState } = form
const submitHandler = handleSubmit(() => {})

return (
<>
<FormProvider {...form}>
<Form onSubmit={submitHandler} noValidate sx={sx}>
<NameFields form={form} prefix />
<AddressFields form={form} />

<FormRow>
<TextField
variant='outlined'
type='text'
error={!!formState.errors.telephone}
required={required.telephone}
label={<Trans id='Telephone' />}
{...muiRegister('telephone', {
required: required.telephone,
pattern: { value: phonePattern, message: i18n._(/* i18n */ 'Invalid phone number') },
})}
helperText={formState.isSubmitted && formState.errors.telephone?.message}
disabled={formState.isSubmitting}
InputProps={{ endAdornment: <InputCheckmark show={valid.telephone} /> }}
/>
</FormRow>
{children ?? (
<>
<NameFields />
<AddressFields />
<TelephoneField />
<FormDivider />

<FormDivider />

<FormActions sx={{ paddingBottom: 0 }}>
<Button
type='submit'
variant='pill'
color='primary'
size='large'
loading={formState.isSubmitting}
>
<Trans id='Save changes' />
</Button>
</FormActions>
<FormActions sx={{ paddingBottom: 0 }}>
<Button
type='submit'
variant='pill'
color='primary'
size='large'
loading={formState.isSubmitting}
>
<Trans id='Save changes' />
</Button>
</FormActions>
<ApolloCustomerErrorAlert />
</>
)}
</Form>

<ApolloCustomerErrorAlert error={error} />
</>
</FormProvider>
)
}
19 changes: 18 additions & 1 deletion packages/magento-cart-billing-address/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@
"project": "./tsconfig.json"
}
},
"devDependencies": {
"@graphcommerce/eslint-config-pwa": "7.1.0-canary.30",
"@graphcommerce/prettier-config-pwa": "7.1.0-canary.30",
"@graphcommerce/typescript-config-pwa": "7.1.0-canary.30"
},
"dependencies": {
"@graphcommerce/framer-next-pages": "7.1.0-canary.30",
"@graphcommerce/graphql": "7.1.0-canary.30",
"@graphcommerce/image": "7.1.0-canary.30",
"@graphcommerce/magento-cart": "7.1.0-canary.30",
"@graphcommerce/magento-customer": "7.1.0-canary.30",
"@graphcommerce/magento-store": "7.1.0-canary.30",
"@graphcommerce/next-ui": "7.1.0-canary.30",
"@graphcommerce/react-hook-form": "7.1.0-canary.30",
"@graphcommerce/ecommerce-ui": "7.1.0-canary.30",
"@graphcommerce/magento-cart-shipping-address": "7.1.0-canary.30"
},
"peerDependencies": {
"@graphcommerce/eslint-config-pwa": "^7.1.0-canary.58",
"@graphcommerce/framer-next-pages": "^7.1.0-canary.58",
Expand All @@ -32,4 +49,4 @@
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function RemoveItemFromCart(props: RemoveItemFromCartProps) {
variant='inline'
color='secondary'
{...buttonProps}
key={uid}
size='medium'
type='submit'
loading={formState.isSubmitting}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import {
phonePattern,
useFormAutoSubmit,
useFormCompose,
UseFormComposeOptions,
useFormPersist,
TextFieldElement,
FormProvider,
FormAutoSubmit,
} from '@graphcommerce/ecommerce-ui'
import { useQuery } from '@graphcommerce/graphql'
import {
Expand All @@ -17,34 +16,31 @@ import {
AddressFields,
CustomerDocument,
NameFields,
TelephoneField,
useCustomerQuery,
} from '@graphcommerce/magento-customer'
import { CountryRegionsDocument, StoreConfigDocument } from '@graphcommerce/magento-store'
import { Form, FormRow, InputCheckmark } from '@graphcommerce/next-ui'
import { i18n } from '@lingui/core'
import { Trans } from '@lingui/react'
import { Form } from '@graphcommerce/next-ui'
import { SxProps, Theme } from '@mui/material'
import React from 'react'
import {
findCustomerAddressFromCartAddress,
isCartAddressACustomerAddress,
} from '../../utils/findCustomerAddressFromCartAddress'
import { isSameAddress } from '../../utils/isSameAddress'
import { GetAddressesDocument } from './GetAddresses.gql'
import { SetBillingAddressDocument } from './SetBillingAddress.gql'
import { SetShippingAddressDocument } from './SetShippingAddress.gql'
import { SetShippingBillingAddressDocument } from './SetShippingBillingAddress.gql'
import { isCartAddressACustomerAddress } from '../../utils/findCustomerAddressFromCartAddress'

export type ShippingAddressFormProps = Pick<UseFormComposeOptions, 'step'> & {
/**
* @deprecated This was used to make sure the form wasn't filled with a customer's address. However this also broke the checkout when navigating back from the checkout. This is now automatically handled.
*/
ignoreCache?: boolean
children?: React.ReactNode
sx?: SxProps<Theme>
}

export const ShippingAddressForm = React.memo<ShippingAddressFormProps>((props) => {
const { step, sx } = props
export const ShippingAddressForm = React.memo((props: ShippingAddressFormProps) => {
const { step, children, ignoreCache = false, sx } = props
const { data: cartQuery } = useCartQuery(GetAddressesDocument)
const { data: config } = useQuery(StoreConfigDocument)
const countryQuery = useQuery(CountryRegionsDocument, { fetchPolicy: 'cache-and-network' })
Expand Down Expand Up @@ -118,41 +114,25 @@ export const ShippingAddressForm = React.memo<ShippingAddressFormProps>((props)
}
},
})
const { handleSubmit, valid, formState, required, error } = form
const { handleSubmit } = form
const submit = handleSubmit(() => {})

useFormPersist({ form, name: 'ShippingAddressForm' })
useFormCompose({ form, step, submit, key: 'ShippingAddressForm' })

const autoSubmitting = useFormAutoSubmit({
form,
submit,
fields: ['postcode', 'countryCode', 'regionId'],
})
const readOnly = formState.isSubmitting && !autoSubmitting

return (
<Form onSubmit={submit} noValidate sx={sx}>
<NameFields form={form} key='name' readOnly={readOnly} />
<AddressFields form={form} key='addressfields' readOnly={readOnly} />
<FormRow key='telephone'>
<TextFieldElement
control={form.control}
name='telephone'
variant='outlined'
type='text'
required={required.telephone}
validation={{
pattern: { value: phonePattern, message: i18n._(/* i18n */ 'Invalid phone number') },
}}
label={<Trans id='Telephone' />}
InputProps={{
readOnly,
endAdornment: <InputCheckmark show={valid.telephone} />,
}}
/>
</FormRow>
<ApolloCartErrorAlert error={error} />
</Form>
<FormProvider {...form}>
<Form onSubmit={submit} noValidate sx={sx}>
{children ?? (
<>
<NameFields prefixes={false} />
<AddressFields />
<TelephoneField />
<ApolloCartErrorAlert />
<FormAutoSubmit name={['postcode', 'countryCode', 'regionId']} />
</>
)}
</Form>
</FormProvider>
)
})
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ import {
import {
FormAutoSubmit,
FormProvider,
useFormAutoSubmit,
useFormCompose,
UseFormComposeOptions,
UseFormGraphQlOptions,
useFormPersist,
useWatch,
} from '@graphcommerce/react-hook-form'
import { i18n } from '@lingui/core'
Expand Down Expand Up @@ -89,7 +87,7 @@ export function ShippingMethodForm(props: ShippingMethodFormProps) {
...options,
})

const { handleSubmit, control, error } = form
const { handleSubmit, control } = form
const submit = handleSubmit(() => {})

useFormCompose({ form, step, submit, key: 'ShippingMethodForm' })
Expand All @@ -111,13 +109,6 @@ export function ShippingMethodForm(props: ShippingMethodFormProps) {

return (
<FormProvider {...form}>
<FormAutoSubmit
control={control}
submit={submit}
name={['carrierMethod']}
parallel
wait={300}
/>
<Form onSubmit={submit} noValidate sx={sx}>
<FormHeader variant='h4' sx={(theme) => ({ marginBottom: 0, mb: theme.spacings.sm })}>
<Trans id='Shipping method' />
Expand All @@ -134,7 +125,8 @@ export function ShippingMethodForm(props: ShippingMethodFormProps) {
ShippingMethodActionCard as React.FC<ActionCardItemRenderProps<ActionCardItemBase>>
}
/>
<ApolloCartErrorAlert error={error} />
<FormAutoSubmit name={['carrierMethod']} parallel wait={300} />
<ApolloCartErrorAlert />
</Form>
{children}
</FormProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CustomerDocument,
} from '@graphcommerce/magento-customer'
import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
import { FieldValues, assertFormGqlOperation, useFormContext } from '@graphcommerce/react-hook-form'
import { i18n } from '@lingui/core'
import { Trans } from '@lingui/react'
import { Button } from '@mui/material'
Expand All @@ -13,7 +14,12 @@ import { useClearCurrentCartId } from '../../hooks'
export type ApolloCartErrorAlertProps = ApolloCustomerErrorAlertProps

export function ApolloCartErrorAlert(props: ApolloCartErrorAlertProps) {
const { error, graphqlErrorAlertProps } = props
const { graphqlErrorAlertProps } = props
const form = useFormContext()

assertFormGqlOperation<FieldValues>(form)

const { error } = form

const email = useQuery(CustomerDocument, { fetchPolicy: 'cache-only' }).data?.customer?.email

Expand Down
Loading