Skip to content

Commit 2c5b49d

Browse files
committed
feat(cart): add mutation lifecycle hooks and cache invalidation option
1 parent b190213 commit 2c5b49d

2 files changed

Lines changed: 308 additions & 35 deletions

File tree

libs/storefront-data/src/cart/hooks.ts

Lines changed: 109 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,29 @@ export type CreateCartHooksConfig<
232232
) => CartAddressValidationResult
233233
buildShippingAddress?: (input: TAddressInput) => TAddressPayload
234234
buildBillingAddress?: (input: TAddressInput) => TAddressPayload
235+
invalidateOnSuccess?: boolean
235236
}
236237

237-
export type CartMutationOptions<TData, TVariables> = {
238-
onSuccess?: (data: TData, variables: TVariables) => void
239-
onError?: (error: unknown) => void
238+
export type CartMutationOptions<TData, TVariables, TContext = unknown> = {
239+
onSuccess?: (
240+
data: TData,
241+
variables: TVariables,
242+
context: TContext | undefined
243+
) => void
244+
onError?: (
245+
error: unknown,
246+
variables: TVariables,
247+
context: TContext | undefined
248+
) => void
249+
onMutate?: (
250+
variables: TVariables
251+
) => TContext | void | Promise<TContext | void>
252+
onSettled?: (
253+
data: TData | undefined,
254+
error: unknown | null,
255+
variables: TVariables,
256+
context: TContext | undefined
257+
) => void
240258
}
241259

242260
export function createCartHooks<
@@ -272,6 +290,7 @@ export function createCartHooks<
272290
validateBillingAddressInput,
273291
buildShippingAddress,
274292
buildBillingAddress,
293+
invalidateOnSuccess = false,
275294
}: CreateCartHooksConfig<
276295
TCart,
277296
TCreateInput,
@@ -321,6 +340,22 @@ export function createCartHooks<
321340
cartStorage?.clearCartId()
322341
}
323342

