Skip to content

Commit

Permalink
Merge branch 'develop' into dpatil/update-docker
Browse files Browse the repository at this point in the history
  • Loading branch information
dpatil-magento committed May 21, 2020
2 parents 80fe547 + 2089baa commit 63285e4
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 38 deletions.
56 changes: 42 additions & 14 deletions packages/peregrine/lib/store/actions/cart/asyncActions.js
@@ -1,4 +1,6 @@
import { clearCartDataFromCache } from '../../../Apollo/clearCartDataFromCache';
import BrowserPersistence from '../../../util/simplePersistence';
import { signOut } from '../user';
import actions from './actions';

const storage = new BrowserPersistence();
Expand Down Expand Up @@ -61,10 +63,11 @@ export const addItemToCart = (payload = {}) => {
await writingImageToCache;
dispatch(actions.addItem.request(payload));

try {
const { cart } = getState();
const { cartId } = cart;
const { cart, user } = getState();
const { cartId } = cart;
const { isSignedIn } = user;

try {
const variables = {
cartId,
parentSku,
Expand Down Expand Up @@ -95,11 +98,18 @@ export const addItemToCart = (payload = {}) => {

// Only retry if the cart is invalid or the cartId is missing.
if (shouldRetry) {
// Delete the cached ID from local storage and Redux.
// In contrast to the save, make sure storage deletion is
// complete before dispatching the error--you don't want an
// upstream action to try and reuse the known-bad ID.
await dispatch(removeCart());
if (isSignedIn) {
// Since simple persistence just deletes auth token without
// informing Redux, we need to perform the sign out action
// to reset the user and cart slices back to initial state.
await dispatch(signOut());
} else {
// Delete the cached ID from local storage and Redux.
// In contrast to the save, make sure storage deletion is
// complete before dispatching the error--you don't want an
// upstream action to try and reuse the known-bad ID.
await dispatch(removeCart());
}

// then create a new one
await dispatch(
Expand Down Expand Up @@ -286,11 +296,12 @@ export const removeItemFromCart = payload => {
};

export const getCartDetails = payload => {
const { fetchCartId, fetchCartDetails } = payload;
const { apolloClient, fetchCartId, fetchCartDetails } = payload;

return async function thunk(dispatch, getState) {
const { cart } = getState();
const { cart, user } = getState();
const { cartId } = cart;
const { isSignedIn } = user;

// if there isn't a cart, create one then retry this operation
if (!cartId) {
Expand Down Expand Up @@ -319,8 +330,21 @@ export const getCartDetails = payload => {

const shouldResetCart = !error.networkError && isInvalidCart(error);
if (shouldResetCart) {
// Delete the cached ID from local storage.
await dispatch(removeCart());
if (isSignedIn) {
// Since simple persistence just deletes auth token without
// informing Redux, we need to perform the sign out action
// to reset the user and cart slices back to initial state.
await dispatch(signOut());
} else {
// Delete the cached ID from local storage.
await dispatch(removeCart());
}

// Clear the cart data from apollo client if we get here and
// have an apolloClient.
if (apolloClient) {
await clearCartDataFromCache(apolloClient);
}

// Create a new one
await dispatch(
Expand Down Expand Up @@ -391,8 +415,12 @@ export async function writeImageToCache(item = {}) {
function isInvalidCart(error) {
return !!(
error.graphQLErrors &&
error.graphQLErrors.find(err =>
err.message.includes('Could not find a cart')
error.graphQLErrors.find(
err =>
err.message.includes('Could not find a cart') ||
err.message.includes(
'The current user cannot perform operations on cart'
)
)
);
}
41 changes: 23 additions & 18 deletions packages/peregrine/lib/store/actions/user/asyncActions.js
Expand Up @@ -6,24 +6,29 @@ import actions from './actions';

const storage = new BrowserPersistence();

export const signOut = ({ revokeToken }) => async dispatch => {
// Send mutation to revoke token.
try {
await revokeToken();
} catch (error) {
console.error('Error Revoking Token', error);
}

// Remove token from local storage and Redux.
await dispatch(clearToken());
await dispatch(actions.reset());
await clearCheckoutDataFromStorage();

// Now that we're signed out, forget the old (customer) cart.
// We don't need to create a new cart here because we're going to refresh
// the page immediately after.
await dispatch(removeCart());
};
export const signOut = (payload = {}) =>
async function thunk(dispatch) {
const { revokeToken } = payload;

if (revokeToken) {
// Send mutation to revoke token.
try {
await revokeToken();
} catch (error) {
console.error('Error Revoking Token', error);
}
}

// Remove token from local storage and Redux.
await dispatch(clearToken());
await dispatch(actions.reset());
await clearCheckoutDataFromStorage();

// Now that we're signed out, forget the old (customer) cart.
// We don't need to create a new cart here because we're going to refresh
// the page immediately after.
await dispatch(removeCart());
};

export const getUserDetails = ({ fetchUserDetails }) =>
async function thunk(...args) {
Expand Down
14 changes: 12 additions & 2 deletions packages/peregrine/lib/talons/AuthModal/useAuthModal.js
Expand Up @@ -39,8 +39,9 @@ export const useAuthModal = props => {
} = props;

const apolloClient = useApolloClient();
const [isSigningOut, setIsSigningOut] = useState(false);
const [username, setUsername] = useState('');
const [{ currentUser }, { signOut }] = useUserContext();
const [{ currentUser, isSignedIn }, { signOut }] = useUserContext();
const [revokeToken] = useMutation(signOutMutation);
const history = useHistory();

Expand All @@ -52,6 +53,14 @@ export const useAuthModal = props => {
}
}, [currentUser, showMyAccount, view]);

// If the user token was invalidated by way of expiration, we need to reset
// the view back to the main menu.
useEffect(() => {
if (!isSignedIn && view === 'MY_ACCOUNT' && !isSigningOut) {
showMainMenu();
}
}, [isSignedIn, isSigningOut, showMainMenu, view]);

const handleClose = useCallback(() => {
showMainMenu();
closeDrawer();
Expand All @@ -62,9 +71,10 @@ export const useAuthModal = props => {
}, [showMyAccount]);

const handleSignOut = useCallback(async () => {
setIsSigningOut(true);

// Delete cart/user data from the redux store.
await signOut({ revokeToken });

await clearCartDataFromCache(apolloClient);

// Refresh the page as a way to say "re-initialize". An alternative
Expand Down
18 changes: 14 additions & 4 deletions packages/peregrine/lib/talons/Header/useCartTrigger.js
@@ -1,5 +1,9 @@
import { useCallback, useEffect } from 'react';
import { useLazyQuery, useMutation } from '@apollo/react-hooks';
import {
useApolloClient,
useLazyQuery,
useMutation
} from '@apollo/react-hooks';
import { useCartContext } from '@magento/peregrine/lib/context/cart';
import { useAppContext } from '@magento/peregrine/lib/context/app';
import { useAwaitQuery } from '@magento/peregrine/lib/hooks/useAwaitQuery';
Expand All @@ -9,18 +13,24 @@ export const useCartTrigger = props => {
mutations: { createCartMutation },
queries: { getCartDetailsQuery, getItemCountQuery }
} = props;

const apolloClient = useApolloClient();
const [, { toggleDrawer }] = useAppContext();
const [{ cartId }, { getCartDetails }] = useCartContext();

const [getItemCount, { data }] = useLazyQuery(getItemCountQuery);
const [getItemCount, { data }] = useLazyQuery(getItemCountQuery, {
fetchPolicy: 'cache-and-network'
});
const [fetchCartId] = useMutation(createCartMutation);
const fetchCartDetails = useAwaitQuery(getCartDetailsQuery);

const itemCount = data ? data.cart.total_quantity : 0;

useEffect(() => {
getCartDetails({ fetchCartId, fetchCartDetails });
}, [fetchCartDetails, fetchCartId, getCartDetails]);
// Passing apolloClient to wipe the store in event of auth token expiry
// This will only happen if the user refreshes.
getCartDetails({ apolloClient, fetchCartId, fetchCartDetails });
}, [apolloClient, fetchCartDetails, fetchCartId, getCartDetails]);

useEffect(() => {
if (cartId) {
Expand Down
Expand Up @@ -5,6 +5,7 @@ import { createTestInstance } from '@magento/peregrine';
import CartTrigger from '../cartTrigger';

jest.mock('@apollo/react-hooks', () => ({
useApolloClient: jest.fn().mockImplementation(() => {}),
useLazyQuery: jest.fn().mockReturnValue([jest.fn(), { data: null }]),
useMutation: jest.fn().mockImplementation(() => [
jest.fn(),
Expand Down
3 changes: 3 additions & 0 deletions pwa-devdocs/src/_data/tutorials.yml
Expand Up @@ -20,6 +20,9 @@ entries:
- label: Create a TagList component
url: /tutorials/create-taglist-component/

- label: Enable SASS or LESS support
url: /tutorials/enable-sass-less-support/

- label: PWA Studio fundamentals
url: /tutorials/pwa-studio-fundamentals/
entries:
Expand Down

0 comments on commit 63285e4

Please sign in to comment.