@graphcommerce/magento-customer 9.0.0-canary.81 → 9.0.0-canary.82

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,11 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.82
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2366](https://github.com/graphcommerce-org/graphcommerce/pull/2366) [`3612c99`](https://github.com/graphcommerce-org/graphcommerce/commit/3612c994b80bb3b1bc02de10668f69a332402dc4) - Add `permissions` config so the website or store can be configurated to run in different modes. ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
8
+
3
9
  ## 9.0.0-canary.81
4
10
 
5
11
  ## 9.0.0-canary.80
@@ -10,22 +10,25 @@ import {
10
10
  extendableComponent,
11
11
  } from '@graphcommerce/next-ui'
12
12
  import { Trans } from '@lingui/react'
13
- import { Box, CircularProgress, Link, SxProps, Theme, Typography } from '@mui/material'
13
+ import { Alert, Box, CircularProgress, Link, SxProps, Theme, Typography } from '@mui/material'
14
14
  import { useRouter } from 'next/router'
15
- import { CustomerDocument, useAccountSignInUpForm } from '../../hooks'
15
+ import { CustomerDocument, useAccountSignInUpForm, useCustomerAccountCanSignUp } from '../../hooks'
16
16
  import { useCustomerQuery } from '../../hooks/useCustomerQuery'
17
17
  import { ApolloCustomerErrorAlert } from '../ApolloCustomerError'
18
18
  import { SignInForm } from '../SignInForm/SignInForm'
19
19
  import { signOut } from '../SignOutForm/signOut'
20
20
  import { SignUpForm } from '../SignUpForm/SignUpForm'
21
21
 
22
- export type AccountSignInUpFormProps = { sx?: SxProps<Theme> }
22
+ export type AccountSignInUpFormProps = {
23
+ sx?: SxProps<Theme>
24
+ signUpDisabled?: React.ReactNode
25
+ }
23
26
 
24
27
  const parts = ['root', 'titleContainer'] as const
25
28
  const { classes } = extendableComponent('AccountSignInUpForm', parts)
26
29
 
27
30
  export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
28
- const { sx = [] } = props
31
+ const { sx = [], signUpDisabled } = props
29
32
  const customerQuery = useCustomerQuery(CustomerDocument)
30
33
 
31
34
  const { email, firstname = '' } = customerQuery.data?.customer ?? {}
@@ -36,6 +39,15 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
36
39
 
37
40
  const client = useApolloClient()
38
41
 
42
+ const canSignUp = useCustomerAccountCanSignUp()
43
+ const isToggleMethod = !import.meta.graphCommerce.enableGuestCheckoutLogin || !canSignUp
44
+
45
+ const showEmail =
46
+ mode === 'email' ||
47
+ mode === 'session-expired' ||
48
+ mode === 'signin' ||
49
+ (mode === 'signup' && canSignUp)
50
+
39
51
  return (
40
52
  <FormDiv sx={sx} className={classes.root}>
41
53
  <Box
@@ -53,7 +65,7 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
53
65
  </>
54
66
  )}
55
67
 
