Skip to content

Commit

Permalink
Merge pull request #55 from MakairaIO/fix/raw-response-in-react-state
Browse files Browse the repository at this point in the history
fix(react wrapper): store raw responses also in state
  • Loading branch information
jembach authored Aug 10, 2022
2 parents 25fac17 + ed7770f commit a14dc04
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 43 deletions.
125 changes: 88 additions & 37 deletions packages/storefront-react/src/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export type ShopProviderProps = React.PropsWithChildren<{
/* The shop adapter client.
*/
client: StorefrontReactClient['client']
/* With this parameters the loading strategy while bootstrapping can be adjusted.
By default the cart, the user and the wishlist are loaded using each get method
/* With these parameters the loading strategy while bootstrapping can be adjusted.
By default, the cart, the user and the wishlist are loaded using each get method
in the provider. By setting one to false loading is disabled.
In addition a custom async function can be passed to have more control.
In addition, a custom async function can be passed to have more control.
*/
bootstrap?: {
/* Define the bootstrapping strategy for the cart. Set it to true for loading cart
Expand All @@ -31,7 +31,7 @@ export type ShopProviderProps = React.PropsWithChildren<{
| (() => Promise<
MakairaResponse<StorefrontReactTypes['cart'], any, Error>
>)
/* Define the bootstrapping strategy for the cuserart. Set it to true for loading user
/* Define the bootstrapping strategy for the user. Set it to true for loading user
by the provider get method. Set it to false for disabled loading at boot time.
Set it to an async function for custom loading strategy
*/
Expand All @@ -56,24 +56,36 @@ export type ShopContextData = {
/* The shop adapter client provided as prop to the ShopProvider.
*/
client: undefined | StorefrontReactClient['client']
/* The current cart if it is loaded without any error.
/* The current cart if it is loaded without any error.
Is null when an error occurred while bootstrapping.
Is undefined when not loaded during bootstrapping.
When after bootstrapping the cart is newly loaded and an error occur, the previous data will be kept.
*/
cart: null | undefined | StorefrontReactTypes['cart']
/* The current user if it is loaded without any error.
/* The current cart (same as var cart) but contains the raw responses from the API calls and not only
the stripped down and mapped data.
*/
rawCart: null | undefined | StorefrontReactTypes['rawCart']
/* The current user if it is loaded without any error.
Is null when an error occurred while bootstrapping.
Is undefined when not loaded during bootstrapping.
When after bootstrapping the cart is newly loaded and an error occur, the previous data will be kept.
*/
user: null | undefined | StorefrontReactTypes['user']
/* The current wishlist if it is loaded without any error.
/* The current user (same as var user) but contains the raw responses from the API calls and not only
the stripped down and mapped data.
*/
rawUser: null | undefined | StorefrontReactTypes['rawUser']
/* The current wishlist if it is loaded without any error.
Is null when an error occurred while bootstrapping.
Is undefined when not loaded during bootstrapping.
When after bootstrapping the cart is newly loaded and an error occur, the previous data will be kept.
*/
wishlist: null | undefined | StorefrontReactTypes['wishlist']
/* The current wishlist (same as var wishlist) but contains the raw responses from the API calls and not only
the stripped down and mapped data.
*/
rawWishlist: null | undefined | StorefrontReactTypes['rawWishlist']
}

//#region create ShopContext and set default data
Expand All @@ -83,6 +95,9 @@ const ShopContext = React.createContext<ShopContextData>({
cart: undefined,
user: undefined,
wishlist: undefined,
rawCart: undefined,
rawUser: undefined,
rawWishlist: undefined,
})

//#endregion
Expand All @@ -94,17 +109,21 @@ const ShopProvider: React.FC<ShopProviderProps> = ({
}) => {
// stores for holding the current state
const [cart, setCart] = useState<ShopContextData['cart']>()
const [rawCart, setRawCart] = useState<ShopContextData['rawCart']>()
const [user, setUser] = useState<ShopContextData['user']>()
const [rawUser, setRawUser] = useState<ShopContextData['rawUser']>()
const [wishlist, setWishlist] = useState<ShopContextData['wishlist']>()
const [rawWishlist, setRawWishlist] =
useState<ShopContextData['rawWishlist']>()

// refs for checking if a bootstrap is running. Just checking if state is fulfilled isn't
// enough because it is running async.
const bootstrapCartRef = useRef(false)
const bootstrapUserRef = useRef(false)
const bootstrapWishlistRef = useRef(false)

// run the bootstrap on startup. In addition run it each time when the bootstrap options
// changes. Each bootstrap function will check if it has already bootstrapped. Therefore
// run the bootstrap on startup. In addition, run it each time when the bootstrap options
// change. Each bootstrap function will check if it has already bootstrapped. Therefore,
// no duplicated loading will cause.
useEffect(() => {
bootstrapProvider()
Expand All @@ -116,63 +135,75 @@ const ShopProvider: React.FC<ShopProviderProps> = ({

// register shop event handlers to update internal state to be reactive
useEffect(() => {
client.addEventListener(CartAddItemEvent.eventName, reloadCartAfterUpdate)
client.addEventListener(
CartAddItemEvent.eventName,
setCartAfterUpdate as EventListener
)
client.addEventListener(
CartRemoveItemEvent.eventName,
reloadCartAfterUpdate
setCartAfterUpdate as EventListener
)
client.addEventListener(
CartUpdateItemEvent.eventName,
reloadCartAfterUpdate
setCartAfterUpdate as EventListener
)

client.addEventListener(UserSignupEvent.eventName, reloadUserAfterUpdate)
client.addEventListener(UserLoginEvent.eventName, reloadUserAfterUpdate)
client.addEventListener(UserLogoutEvent.eventName, reloadUserAfterUpdate)
client.addEventListener(
UserSignupEvent.eventName,
reloadUserAfterUpdate as EventListener
)
client.addEventListener(
UserLoginEvent.eventName,
reloadUserAfterUpdate as EventListener
)
client.addEventListener(
UserLogoutEvent.eventName,
reloadUserAfterUpdate as EventListener
)

client.addEventListener(
WishlistAddItemEvent.eventName,
reloadWishlistAfterUpdate
reloadWishlistAfterUpdate as EventListener
)
client.addEventListener(
WishlistRemoveItemEvent.eventName,
reloadWishlistAfterUpdate
reloadWishlistAfterUpdate as EventListener
)

return () => {
client.removeEventListener(
CartAddItemEvent.eventName,
reloadCartAfterUpdate
setCartAfterUpdate as EventListener
)
client.removeEventListener(
CartRemoveItemEvent.eventName,
reloadCartAfterUpdate
setCartAfterUpdate as EventListener
)
client.removeEventListener(
CartUpdateItemEvent.eventName,
reloadCartAfterUpdate
setCartAfterUpdate as EventListener
)

client.removeEventListener(
UserSignupEvent.eventName,
reloadUserAfterUpdate
reloadUserAfterUpdate as EventListener
)
client.removeEventListener(
UserLoginEvent.eventName,
reloadUserAfterUpdate
reloadUserAfterUpdate as EventListener
)
client.removeEventListener(
UserLogoutEvent.eventName,
reloadUserAfterUpdate
reloadUserAfterUpdate as EventListener
)

client.removeEventListener(
WishlistAddItemEvent.eventName,
reloadWishlistAfterUpdate
reloadWishlistAfterUpdate as EventListener
)
client.removeEventListener(
WishlistRemoveItemEvent.eventName,
reloadWishlistAfterUpdate
reloadWishlistAfterUpdate as EventListener
)
}
}, [])
Expand Down Expand Up @@ -289,33 +320,50 @@ const ShopProvider: React.FC<ShopProviderProps> = ({
/**
* method to reload the cart after a shop cart event fires that the cart has a change
*/
async function reloadCartAfterUpdate() {
const res = await client.cart.getCart({ input: {} })
function setCartAfterUpdate(
event: CartAddItemEvent | CartUpdateItemEvent | CartRemoveItemEvent
) {
const { data: eventData } = event

if (eventData.data) {
setCart(eventData.data)
}

if (res.data) {
setCart(res.data)
if (eventData.raw) {
setRawCart(eventData.raw)
}
}

/**
* method to reload the user after a shop user event fires that the user has a change
*/
async function reloadUserAfterUpdate() {
const res = await client.user.getUser({ input: {} })
function reloadUserAfterUpdate(
event: UserLoginEvent | UserLogoutEvent | UserSignupEvent
) {
const { data: eventData } = event

if (eventData.data) {
setUser(eventData.data)
}

if (!res.error) {
setUser(res.data)
if (eventData.raw) {
setRawUser(eventData.raw)
}
}

/**
* method to reload the user after a shop user event fires that the user has a change
*/
async function reloadWishlistAfterUpdate() {
const res = await client.wishlist.getWishlist({ input: {} })
function reloadWishlistAfterUpdate(
event: WishlistAddItemEvent | WishlistRemoveItemEvent
) {
const { data: eventData } = event

if (res.data) {
setWishlist(res.data)
if (eventData.data) {
setWishlist(eventData.data)
}
if (eventData.raw) {
setRawWishlist(eventData.raw)
}
}

Expand All @@ -324,8 +372,11 @@ const ShopProvider: React.FC<ShopProviderProps> = ({
value={{
client,
cart,
rawCart,
user,
rawUser,
wishlist,
rawWishlist,
}}
>
{children}
Expand Down
8 changes: 6 additions & 2 deletions packages/storefront-react/src/hooks/use-shop-cart.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export type UseShopCartData = {
* The current cart with the products.
*/
cart: ShopContextData['cart']
/**
* The current cart with the raw products.
*/
rawCart: ShopContextData['rawCart']
/**
* The current amount of products in the cart.
* It counts the number of unique products but not
Expand All @@ -31,7 +35,7 @@ export type UseShopCartData = {
}

export function useShopCart(): UseShopCartData {
const { cart } = useContext(ShopContext)
const { cart, rawCart } = useContext(ShopContext)

const productsInCart = cart?.items.length ?? 0

Expand All @@ -46,5 +50,5 @@ export function useShopCart(): UseShopCartData {
0
) ?? 0

return { cart, productsInCart, quantityInCart, totalPriceInCart }
return { cart, productsInCart, quantityInCart, totalPriceInCart, rawCart }
}
8 changes: 6 additions & 2 deletions packages/storefront-react/src/hooks/use-shop-user.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ export type UseShopUserData = {
* logged in or when reloading the user fails.
*/
user: ShopContextData['user']
/**
* The current raw user.
*/
rawUser: ShopContextData['rawUser']
}

export function useShopUser(): UseShopUserData {
const { user } = useContext(ShopContext)
const { user, rawUser } = useContext(ShopContext)

return { user }
return { user, rawUser }
}
8 changes: 6 additions & 2 deletions packages/storefront-react/src/hooks/use-shop-wishlist.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ export type UseShopWishlistData = {
* The current wishlist with the products
*/
wishlist: ShopContextData['wishlist']
/**
* The current raw wishlist
*/
rawWishlist: ShopContextData['rawWishlist']
/**
*
*/
Expand All @@ -16,7 +20,7 @@ export type UseShopWishlistData = {
}

export function useShopWishlist(): UseShopWishlistData {
const { wishlist } = useContext(ShopContext)
const { wishlist, rawWishlist } = useContext(ShopContext)

const isProductInWishlist = useCallback(
(id: string): MakairaResponse<boolean, undefined, Error> => {
Expand All @@ -37,5 +41,5 @@ export function useShopWishlist(): UseShopWishlistData {
[wishlist]
)

return { wishlist, isProductInWishlist }
return { wishlist, isProductInWishlist, rawWishlist }
}
9 changes: 9 additions & 0 deletions packages/storefront-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,21 @@ export type StorefrontReactTypes = MergeBy<
cart: Awaited<
ReturnType<StorefrontReactClient['client']['cart']['getCart']>
>['data']
rawCart: Awaited<
ReturnType<StorefrontReactClient['client']['cart']['getCart']>
>['raw']
user: Awaited<
ReturnType<StorefrontReactClient['client']['user']['getUser']>
>['data']
rawUser: Awaited<
ReturnType<StorefrontReactClient['client']['user']['getUser']>
>['raw']
wishlist: Awaited<
ReturnType<StorefrontReactClient['client']['wishlist']['getWishlist']>
>['data']
rawWishlist: Awaited<
ReturnType<StorefrontReactClient['client']['wishlist']['getWishlist']>
>['raw']
},
StorefrontReactCustomTypes
>

0 comments on commit a14dc04

Please sign in to comment.