@graphcommerce/magento-customer 6.2.0-canary.8 → 6.2.0-canary.80

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 CHANGED
@@ -1,5 +1,185 @@
1
1
  # Change Log
2
2
 
3
+ ## 6.2.0-canary.80
4
+
5
+ ## 6.2.0-canary.79
6
+
7
+ ## 6.2.0-canary.78
8
+
9
+ ## 6.2.0-canary.77
10
+
11
+ ## 6.2.0-canary.76
12
+
13
+ ## 6.2.0-canary.75
14
+
15
+ ### Patch Changes
16
+
17
+ - [#2016](https://github.com/graphcommerce-org/graphcommerce/pull/2016) [`227ddcee8`](https://github.com/graphcommerce-org/graphcommerce/commit/227ddcee8808715928371c1f3a4c7925032df0ef) - Made cardProps on CustomerAddressActionCards overridable. ([@Jessevdpoel](https://github.com/Jessevdpoel))
18
+
19
+ ## 6.2.0-canary.74
20
+
21
+ ### Patch Changes
22
+
23
+ - [#2006](https://github.com/graphcommerce-org/graphcommerce/pull/2006) [`80b60cb40`](https://github.com/graphcommerce-org/graphcommerce/commit/80b60cb404882260bd0e8184f3e54f4720925c96) - Bugfix for unintentionally overriding the billing address even if a default address was set. Also made prefix optional when creating an address ([@Jessevdpoel](https://github.com/Jessevdpoel))
24
+
25
+ ## 6.2.0-canary.73
26
+
27
+ ## 6.2.0-canary.72
28
+
29
+ ## 6.2.0-canary.71
30
+
31
+ ## 6.2.0-canary.70
32
+
33
+ ## 6.2.0-canary.69
34
+
35
+ ## 6.2.0-canary.68
36
+
37
+ ## 6.2.0-canary.67
38
+
39
+ ## 6.2.0-canary.66
40
+
41
+ ## 6.2.0-canary.65
42
+
43
+ ## 6.2.0-canary.64
44
+
45
+ ## 6.2.0-canary.63
46
+
47
+ ## 6.2.0-canary.62
48
+
49
+ ## 6.2.0-canary.61
50
+
51
+ ## 6.2.0-canary.60
52
+
53
+ ## 6.2.0-canary.59
54
+
55
+ ## 6.2.0-canary.58
56
+
57
+ ## 6.2.0-canary.57
58
+
59
+ ## 6.2.0-canary.56
60
+
61
+ ## 6.2.0-canary.55
62
+
63
+ ## 6.2.0-canary.54
64
+
65
+ ## 6.2.0-canary.53
66
+
67
+ ## 6.2.0-canary.52
68
+
69
+ ### Patch Changes
70
+
71
+ - [#1972](https://github.com/graphcommerce-org/graphcommerce/pull/1972) [`cda89820d`](https://github.com/graphcommerce-org/graphcommerce/commit/cda89820dc50e2019a26239b7450863d8c862bfb) - Ensure correct width for CircularProgress and fix misalignment in rotate animation ([@carlocarels90](https://github.com/carlocarels90))
72
+
73
+ ## 6.2.0-canary.51
74
+
75
+ ## 6.2.0-canary.50
76
+
77
+ ## 6.2.0-canary.49
78
+
79
+ ## 6.2.0-canary.48
80
+
81
+ ## 6.2.0-canary.47
82
+
83
+ ### Patch Changes
84
+
85
+ - [#1969](https://github.com/graphcommerce-org/graphcommerce/pull/1969) [`838322a97`](https://github.com/graphcommerce-org/graphcommerce/commit/838322a97c7ef1b8aa919196e756da381904bf04) - Fixing the Internal Server Error if the third address line is empty. ([@action-simon](https://github.com/action-simon))
86
+
87
+ ## 6.2.0-canary.46
88
+
89
+ ## 6.2.0-canary.45
90
+
91
+ ### Minor Changes
92
+
93
+ - [#1962](https://github.com/graphcommerce-org/graphcommerce/pull/1962) [`518b6ca24`](https://github.com/graphcommerce-org/graphcommerce/commit/518b6ca248fc94624dc06eb02de5b3eac0fc9483) - Created a new `<ValidatedPasswordElement/>` which validates according to Magento's validation groups and implement on all locations. Move remaining password fields to `<PasswordElement />` ([@carlocarels90](https://github.com/carlocarels90))
94
+
95
+ ## 6.2.0-canary.44
96
+
97
+ ## 6.2.0-canary.43
98
+
99
+ ## 6.2.0-canary.42
100
+
101
+ ## 6.2.0-canary.41
102
+
103
+ ## 6.2.0-canary.40
104
+
105
+ ## 6.2.0-canary.39
106
+
107
+ ## 6.2.0-canary.38
108
+
109
+ ## 6.2.0-canary.37
110
+
111
+ ### Patch Changes
112
+
113
+ - [#1952](https://github.com/graphcommerce-org/graphcommerce/pull/1952) [`f1fe4f598`](https://github.com/graphcommerce-org/graphcommerce/commit/f1fe4f5986cee1f7c8313152e43691ed939c8f21) - enable password fields when there is an error and user input correction is required. ([@carlocarels90](https://github.com/carlocarels90))
114
+
115
+ ## 6.2.0-canary.36
116
+
117
+ ## 6.2.0-canary.35
118
+
119
+ ## 6.2.0-canary.34
120
+
121
+ ## 6.2.0-canary.33
122
+
123
+ ## 6.2.0-canary.32
124
+
125
+ ## 6.2.0-canary.31
126
+
127
+ ## 6.2.0-canary.30
128
+
129
+ ### Patch Changes
130
+
131
+ - [#1942](https://github.com/graphcommerce-org/graphcommerce/pull/1942) [`21b0d0c48`](https://github.com/graphcommerce-org/graphcommerce/commit/21b0d0c48603343c09f287978bf051140e9be912) - Customer's session is now revalidated when a previous session is detected on pageload, making sure the customer is still logged in. ([@paales](https://github.com/paales))
132
+
133
+ ## 6.2.0-canary.29
134
+
135
+ ## 6.2.0-canary.28
136
+
137
+ ## 6.2.0-canary.27
138
+
139
+ ## 6.2.0-canary.26
140
+
141
+ ## 6.2.0-canary.25
142
+
143
+ ## 6.2.0-canary.24
144
+
145
+ ## 6.2.0-canary.23
146
+
147
+ ## 6.2.0-canary.22
148
+
149
+ ## 6.2.0-canary.21
150
+
151
+ ## 6.2.0-canary.20
152
+
153
+ ## 6.2.0-canary.19
154
+
155
+ ## 6.2.0-canary.18
156
+
157
+ ## 6.2.0-canary.17
158
+
159
+ ## 6.2.0-canary.16
160
+
161
+ ### Patch Changes
162
+
163
+ - [#1930](https://github.com/graphcommerce-org/graphcommerce/pull/1930) [`c8d023e9e`](https://github.com/graphcommerce-org/graphcommerce/commit/c8d023e9e874131cd9f8fe192b1fca5fe1a26ee3) - Fix the close menu on search and add the option to secondary menu items ([@StefanAngenent](https://github.com/StefanAngenent))
164
+
165
+ ## 6.2.0-canary.15
166
+
167
+ ### Minor Changes
168
+
169
+ - [#1926](https://github.com/graphcommerce-org/graphcommerce/pull/1926) [`ab8877fdb`](https://github.com/graphcommerce-org/graphcommerce/commit/ab8877fdb6147960ce656d28306d719e92f6de68) - Made the follow order link in the order card & order details a working <Link /> if provided from magento backend. ([@JoshuaS98](https://github.com/JoshuaS98))
170
+
171
+ ## 6.2.0-canary.14
172
+
173
+ ## 6.2.0-canary.13
174
+
175
+ ## 6.2.0-canary.12
176
+
177
+ ## 6.2.0-canary.11
178
+
179
+ ## 6.2.0-canary.10
180
+
181
+ ## 6.2.0-canary.9
182
+
3
183
  ## 6.2.0-canary.8
4
184
 
5
185
  ## 6.2.0-canary.7
@@ -118,7 +118,9 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
118
118
  pattern: { value: emailPattern, message: '' },
119
119
  })}
120
120
  InputProps={{
121
- endAdornment: formState.isSubmitting && <CircularProgress />,
121
+ endAdornment: formState.isSubmitting && (
122
+ <CircularProgress sx={{ display: 'inline-flex' }} />
123
+ ),
122
124
  readOnly: !!customerQuery.data?.customer?.email,
123
125
  }}
124
126
  />
@@ -1,3 +1,9 @@
1
+ import {
2
+ ApolloErrorSnackbar,
3
+ PasswordElement,
4
+ PasswordRepeatElement,
5
+ } from '@graphcommerce/ecommerce-ui'
6
+ import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
1
7
  import {
2
8
  Form,
3
9
  FormActions,
@@ -7,10 +13,8 @@ import {
7
13
  Button,
8
14
  } from '@graphcommerce/next-ui'
9
15
  import { useFormGqlMutation } from '@graphcommerce/react-hook-form'
10
- import { i18n } from '@lingui/core'
11
16
  import { Trans } from '@lingui/react'
12
- import { TextField } from '@mui/material'
13
- import { ApolloCustomerErrorAlert } from '../ApolloCustomerError/ApolloCustomerErrorAlert'
17
+ import { ValidatedPasswordElement } from '../ValidatedPasswordElement/ValidatedPasswordElement'
14
18
  import {
15
19
  ChangePasswordDocument,
16
20
  ChangePasswordMutation,
@@ -21,55 +25,61 @@ export function ChangePasswordForm() {
21
25
  const form = useFormGqlMutation<
22
26
  ChangePasswordMutation,
23
27
  ChangePasswordMutationVariables & { confirmPassword?: string }
24
- >(ChangePasswordDocument)
25
- const { muiRegister, handleSubmit, required, watch, data, formState, error } = form
28
+ >(ChangePasswordDocument, {}, { errorPolicy: 'all' })
29
+ const { handleSubmit, required, data, formState, error, control } = form
30
+ const [remainingError0, authenticationError] = graphqlErrorByCategory({
31
+ category: 'graphql-authentication',
32
+ error,
33
+ })
34
+ const [remainingError, inputError] = graphqlErrorByCategory({
35
+ category: 'graphql-input',
36
+ error: remainingError0,
37
+ })
38
+
26
39
  const submitHandler = handleSubmit(() => {})
27
- const pass = watch('newPassword')
40
+
41
+ const showSuccess = !formState.isSubmitting && formState.isSubmitSuccessful && !error?.message
28
42
 
29
43
  return (
30
44
  <Form onSubmit={submitHandler} noValidate>
31
45
  <FormRow>
32
- <TextField
46
+ <PasswordElement
47
+ control={control}
48
+ name='currentPassword'
33
49
  variant='outlined'
34
- type='password'
35
- error={!!formState.errors.currentPassword}
50
+ autoComplete='current-password'
36
51
  label={<Trans id='Current Password' />}
37
52
  required={required.currentPassword}
38
- {...muiRegister('currentPassword', { required: required.currentPassword })}
39
- helperText={formState.errors.currentPassword?.message}
40
53
  disabled={formState.isSubmitting}
54
+ error={Boolean(authenticationError)}
55
+ helperText={authenticationError?.message}
41
56
  />
42
57
  </FormRow>
43
58
 
44
59
  <FormRow>
45
- <TextField
60
+ <ValidatedPasswordElement
61
+ control={control}
62
+ name='newPassword'
46
63
  variant='outlined'
47
- type='password'
48
- error={!!formState.errors.newPassword}
64
+ autoComplete='new-password'
49
65
  label={<Trans id='New password' />}
50
66
  required={required.newPassword}
51
- {...muiRegister('newPassword', { required: required.newPassword })}
52
- helperText={formState.errors.newPassword?.message}
53
67
  disabled={formState.isSubmitting}
68
+ error={Boolean(inputError)}
69
+ helperText={inputError?.message}
54
70
  />
55
-
56
- <TextField
71
+ <PasswordRepeatElement
72
+ control={control}
73
+ name='confirmPassword'
74
+ passwordFieldName='newPassword'
75
+ autoComplete='new-password'
57
76
  variant='outlined'
58
- type='password'
59
- error={!!formState.errors.confirmPassword}
60
77
  label={<Trans id='Confirm password' />}
61
78
  required
62
- {...muiRegister('confirmPassword', {
63
- required: true,
64
- validate: (value) => value === pass || i18n._(/* i18n */ "Passwords don't match"),
65
- })}
66
- helperText={formState.errors.confirmPassword?.message}
67
79
  disabled={formState.isSubmitting}
68
80
  />
69
81
  </FormRow>
70
82
 
71
- <ApolloCustomerErrorAlert error={error} />
72
-
73
83
  <FormDivider />
74
84
 
75
85
  <FormActions>
@@ -84,9 +94,13 @@ export function ChangePasswordForm() {
84
94
  </Button>
85
95
  </FormActions>
86
96
 
87
- <MessageSnackbar sticky open={Boolean(formState.isSubmitSuccessful && data)}>
88
- <Trans id='Successfully changed password' />
89
- </MessageSnackbar>
97
+ <ApolloErrorSnackbar error={remainingError} />
98
+
99
+ {showSuccess && (
100
+ <MessageSnackbar open={showSuccess} sticky variant='pill'>
101
+ <Trans id='Successfully changed password' />
102
+ </MessageSnackbar>
103
+ )}
90
104
  </Form>
91
105
  )
92
106
  }
@@ -1,5 +1,5 @@
1
1
  mutation CreateCustomerAddress(
2
- $prefix: String!
2
+ $prefix: String
3
3
  $firstname: String!
4
4
  $middlename: String
5
5
  $lastname: String!
@@ -7,7 +7,7 @@ mutation CreateCustomerAddress(
7
7
  $telephone: String!
8
8
  $street: String!
9
9
  $houseNumber: String!
10
- $addition: String
10
+ $addition: String = ""
11
11
  $city: String!
12
12
  $postcode: String!
13
13
  $region: CustomerAddressRegionInput!
@@ -20,4 +20,5 @@ fragment CustomerAddress on CustomerAddress {
20
20
 
21
21
  vat_id
22
22
  default_shipping
23
+ default_billing
23
24
  }
@@ -8,6 +8,7 @@ import { i18n } from '@lingui/core'
8
8
  import { Fab, FabProps as FabPropsType, NoSsr, SxProps, Theme } from '@mui/material'
9
9
  import React from 'react'
10
10
  import { useCustomerSession, UseCustomerSessionReturn } from '../../hooks'
11
+ import { useCustomerValidateToken } from '../../hooks/useCustomerValidateToken'
11
12
 
12
13
  type CustomerFabContentProps = {
13
14
  icon?: React.ReactNode
@@ -53,6 +54,8 @@ export type CustomerFabProps = Omit<CustomerFabContentProps, 'session'>
53
54
  export function CustomerFab(props: CustomerFabProps) {
54
55
  const session = useCustomerSession()
55
56
 
57
+ useCustomerValidateToken()
58
+
56
59
  return (
57
60
  <NoSsr fallback={<CustomerFabContent {...props} />}>
58
61
  <CustomerFabContent session={session} {...props} />
@@ -1,6 +1,6 @@
1
1
  import { MenuFabSecondaryItem, iconPerson, IconSvg } from '@graphcommerce/next-ui'
2
2
  import { Badge, NoSsr, SxProps, Theme } from '@mui/material'
3
- import React from 'react'
3
+ import React, { MouseEventHandler } from 'react'
4
4
  import { useCustomerSession, UseCustomerSessionReturn } from '../../hooks/useCustomerSession'
5
5
 
6
6
  type CustomerMenuFabItemProps = {
@@ -10,13 +10,15 @@ type CustomerMenuFabItemProps = {
10
10
  guestHref: string
11
11
  sx?: SxProps<Theme>
12
12
  session?: UseCustomerSessionReturn
13
+ onClick?: MouseEventHandler<HTMLElement>
13
14
  }
14
15
 
15
16
  function CustomerMenuFabItemContent(props: CustomerMenuFabItemProps) {
16
- const { session, icon, children, guestHref, authHref, sx = [] } = props
17
+ const { session, icon, children, onClick, guestHref, authHref, sx = [] } = props
17
18
 
18
19
  return (
19
20
  <MenuFabSecondaryItem
21
+ onClick={onClick}
20
22
  sx={sx}
21
23
  icon={
22
24
  <Badge
@@ -26,7 +26,6 @@ const parts = [
26
26
  'totalsRow',
27
27
  'totalsDivider',
28
28
  'totalsVat',
29
- 'iconContainer',
30
29
  'invoice',
31
30
  ] as const
32
31
  const { classes } = extendableComponent(componentName, parts)
@@ -85,18 +84,11 @@ const TotalsVat = styled(TotalsRow, { target: classes.totalsVat })(({ theme }) =
85
84
  padding: `${theme.spacings.xxs} 0`,
86
85
  }),
87
86
  )
88
- const IconContainer = styled(TotalsRow, { target: classes.iconContainer })(({ theme }) =>
89
- theme.unstable_sx({
90
- marginLeft: '-6px',
91
- '& > div': {
92
- padding: '4px 0',
93
- },
94
- }),
95
- )
96
87
 
97
88
  const Invoice = styled(TotalsRow, { target: classes.invoice })(({ theme }) =>
98
89
  theme.unstable_sx({
99
90
  display: 'flex',
91
+ justifyContent: 'flex-start',
100
92
  alignItems: 'center',
101
93
  color: 'primary.main',
102
94
  }),
@@ -248,9 +240,7 @@ export function OrderDetails(props: OrderDetailsProps) {
248
240
  <>
249
241
  <div>{shipments?.[0]?.tracking && shipments?.[0]?.tracking?.[0]?.title}</div>
250
242
  {shipments?.[0]?.tracking?.[0] && (
251
- <IconContainer>
252
- <TrackingLink {...shipments?.[0].tracking?.[0]} />
253
- </IconContainer>
243
+ <TrackingLink {...shipments?.[0].tracking?.[0]} sx={{ padding: '4px 0' }} />
254
244
  )}
255
245
  </>
256
246
  )}
@@ -275,12 +265,10 @@ export function OrderDetails(props: OrderDetailsProps) {
275
265
  <div>{payment_methods[0].name}</div>
276
266
 
277
267
  {invoices && invoices?.length > 0 && (
278
- <IconContainer>
279
- <Invoice>
280
- <IconSvg src={iconInvoice} size='small' />
281
- {invoices?.[0]?.number}
282
- </Invoice>
283
- </IconContainer>
268
+ <Invoice>
269
+ <IconSvg src={iconInvoice} size='small' />
270
+ {invoices?.[0]?.number}
271
+ </Invoice>
284
272
  )}
285
273
  </>
286
274
  )}
@@ -1,14 +1,10 @@
1
- import {
2
- PasswordElement,
3
- PasswordRepeatElement,
4
- TextFieldElement,
5
- } from '@graphcommerce/ecommerce-ui'
1
+ import { PasswordRepeatElement, TextFieldElement } from '@graphcommerce/ecommerce-ui'
6
2
  import { Button, Form, FormActions, FormRow } from '@graphcommerce/next-ui'
7
3
  import { useFormGqlMutation } from '@graphcommerce/react-hook-form'
8
4
  import { Trans } from '@lingui/react'
9
- import { TextField } from '@mui/material'
10
5
  import { useRouter } from 'next/router'
11
6
  import { ApolloCustomerErrorAlert } from '../ApolloCustomerError/ApolloCustomerErrorAlert'
7
+ import { ValidatedPasswordElement } from '../ValidatedPasswordElement/ValidatedPasswordElement'
12
8
  import {
13
9
  ResetPasswordDocument,
14
10
  ResetPasswordMutation,
@@ -59,11 +55,11 @@ export function ResetPasswordForm(props: ResetPasswordFormProps) {
59
55
  />
60
56
  </FormRow>
61
57
  <FormRow>
62
- <PasswordElement
58
+ <ValidatedPasswordElement
63
59
  control={control}
64
60
  name='newPassword'
61
+ autoComplete='new-password'
65
62
  variant='outlined'
66
- type='password'
67
63
  label={<Trans id='New password' />}
68
64
  required
69
65
  disabled={formState.isSubmitting}
@@ -71,9 +67,9 @@ export function ResetPasswordForm(props: ResetPasswordFormProps) {
71
67
  <PasswordRepeatElement
72
68
  control={control}
73
69
  name='confirmPassword'
70
+ autoComplete='new-password'
74
71
  passwordFieldName='newPassword'
75
72
  variant='outlined'
76
- type='password'
77
73
  label={<Trans id='Confirm password' />}
78
74
  required
79
75
  disabled={formState.isSubmitting}
@@ -1,9 +1,18 @@
1
+ import { PasswordElement } from '@graphcommerce/ecommerce-ui'
1
2
  import { useApolloClient } from '@graphcommerce/graphql'
2
3
  import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
3
- import { Button, FormRow, FormActions } from '@graphcommerce/next-ui'
4
+ import {
5
+ Button,
6
+ FormRow,
7
+ FormActions,
8
+ iconEyeCrossed,
9
+ iconEye,
10
+ IconSvg,
11
+ } from '@graphcommerce/next-ui'
4
12
  import { useFormGqlMutation } from '@graphcommerce/react-hook-form'
5
13
  import { Trans } from '@lingui/react'
6
- import { Box, FormControl, Link, SxProps, TextField, Theme } from '@mui/material'
14
+ import { Box, FormControl, IconButton, InputAdornment, Link, SxProps, Theme } from '@mui/material'
15
+ import { MouseEvent, useState } from 'react'
7
16
  import { CustomerDocument } from '../../hooks'
8
17
  import { ApolloCustomerErrorAlert } from '../ApolloCustomerError/ApolloCustomerErrorAlert'
9
18
  import { SignInDocument } from './SignIn.gql'
@@ -12,7 +21,6 @@ type SignInFormProps = { email: string; sx?: SxProps<Theme> }
12
21
 
13
22
  export function SignInForm(props: SignInFormProps) {
14
23
  const { email, sx } = props
15
-
16
24
  const client = useApolloClient()
17
25
  const form = useFormGqlMutation(
18
26
  SignInDocument,
@@ -32,7 +40,7 @@ export function SignInForm(props: SignInFormProps) {
32
40
  { errorPolicy: 'all' },
33
41
  )
34
42
 
35
- const { muiRegister, handleSubmit, required, formState, error } = form
43
+ const { handleSubmit, required, formState, error, control } = form
36
44
  const [remainingError, authError] = graphqlErrorByCategory({
37
45
  category: 'graphql-authentication',
38
46
  error,
@@ -41,18 +49,19 @@ export function SignInForm(props: SignInFormProps) {
41
49
 
42
50
  return (
43
51
  <Box component='form' onSubmit={submitHandler} noValidate sx={sx}>
44
- <FormRow>
45
- <TextField
46
- key='password'
52
+ <FormRow sx={{ gridTemplateColumns: 'none' }}>
53
+ <PasswordElement
47
54
  variant='outlined'
48
- type='password'
49
55
  error={!!formState.errors.password || !!authError}
56
+ control={control}
57
+ name='password'
50
58
  label={<Trans id='Password' />}
51
59
  autoFocus
52
60
  autoComplete='current-password'
53
61
  id='current-password'
54
62
  required={required.password}
55
- {...muiRegister('password', { required: required.password })}
63
+ disabled={formState.isSubmitting}
64
+ helperText={!!formState.errors.password || authError?.message}
56
65
  InputProps={{
57
66
  endAdornment: (
58
67
  <Link href='/account/forgot-password' underline='hover' sx={{ whiteSpace: 'nowrap' }}>
@@ -60,8 +69,6 @@ export function SignInForm(props: SignInFormProps) {
60
69
  </Link>
61
70
  ),
62
71
  }}
63
- helperText={formState.errors.password?.message || authError?.message}
64
- disabled={formState.isSubmitting}
65
72
  />
66
73
  </FormRow>
67
74
 
@@ -1,7 +1,8 @@
1
+ import { PasswordElement } from '@graphcommerce/ecommerce-ui'
1
2
  import { Button, extendableComponent } from '@graphcommerce/next-ui'
2
3
  import { useFormGqlMutation } from '@graphcommerce/react-hook-form'
3
4
  import { Trans } from '@lingui/react'
4
- import { Box, SxProps, TextField, Theme } from '@mui/material'
5
+ import { Box, Link, SxProps, Theme } from '@mui/material'
5
6
  import { SignInDocument, SignInMutationVariables } from './SignIn.gql'
6
7
 
7
8
  type InlineSignInFormProps = Omit<SignInMutationVariables, 'password'> & {
@@ -12,13 +13,13 @@ type InlineSignInFormProps = Omit<SignInMutationVariables, 'password'> & {
12
13
  const { classes } = extendableComponent('SignInFormInline', ['form', 'button'] as const)
13
14
 
14
15
  export function SignInFormInline(props: InlineSignInFormProps) {
15
- const { email, sx = [] } = props
16
+ const { email, children, sx = [] } = props
16
17
  const form = useFormGqlMutation(
17
18
  SignInDocument,
18
19
  { defaultValues: { email }, onBeforeSubmit: (values) => ({ ...values, email }) },
19
20
  { errorPolicy: 'all' },
20
21
  )
21
- const { muiRegister, handleSubmit, required, formState, error } = form
22
+ const { handleSubmit, required, formState, control } = form
22
23
  const submitHandler = handleSubmit(() => {})
23
24
 
24
25
  return (
@@ -41,35 +42,34 @@ export function SignInFormInline(props: InlineSignInFormProps) {
41
42
  ...(Array.isArray(sx) ? sx : [sx]),
42
43
  ]}
43
44
  >
44
- <TextField
45
+ <PasswordElement
46
+ control={control}
45
47
  variant='outlined'
46
- type='password'
47
- error={!!formState.errors.password || !!error?.message}
48
+ name='password'
48
49
  label={<Trans id='Password' />}
49
50
  autoFocus
50
51
  autoComplete='current-password'
51
52
  id='current-password'
52
53
  required={required.password}
53
- {...muiRegister('password', { required: required.password })}
54
- helperText={error?.message}
55
54
  disabled={formState.isSubmitting}
56
55
  InputProps={{
57
56
  endAdornment: (
58
- <Button
59
- href='/account/forgot-password'
60
- color='secondary'
61
- variant='text'
62
- className={classes.button}
63
- sx={{ minWidth: 'max-content' }}
64
- >
57
+ <Link href='/account/forgot-password' underline='hover' sx={{ whiteSpace: 'nowrap' }}>
65
58
  <Trans id='Forgot password?' />
66
- </Button>
59
+ </Link>
67
60
  ),
68
61
  }}
69
62
  />
70
- <Button type='submit' loading={formState.isSubmitting} color='secondary' variant='pill'>
63
+ <Button
64
+ type='submit'
65
+ loading={formState.isSubmitting}
66
+ color='secondary'
67
+ variant='pill'
68
+ sx={{ alignSelf: 'start', marginTop: (theme) => `calc(${theme.spacings.xxs} * .33)` }}
69
+ >
71
70
  <Trans id='Sign in' />
72
71
  </Button>
72
+ {children}
73
73
  </Box>
74
74
  )
75
75
  }
@@ -1,15 +1,14 @@
1
- import { useQuery } from '@graphcommerce/graphql'
1
+ import { PasswordElement, PasswordRepeatElement } from '@graphcommerce/ecommerce-ui'
2
2
  import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
3
- import { StoreConfigDocument } from '@graphcommerce/magento-store'
4
3
  import { Button, FormActions, FormRow } from '@graphcommerce/next-ui'
5
4
  import { useFormGqlMutation, useFormPersist } from '@graphcommerce/react-hook-form'
6
- import { i18n } from '@lingui/core'
7
5
  import { Trans } from '@lingui/react'
8
- import { Alert, FormControlLabel, Switch, TextField } from '@mui/material'
6
+ import { Alert, FormControlLabel, Switch } from '@mui/material'
9
7
  import { ApolloCustomerErrorSnackbar } from '../ApolloCustomerError/ApolloCustomerErrorSnackbar'
10
8
  import { NameFields } from '../NameFields/NameFields'
11
9
  import { SignUpDocument, SignUpMutation, SignUpMutationVariables } from './SignUp.gql'
12
10
  import { SignUpConfirmDocument } from './SignUpConfirm.gql'
11
+ import { ValidatedPasswordElement } from '../ValidatedPasswordElement/ValidatedPasswordElement'
13
12
 
14
13
  type SignUpFormProps = { email: string }
15
14
 
@@ -18,8 +17,6 @@ const requireEmailValidation = import.meta.graphCommerce.customerRequireEmailCon
18
17
  export function SignUpForm(props: SignUpFormProps) {
19
18
  const { email } = props
20
19
 
21
- const storeConfig = useQuery(StoreConfigDocument).data?.storeConfig
22
-
23
20
  const Mutation = requireEmailValidation ? SignUpConfirmDocument : SignUpDocument
24
21
 
25
22
  const form = useFormGqlMutation<
@@ -31,11 +28,10 @@ export function SignUpForm(props: SignUpFormProps) {
31
28
  { errorPolicy: 'all' },
32
29
  )
33
30
 
34
- const { muiRegister, handleSubmit, required, watch, formState, error } = form
31
+ const { muiRegister, handleSubmit, required, formState, error, control } = form
35
32
  const [remainingError, inputError] = graphqlErrorByCategory({ category: 'graphql-input', error })
36
33
 
37
34
  const submitHandler = handleSubmit(() => {})
38
- const watchPassword = watch('password')
39
35
 
40
36
  useFormPersist({ form, name: 'SignUp', exclude: ['password', 'confirmPassword'] })
41
37
 
@@ -50,37 +46,27 @@ export function SignUpForm(props: SignUpFormProps) {
50
46
  return (
51
47
  <form onSubmit={submitHandler} noValidate>
52
48
  <FormRow>
53
- <TextField
49
+ <ValidatedPasswordElement
50
+ control={control}
51
+ name='password'
54
52
  variant='outlined'
55
- type='password'
56
53
  error={!!formState.errors.password || !!inputError}
57
54
  label={<Trans id='Password' />}
58
55
  autoFocus
59
56
  autoComplete='new-password'
60
57
  required={required.password}
61
- {...muiRegister('password', {
62
- required: required.password,
63
- minLength: {
64
- value: Number(storeConfig?.minimum_password_length ?? 8),
65
- message: i18n._(/* i18n */ 'Password must have at least 8 characters'),
66
- },
67
- })}
68
- helperText={formState.errors.password?.message || inputError?.message}
69
58
  disabled={formState.isSubmitting}
59
+ helperText={inputError?.message}
70
60
  />
71
- <TextField
61
+ <PasswordRepeatElement
62
+ control={control}
63
+ name='confirmPassword'
64
+ passwordFieldName='password'
72
65
  variant='outlined'
73
- type='password'
74
- error={!!formState.errors.confirmPassword}
66
+ error={!!formState.errors.confirmPassword || !!inputError}
75
67
  label={<Trans id='Confirm password' />}
76
68
  autoComplete='new-password'
77
69
  required
78
- {...muiRegister('confirmPassword', {
79
- required: true,
80
- validate: (value) =>
81
- value === watchPassword || i18n._(/* i18n */ "Passwords don't match"),
82
- })}
83
- helperText={formState.errors.confirmPassword?.message}
84
70
  disabled={formState.isSubmitting}
85
71
  />
86
72
  </FormRow>
@@ -1,13 +1,17 @@
1
- import { useQuery } from '@graphcommerce/graphql'
2
- import { StoreConfigDocument } from '@graphcommerce/magento-store'
1
+ import {
2
+ ApolloErrorAlert,
3
+ PasswordElement,
4
+ PasswordRepeatElement,
5
+ } from '@graphcommerce/ecommerce-ui'
6
+ import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
3
7
  import { Button, extendableComponent, Form, FormRow } from '@graphcommerce/next-ui'
4
8
  import { useFormGqlMutation } from '@graphcommerce/react-hook-form'
5
- import { i18n } from '@lingui/core'
6
9
  import { Trans } from '@lingui/react'
7
- import { Alert, Box, TextField } from '@mui/material'
10
+ import { Alert, Box } from '@mui/material'
8
11
  import React from 'react'
9
12
  import { SignUpMutationVariables, SignUpMutation, SignUpDocument } from './SignUp.gql'
10
13
  import { SignUpConfirmDocument } from './SignUpConfirm.gql'
14
+ import { ValidatedPasswordElement } from '../ValidatedPasswordElement/ValidatedPasswordElement'
11
15
 
12
16
  type SignUpFormInlineProps = Pick<SignUpMutationVariables, 'email'> & {
13
17
  children?: React.ReactNode
@@ -25,37 +29,35 @@ const { classes } = extendableComponent('SignUpFormInline', [
25
29
 
26
30
  const requireEmailValidation = import.meta.graphCommerce.customerRequireEmailConfirmation ?? false
27
31
 
28
- export function SignUpFormInline({
29
- email,
30
- children,
31
- firstname,
32
- lastname,
33
- onSubmitted = () => {},
34
- }: SignUpFormInlineProps) {
32
+ export function SignUpFormInline(props: SignUpFormInlineProps) {
33
+ const { email, children, firstname, lastname, onSubmitted = () => {} } = props
35
34
  const Mutation = requireEmailValidation ? SignUpConfirmDocument : SignUpDocument
36
35
 
37
36
  const form = useFormGqlMutation<
38
37
  SignUpMutation,
39
38
  SignUpMutationVariables & { confirmPassword?: string }
40
- >(Mutation, {
41
- // todo(paales): This causes dirty data to be send to the backend.
42
- defaultValues: {
43
- email,
44
- prefix: '-',
45
- firstname: firstname ?? '-',
46
- lastname: lastname ?? '-',
39
+ >(
40
+ Mutation,
41
+ {
42
+ // todo(paales): This causes dirty data to be send to the backend.
43
+ defaultValues: {
44
+ email,
45
+ prefix: '-',
46
+ firstname: firstname ?? '-',
47
+ lastname: lastname ?? '-',
48
+ },
49
+ onBeforeSubmit: (values) => ({ ...values, email }),
50
+ onComplete: (result) => {
51
+ if (!result.errors) onSubmitted()
52
+ },
47
53
  },
48
- onBeforeSubmit: (values) => ({ ...values, email }),
49
- })
50
-
51
- const { muiRegister, watch, handleSubmit, required, formState, error } = form
52
- const submitHandler = handleSubmit(onSubmitted)
53
- const watchPassword = watch('password')
54
-
55
- const minPasswordLength = Number(
56
- useQuery(StoreConfigDocument).data?.storeConfig?.minimum_password_length ?? 8,
54
+ { errorPolicy: 'all' },
57
55
  )
58
56
 
57
+ const { handleSubmit, formState, control, error, required } = form
58
+ const [remainingError, inputError] = graphqlErrorByCategory({ category: 'graphql-input', error })
59
+ const submitHandler = handleSubmit(() => {})
60
+
59
61
  if (requireEmailValidation && form.formState.isSubmitSuccessful) {
60
62
  return (
61
63
  <Alert>
@@ -66,43 +68,31 @@ export function SignUpFormInline({
66
68
 
67
69
  return (
68
70
  <Form onSubmit={submitHandler} noValidate className={classes.form} sx={{ padding: 0 }}>
69
- <FormRow key='inline-signup' className={classes.row} sx={{ padding: 0 }}>
70
- <TextField
71
+ <FormRow className={classes.row} sx={{ padding: 0 }}>
72
+ <ValidatedPasswordElement
73
+ control={control}
74
+ name='password'
75
+ autoComplete='new-password'
71
76
  variant='outlined'
72
- type='password'
73
- error={!!formState.errors.password || !!error?.message}
74
77
  label={<Trans id='Password' />}
75
- autoFocus
76
- autoComplete='new-password'
77
- id='new-password'
78
78
  required={required.password}
79
- {...muiRegister('password', {
80
- required: required.password,
81
- minLength: {
82
- value: minPasswordLength,
83
- message: i18n._(/* i18n */ 'Password must have at least 8 characters'),
84
- },
85
- })}
86
- helperText={error?.message}
87
79
  disabled={formState.isSubmitting}
80
+ error={!!inputError}
81
+ helperText={inputError?.message}
88
82
  />
89
- <TextField
83
+ <PasswordRepeatElement
84
+ control={control}
85
+ name='confirmPassword'
86
+ passwordFieldName='password'
87
+ autoComplete='new-password'
90
88
  variant='outlined'
91
- type='password'
92
- error={!!formState.errors.confirmPassword || !!error?.message}
93
89
  label={<Trans id='Confirm password' />}
94
- autoComplete='new-password'
95
90
  required
96
- {...muiRegister('confirmPassword', {
97
- required: true,
98
- validate: (value) => value === watchPassword,
99
- })}
100
- helperText={!!formState.errors.confirmPassword && <Trans id='Passwords should match' />}
101
91
  disabled={formState.isSubmitting}
102
92
  />
103
93
  </FormRow>
104
94
 
105
- <FormRow key='signup-submit'>
95
+ <FormRow>
106
96
  <FormRow
107
97
  className={classes.buttonFormRow}
108
98
  sx={(theme) => ({
@@ -126,6 +116,7 @@ export function SignUpFormInline({
126
116
  </Box>
127
117
  </FormRow>
128
118
  </FormRow>
119
+ <ApolloErrorAlert error={remainingError} />
129
120
  </Form>
130
121
  )
131
122
  }
@@ -1,7 +1,6 @@
1
1
  import { IconSvg, iconLocation } from '@graphcommerce/next-ui'
2
2
  import { Trans } from '@lingui/react'
3
- import { Box, SxProps, Theme } from '@mui/material'
4
- import React from 'react'
3
+ import { Box, Link, SxProps, Theme, Typography } from '@mui/material'
5
4
  import { TrackingLinkFragment } from './TrackingLink.gql'
6
5
 
7
6
  export type TrackingLinkProps = TrackingLinkFragment & { sx?: SxProps<Theme> }
@@ -9,6 +8,8 @@ export type TrackingLinkProps = TrackingLinkFragment & { sx?: SxProps<Theme> }
9
8
  export function TrackingLink(props: TrackingLinkProps) {
10
9
  const { number, sx = [] } = props
11
10
 
11
+ const validUrl = number?.startsWith('http://') || number?.startsWith('https://')
12
+
12
13
  return (
13
14
  <Box
14
15
  className='TrackingLink-root'
@@ -21,12 +22,20 @@ export function TrackingLink(props: TrackingLinkProps) {
21
22
  ...(Array.isArray(sx) ? sx : [sx]),
22
23
  ]}
23
24
  >
24
- {number && (
25
- <>
25
+ {number && validUrl && (
26
+ <Link
27
+ onClick={(e) => e.stopPropagation()}
28
+ href={number}
29
+ target='_blank'
30
+ underline='hover'
31
+ sx={{ display: 'inline-flex', alignItems: 'center' }}
32
+ >
26
33
  <IconSvg src={iconLocation} size='small' />
27
34
  <Trans id='Follow order' />
28
- </>
35
+ </Link>
29
36
  )}
37
+
38
+ {number && !validUrl && <Typography>{number}</Typography>}
30
39
  </Box>
31
40
  )
32
41
  }
@@ -1,3 +1,4 @@
1
+ import { PasswordElement } from '@graphcommerce/ecommerce-ui'
1
2
  import {
2
3
  Button,
3
4
  Form,
@@ -16,6 +17,8 @@ import {
16
17
  UpdateCustomerEmailMutation,
17
18
  UpdateCustomerEmailMutationVariables,
18
19
  } from './UpdateCustomerEmail.gql'
20
+ import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
21
+ import { ApolloCustomerErrorSnackbar } from '../ApolloCustomerError'
19
22
 
20
23
  type UpdateCustomerEmailFormProps = {
21
24
  email: string
@@ -26,13 +29,20 @@ export function UpdateCustomerEmailForm(props: UpdateCustomerEmailFormProps) {
26
29
 
27
30
  const form = useFormGqlMutation<
28
31
  UpdateCustomerEmailMutation,
29
- UpdateCustomerEmailMutationVariables & {
30
- currentEmail?: string
31
- confirmEmail?: string
32
- }
33
- >(UpdateCustomerEmailDocument)
32
+ UpdateCustomerEmailMutationVariables & { currentEmail?: string; confirmEmail?: string }
33
+ >(
34
+ UpdateCustomerEmailDocument,
35
+ {},
36
+ {
37
+ errorPolicy: 'all',
38
+ },
39
+ )
34
40
 
35
- const { handleSubmit, error, required, formState, watch, muiRegister, reset } = form
41
+ const { handleSubmit, error, required, formState, watch, muiRegister, reset, control } = form
42
+ const [remainingError, authenticationError] = graphqlErrorByCategory({
43
+ category: 'graphql-authentication',
44
+ error,
45
+ })
36
46
  const submit = handleSubmit(() => {
37
47
  reset()
38
48
  })
@@ -45,7 +55,7 @@ export function UpdateCustomerEmailForm(props: UpdateCustomerEmailFormProps) {
45
55
  key='current-email'
46
56
  variant='outlined'
47
57
  type='text'
48
- autoComplete='currentEmail'
58
+ autoComplete='email'
49
59
  autoFocus
50
60
  error={formState.isSubmitted && !!formState.errors.currentEmail}
51
61
  helperText={formState.isSubmitted && formState.errors.currentEmail?.message}
@@ -67,8 +77,7 @@ export function UpdateCustomerEmailForm(props: UpdateCustomerEmailFormProps) {
67
77
  key='email'
68
78
  variant='outlined'
69
79
  type='text'
70
- autoComplete='email'
71
- autoFocus
80
+ autoComplete='off'
72
81
  error={formState.isSubmitted && !!formState.errors.email}
73
82
  helperText={formState.isSubmitted && formState.errors.email?.message}
74
83
  label={<Trans id='New email' />}
@@ -82,8 +91,7 @@ export function UpdateCustomerEmailForm(props: UpdateCustomerEmailFormProps) {
82
91
  key='confirm-email'
83
92
  variant='outlined'
84
93
  type='text'
85
- autoComplete='confirmEmail'
86
- autoFocus
94
+ autoComplete='off'
87
95
  error={formState.isSubmitted && !!formState.errors.confirmEmail}
88
96
  helperText={formState.isSubmitted && formState.errors.confirmEmail?.message}
89
97
  label={<Trans id='Confirm new email' />}
@@ -96,21 +104,21 @@ export function UpdateCustomerEmailForm(props: UpdateCustomerEmailFormProps) {
96
104
  </FormRow>
97
105
 
98
106
  <FormRow>
99
- <TextField
107
+ <PasswordElement
108
+ control={control}
100
109
  variant='outlined'
101
- type='password'
102
- error={!!formState.errors.password}
110
+ name='password'
103
111
  label={<Trans id='Password' />}
104
- autoComplete='password'
112
+ autoComplete='current-password'
105
113
  required={required.password}
106
- {...muiRegister('password', {
107
- required: required.password,
108
- })}
109
- helperText={formState.errors.password?.message}
110
114
  disabled={formState.isSubmitting}
115
+ error={Boolean(authenticationError)}
116
+ helperText={authenticationError?.message}
111
117
  />
112
118
  </FormRow>
113
119
 
120
+ <ApolloCustomerErrorSnackbar error={remainingError} />
121
+
114
122
  <FormDivider />
115
123
  <FormActions>
116
124
  <Button
@@ -123,7 +131,6 @@ export function UpdateCustomerEmailForm(props: UpdateCustomerEmailFormProps) {
123
131
  <Trans id='Save changes' />
124
132
  </Button>
125
133
  </FormActions>
126
- <ApolloCustomerErrorAlert error={error} />
127
134
 
128
135
  <MessageSnackbar sticky open={formState.isSubmitSuccessful && !error}>
129
136
  <Trans id='Successfully updated email' />
@@ -0,0 +1,47 @@
1
+ import { PasswordElement, PasswordElementProps } from '@graphcommerce/ecommerce-ui'
2
+ import { useQuery } from '@graphcommerce/graphql'
3
+ import { StoreConfigDocument } from '@graphcommerce/magento-store'
4
+ import { FieldValues } from '@graphcommerce/react-hook-form'
5
+ import { i18n } from '@lingui/core'
6
+
7
+ export type ValidatedPasswordElementProps<T extends FieldValues> = PasswordElementProps<T>
8
+
9
+ export function ValidatedPasswordElement<TFieldValues extends FieldValues>(
10
+ props: PasswordElementProps<TFieldValues>,
11
+ ): JSX.Element {
12
+ const { ...textFieldProps } = props
13
+
14
+ const storeConfig = useQuery(StoreConfigDocument).data?.storeConfig
15
+ const minPasswordLength = Number(storeConfig?.minimum_password_length) ?? 0
16
+ const passwordMinCharacterSets = Number(storeConfig?.required_character_classes_number) ?? 0
17
+
18
+ const validation: NonNullable<PasswordElementProps<TFieldValues>['validation']> = {}
19
+
20
+ validation.minLength = {
21
+ value: minPasswordLength,
22
+ message: i18n._(/* i18n */ 'Password must have at least {minPasswordLength} characters', {
23
+ minPasswordLength,
24
+ }),
25
+ }
26
+
27
+ validation.validate = (value: string) => {
28
+ const pass = value.trim()
29
+ let counter = 0
30
+
31
+ if (pass.match(/\d+/)) counter++
32
+ if (pass.match(/[a-z]+/)) counter++
33
+ if (pass.match(/[A-Z]+/)) counter++
34
+ if (pass.match(/[^a-zA-Z0-9]+/)) counter++
35
+
36
+ if (counter < passwordMinCharacterSets) {
37
+ return i18n._(
38
+ /* i18n */ 'Minimum of different classes of characters in password is {passwordMinCharacterSets}. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.',
39
+ { passwordMinCharacterSets },
40
+ )
41
+ }
42
+
43
+ return true
44
+ }
45
+
46
+ return <PasswordElement {...textFieldProps} validation={validation} />
47
+ }
@@ -2,6 +2,7 @@ fragment CustomerInfo on Customer {
2
2
  default_billing
3
3
  default_shipping
4
4
  addresses {
5
+ default_billing
5
6
  ...CustomerAddress
6
7
  }
7
8
  email
@@ -0,0 +1,5 @@
1
+ query UseCustomerValidateToken {
2
+ customer {
3
+ email
4
+ }
5
+ }
@@ -0,0 +1,23 @@
1
+ import { useApolloClient } from '@graphcommerce/graphql'
2
+ import { ErrorCategory } from '@graphcommerce/magento-graphql'
3
+ import { useRouter } from 'next/router'
4
+ import { UseCustomerValidateTokenDocument } from './UseCustomerValidateToken.gql'
5
+ import { useCustomerQuery } from './useCustomerQuery'
6
+
7
+ /** Validates the current customer token. This hook is supposed to be called only once. */
8
+ export function useCustomerValidateToken() {
9
+ const client = useApolloClient()
10
+ const router = useRouter()
11
+
12
+ useCustomerQuery(UseCustomerValidateTokenDocument, {
13
+ initialFetchPolicy: 'network-only',
14
+ onError: async ({ graphQLErrors }) => {
15
+ const category: ErrorCategory = 'graphql-authorization'
16
+ // If there is no authorization error, do nothing.
17
+ if (!graphQLErrors.some((e) => e.extensions?.category === category)) return
18
+
19
+ await client.clearStore()
20
+ router.reload()
21
+ },
22
+ })
23
+ }
@@ -1,7 +1,5 @@
1
- import { NormalizedCacheObject } from '@graphcommerce/graphql'
2
- import { ApolloLink, ApolloCache, setContext } from '@graphcommerce/graphql/apollo'
1
+ import { setContext } from '@graphcommerce/graphql/apollo'
3
2
  import { CustomerTokenDocument } from '../hooks'
4
- import { onAuthorizationError } from './onAuthenticationError'
5
3
 
6
4
  export const addTokenHeader = setContext((_, context) => {
7
5
  if (!context.headers) context.headers = {}
@@ -17,7 +15,4 @@ export const addTokenHeader = setContext((_, context) => {
17
15
  }
18
16
  })
19
17
 
20
- export const customerTokenLink = ApolloLink.from([addTokenHeader, onAuthorizationError])
21
-
22
- /** Not really required anymore, you can use customerTokenLink directly */
23
- export const createCustomerTokenLink = (_: ApolloCache<NormalizedCacheObject>) => customerTokenLink
18
+ export const customerTokenLink = addTokenHeader
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/magento-customer",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "6.2.0-canary.8",
5
+ "version": "6.2.0-canary.80",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,24 +12,25 @@
12
12
  }
13
13
  },
14
14
  "devDependencies": {
15
- "@graphcommerce/eslint-config-pwa": "6.2.0-canary.8",
16
- "@graphcommerce/prettier-config-pwa": "6.2.0-canary.8",
17
- "@graphcommerce/typescript-config-pwa": "6.2.0-canary.8"
15
+ "@graphcommerce/eslint-config-pwa": "6.2.0-canary.80",
16
+ "@graphcommerce/prettier-config-pwa": "6.2.0-canary.80",
17
+ "@graphcommerce/typescript-config-pwa": "6.2.0-canary.80"
18
18
  },
19
19
  "dependencies": {
20
- "@graphcommerce/ecommerce-ui": "6.2.0-canary.8",
21
- "@graphcommerce/framer-utils": "6.2.0-canary.8",
22
- "@graphcommerce/graphql": "6.2.0-canary.8",
23
- "@graphcommerce/graphql-mesh": "6.2.0-canary.8",
24
- "@graphcommerce/image": "6.2.0-canary.8",
25
- "@graphcommerce/magento-graphql": "6.2.0-canary.8",
26
- "@graphcommerce/magento-store": "6.2.0-canary.8",
27
- "@graphcommerce/next-ui": "6.2.0-canary.8",
28
- "@graphcommerce/react-hook-form": "6.2.0-canary.8"
20
+ "@graphcommerce/ecommerce-ui": "6.2.0-canary.80",
21
+ "@graphcommerce/framer-utils": "6.2.0-canary.80",
22
+ "@graphcommerce/graphql": "6.2.0-canary.80",
23
+ "@graphcommerce/graphql-mesh": "6.2.0-canary.80",
24
+ "@graphcommerce/image": "6.2.0-canary.80",
25
+ "@graphcommerce/magento-graphql": "6.2.0-canary.80",
26
+ "@graphcommerce/magento-store": "6.2.0-canary.80",
27
+ "@graphcommerce/next-ui": "6.2.0-canary.80",
28
+ "@graphcommerce/react-hook-form": "6.2.0-canary.80"
29
29
  },
30
30
  "peerDependencies": {
31
- "@lingui/react": "^3.13.2",
32
- "@lingui/core": "^3.13.2",
31
+ "@lingui/react": "^4.2.1",
32
+ "@lingui/core": "^4.2.1",
33
+ "@lingui/macro": "^4.2.1",
33
34
  "@mui/material": "^5.10.16",
34
35
  "framer-motion": "^10.0.0",
35
36
  "graphql": "^16.0.0",
@@ -1,39 +0,0 @@
1
- import { InMemoryCache } from '@graphcommerce/graphql'
2
- import { onError } from '@graphcommerce/graphql/apollo'
3
- import { CustomerTokenDocument } from '../hooks/CustomerToken.gql'
4
-
5
- function invalidateToken(cache: InMemoryCache) {
6
- const res = cache.readQuery({
7
- query: CustomerTokenDocument,
8
- })
9
-
10
- if (res?.customerToken?.valid) {
11
- // Write arbitrary old token to document
12
- cache.writeQuery({
13
- query: CustomerTokenDocument,
14
- data: {
15
- customerToken: {
16
- ...res.customerToken,
17
- token: null,
18
- createdAt: new Date('2000').toUTCString(),
19
- valid: false,
20
- },
21
- },
22
- broadcast: true,
23
- })
24
- }
25
- }
26
-
27
- export const onAuthorizationError = onError(({ graphQLErrors, operation }) => {
28
- const { cache } = operation.getContext()
29
- if (graphQLErrors) {
30
- for (const err of graphQLErrors) {
31
- const isCustomerError = err.path?.join('.').toLowerCase().includes('customer')
32
- if (err.extensions?.category === 'graphql-authorization' && isCustomerError) {
33
- // Modify the operation context with a new token
34
- invalidateToken(cache as InMemoryCache)
35
- break
36
- }
37
- }
38
- }
39
- })