@graphcommerce/magento-customer 4.4.2 → 4.5.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 +21 -0
- package/components/ApolloCustomerError/ApolloCustomerErrorAlert.tsx +23 -12
- package/components/ApolloCustomerError/ApolloCustomerErrorFullPage.tsx +21 -21
- package/components/ApolloCustomerError/ApolloCustomerErrorSnackbar.tsx +26 -2
- package/components/ApolloCustomerError/index.ts +3 -0
- package/components/ApolloCustomerError/useAuthorizationErrorMasked.ts +16 -0
- package/components/index.ts +1 -3
- package/hooks/index.ts +0 -1
- package/link/createCustomerTokenLink.ts +25 -14
- package/link/onAuthenticationError.ts +35 -0
- package/package.json +8 -7
- package/hooks/useExtractCustomerErrors.tsx +0 -43
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1499](https://github.com/graphcommerce-org/graphcommerce/pull/1499) [`d205b037f`](https://github.com/graphcommerce-org/graphcommerce/commit/d205b037fee82b8c03993f2c586f477e826093bf) Thanks [@paales](https://github.com/paales)! - Unified and simplified the customer authentication error handling
|
|
8
|
+
|
|
9
|
+
## 4.5.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#1492](https://github.com/graphcommerce-org/graphcommerce/pull/1492) [`bed806ddd`](https://github.com/graphcommerce-org/graphcommerce/commit/bed806dddd7e025806a69798ef9587aa165d392f) Thanks [@mikekeehnen](https://github.com/mikekeehnen)! - Removed useExtractCustomerErrors hook and implemented error handling via HttpLink Error
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [[`ffec8800a`](https://github.com/graphcommerce-org/graphcommerce/commit/ffec8800a50ff2fe9b9fc5feeb5a0a878b573f0e), [`bed806ddd`](https://github.com/graphcommerce-org/graphcommerce/commit/bed806dddd7e025806a69798ef9587aa165d392f)]:
|
|
18
|
+
- @graphcommerce/react-hook-form@3.2.1
|
|
19
|
+
- @graphcommerce/graphql@3.2.0
|
|
20
|
+
- @graphcommerce/ecommerce-ui@1.0.17
|
|
21
|
+
- @graphcommerce/magento-graphql@3.0.13
|
|
22
|
+
- @graphcommerce/magento-store@4.2.8
|
|
23
|
+
|
|
3
24
|
## 4.4.2
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -2,20 +2,31 @@ import { ApolloErrorAlert, ApolloErrorAlertProps } from '@graphcommerce/ecommerc
|
|
|
2
2
|
import { Trans } from '@lingui/react'
|
|
3
3
|
import { Link } from '@mui/material'
|
|
4
4
|
import NextLink from 'next/link'
|
|
5
|
-
import {
|
|
5
|
+
import { useCustomerSession } from '../../hooks/useCustomerSession'
|
|
6
|
+
import { useAuthorizationErrorMasked } from './useAuthorizationErrorMasked'
|
|
6
7
|
|
|
7
|
-
type
|
|
8
|
+
export type ApolloCustomerErrorAlertProps = ApolloErrorAlertProps
|
|
8
9
|
|
|
9
|
-
export function ApolloCustomerErrorAlert(props:
|
|
10
|
-
const { error,
|
|
10
|
+
export function ApolloCustomerErrorAlert(props: ApolloCustomerErrorAlertProps) {
|
|
11
|
+
const { error, graphqlErrorAlertProps } = props
|
|
12
|
+
const [newError, unauthorized] = useAuthorizationErrorMasked(error)
|
|
13
|
+
const { token } = useCustomerSession()
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
return (
|
|
16
|
+
<ApolloErrorAlert
|
|
17
|
+
{...props}
|
|
18
|
+
error={newError}
|
|
19
|
+
graphqlErrorAlertProps={{
|
|
20
|
+
action: unauthorized ? (
|
|
21
|
+
<NextLink href='/account/signin' passHref>
|
|
22
|
+
<Link underline='hover'>
|
|
23
|
+
{token ? <Trans id='Sign in' /> : <Trans id='Create Account' />}
|
|
24
|
+
</Link>
|
|
25
|
+
</NextLink>
|
|
26
|
+
) : (
|
|
27
|
+
graphqlErrorAlertProps?.action
|
|
28
|
+
),
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
18
31
|
)
|
|
19
|
-
|
|
20
|
-
return <ApolloErrorAlert error={error} graphqlErrorAlertProps={{ action }} />
|
|
21
32
|
}
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import { ApolloErrorFullPage,
|
|
1
|
+
import { ApolloErrorFullPage, ApolloErrorFullPageProps } from '@graphcommerce/ecommerce-ui'
|
|
2
2
|
import { iconPerson, IconSvg } from '@graphcommerce/next-ui'
|
|
3
3
|
import { Trans } from '@lingui/react'
|
|
4
4
|
import { Button } from '@mui/material'
|
|
5
5
|
import PageLink from 'next/link'
|
|
6
|
-
import {
|
|
6
|
+
import type { SetOptional } from 'type-fest'
|
|
7
|
+
import { useCustomerSession } from '../../hooks/useCustomerSession'
|
|
8
|
+
import { useAuthorizationErrorMasked } from './useAuthorizationErrorMasked'
|
|
7
9
|
|
|
8
|
-
type ApolloCustomerErrorFullPageProps = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
export type ApolloCustomerErrorFullPageProps = {
|
|
11
|
+
/** @deprecated Not used */
|
|
12
|
+
signInHref?: string
|
|
13
|
+
/** @deprecated Not used */
|
|
14
|
+
signUpHref?: string
|
|
15
|
+
} & SetOptional<ApolloErrorFullPageProps, 'icon'>
|
|
12
16
|
|
|
13
17
|
export function ApolloCustomerErrorFullPage(props: ApolloCustomerErrorFullPageProps) {
|
|
14
|
-
const {
|
|
15
|
-
const
|
|
18
|
+
const { error, icon, altButton, button, ...alertProps } = props
|
|
19
|
+
const [, unauthorized] = useAuthorizationErrorMasked()
|
|
20
|
+
const { token } = useCustomerSession()
|
|
16
21
|
|
|
17
22
|
return (
|
|
18
23
|
<ApolloErrorFullPage
|
|
19
|
-
error={error}
|
|
20
24
|
icon={<IconSvg src={iconPerson} size='xxl' />}
|
|
25
|
+
{...props}
|
|
26
|
+
error={error}
|
|
21
27
|
button={
|
|
22
28
|
unauthorized ? (
|
|
23
|
-
<PageLink href=
|
|
29
|
+
<PageLink href='/account/signin' passHref>
|
|
24
30
|
<Button variant='contained' color='primary' size='large'>
|
|
25
|
-
<Trans id='
|
|
26
|
-
</Button>
|
|
27
|
-
</PageLink>
|
|
28
|
-
) : undefined
|
|
29
|
-
}
|
|
30
|
-
altButton={
|
|
31
|
-
unauthorized ? (
|
|
32
|
-
<PageLink href={signUpHref} passHref>
|
|
33
|
-
<Button variant='text' color='primary'>
|
|
34
|
-
<Trans id='Or create an account' />
|
|
31
|
+
{token ? <Trans id='Sign in' /> : <Trans id='Create Account' />}
|
|
35
32
|
</Button>
|
|
36
33
|
</PageLink>
|
|
37
|
-
) :
|
|
34
|
+
) : (
|
|
35
|
+
button
|
|
36
|
+
)
|
|
38
37
|
}
|
|
38
|
+
{...alertProps}
|
|
39
39
|
/>
|
|
40
40
|
)
|
|
41
41
|
}
|
|
@@ -1,7 +1,31 @@
|
|
|
1
1
|
import { ApolloErrorSnackbar, ApolloErrorSnackbarProps } from '@graphcommerce/ecommerce-ui'
|
|
2
|
+
import { Trans } from '@lingui/react'
|
|
3
|
+
import { Button, Link } from '@mui/material'
|
|
4
|
+
import NextLink from 'next/link'
|
|
5
|
+
import { useCustomerSession } from '../../hooks/useCustomerSession'
|
|
6
|
+
import { useAuthorizationErrorMasked } from './useAuthorizationErrorMasked'
|
|
2
7
|
|
|
3
|
-
type ApolloCustomerErrorSnackbarProps = ApolloErrorSnackbarProps
|
|
8
|
+
export type ApolloCustomerErrorSnackbarProps = ApolloErrorSnackbarProps
|
|
4
9
|
|
|
5
10
|
export function ApolloCustomerErrorSnackbar(props: ApolloCustomerErrorSnackbarProps) {
|
|
6
|
-
|
|
11
|
+
const { error, action } = props
|
|
12
|
+
const [newError, unauthorized] = useAuthorizationErrorMasked(error)
|
|
13
|
+
const { token } = useCustomerSession()
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<ApolloErrorSnackbar
|
|
17
|
+
{...props}
|
|
18
|
+
action={
|
|
19
|
+
unauthorized ? (
|
|
20
|
+
<NextLink href='/account/signin' passHref>
|
|
21
|
+
<Button variant='pill' color='secondary'>
|
|
22
|
+
{token ? <Trans id='Sign in' /> : <Trans id='Create Account' />}
|
|
23
|
+
</Button>
|
|
24
|
+
</NextLink>
|
|
25
|
+
) : (
|
|
26
|
+
action
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
/>
|
|
30
|
+
)
|
|
7
31
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ApolloError } from '@graphcommerce/graphql'
|
|
2
|
+
import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
|
|
3
|
+
import { i18n } from '@lingui/core'
|
|
4
|
+
import { useCustomerSession } from '../../hooks/useCustomerSession'
|
|
5
|
+
|
|
6
|
+
export function useAuthorizationErrorMasked(error?: ApolloError) {
|
|
7
|
+
const { token } = useCustomerSession()
|
|
8
|
+
|
|
9
|
+
return graphqlErrorByCategory({
|
|
10
|
+
category: 'graphql-authorization',
|
|
11
|
+
error,
|
|
12
|
+
mask: token
|
|
13
|
+
? i18n._(/* i18n */ `Please reauthenticate and try again`)
|
|
14
|
+
: i18n._(/* i18n */ `You must sign in to continue`),
|
|
15
|
+
})
|
|
16
|
+
}
|
package/components/index.ts
CHANGED
|
@@ -4,9 +4,7 @@ export * from './AccountAddresses/AccountAddresses'
|
|
|
4
4
|
export * from './AddressFields/AddressFields'
|
|
5
5
|
export * from './AddressMultiLine/AddressMultiLine'
|
|
6
6
|
export * from './AddressSingleLine/AddressSingleLine'
|
|
7
|
-
export * from './ApolloCustomerError
|
|
8
|
-
export * from './ApolloCustomerError/ApolloCustomerErrorFullPage'
|
|
9
|
-
export * from './ApolloCustomerError/ApolloCustomerErrorSnackbar'
|
|
7
|
+
export * from './ApolloCustomerError'
|
|
10
8
|
export * from './ChangeNameForm/ChangeNameForm'
|
|
11
9
|
export * from './ChangePasswordForm/ChangePassword.gql'
|
|
12
10
|
export * from './ChangePasswordForm/ChangePasswordForm'
|
package/hooks/index.ts
CHANGED
|
@@ -4,6 +4,5 @@ export * from './CustomerToken.gql'
|
|
|
4
4
|
export * from './IsEmailAvailable.gql'
|
|
5
5
|
export * from './useCustomerQuery'
|
|
6
6
|
export * from './useCustomerSession'
|
|
7
|
-
export * from './useExtractCustomerErrors'
|
|
8
7
|
export * from './useFormIsEmailAvailable'
|
|
9
8
|
export * from './useGuestQuery'
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
ApolloCache,
|
|
3
|
+
ApolloLink,
|
|
4
|
+
ClientContext,
|
|
5
|
+
NormalizedCacheObject,
|
|
6
|
+
setContext,
|
|
7
|
+
} from '@graphcommerce/graphql'
|
|
8
|
+
import { CustomerTokenDocument } from '../hooks'
|
|
9
|
+
import { onAuthenticationError } from './onAuthenticationError'
|
|
3
10
|
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
context.headers.authorization = `Bearer ${query?.customerToken?.token}`
|
|
11
|
-
return context
|
|
12
|
-
}
|
|
13
|
-
return context
|
|
14
|
-
} catch (error) {
|
|
11
|
+
export const addTokenHeader = setContext((_, context: ClientContext) => {
|
|
12
|
+
if (!context.headers) context.headers = {}
|
|
13
|
+
try {
|
|
14
|
+
const query = context.cache.readQuery({ query: CustomerTokenDocument })
|
|
15
|
+
if (query?.customerToken?.token) {
|
|
16
|
+
context.headers.authorization = `Bearer ${query?.customerToken?.token}`
|
|
15
17
|
return context
|
|
16
18
|
}
|
|
17
|
-
|
|
19
|
+
return context
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return context
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const customerTokenLink = ApolloLink.from([addTokenHeader, onAuthenticationError])
|
|
26
|
+
|
|
27
|
+
/** Not really required anymore, you can use customerTokenLink directly */
|
|
28
|
+
export const createCustomerTokenLink = (_: ApolloCache<NormalizedCacheObject>) => customerTokenLink
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { InMemoryCache, onError } from '@graphcommerce/graphql'
|
|
2
|
+
import { CustomerTokenDocument } from '../hooks/CustomerToken.gql'
|
|
3
|
+
|
|
4
|
+
function invalidateToken(cache: InMemoryCache) {
|
|
5
|
+
const res = cache.readQuery({
|
|
6
|
+
query: CustomerTokenDocument,
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
if (res?.customerToken?.valid) {
|
|
10
|
+
// Write arbitrary old token to document
|
|
11
|
+
cache.writeQuery({
|
|
12
|
+
query: CustomerTokenDocument,
|
|
13
|
+
data: {
|
|
14
|
+
customerToken: {
|
|
15
|
+
...res.customerToken,
|
|
16
|
+
createdAt: new Date('2000').toUTCString(),
|
|
17
|
+
valid: false,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
broadcast: true,
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const onAuthenticationError = onError(({ graphQLErrors, operation }) => {
|
|
26
|
+
const { cache } = operation.getContext()
|
|
27
|
+
if (graphQLErrors) {
|
|
28
|
+
for (const err of graphQLErrors) {
|
|
29
|
+
if (err.extensions.category === 'graphql-authorization') {
|
|
30
|
+
// Modify the operation context with a new token
|
|
31
|
+
invalidateToken(cache as InMemoryCache)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|
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": "4.
|
|
5
|
+
"version": "4.5.1",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -15,17 +15,18 @@
|
|
|
15
15
|
"@graphcommerce/eslint-config-pwa": "^4.1.7",
|
|
16
16
|
"@graphcommerce/prettier-config-pwa": "^4.0.6",
|
|
17
17
|
"@graphcommerce/typescript-config-pwa": "^4.0.3",
|
|
18
|
-
"@playwright/test": "^1.21.1"
|
|
18
|
+
"@playwright/test": "^1.21.1",
|
|
19
|
+
"type-fest": "^2.12.2"
|
|
19
20
|
},
|
|
20
21
|
"dependencies": {
|
|
21
|
-
"@graphcommerce/ecommerce-ui": "1.0.
|
|
22
|
-
"@graphcommerce/graphql": "3.
|
|
22
|
+
"@graphcommerce/ecommerce-ui": "1.0.17",
|
|
23
|
+
"@graphcommerce/graphql": "3.2.0",
|
|
23
24
|
"@graphcommerce/graphql-mesh": "4.1.3",
|
|
24
25
|
"@graphcommerce/image": "3.1.6",
|
|
25
|
-
"@graphcommerce/magento-graphql": "3.0.
|
|
26
|
-
"@graphcommerce/magento-store": "4.2.
|
|
26
|
+
"@graphcommerce/magento-graphql": "3.0.13",
|
|
27
|
+
"@graphcommerce/magento-store": "4.2.8",
|
|
27
28
|
"@graphcommerce/next-ui": "4.8.3",
|
|
28
|
-
"@graphcommerce/react-hook-form": "3.2.
|
|
29
|
+
"@graphcommerce/react-hook-form": "3.2.1"
|
|
29
30
|
},
|
|
30
31
|
"peerDependencies": {
|
|
31
32
|
"@lingui/react": "^3.13.2",
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { ApolloError, useApolloClient } from '@graphcommerce/graphql'
|
|
2
|
-
import { graphqlErrorByCategory } from '@graphcommerce/magento-graphql'
|
|
3
|
-
import { i18n } from '@lingui/core'
|
|
4
|
-
import { useEffect } from 'react'
|
|
5
|
-
import { CustomerTokenDocument } from './CustomerToken.gql'
|
|
6
|
-
|
|
7
|
-
export type UseExtractErrors = { error?: ApolloError }
|
|
8
|
-
export function useExtractCustomerErrors({ error }: UseExtractErrors) {
|
|
9
|
-
const client = useApolloClient()
|
|
10
|
-
|
|
11
|
-
const [newError, unauthorized] = graphqlErrorByCategory({
|
|
12
|
-
category: 'graphql-authorization',
|
|
13
|
-
error,
|
|
14
|
-
extract: false,
|
|
15
|
-
mask: i18n._(/* i18n */ `You must sign in to continue`),
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
if (!unauthorized) return
|
|
20
|
-
|
|
21
|
-
const { customerToken } =
|
|
22
|
-
client.cache.readQuery({
|
|
23
|
-
query: CustomerTokenDocument,
|
|
24
|
-
}) ?? {}
|
|
25
|
-
|
|
26
|
-
if (customerToken) {
|
|
27
|
-
// Write arbitrary old token to document
|
|
28
|
-
client.cache.writeQuery({
|
|
29
|
-
query: CustomerTokenDocument,
|
|
30
|
-
data: {
|
|
31
|
-
customerToken: {
|
|
32
|
-
...customerToken,
|
|
33
|
-
createdAt: new Date('2000').toUTCString(),
|
|
34
|
-
valid: false,
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
broadcast: true,
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
}, [client.cache, unauthorized])
|
|
41
|
-
|
|
42
|
-
return { error: newError, unauthorized }
|
|
43
|
-
}
|