343+
const invalidateCart = (
344+
queryClient: ReturnType<typeof useQueryClient>,
345+
cart: CartLike | null
346+
) => {
347+
if (!invalidateOnSuccess || !cart?.id) {
348+
return
349+
}
350+
351+
queryClient.invalidateQueries({
352+
queryKey: resolvedQueryKeys.active({
353+
cartId: cart.id,
354+
regionId: cart.region_id ?? null,
355+
}),
356+
})
357+
}
358+
324359
type LoadCartOptions = {
325360
input: CartInputBase
326361
cartId: string | null
@@ -530,7 +565,8 @@ export function createCartHooks<
530565
return useMutation({
531566
mutationFn: (input: TCreateInput) =>
532567
service.createCart(buildCreate(input)),
533-
onSuccess: (cart, variables) => {
568+
onMutate: (variables) => options?.onMutate?.(variables),
569+
onSuccess: (cart, variables, context) => {
534570
persistCartId(cart.id)
535571
queryClient.setQueryData(
536572
resolvedQueryKeys.active({
@@ -539,10 +575,14 @@ export function createCartHooks<
539575
}),
540576
cart
541577
)
542-
options?.onSuccess?.(cart, variables)
578+
invalidateCart(queryClient, cart)
579+
options?.onSuccess?.(cart, variables, context)
580+
},
581+
onError: (error, variables, context) => {
582+
options?.onError?.(error, variables, context)
543583
},
544-
onError: (error) => {
545-
options?.onError?.(error)
584+
onSettled: (data, error, variables, context) => {
585+
options?.onSettled?.(data, error, variables, context)
546586
},
547587
})
548588
}
@@ -560,18 +600,23 @@ export function createCartHooks<
560600
}
561601
return service.updateCart(cartId, buildUpdate(input))
562602
},
563-
onSuccess: (cart, variables) => {
603+
onMutate: (variables) => options?.onMutate?.(variables),
604+
onSuccess: (cart, variables, context) => {
564605
queryClient.setQueryData(
565606
resolvedQueryKeys.active({
566607
cartId: cart.id,
567608
regionId: cart.region_id ?? null,
568609
}),
569610
cart
570611
)
571-
options?.onSuccess?.(cart, variables)
612+
invalidateCart(queryClient, cart)
613+
options?.onSuccess?.(cart, variables, context)
614+
},
615+
onError: (error, variables, context) => {
616+
options?.onError?.(error, variables, context)
572617
},
573-
onError: (error) => {
574-
options?.onError?.(error)
618+
onSettled: (data, error, variables, context) => {
619+
options?.onSettled?.(data, error, variables, context)
575620
},
576621
})
577622
}
@@ -628,18 +673,23 @@ export function createCartHooks<
628673
}
629674
return service.updateCart(cartId, buildUpdate(updateInput))
630675
},
631-
onSuccess: (cart, variables) => {
676+
onMutate: (variables) => options?.onMutate?.(variables),
677+
onSuccess: (cart, variables, context) => {
632678
queryClient.setQueryData(
633679
resolvedQueryKeys.active({
634680
cartId: cart.id,
635681
regionId: cart.region_id ?? null,
636682
}),
637683
cart
638684
)
639-
options?.onSuccess?.(cart, variables)
685+
invalidateCart(queryClient, cart)
686+
options?.onSuccess?.(cart, variables, context)
640687
},
641-
onError: (error) => {
642-
options?.onError?.(error)
688+
onError: (error, variables, context) => {
689+
options?.onError?.(error, variables, context)
690+
},
691+
onSettled: (data, error, variables, context) => {
692+
options?.onSettled?.(data, error, variables, context)
643693
},
644694
})
645695
}
@@ -684,18 +734,23 @@ export function createCartHooks<
684734
persistCartId(updated.id)
685735
return updated
686736
},
687-
onSuccess: (cart, variables) => {
737+
onMutate: (variables) => options?.onMutate?.(variables),
738+
onSuccess: (cart, variables, context) => {
688739
queryClient.setQueryData(
689740
resolvedQueryKeys.active({
690741
cartId: cart.id,
691742
regionId: cart.region_id ?? null,
692743
}),
693744
cart
694745
)
695-
options?.onSuccess?.(cart, variables)
746+
invalidateCart(queryClient, cart)
747+
options?.onSuccess?.(cart, variables, context)
748+
},
749+
onError: (error, variables, context) => {
750+
options?.onError?.(error, variables, context)
696751
},
697-
onError: (error) => {
698-
options?.onError?.(error)
752+
onSettled: (data, error, variables, context) => {
753+
options?.onSettled?.(data, error, variables, context)
699754
},
700755
})
701756
}
@@ -719,18 +774,23 @@ export function createCartHooks<
719774
buildUpdateItem(input)
720775
)
721776
},
722-
onSuccess: (cart, variables) => {
777+
onMutate: (variables) => options?.onMutate?.(variables),
778+
onSuccess: (cart, variables, context) => {
723779
queryClient.setQueryData(
724780
resolvedQueryKeys.active({
725781
cartId: cart.id,
726782
regionId: cart.region_id ?? null,
727783
}),
728784
cart
729785
)
730-
options?.onSuccess?.(cart, variables)
786+
invalidateCart(queryClient, cart)
787+
options?.onSuccess?.(cart, variables, context)
731788
},
732-
onError: (error) => {
733-
options?.onError?.(error)
789+
onError: (error, variables, context) => {
790+
options?.onError?.(error, variables, context)
791+
},
792+
onSettled: (data, error, variables, context) => {
793+
options?.onSettled?.(data, error, variables, context)
734794
},
735795
})
736796
}
@@ -750,18 +810,23 @@ export function createCartHooks<
750810
}
751811
return service.removeLineItem(cartId, input.lineItemId)
752812
},
753-
onSuccess: (cart, variables) => {
813+
onMutate: (variables) => options?.onMutate?.(variables),
814+
onSuccess: (cart, variables, context) => {
754815
queryClient.setQueryData(
755816
resolvedQueryKeys.active({
756817
cartId: cart.id,
757818
regionId: cart.region_id ?? null,
758819
}),
759820
cart
760821
)
761-
options?.onSuccess?.(cart, variables)
822+
invalidateCart(queryClient, cart)
823+
options?.onSuccess?.(cart, variables, context)
824+
},
825+
onError: (error, variables, context) => {
826+
options?.onError?.(error, variables, context)
762827
},
763-
onError: (error) => {
764-
options?.onError?.(error)
828+
onSettled: (data, error, variables, context) => {
829+
options?.onSettled?.(data, error, variables, context)
765830
},
766831
})
767832
}
@@ -781,18 +846,23 @@ export function createCartHooks<
781846
}
782847
return service.transferCart(cartId)
783848
},
784-
onSuccess: (cart, variables) => {
849+
onMutate: (variables) => options?.onMutate?.(variables),
850+
onSuccess: (cart, variables, context) => {
785851
queryClient.setQueryData(
786852
resolvedQueryKeys.active({
787853
cartId: cart.id,
788854
regionId: cart.region_id ?? null,
789855
}),
790856
cart
791857
)
792-
options?.onSuccess?.(cart, variables)
858+
invalidateCart(queryClient, cart)
859+
options?.onSuccess?.(cart, variables, context)
793860
},
794-
onError: (error) => {
795-
options?.onError?.(error)
861+
onError: (error, variables, context) => {
862+
options?.onError?.(error, variables, context)
863+
},
864+
onSettled: (data, error, variables, context) => {
865+
options?.onSettled?.(data, error, variables, context)
796866
},
797867
})
798868
}
@@ -813,14 +883,18 @@ export function createCartHooks<
813883
}
814884
return service.completeCart(cartId)
815885
},
816-
onSuccess: (data, variables) => {
886+
onMutate: (variables) => options?.onMutate?.(variables),
887+
onSuccess: (data, variables, context) => {
817888
if (options?.clearCartOnSuccess === true) {
818889
clearCartId()
819890
}
820-
options?.onSuccess?.(data, variables)
891+
options?.onSuccess?.(data, variables, context)
892+
},
893+
onError: (error, variables, context) => {
894+
options?.onError?.(error, variables, context)
821895
},
822-
onError: (error) => {
823-
options?.onError?.(error)
896+
onSettled: (data, error, variables, context) => {
897+
options?.onSettled?.(data, error, variables, context)
824898
},
825899
})
826900
}

0 commit comments

Comments
 (0)