@graphcommerce/magento-customer 5.1.1 → 5.2.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/components/AccountLatestOrder/AccountLatestOrder.tsx +31 -0
- package/components/AccountMenu/AccountMenu.tsx +21 -0
- package/components/AccountMenuItem/AccountMenuItem.tsx +105 -0
- package/components/AccountOrders/AccountOrders.graphql +13 -0
- package/components/AccountOrders/AccountOrders.tsx +88 -0
- package/components/AccountSignInUpForm/AccountSignInUpForm.tsx +167 -0
- package/components/CreateCustomerAddressForm/CreateCustomerAddressForm.tsx +1 -1
- package/components/DeleteCustomerAddressForm/DeleteCustomerAddressForm.tsx +11 -1
- package/components/NoOrdersFound/NoOrdersFound.tsx +22 -0
- package/components/OrderCard/OrderCard.graphql +18 -0
- package/components/OrderCard/OrderCard.tsx +160 -0
- package/components/OrderCardItem/OrderCardItem.graphql +4 -0
- package/components/OrderCardItem/OrderCardItem.tsx +17 -0
- package/components/OrderCardItemImage/OrderCardItemImage.tsx +35 -0
- package/components/OrderDetails/OrderDetails.graphql +77 -0
- package/components/OrderDetails/OrderDetails.tsx +371 -0
- package/components/OrderItem/OrderItem.graphql +14 -0
- package/components/OrderItem/OrderItem.tsx +208 -0
- package/components/OrderItems/OrderItems.graphql +5 -0
- package/components/OrderItems/OrderItems.tsx +127 -0
- package/components/OrderStateLabel/OrderStateLabel.graphql +10 -0
- package/components/OrderStateLabel/OrderStateLabel.tsx +92 -0
- package/components/OrderStateLabel/OrderStateLabelInline.tsx +38 -0
- package/components/TrackingLink/TrackingLink.graphql +5 -0
- package/components/TrackingLink/TrackingLink.tsx +32 -0
- package/components/WaitForCustomer/WaitForCustomer.tsx +27 -21
- package/components/index.ts +14 -0
- package/graphql/AccountDashboard.graphql +16 -0
- package/graphql/AccountDashboardAddresses.graphql +5 -0
- package/graphql/AccountDashboardCustomer.graphql +3 -0
- package/graphql/AccountDashboardOrders.graphql +5 -0
- package/graphql/OrderDetailPage.graphql +10 -0
- package/hooks/OrderCardItemImage.graphql +7 -0
- package/hooks/OrderCardItemImages.graphql +7 -0
- package/hooks/UseOrderCardItemImages.graphql +7 -0
- package/hooks/index.ts +4 -0
- package/hooks/useOrderCardItemImages.ts +22 -0
- package/index.ts +4 -0
- package/package.json +13 -13
- package/test/authentication.playwright.ts +65 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 5.2.0-canary.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1768](https://github.com/graphcommerce-org/graphcommerce/pull/1768) [`23e9a4728`](https://github.com/graphcommerce-org/graphcommerce/commit/23e9a472899dfc0b56b989f5d0e8ffb802c8cc5f) - Move magento-customer-account & magento-customer-order into magento-customer package (magento-customer-account & magento-customer-order are now deprecated) ([@bramvanderholst](https://github.com/bramvanderholst))
|
|
8
|
+
|
|
9
|
+
- [#1768](https://github.com/graphcommerce-org/graphcommerce/pull/1768) [`7e8dcf447`](https://github.com/graphcommerce-org/graphcommerce/commit/7e8dcf44777aca527c07aaee397d272dd2f6ae44) - Update account address list after deleting an address ([@bramvanderholst](https://github.com/bramvanderholst))
|
|
10
|
+
|
|
11
|
+
- [#1768](https://github.com/graphcommerce-org/graphcommerce/pull/1768) [`9f0e9ab2d`](https://github.com/graphcommerce-org/graphcommerce/commit/9f0e9ab2dec3f9261ae00e9fd44d06a65ddb1d0d) - Redirect to address overview page after creating an address instead of redirecting to the edit page for the address that was just created ([@bramvanderholst](https://github.com/bramvanderholst))
|
|
12
|
+
|
|
13
|
+
## 5.2.0-canary.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [#1769](https://github.com/graphcommerce-org/graphcommerce/pull/1769) [`2693a616a`](https://github.com/graphcommerce-org/graphcommerce/commit/2693a616af2f9793012a5fb2eeacc084e695b83e) - WaitForCustomer now accepts overridable components for the fallback and unauthenticated state. ([@mikekeehnen](https://github.com/mikekeehnen))
|
|
18
|
+
|
|
3
19
|
## 5.1.1
|
|
4
20
|
|
|
5
21
|
## 5.1.1-canary.1
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SectionContainer } from '@graphcommerce/next-ui'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import useOrderCardItemImages from '../../hooks/useOrderCardItemImages'
|
|
4
|
+
import { AccountOrdersFragment } from '../AccountOrders/AccountOrders.gql'
|
|
5
|
+
import { NoOrdersFound } from '../NoOrdersFound/NoOrdersFound'
|
|
6
|
+
import { OrderCard } from '../OrderCard/OrderCard'
|
|
7
|
+
|
|
8
|
+
export type AccountLatestOrderProps = AccountOrdersFragment & {
|
|
9
|
+
loading: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function AccountLatestOrder(props: AccountLatestOrderProps) {
|
|
13
|
+
const { orders, loading } = props
|
|
14
|
+
const latestOrderCard = orders?.items?.[(orders?.items?.length ?? 1) - 1]
|
|
15
|
+
const images = useOrderCardItemImages(orders)
|
|
16
|
+
|
|
17
|
+
// TODO: when Magento fixes their API sorting
|
|
18
|
+
// const latestOrderCard = orders?.items?.[0]
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<SectionContainer labelLeft='Latest order'>
|
|
22
|
+
{!loading && (
|
|
23
|
+
<>
|
|
24
|
+
{!latestOrderCard && <NoOrdersFound />}
|
|
25
|
+
{latestOrderCard && <OrderCard {...latestOrderCard} images={images} />}
|
|
26
|
+
</>
|
|
27
|
+
)}
|
|
28
|
+
{loading && <OrderCard loading />}
|
|
29
|
+
</SectionContainer>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { extendableComponent } from '@graphcommerce/next-ui'
|
|
2
|
+
import { List, SxProps, Theme } from '@mui/material'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
export type AccountMenuProps = { children: React.ReactNode; sx?: SxProps<Theme> }
|
|
6
|
+
|
|
7
|
+
const { classes } = extendableComponent('AccountMenu', ['root'] as const)
|
|
8
|
+
|
|
9
|
+
export function AccountMenu(props: AccountMenuProps) {
|
|
10
|
+
const { children, sx = [] } = props
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<List
|
|
14
|
+
classes={classes}
|
|
15
|
+
disablePadding
|
|
16
|
+
sx={[(theme) => ({ marginBottom: theme.spacings.lg }), ...(Array.isArray(sx) ? sx : [sx])]}
|
|
17
|
+
>
|
|
18
|
+
{children}
|
|
19
|
+
</List>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ImageProps } from '@graphcommerce/image'
|
|
2
|
+
import {
|
|
3
|
+
responsiveVal,
|
|
4
|
+
iconChevronRight,
|
|
5
|
+
IconSvg,
|
|
6
|
+
Button,
|
|
7
|
+
ButtonProps,
|
|
8
|
+
extendableComponent,
|
|
9
|
+
} from '@graphcommerce/next-ui'
|
|
10
|
+
import { ListItem, ListItemIcon, ListItemText, SxProps, Theme } from '@mui/material'
|
|
11
|
+
import PageLink from 'next/link'
|
|
12
|
+
import React from 'react'
|
|
13
|
+
|
|
14
|
+
export type AccountMenuItemProps = {
|
|
15
|
+
iconSrc: ImageProps['src']
|
|
16
|
+
title: React.ReactNode
|
|
17
|
+
subtitle?: React.ReactNode
|
|
18
|
+
endIcon?: React.ReactNode
|
|
19
|
+
sx?: SxProps<Theme>
|
|
20
|
+
} & Omit<ButtonProps, 'endIcon' | 'startIcon' | 'title'> &
|
|
21
|
+
OwnerState
|
|
22
|
+
|
|
23
|
+
type OwnerState = { noBorderBottom?: boolean }
|
|
24
|
+
const name = 'AccountMenuItem'
|
|
25
|
+
const parts = ['root', 'icon'] as const
|
|
26
|
+
const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
|
|
27
|
+
|
|
28
|
+
export function AccountMenuItem(props: AccountMenuItemProps) {
|
|
29
|
+
const {
|
|
30
|
+
title,
|
|
31
|
+
subtitle,
|
|
32
|
+
iconSrc,
|
|
33
|
+
endIcon,
|
|
34
|
+
href,
|
|
35
|
+
disabled,
|
|
36
|
+
noBorderBottom = false,
|
|
37
|
+
sx = [],
|
|
38
|
+
...buttonProps
|
|
39
|
+
} = props
|
|
40
|
+
const classes = withState({ noBorderBottom })
|
|
41
|
+
|
|
42
|
+
const button = (
|
|
43
|
+
<Button
|
|
44
|
+
disabled={disabled}
|
|
45
|
+
className={classes.root}
|
|
46
|
+
sx={[
|
|
47
|
+
(theme) => ({
|
|
48
|
+
width: '100%',
|
|
49
|
+
height: responsiveVal(88, 104),
|
|
50
|
+
padding: 0,
|
|
51
|
+
borderRadius: 0,
|
|
52
|
+
background: theme.palette.background.paper,
|
|
53
|
+
'&:hover': {
|
|
54
|
+
background: theme.palette.background.default,
|
|
55
|
+
},
|
|
56
|
+
'&:disabled': {
|
|
57
|
+
background: theme.palette.background.default,
|
|
58
|
+
},
|
|
59
|
+
'&:focus': {
|
|
60
|
+
// fix: disableElevation does not work when button is focused
|
|
61
|
+
boxShadow: 'none',
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
'&:not(.noBorderBottom)': {
|
|
65
|
+
borderBottom: `1px solid ${theme.palette.divider}`,
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
69
|
+
]}
|
|
70
|
+
{...buttonProps}
|
|
71
|
+
>
|
|
72
|
+
<ListItem disableGutters>
|
|
73
|
+
<ListItemIcon
|
|
74
|
+
className={classes.icon}
|
|
75
|
+
sx={(theme) => ({
|
|
76
|
+
paddingRight: theme.spacings.xs,
|
|
77
|
+
})}
|
|
78
|
+
>
|
|
79
|
+
<IconSvg src={iconSrc} size='large' />
|
|
80
|
+
</ListItemIcon>
|
|
81
|
+
<ListItemText
|
|
82
|
+
primaryTypographyProps={{ sx: { typography: 'subtitle1' } }}
|
|
83
|
+
secondaryTypographyProps={{
|
|
84
|
+
sx: {
|
|
85
|
+
whiteSpace: 'nowrap',
|
|
86
|
+
overflow: 'hidden',
|
|
87
|
+
textOverflow: 'elipsis',
|
|
88
|
+
},
|
|
89
|
+
}}
|
|
90
|
+
primary={title}
|
|
91
|
+
secondary={subtitle}
|
|
92
|
+
/>
|
|
93
|
+
{endIcon ?? <IconSvg src={iconChevronRight} />}
|
|
94
|
+
</ListItem>
|
|
95
|
+
</Button>
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return href ? (
|
|
99
|
+
<PageLink href={href} passHref>
|
|
100
|
+
{button}
|
|
101
|
+
</PageLink>
|
|
102
|
+
) : (
|
|
103
|
+
button
|
|
104
|
+
)
|
|
105
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Pagination, SectionContainer, extendableComponent } from '@graphcommerce/next-ui'
|
|
2
|
+
import { Trans } from '@lingui/react'
|
|
3
|
+
import { Box, Link, SxProps, Theme } from '@mui/material'
|
|
4
|
+
import PageLink from 'next/link'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import useOrderCardItemImages from '../../hooks/useOrderCardItemImages'
|
|
7
|
+
import { NoOrdersFound } from '../NoOrdersFound/NoOrdersFound'
|
|
8
|
+
import { OrderCard } from '../OrderCard/OrderCard'
|
|
9
|
+
import { AccountOrdersFragment } from './AccountOrders.gql'
|
|
10
|
+
|
|
11
|
+
export type AccountOrdersProps = AccountOrdersFragment & { sx?: SxProps<Theme> }
|
|
12
|
+
|
|
13
|
+
const parts = ['root', 'older'] as const
|
|
14
|
+
const { classes } = extendableComponent('AccountOrders', parts)
|
|
15
|
+
|
|
16
|
+
export function AccountOrders(props: AccountOrdersProps) {
|
|
17
|
+
const { orders, sx = [] } = props
|
|
18
|
+
const amountLatestOrders = 2
|
|
19
|
+
const images = useOrderCardItemImages(orders)
|
|
20
|
+
|
|
21
|
+
const pageInfo = orders?.page_info
|
|
22
|
+
const isFirstPage = pageInfo?.current_page === 1
|
|
23
|
+
|
|
24
|
+
// whenever it's possible, pick last {amountLatestOrders} items, then reverse the resulting array,
|
|
25
|
+
// because we want to render the latest order first,
|
|
26
|
+
// but the API returns the orders in ASC order...
|
|
27
|
+
const latestOrders = orders?.items
|
|
28
|
+
.slice(Math.max((orders?.items?.length ?? 0) - 2, 0), orders?.items?.length)
|
|
29
|
+
.reverse()
|
|
30
|
+
|
|
31
|
+
const olderOrders = isFirstPage
|
|
32
|
+
? orders?.items.slice(0, Math.max((orders?.items?.length ?? 0) - 2, 0)).reverse()
|
|
33
|
+
: orders?.items
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Box
|
|
37
|
+
className={classes.root}
|
|
38
|
+
sx={[
|
|
39
|
+
(theme) => ({
|
|
40
|
+
typography: 'body2',
|
|
41
|
+
marginBottom: theme.spacings.md,
|
|
42
|
+
}),
|
|
43
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
44
|
+
]}
|
|
45
|
+
>
|
|
46
|
+
{isFirstPage && (
|
|
47
|
+
<SectionContainer labelLeft={<Trans id='Latest orders' />}>
|
|
48
|
+
{latestOrders?.map(
|
|
49
|
+
(order) => order && <OrderCard key={order.number} {...order} images={images} />,
|
|
50
|
+
)}
|
|
51
|
+
{orders?.items && !orders?.items?.length && <NoOrdersFound />}
|
|
52
|
+
</SectionContainer>
|
|
53
|
+
)}
|
|
54
|
+
|
|
55
|
+
{orders?.items &&
|
|
56
|
+
((isFirstPage && orders?.items?.length >= amountLatestOrders + 1) || !isFirstPage) && (
|
|
57
|
+
<SectionContainer
|
|
58
|
+
labelLeft={<Trans id='Older' />}
|
|
59
|
+
className={classes.older}
|
|
60
|
+
sx={(theme) => ({
|
|
61
|
+
[theme.breakpoints.up('md')]: {
|
|
62
|
+
marginTop: theme.spacings.lg,
|
|
63
|
+
marginBottom: theme.spacings.lg,
|
|
64
|
+
},
|
|
65
|
+
marginTop: theme.spacings.md,
|
|
66
|
+
marginBottom: theme.spacings.md,
|
|
67
|
+
})}
|
|
68
|
+
>
|
|
69
|
+
{olderOrders?.map(
|
|
70
|
+
(order) => order && <OrderCard key={order.number} {...order} images={images} />,
|
|
71
|
+
)}
|
|
72
|
+
</SectionContainer>
|
|
73
|
+
)}
|
|
74
|
+
|
|
75
|
+
<Pagination
|
|
76
|
+
count={pageInfo?.total_pages ?? 1}
|
|
77
|
+
page={pageInfo?.current_page ?? 1}
|
|
78
|
+
renderLink={(p: number, icon: React.ReactNode) => (
|
|
79
|
+
<PageLink href={p === 1 ? '/account/orders' : `/account/orders?page=${p}`} passHref>
|
|
80
|
+
<Link color='primary' underline='hover'>
|
|
81
|
+
{icon}
|
|
82
|
+
</Link>
|
|
83
|
+
</PageLink>
|
|
84
|
+
)}
|
|
85
|
+
/>
|
|
86
|
+
</Box>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApolloCustomerErrorAlert,
|
|
3
|
+
SignInForm,
|
|
4
|
+
SignUpForm,
|
|
5
|
+
useFormIsEmailAvailable,
|
|
6
|
+
CustomerDocument,
|
|
7
|
+
} from '@graphcommerce/magento-customer'
|
|
8
|
+
import { useCustomerQuery } from '@graphcommerce/magento-customer/hooks'
|
|
9
|
+
import {
|
|
10
|
+
Button,
|
|
11
|
+
FormDiv,
|
|
12
|
+
FormActions,
|
|
13
|
+
FormRow,
|
|
14
|
+
LayoutTitle,
|
|
15
|
+
extendableComponent,
|
|
16
|
+
} from '@graphcommerce/next-ui'
|
|
17
|
+
import { emailPattern } from '@graphcommerce/react-hook-form'
|
|
18
|
+
import { Trans } from '@lingui/react'
|
|
19
|
+
import { Box, CircularProgress, Link, SxProps, TextField, Theme, Typography } from '@mui/material'
|
|
20
|
+
import PageLink from 'next/link'
|
|
21
|
+
import router from 'next/router'
|
|
22
|
+
|
|
23
|
+
export type AccountSignInUpFormProps = { sx?: SxProps<Theme> }
|
|
24
|
+
|
|
25
|
+
const parts = ['root', 'titleContainer'] as const
|
|
26
|
+
const { classes } = extendableComponent('AccountSignInUpForm', parts)
|
|
27
|
+
|
|
28
|
+
const titleContainerSx: SxProps<Theme> = (theme) => ({
|
|
29
|
+
typography: 'body1',
|
|
30
|
+
marginBottom: theme.spacings.xs,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
|
|
34
|
+
const { sx = [] } = props
|
|
35
|
+
const customerQuery = useCustomerQuery(CustomerDocument)
|
|
36
|
+
|
|
37
|
+
const { email, firstname = '' } = customerQuery.data?.customer ?? {}
|
|
38
|
+
const { mode, form, autoSubmitting, submit } = useFormIsEmailAvailable({ email })
|
|
39
|
+
const { formState, muiRegister, required, watch, error } = form
|
|
40
|
+
const disableFields = formState.isSubmitting && !autoSubmitting
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<FormDiv sx={sx} className={classes.root}>
|
|
44
|
+
{mode === 'email' && (
|
|
45
|
+
<Box className={classes.titleContainer} sx={titleContainerSx}>
|
|
46
|
+
<LayoutTitle variant='h2' gutterBottom={false}>
|
|
47
|
+
<Trans id='Sign in or create an account!' />
|
|
48
|
+
</LayoutTitle>
|
|
49
|
+
<Typography variant='h6' align='center'>
|
|
50
|
+
<Trans id='Fill in your e-mail to login or create an account' />
|
|
51
|
+
</Typography>
|
|
52
|
+
</Box>
|
|
53
|
+
)}
|
|
54
|
+
|
|
55
|
+
{mode === 'signin' && (
|
|
56
|
+
<Box className={classes.titleContainer} sx={titleContainerSx}>
|
|
57
|
+
<LayoutTitle variant='h2' gutterBottom={false}>
|
|
58
|
+
<Trans id='Welcome back!' />
|
|
59
|
+
</LayoutTitle>
|
|
60
|
+
<Typography variant='h6' align='center'>
|
|
61
|
+
<Trans id='Fill in your password' />
|
|
62
|
+
</Typography>
|
|
63
|
+
</Box>
|
|
64
|
+
)}
|
|
65
|
+
|
|
66
|
+
{mode === 'signup' && (
|
|
67
|
+
<Box className={classes.titleContainer} sx={titleContainerSx}>
|
|
68
|
+
<LayoutTitle variant='h2' gutterBottom={false}>
|
|
69
|
+
<Trans id='Create account!' />
|
|
70
|
+
</LayoutTitle>
|
|
71
|
+
<Typography variant='h6' align='center'>
|
|
72
|
+
<Trans id='Create a password and tell us your name' />
|
|
73
|
+
</Typography>
|
|
74
|
+
</Box>
|
|
75
|
+
)}
|
|
76
|
+
|
|
77
|
+
{mode === 'signedin' && (
|
|
78
|
+
<Box className={classes.titleContainer} sx={titleContainerSx}>
|
|
79
|
+
<LayoutTitle variant='h2' gutterBottom={false}>
|
|
80
|
+
<Trans id='Hi {firstname}! You’re now logged in!' values={{ firstname }} />
|
|
81
|
+
</LayoutTitle>
|
|
82
|
+
<Typography variant='h6' align='center'>
|
|
83
|
+
<PageLink href='/account' passHref>
|
|
84
|
+
<Link underline='hover' color='secondary'>
|
|
85
|
+
<Trans id='View your account' />
|
|
86
|
+
</Link>
|
|
87
|
+
</PageLink>
|
|
88
|
+
</Typography>
|
|
89
|
+
|
|
90
|
+
<FormActions>
|
|
91
|
+
<Button onClick={() => router.back()} variant='pill' color='secondary' size='large'>
|
|
92
|
+
<Trans id='Continue shopping' />
|
|
93
|
+
</Button>
|
|
94
|
+
</FormActions>
|
|
95
|
+
</Box>
|
|
96
|
+
)}
|
|
97
|
+
|
|
98
|
+
{mode === 'session-expired' && (
|
|
99
|
+
<Box className={classes.titleContainer} sx={titleContainerSx}>
|
|
100
|
+
<LayoutTitle variant='h2' gutterBottom={false}>
|
|
101
|
+
<Trans id='Your session is expired' />
|
|
102
|
+
</LayoutTitle>
|
|
103
|
+
<Typography variant='h6' align='center'>
|
|
104
|
+
<Trans id='Log in to continue shopping' />
|
|
105
|
+
</Typography>
|
|
106
|
+
</Box>
|
|
107
|
+
)}
|
|
108
|
+
|
|
109
|
+
{mode !== 'signedin' && (
|
|
110
|
+
<form noValidate onSubmit={submit}>
|
|
111
|
+
<Box>
|
|
112
|
+
<FormRow>
|
|
113
|
+
<TextField
|
|
114
|
+
variant='outlined'
|
|
115
|
+
type='text'
|
|
116
|
+
autoComplete='email'
|
|
117
|
+
error={formState.isSubmitted && !!formState.errors.email}
|
|
118
|
+
helperText={formState.isSubmitted && formState.errors.email?.message}
|
|
119
|
+
label={<Trans id='Email' />}
|
|
120
|
+
required={required.email}
|
|
121
|
+
disabled={disableFields}
|
|
122
|
+
{...muiRegister('email', {
|
|
123
|
+
required: required.email,
|
|
124
|
+
pattern: { value: emailPattern, message: '' },
|
|
125
|
+
})}
|
|
126
|
+
InputProps={{
|
|
127
|
+
endAdornment: formState.isSubmitting && <CircularProgress />,
|
|
128
|
+
readOnly: !!customerQuery.data?.customer?.email,
|
|
129
|
+
}}
|
|
130
|
+
/>
|
|
131
|
+
</FormRow>
|
|
132
|
+
</Box>
|
|
133
|
+
|
|
134
|
+
<ApolloCustomerErrorAlert error={error} />
|
|
135
|
+
|
|
136
|
+
{(mode === 'email' || mode === 'session-expired') && (
|
|
137
|
+
<Box>
|
|
138
|
+
<FormActions>
|
|
139
|
+
<Button
|
|
140
|
+
type='submit'
|
|
141
|
+
loading={formState.isSubmitting}
|
|
142
|
+
variant='pill'
|
|
143
|
+
color='primary'
|
|
144
|
+
size='large'
|
|
145
|
+
>
|
|
146
|
+
<Trans id='Continue' />
|
|
147
|
+
</Button>
|
|
148
|
+
</FormActions>
|
|
149
|
+
</Box>
|
|
150
|
+
)}
|
|
151
|
+
</form>
|
|
152
|
+
)}
|
|
153
|
+
|
|
154
|
+
{mode === 'signin' && (
|
|
155
|
+
<Box>
|
|
156
|
+
<SignInForm email={watch('email')} />
|
|
157
|
+
</Box>
|
|
158
|
+
)}
|
|
159
|
+
|
|
160
|
+
{mode === 'signup' && (
|
|
161
|
+
<Box>
|
|
162
|
+
<SignUpForm email={watch('email')} />
|
|
163
|
+
</Box>
|
|
164
|
+
)}
|
|
165
|
+
</FormDiv>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
@@ -44,7 +44,7 @@ export function CreateCustomerAddressForm() {
|
|
|
44
44
|
},
|
|
45
45
|
onComplete: (e) => {
|
|
46
46
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
47
|
-
router.push(`/account/addresses
|
|
47
|
+
router.push(`/account/addresses`)
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
50
|
{ errorPolicy: 'all' },
|
|
@@ -2,6 +2,8 @@ import { ApolloErrorSnackbar } from '@graphcommerce/ecommerce-ui'
|
|
|
2
2
|
import { useFormGqlMutation } from '@graphcommerce/react-hook-form'
|
|
3
3
|
import { Trans } from '@lingui/react'
|
|
4
4
|
import { Button } from '@mui/material'
|
|
5
|
+
import { AccountDashboardAddressesDocument } from '../../graphql/AccountDashboardAddresses.gql'
|
|
6
|
+
import { useCustomerQuery } from '../../hooks/useCustomerQuery'
|
|
5
7
|
import { DeleteCustomerAddressFormDocument } from './DeleteCustomerAddressForm.gql'
|
|
6
8
|
|
|
7
9
|
export type DeleteCustomerAddressFormProps = {
|
|
@@ -10,10 +12,18 @@ export type DeleteCustomerAddressFormProps = {
|
|
|
10
12
|
|
|
11
13
|
export function DeleteCustomerAddressForm(props: DeleteCustomerAddressFormProps) {
|
|
12
14
|
const { addressId } = props
|
|
15
|
+
const { refetch } = useCustomerQuery(AccountDashboardAddressesDocument, {
|
|
16
|
+
fetchPolicy: 'cache-and-network',
|
|
17
|
+
})
|
|
13
18
|
const { handleSubmit, error } = useFormGqlMutation(
|
|
14
19
|
DeleteCustomerAddressFormDocument,
|
|
15
20
|
{ defaultValues: { id: addressId } },
|
|
16
|
-
{
|
|
21
|
+
{
|
|
22
|
+
errorPolicy: 'all',
|
|
23
|
+
onCompleted: async () => {
|
|
24
|
+
await refetch()
|
|
25
|
+
},
|
|
26
|
+
},
|
|
17
27
|
)
|
|
18
28
|
const submitHandler = handleSubmit(() => {})
|
|
19
29
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IconHeader, iconBox, extendableComponent } from '@graphcommerce/next-ui'
|
|
2
|
+
import { Trans } from '@lingui/react'
|
|
3
|
+
import { Box, SxProps, Theme } from '@mui/material'
|
|
4
|
+
|
|
5
|
+
const parts = ['root'] as const
|
|
6
|
+
const { classes } = extendableComponent('NoOrdersFound', parts)
|
|
7
|
+
|
|
8
|
+
type NoOrdersFoundProps = { sx?: SxProps<Theme> }
|
|
9
|
+
|
|
10
|
+
export function NoOrdersFound(props: NoOrdersFoundProps) {
|
|
11
|
+
const { sx = [] } = props
|
|
12
|
+
return (
|
|
13
|
+
<Box
|
|
14
|
+
className={classes.root}
|
|
15
|
+
sx={[(theme) => ({ marginTop: theme.spacings.sm }), ...(Array.isArray(sx) ? sx : [sx])]}
|
|
16
|
+
>
|
|
17
|
+
<IconHeader src={iconBox} size='small'>
|
|
18
|
+
<Trans id='No orders found' />
|
|
19
|
+
</IconHeader>
|
|
20
|
+
</Box>
|
|
21
|
+
)
|
|
22
|
+
}
|