56
- {mode === 'signin' && (
68
+ {(mode === 'signin' || (mode === 'signup' && !canSignUp)) && (
57
69
  <>
58
70
  <LayoutTitle variant='h2' gutterBottom={false}>
59
71
  <Trans id='Sign in' />
@@ -64,7 +76,7 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
64
76
  </>
65
77
  )}
66
78
 
67
- {mode === 'signup' && (
79
+ {mode === 'signup' && canSignUp && (
68
80
  <>
69
81
  <LayoutTitle variant='h2' gutterBottom={false}>
70
82
  <Trans id='Create account!' />
@@ -106,33 +118,32 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
106
118
  )}
107
119
  </Box>
108
120
 
109
- {!import.meta.graphCommerce.enableGuestCheckoutLogin &&
110
- (mode === 'signin' || mode === 'signup' || mode === 'email') && (
111
- <FormRow>
112
- <ActionCardListForm
113
- control={form.control}
114
- name='requestedMode'
115
- layout='grid'
116
- size='large'
117
- render={ActionCard}
118
- sx={(theme) => ({
119
- '&.layoutGrid': {
120
- gridTemplateColumns: 'auto auto',
121
- justifyContent: 'center',
122
- },
123
- '& .ActionCard-root.sizeLarge': {
124
- px: theme.spacings.md,
125
- },
126
- })}
127
- items={[
128
- { value: 'signin', title: <Trans id='Sign in' /> },
129
- { value: 'signup', title: <Trans id='Create Account' /> },
130
- ]}
131
- />
132
- </FormRow>
133
- )}
121
+ {isToggleMethod && (mode === 'signin' || mode === 'signup' || mode === 'email') && (
122
+ <FormRow>
123
+ <ActionCardListForm
124
+ control={form.control}
125
+ name='requestedMode'
126
+ layout='grid'
127
+ size='large'
128
+ render={ActionCard}
129
+ sx={(theme) => ({
130
+ '&.layoutGrid': {
131
+ gridTemplateColumns: 'auto auto',
132
+ justifyContent: 'center',
133
+ },
134
+ '& .ActionCard-root.sizeLarge': {
135
+ px: theme.spacings.md,
136
+ },
137
+ })}
138
+ items={[
139
+ { value: 'signin', title: <Trans id='Sign in' /> },
140
+ { value: 'signup', title: <Trans id='Create Account' /> },
141
+ ]}
142
+ />
143
+ </FormRow>
144
+ )}
134
145
 
135
- {mode !== 'signedin' && (
146
+ {showEmail && (
136
147
  <form onSubmit={submit}>
137
148
  <FormAutoSubmit {...form} submit={submit} />
138
149
  <Box>
@@ -193,11 +204,20 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
193
204
  </Box>
194
205
  )}
195
206
 
196
- {mode === 'signup' && (
207
+ {mode === 'signup' && canSignUp && (
197
208
  <Box>
198
209
  <SignUpForm email={watch('email')} />
199
210
  </Box>
200
211
  )}
212
+ {mode === 'signup' && !canSignUp && (
213
+ <Box>
214
+ {signUpDisabled || (
215
+ <Alert severity='success'>
216
+ <Trans id='Sign up is disabled, please contact us for more information.' />
217
+ </Alert>
218
+ )}
219
+ </Box>
220
+ )}
201
221
  </FormDiv>
202
222
  )
203
223
  }
@@ -1,7 +1,6 @@
1
1
  import { ApolloErrorAlert, ApolloErrorAlertProps } from '@graphcommerce/ecommerce-ui'
2
2
  import { Button } from '@graphcommerce/next-ui'
3
3
  import { Trans } from '@lingui/react'
4
- import { useCustomerSession } from '../../hooks/useCustomerSession'
5
4
  import { useAuthorizationErrorMasked } from './useAuthorizationErrorMasked'
6
5
 
7
6
  export type ApolloCustomerErrorAlertProps = ApolloErrorAlertProps
@@ -9,7 +8,6 @@ export type ApolloCustomerErrorAlertProps = ApolloErrorAlertProps
9
8
  export function ApolloCustomerErrorAlert(props: ApolloCustomerErrorAlertProps) {
10
9
  const { error, graphqlErrorAlertProps } = props
11
10
  const [newError, unauthorized] = useAuthorizationErrorMasked(error)
12
- const { query } = useCustomerSession()
13
11
 
14
12
  return (
15
13
  <ApolloErrorAlert
@@ -20,7 +18,7 @@ export function ApolloCustomerErrorAlert(props: ApolloCustomerErrorAlertProps) {
20
18
  <>
21
19
  {graphqlErrorAlertProps?.action}
22
20
  <Button href='/account/signin' color='error' size='small'>
23
- {query.data?.customerToken ? <Trans id='Sign in' /> : <Trans id='Create Account' />}
21
+ <Trans id='Sign in' />
24
22
  </Button>
25
23
  </>
26
24
  ) : (
@@ -3,7 +3,7 @@ import { iconPerson, IconSvg } from '@graphcommerce/next-ui'
3
3
  import { Trans } from '@lingui/react'
4
4
  import { Button } from '@mui/material'
5
5
  import type { SetOptional } from 'type-fest'
6
- import { useCustomerSession } from '../../hooks/useCustomerSession'
6
+ import { useCustomerAccountCanSignUp } from '../../hooks'
7
7
  import { useAuthorizationErrorMasked } from './useAuthorizationErrorMasked'
8
8
 
9
9
  export type ApolloCustomerErrorFullPageProps = {
@@ -16,7 +16,7 @@ export type ApolloCustomerErrorFullPageProps = {
16
16
  export function ApolloCustomerErrorFullPage(props: ApolloCustomerErrorFullPageProps) {
17
17
  const { error, icon, altButton, button, ...alertProps } = props
18
18
  const [newError, unauthorized] = useAuthorizationErrorMasked(error)
19
- const { token } = useCustomerSession()
19
+ const canSignUp = useCustomerAccountCanSignUp()
20
20
 
21
21
  return (
22
22
  <ApolloErrorFullPage
@@ -26,7 +26,7 @@ export function ApolloCustomerErrorFullPage(props: ApolloCustomerErrorFullPagePr
26
26
  button={
27
27
  unauthorized ? (
28
28
  <Button href='/account/signin' variant='pill' color='primary' size='large'>
29
- {token ? <Trans id='Sign in' /> : <Trans id='Sign in or create an account!' />}
29
+ {canSignUp ? <Trans id='Sign in or create an account!' /> : <Trans id='Sign in' />}
30
30
  </Button>
31
31
  ) : (
32
32
  button
@@ -11,7 +11,7 @@ export function useAuthorizationErrorMasked(error?: ApolloError) {
11
11
  error,
12
12
  mask: token
13
13
  ? i18n._(/* i18n */ 'Please reauthenticate and try again')
14
- : i18n._(/* i18n */ 'You must sign in to continue'),
14
+ : i18n._(/* i18n */ 'You must be signed in to continue'),
15
15
  extract: false,
16
16
  })
17
17
  }
@@ -7,7 +7,11 @@ import {
7
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
- import { useCustomerSession, UseCustomerSessionReturn } from '../../hooks'
10
+ import {
11
+ useCustomerAccountCanSignIn,
12
+ useCustomerSession,
13
+ UseCustomerSessionReturn,
14
+ } from '../../hooks'
11
15
 
12
16
  type CustomerFabContentProps = {
13
17
  icon?: React.ReactNode
@@ -52,6 +56,9 @@ export type CustomerFabProps = Omit<CustomerFabContentProps, 'session'>
52
56
 
53
57
  export function CustomerFab(props: CustomerFabProps) {
54
58
  const session = useCustomerSession()
59
+ const canSignIn = useCustomerAccountCanSignIn()
60
+
61
+ if (!canSignIn) return null
55
62
 
56
63
  return (
57
64
  <NoSsr fallback={<CustomerFabContent {...props} />}>
@@ -1,6 +1,7 @@
1
1
  import { MenuFabSecondaryItem, iconPerson, IconSvg } from '@graphcommerce/next-ui'
2
2
  import { Badge, NoSsr, SxProps, Theme } from '@mui/material'
3
3
  import React, { MouseEventHandler } from 'react'
4
+ import { useCustomerAccountCanSignIn } from '../../hooks'
4
5
  import { useCustomerSession, UseCustomerSessionReturn } from '../../hooks/useCustomerSession'
5
6
 
6
7
  type CustomerMenuFabItemProps = {
@@ -40,6 +41,9 @@ function CustomerMenuFabItemContent(props: CustomerMenuFabItemProps) {
40
41
  export function CustomerMenuFabItem(props: CustomerMenuFabItemProps) {
41
42
  const session = useCustomerSession()
42
43
 
44
+ const canSignIn = useCustomerAccountCanSignIn()
45
+ if (!canSignIn) return null
46
+
43
47
  return (
44
48
  <NoSsr fallback={<CustomerMenuFabItemContent {...props} />}>
45
49
  <CustomerMenuFabItemContent session={session} {...props} />
@@ -1,5 +1,5 @@
1
1
  import { mergeErrors, WaitForQueries, WaitForQueriesProps } from '@graphcommerce/ecommerce-ui'
2
- import { FullPageMessage, FullPageMessageProps, IconSvg, iconPerson } from '@graphcommerce/next-ui'
2
+ import { FullPageMessage, FullPageMessageProps, iconPerson, IconSvg } from '@graphcommerce/next-ui'
3
3
  import { Trans } from '@lingui/react'
4
4
  import { Button, CircularProgress } from '@mui/material'
5
5
  import React from 'react'
@@ -0,0 +1,12 @@
1
+ enum CustomerAccountPermissions {
2
+ ENABLED
3
+ DISABLE_REGISTRATION
4
+ DISABLED
5
+ }
6
+
7
+ extend input GraphCommercePermissions {
8
+ """
9
+ Enables / disabled the account section of the website. DISABLE_REGISTRATION will only disable the registration page.
10
+ """
11
+ customerAccount: CustomerAccountPermissions
12
+ }
package/hooks/index.ts CHANGED
@@ -6,6 +6,7 @@ export * from './OrderCardItemImage.gql'
6
6
  export * from './OrderCardItemImages.gql'
7
7
  export * from './UseOrderCardItemImages.gql'
8
8
  export * from './useAccountSignInUpForm'
9
+ export * from './useCustomerPermissions'
9
10
  export * from './useCustomerQuery'
10
11
  export * from './useCustomerSession'
11
12
  export * from './useGuestQuery'
@@ -9,6 +9,7 @@ import {
9
9
  IsEmailAvailableQuery,
10
10
  IsEmailAvailableQueryVariables,
11
11
  } from './IsEmailAvailable.gql'
12
+ import { useCustomerAccountCanSignUp } from './useCustomerPermissions'
12
13
  import { useCustomerSession } from './useCustomerSession'
13
14
 
14
15
  export type UseFormIsEmailAvailableProps = {
@@ -17,11 +18,13 @@ export type UseFormIsEmailAvailableProps = {
17
18
 
18
19
  export type AccountSignInUpState = 'email' | 'signin' | 'signup' | 'signedin' | 'session-expired'
19
20
 
20
- export const isToggleMethod = !import.meta.graphCommerce.enableGuestCheckoutLogin
21
-
22
21
  export function useAccountSignInUpForm(props: UseFormIsEmailAvailableProps = {}) {
23
22
  const { onSubmitted } = props
24
23
  const { token, valid } = useCustomerSession()
24
+
25
+ const canSignUp = useCustomerAccountCanSignUp()
26
+ const isToggleMethod = !import.meta.graphCommerce.enableGuestCheckoutLogin || !canSignUp
27
+
25
28
  const [queryState, setRouterQuery] = useUrlQuery<{ email?: string | null }>()
26
29
 
27
30
  const customerQuery = useQuery(CustomerDocument, { fetchPolicy: 'cache-only' })
@@ -0,0 +1,17 @@
1
+ import { useStorefrontConfig } from '@graphcommerce/next-ui'
2
+
3
+ function useCustomerAccountPermission() {
4
+ return (
5
+ useStorefrontConfig().permissions?.customerAccount ??
6
+ import.meta.graphCommerce.permissions?.customerAccount ??
7
+ 'ENABLED'
8
+ )
9
+ }
10
+
11
+ export function useCustomerAccountCanSignIn() {
12
+ return useCustomerAccountPermission() !== 'DISABLED'
13
+ }
14
+
15
+ export function useCustomerAccountCanSignUp() {
16
+ return useCustomerAccountPermission() === 'ENABLED'
17
+ }
@@ -7,12 +7,12 @@ import {
7
7
  setContext,
8
8
  } from '@graphcommerce/graphql/apollo'
9
9
  import { ErrorCategory } from '@graphcommerce/magento-graphql'
10
- import type { GraphQLError } from 'graphql'
10
+ import { GraphQLError } from 'graphql'
11
11
  import { NextRouter } from 'next/router'
12
12
  import { signOut } from '../components/SignOutForm/signOut'
13
13
  import { CustomerTokenDocument } from '../hooks'
14
14
 
15
- export type PushRouter = Pick<NextRouter, 'push' | 'events'>
15
+ export type PushRouter = Pick<NextRouter, 'push' | 'events' | 'locale'>
16
16
 
17
17
  declare module '@apollo/client' {
18
18
  interface DefaultContext {
@@ -21,7 +21,7 @@ declare module '@apollo/client' {
21
21
  }
22
22
  }
23
23
 
24
- async function pushWithPromise(router: Pick<NextRouter, 'push' | 'events'>, url: string) {
24
+ export async function pushWithPromise(router: Pick<NextRouter, 'push' | 'events'>, url: string) {
25
25
  try {
26
26
  await router.push(url)
27
27
  } catch {
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": "9.0.0-canary.81",
5
+ "version": "9.0.0-canary.82",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,19 +12,19 @@
12
12
  }
13
13
  },
14
14
  "peerDependencies": {
15
- "@graphcommerce/ecommerce-ui": "^9.0.0-canary.81",
16
- "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.81",
17
- "@graphcommerce/framer-next-pages": "^9.0.0-canary.81",
18
- "@graphcommerce/framer-utils": "^9.0.0-canary.81",
19
- "@graphcommerce/graphql": "^9.0.0-canary.81",
20
- "@graphcommerce/graphql-mesh": "^9.0.0-canary.81",
21
- "@graphcommerce/image": "^9.0.0-canary.81",
22
- "@graphcommerce/magento-graphql": "^9.0.0-canary.81",
23
- "@graphcommerce/magento-store": "^9.0.0-canary.81",
24
- "@graphcommerce/next-ui": "^9.0.0-canary.81",
25
- "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.81",
26
- "@graphcommerce/react-hook-form": "^9.0.0-canary.81",
27
- "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.81",
15
+ "@graphcommerce/ecommerce-ui": "^9.0.0-canary.82",
16
+ "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.82",
17
+ "@graphcommerce/framer-next-pages": "^9.0.0-canary.82",
18
+ "@graphcommerce/framer-utils": "^9.0.0-canary.82",
19
+ "@graphcommerce/graphql": "^9.0.0-canary.82",
20
+ "@graphcommerce/graphql-mesh": "^9.0.0-canary.82",
21
+ "@graphcommerce/image": "^9.0.0-canary.82",
22
+ "@graphcommerce/magento-graphql": "^9.0.0-canary.82",
23
+ "@graphcommerce/magento-store": "^9.0.0-canary.82",
24
+ "@graphcommerce/next-ui": "^9.0.0-canary.82",
25
+ "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.82",
26
+ "@graphcommerce/react-hook-form": "^9.0.0-canary.82",
27
+ "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.82",
28
28
  "@lingui/core": "^4.2.1",
29
29
  "@lingui/macro": "^4.2.1",
30
30
  "@lingui/react": "^4.2.1",
@@ -15,6 +15,7 @@ export function GraphQLProvider(props: PluginProps<GraphQLProviderProps>) {
15
15
  const { Prev, links = [], policies = [], migrations = [], router, ...rest } = props
16
16
 
17
17
  const push = useEventCallback<NextRouter['push']>((...args) => router.push(...args))
18
+
18
19
  const customerLinkMemo = useMemo(
19
20
  () => customerLink({ push, events: router.events }),
20
21
  [push, router.events],
@@ -0,0 +1,17 @@
1
+ import { storefrontConfig } from '@graphcommerce/next-ui'
2
+
3
+ function getCustomerAccountPermission(locale: string | undefined) {
4
+ return (
5
+ storefrontConfig(locale)?.permissions?.customerAccount ??
6
+ import.meta.graphCommerce.permissions?.customerAccount ??
7
+ 'ENABLED'
8
+ )
9
+ }
10
+
11
+ export function getCustomerAccountIsDisabled(locale: string | undefined) {
12
+ return getCustomerAccountPermission(locale) === 'DISABLED'
13
+ }
14
+
15
+ export function getCustomerAccountCanSignIn(locale: string | undefined) {
16
+ return getCustomerAccountPermission(locale) !== 'DISABLED'
17
+ }
package/utils/index.ts CHANGED
@@ -1 +1,2 @@
1
+ export * from './customerPermissions'
1
2
  export * from './orderState'