Skip to content

Commit

Permalink
Merge pull request #1999 from graphcommerce-org/fix/revalidate-token
Browse files Browse the repository at this point in the history
Apollo link signInAgainPromise modal
  • Loading branch information
paales authored Jan 4, 2024
2 parents 0cd1018 + 37e7a36 commit ff0061a
Show file tree
Hide file tree
Showing 28 changed files with 411 additions and 321 deletions.
5 changes: 5 additions & 0 deletions .changeset/four-peaches-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@graphcommerce/magento-cart": patch
---

When signing in the cartFab would not always properly reflect the current items in the cart
6 changes: 6 additions & 0 deletions .changeset/quiet-boats-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@graphcommerce/magento-customer': patch
'@graphcommerce/magento-cart': patch
---

Added user session reevaluation after unathenticated call. Queries will be paused untill user has signed in again
5 changes: 5 additions & 0 deletions .changeset/rude-bags-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@graphcommerce/magento-customer": patch
---

Created a debug.sessions config that allows debugging sessions. Enable with GC_DEBUG_SESSIONS=1 in your env or modify your graphcommerce.config.js
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# dependencies
node_modules
/.pnp
.pnp.js
.swc

# testing
/coverage
Expand Down
4 changes: 4 additions & 0 deletions docs/framework/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,10 @@ Debug configuration for GraphCommerce

Reports which plugins are enabled or disabled.

#### sessions: boolean

Enable debugging interface to debug sessions

#### webpackCircularDependencyPlugin: boolean

