Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

6 changes: 1 addition & 5 deletions client-app/pages/cart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
<CartForLater
v-if="savedForLaterList?.items?.length && !shouldHide('cart-for-later')"
:saved-for-later-list="savedForLaterList"
:loading="moveFromSavedForLaterOverflowed"
class="mt-5"
@add-to-cart="(lineItemId) => handleMoveToCart([lineItemId])"
/>
Expand All @@ -84,7 +83,7 @@
:items-grouped-by-vendor="lineItemsGroupedByVendor"
:selected-item-ids="selectedItemIds"
:validation-errors="cart.validationErrors"
:disabled="changeItemQuantityBatchedOverflowed || moveToSavedForLaterOverflowed || selectionOverflowed"
:disabled="changeItemQuantityBatchedOverflowed || selectionOverflowed"
data-test-id="cart.products-section"
:hide-controls="hideControls"
@change:item-quantity="changeItemQuantityBatched($event.itemId, $event.quantity)"
Expand Down Expand Up @@ -114,7 +113,6 @@
<CartForLater
v-if="savedForLaterList?.items?.length && !shouldHide('cart-for-later')"
:saved-for-later-list="savedForLaterList"
:loading="moveFromSavedForLaterOverflowed"
class="mt-5"
@add-to-cart="(lineItemId) => handleMoveToCart([lineItemId])"
/>
Expand Down Expand Up @@ -292,9 +290,7 @@ const { couponCode, couponIsApplied, couponValidationError, applyCoupon, removeC
const {
savedForLaterList,
moveToSavedForLater,
moveToSavedForLaterOverflowed,
moveFromSavedForLater,
moveFromSavedForLaterOverflowed,
getSavedForLater,
loading: saveForLaterLoading,
} = useSavedForLater();
Expand Down
114 changes: 73 additions & 41 deletions client-app/shared/cart/composables/useSaveForLater.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,68 @@
import { ApolloError } from "@apollo/client/core";
import { useMutation } from "@vue/apollo-composable";
import { useMutation, useQuery } from "@vue/apollo-composable";
import { createSharedComposable } from "@vueuse/core";
import { ref, computed } from "vue";
import { computed } from "vue";
import { AbortReason } from "@/core/api/common/enums";
import { getSavedForLater as getSavedForLaterQuery } from "@/core/api/graphql/cart/queries/getSavedForLater";
import { MoveToSavedForLaterDocument, MoveFromSavedForLaterDocument } from "@/core/api/graphql/types";
import { useMutationBatcher } from "@/core/composables/useMutationBatcher";
import {
MoveToSavedForLaterDocument,
MoveFromSavedForLaterDocument,
GetSavedForLaterDocument,
} from "@/core/api/graphql/types";
import { globals } from "@/core/globals";
import { Logger } from "@/core/utilities";
import type { SavedForLaterListFragment } from "@/core/api/graphql/types";
import { useFullCart } from "@/shared/cart";

function _useSavedForLater() {
const { storeId, currencyCode, cultureName, userId } = globals;

const savedForLaterList = ref<SavedForLaterListFragment>();
const { cart } = useFullCart();

const { mutate: _moveToSavedForLater, loading: _moveToSavedForLaterLoading } =
useMutation(MoveToSavedForLaterDocument);
const savedForLaterList = computed(() => _savedForLaterQueryResult.value?.getSavedForLater);

const {
add: _moveToSavedForLaterBatched,
overflowed: moveToSavedForLaterOverflowed,
loading: _moveToSavedForLaterBatchedLoading,
} = useMutationBatcher(_moveToSavedForLater);
refetch: getSavedForLater,
loading: _getSavedForLaterLoading,
result: _savedForLaterQueryResult,
} = useQuery(
GetSavedForLaterDocument,
{
storeId,
userId,
cultureName,
currencyCode,
},
{
notifyOnNetworkStatusChange: true,
fetchPolicy: "cache-first",
},
);

const { mutate: _moveToSavedForLater, loading: _moveToSavedForLaterLoading } = useMutation(
MoveToSavedForLaterDocument,
{
optimisticResponse(vars, { IGNORE }) {
const movedItemIds = vars.command?.lineItemIds;

if (!movedItemIds?.length || !cart.value || !savedForLaterList.value) {
return IGNORE;
}

return {
moveToSavedForLater: {
cart: {
...cart.value,
items: cart.value.items.filter((item) => !movedItemIds.includes(item.id)),
},
list: savedForLaterList.value,
},
};
},
},
);
Copy link

Choose a reason for hiding this comment

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

Bug: Items Temporarily Disappear During Move

The optimistic responses for moveToSavedForLater and moveFromSavedForLater are incomplete. Items are correctly removed from their source list (cart or saved for later) but aren't added to their destination. This makes items temporarily disappear from the UI, creating a confusing experience until the server response updates the state.

Additional Locations (1)

Fix in Cursor Fix in Web


async function moveToSavedForLater(cartId: string, itemIds: string[]) {
try {
const moveResult = await _moveToSavedForLaterBatched({
await _moveToSavedForLater({
command: {
storeId,
userId,
Expand All @@ -36,8 +72,6 @@ function _useSavedForLater() {
lineItemIds: itemIds,
},
});

savedForLaterList.value = moveResult?.data?.moveToSavedForLater?.list;
} catch (err) {
if (err instanceof ApolloError && err.networkError?.toString() === (AbortReason.Explicit as string)) {
return;
Expand All @@ -46,18 +80,32 @@ function _useSavedForLater() {
}
}

const { mutate: _moveFromSavedForLater, loading: _moveFromSavedForLaterLoading } =
useMutation(MoveFromSavedForLaterDocument);
const { mutate: _moveFromSavedForLater, loading: _moveFromSavedForLaterLoading } = useMutation(
MoveFromSavedForLaterDocument,
{
optimisticResponse(vars, { IGNORE }) {
const movedItemIds = vars.command?.lineItemIds;

const {
add: _moveFromSavedForLaterBatched,
overflowed: moveFromSavedForLaterOverflowed,
loading: _moveFromSavedForLaterBatchedLoading,
} = useMutationBatcher(_moveFromSavedForLater);
if (!movedItemIds?.length || !cart.value || !savedForLaterList.value) {
return IGNORE;
}

return {
moveFromSavedForLater: {
cart: cart.value,
list: {
...savedForLaterList.value,
items: savedForLaterList.value.items.filter((item) => !movedItemIds.includes(item.id)),
},
},
};
},
},
);
Copy link

Choose a reason for hiding this comment

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

Bug: Optimistic Response Fails to Update Cart

The moveFromSavedForLater optimistic response removes items from the saved-for-later list but doesn't add them to the cart. This causes items to temporarily vanish from the UI, impacting user experience.

Fix in Cursor Fix in Web


async function moveFromSavedForLater(cartId: string, itemIds: string[]) {
try {
const moveResult = await _moveFromSavedForLaterBatched({
await _moveFromSavedForLater({
command: {
storeId,
userId,
Expand All @@ -67,8 +115,6 @@ function _useSavedForLater() {
lineItemIds: itemIds,
},
});

savedForLaterList.value = moveResult?.data?.moveFromSavedForLater?.list;
} catch (err) {
if (err instanceof ApolloError && err.networkError?.toString() === (AbortReason.Explicit as string)) {
return;
Expand All @@ -77,29 +123,15 @@ function _useSavedForLater() {
}
}

async function getSavedForLater() {
try {
savedForLaterList.value = await getSavedForLaterQuery();
} catch (err) {
Logger.error(`useSavedForLater.${getSavedForLater.name}`, err);
}
}

return {
savedForLaterList,

moveToSavedForLater,
moveToSavedForLaterOverflowed,
moveFromSavedForLater,
moveFromSavedForLaterOverflowed,
getSavedForLater,

loading: computed(
() =>
_moveToSavedForLaterLoading.value ||
_moveToSavedForLaterBatchedLoading.value ||
_moveFromSavedForLaterLoading.value ||
_moveFromSavedForLaterBatchedLoading.value,
() => _getSavedForLaterLoading.value || _moveToSavedForLaterLoading.value || _moveFromSavedForLaterLoading.value,
),
};
}
Expand Down
Loading