Cyclic dependencies can cause memory issues and other strange bugs.
Expand Down
1 change: 1 addition & 0 deletions packages/magento-cart/hooks/UseMergeCustomerCart.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ mutation UseMergeCustomerCart($sourceCartId: String!, $destinationCartId: String
mergeCarts(source_cart_id: $sourceCartId, destination_cart_id: $destinationCartId) {
__typename
id
...CartItemCountChanged
}
}
6 changes: 1 addition & 5 deletions packages/magento-cart/link/createCartErrorLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ export const cartErrorLink = onError(({ graphQLErrors, operation, forward }) =>
const isErrorCategory = (err: GraphQLError, category: ErrorCategory) =>
err.extensions?.category === category

const isAuthorizationError = (err: GraphQLError) =>
isErrorCategory(err, 'graphql-authorization') &&
errorIsIncluded(err.path, ['addProductsToCart'])

const isNoSuchEntityError = (err: GraphQLError) =>
isErrorCategory(err, 'graphql-no-such-entity') &&
errorIsIncluded(err.path, [
Expand All @@ -49,7 +45,7 @@ export const cartErrorLink = onError(({ graphQLErrors, operation, forward }) =>
// 'applyCouponToCart',
// 'removeCouponFromCart'
])
const cartErr = graphQLErrors.find((err) => isNoSuchEntityError(err) || isAuthorizationError(err))
const cartErr = graphQLErrors.find((err) => isNoSuchEntityError(err))

if (!cartErr) return undefined

Expand Down
7 changes: 7 additions & 0 deletions packages/magento-customer/Config.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,10 @@ extend input GraphCommerceConfig {
"""
enableGuestCheckoutLogin: Boolean
}

extend input GraphCommerceDebugConfig {
"""
Enable debugging interface to debug sessions
"""
sessions: Boolean
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TextFieldElement, emailPattern } from '@graphcommerce/ecommerce-ui'
import { FormAutoSubmit, TextFieldElement, emailPattern } from '@graphcommerce/ecommerce-ui'
import { useApolloClient } from '@graphcommerce/graphql'
import {
ActionCard,
ActionCardLayout,
ActionCardListForm,
Button,
FormActions,
Expand All @@ -13,108 +13,99 @@ import {
import { Trans } from '@lingui/react'
import { Box, CircularProgress, Link, SxProps, Theme, Typography } from '@mui/material'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
import { CustomerDocument, useFormIsEmailAvailable } from '../../hooks'
import { CustomerDocument, useAccountSignInUpForm } from '../../hooks'
import { useCustomerQuery } from '../../hooks/useCustomerQuery'
import { ApolloCustomerErrorAlert } from '../ApolloCustomerError'
import { SignInForm } from '../SignInForm/SignInForm'
import { signOut } from '../SignOutForm/signOut'
import { SignUpForm } from '../SignUpForm/SignUpForm'

export type AccountSignInUpFormProps = { sx?: SxProps<Theme> }

const parts = ['root', 'titleContainer'] as const
const { classes } = extendableComponent('AccountSignInUpForm', parts)

const titleContainerSx: SxProps<Theme> = (theme) => ({
typography: 'body1',
marginBottom: theme.spacings.xs,
})

export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
const { sx = [] } = props
const customerQuery = useCustomerQuery(CustomerDocument)

const { email, firstname = '' } = customerQuery.data?.customer ?? {}

const { mode, form, autoSubmitting, submit } = useFormIsEmailAvailable({ email })
const { mode, form, submit } = useAccountSignInUpForm()
const { formState, watch, control, error } = form
const disableFields = formState.isSubmitting && !autoSubmitting

const { setValue, trigger } = form
const router = useRouter()
useEffect(() => {
const emailFromParams = router.query.email as string
if (!email && emailFromParams) {
setValue('email', emailFromParams)
// eslint-disable-next-line @typescript-eslint/no-floating-promises
trigger('email')
}
}, [email, router.query.email, setValue, trigger])

const client = useApolloClient()

return (
<FormDiv sx={sx} className={classes.root}>
{mode === 'email' && (
<Box className={classes.titleContainer} sx={titleContainerSx}>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Sign in or create an account!' />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Trans id='Fill in your e-mail to login or create an account' />
</Typography>
</Box>
)}
<Box
className={classes.titleContainer}
sx={(theme) => ({ typography: 'body1', marginBottom: theme.spacings.xs })}
>
{mode === 'email' && (
<>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Sign in or create an account!' />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Trans id='Fill in your e-mail to login or create an account' />
</Typography>
</>
)}

{mode === 'signin' && (
<Box className={classes.titleContainer} sx={titleContainerSx}>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Welcome back!' />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Trans id='Fill in your password' />
</Typography>
</Box>
)}
{mode === 'signin' && (
<>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Sign in' />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Trans id='Fill in your password' />
</Typography>
</>
)}

{mode === 'signup' && (
<Box className={classes.titleContainer} sx={titleContainerSx}>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Create account!' />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Trans id='Create a password and tell us your name' />
</Typography>
</Box>
)}
{mode === 'signup' && (
<>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Create account!' />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Trans id='Create a password and tell us your name' />
</Typography>
</>
)}

{mode === 'signedin' && (
<Box className={classes.titleContainer} sx={titleContainerSx}>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Hi {firstname}! You’re now logged in!' values={{ firstname }} />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Link href='/account' underline='hover' color='secondary'>
<Trans id='View your account' />
</Link>
</Typography>

<FormActions>
<Button onClick={() => router.back()} variant='pill' color='secondary' size='large'>
<Trans id='Continue shopping' />
</Button>
</FormActions>
</Box>
)}
{mode === 'signedin' && (
<>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Hi {firstname}! You’re now logged in!' values={{ firstname }} />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Link href='/account' underline='hover' color='secondary'>
<Trans id='View your account' />
</Link>
</Typography>

<FormActions>
<Button onClick={() => router.back()} variant='pill' color='secondary' size='large'>
<Trans id='Continue shopping' />
</Button>
</FormActions>
</>
)}

{mode === 'session-expired' && (
<Box className={classes.titleContainer} sx={titleContainerSx}>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Your session is expired' />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Trans id='Log in to continue shopping' />
</Typography>
</Box>
)}
{mode === 'session-expired' && (
<>
<LayoutTitle variant='h2' gutterBottom={false}>
<Trans id='Your session is expired' />
</LayoutTitle>
<Typography variant='h6' align='center'>
<Trans id='Log in to continue shopping' />
</Typography>
</>
)}
</Box>

{!import.meta.graphCommerce.enableGuestCheckoutLogin &&
(mode === 'signin' || mode === 'signup' || mode === 'email') && (
Expand Down Expand Up @@ -144,6 +135,7 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {

{mode !== 'signedin' && (
<form onSubmit={submit}>
<FormAutoSubmit {...form} submit={submit} />
<Box>
<FormRow>
<TextFieldElement
Expand All @@ -158,11 +150,25 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
}}
error={formState.isSubmitted && !!formState.errors.email}
label={<Trans id='Email' />}
disabled={disableFields}
InputProps={{
endAdornment: formState.isSubmitting && (
<CircularProgress sx={{ display: 'inline-flex' }} />
),
endAdornment:
mode === 'session-expired' ? (
<Button
type='submit'
variant='inline'
color='primary'
loading={formState.isSubmitting}
sx={{ whiteSpace: 'nowrap' }}
onClick={() => {
signOut(client)
form.resetField('email')
}}
>
<Trans id='Sign out' />
</Button>
) : (
formState.isSubmitting && <CircularProgress sx={{ display: 'inline-flex' }} />
),
readOnly: !!email,
}}
/>
Expand All @@ -171,7 +177,7 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {

<ApolloCustomerErrorAlert error={error} />

{(mode === 'email' || mode === 'session-expired') && (
{mode === 'email' && (
<Box>
<FormActions>
<Button
Expand All @@ -189,7 +195,7 @@ export function AccountSignInUpForm(props: AccountSignInUpFormProps) {
</form>
)}

{mode === 'signin' && (
{(mode === 'signin' || mode === 'session-expired') && (
<Box>
<SignInForm email={watch('email')} />
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { i18n } from '@lingui/core'
import { Fab, FabProps as FabPropsType, NoSsr, SxProps, Theme } from '@mui/material'
import React from 'react'
import { useCustomerSession, UseCustomerSessionReturn } from '../../hooks'
import { useCustomerValidateToken } from '../../hooks/useCustomerValidateToken'

type CustomerFabContentProps = {
icon?: React.ReactNode
Expand All @@ -28,7 +27,7 @@ function CustomerFabContent(props: CustomerFabContentProps) {

return (
<Fab
href={session?.requireAuth ? guestHref : authHref}
href={session?.loggedIn ? authHref : guestHref}
color='inherit'
id='account'
aria-label={i18n._(/* i18n */ 'Account')}
Expand All @@ -54,8 +53,6 @@ export type CustomerFabProps = Omit<CustomerFabContentProps, 'session'>
export function CustomerFab(props: CustomerFabProps) {
const session = useCustomerSession()

useCustomerValidateToken()

return (
<NoSsr fallback={<CustomerFabContent {...props} />}>
<CustomerFabContent session={session} {...props} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function CustomerMenuFabItemContent(props: CustomerMenuFabItemProps) {
{icon ?? <IconSvg src={iconPerson} size='medium' />}
</Badge>
}
href={session?.requireAuth ? guestHref : authHref}
href={session?.loggedIn ? authHref : guestHref}
>
{children}
</MenuFabSecondaryItem>
Expand Down
Loading

1 comment on commit ff0061a

@vercel
Copy link

@vercel vercel bot commented on ff0061a Jan 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

graphcommerce-hygraph-dynamic-rows-ui – ./packages/hygraph-dynamic-rows-ui

graphcommerce-hygraph-dynamic-rows-ui-git-canary-graphcommerce.vercel.app
graphcommerce-hygraph-dynamic-rows-ui-graphcommerce.vercel.app
graphcommerce-hygraph-dynamic-rows-ui.vercel.app

Please sign in to comment.