1- import { useContext , useEffect } from 'react' ;
1+ import { ChangeEvent } from 'react' ;
22import { useMutation , useQuery } from '@apollo/client' ;
33import Link from 'next/link' ;
44import Image from 'next/image' ;
55import { useRouter } from 'next/router' ;
66import { v4 as uuidv4 } from 'uuid' ;
77
8- import { CartContext } from '@/stores/CartProvider ' ;
8+ import useCartStore , { RootObject , Product } from '@/stores/cart ' ;
99import Button from '@/components/UI/Button.component' ;
10- import LoadingSpinner from '../LoadingSpinner/LoadingSpinner.component' ;
1110
1211import {
1312 getFormattedCart ,
14- getUpdatedItems ,
1513 handleQuantityChange ,
16- IProductRootObject ,
1714} from '@/utils/functions/functions' ;
1815
1916import { GET_CART } from '@/utils/gql/GQL_QUERIES' ;
2017import { UPDATE_CART } from '@/utils/gql/GQL_MUTATIONS' ;
2118
2219const CartContents = ( ) => {
2320 const router = useRouter ( ) ;
24- const { setCart } = useContext ( CartContext ) ;
21+ const { cart , setCart } = useCartStore ( ) ;
2522 const isCheckoutPage = router . pathname === '/kasse' ;
2623
27- const { data , refetch } = useQuery ( GET_CART , {
24+ useQuery ( GET_CART , {
2825 notifyOnNetworkStatusChange : true ,
29- onCompleted : ( ) => {
30- const updatedCart = getFormattedCart ( data ) ;
31- if ( ! updatedCart && ! data . cart . contents . nodes . length ) {
32- localStorage . removeItem ( 'woocommerce-cart' ) ;
33- setCart ( null ) ;
34- return ;
26+ onCompleted : ( data ) => {
27+ // Only update if there's a significant difference to avoid unnecessary re-renders
28+ const updatedCart = getFormattedCart ( data ) as RootObject | undefined ;
29+ if ( ! cart || cart . totalProductsCount !== updatedCart ?. totalProductsCount ) {
30+ setCart ( updatedCart || null ) ;
3531 }
36- localStorage . setItem ( 'woocommerce-cart' , JSON . stringify ( updatedCart ) ) ;
37- setCart ( updatedCart ) ;
3832 } ,
3933 } ) ;
4034
41- const [ updateCart , { loading : updateCartProcessing } ] = useMutation (
42- UPDATE_CART ,
43- {
44- onCompleted : ( ) => {
45- refetch ( ) ;
46- setTimeout ( ( ) => {
47- refetch ( ) ;
48- } , 3000 ) ;
49- } ,
50- } ,
51- ) ;
52-
53- const handleRemoveProductClick = (
54- cartKey : string ,
55- products : IProductRootObject [ ] ,
56- ) => {
57- if ( products ?. length ) {
58- const updatedItems = getUpdatedItems ( products , 0 , cartKey ) ;
59- updateCart ( {
60- variables : {
61- input : {
62- clientMutationId : uuidv4 ( ) ,
63- items : updatedItems ,
64- } ,
65- } ,
66- } ) ;
67- }
68- refetch ( ) ;
69- setTimeout ( ( ) => {
70- refetch ( ) ;
71- } , 3000 ) ;
72- } ;
73-
74- useEffect ( ( ) => {
75- refetch ( ) ;
76- } , [ refetch ] ) ;
35+ const [ updateCart ] = useMutation ( UPDATE_CART ) ;
7736
78- const cartTotal = data ?. cart ?. total || '0' ;
37+ const handleRemoveProductClick = ( cartKey : string ) => {
38+ // Update local state
39+ useCartStore . getState ( ) . removeProduct ( cartKey ) ;
7940
80- const getUnitPrice = ( subtotal : string , quantity : number ) => {
81- const numericSubtotal = parseFloat ( subtotal . replace ( / [ ^ 0 - 9 . - ] + / g, '' ) ) ;
82- return isNaN ( numericSubtotal )
83- ? 'N/A'
84- : ( numericSubtotal / quantity ) . toFixed ( 2 ) ;
41+ // Update remote state in background
42+ updateCart ( {
43+ variables : {
44+ input : {
45+ clientMutationId : uuidv4 ( ) ,
46+ items : [ {
47+ key : cartKey ,
48+ quantity : 0
49+ } ] ,
50+ } ,
51+ } ,
52+ } ) ;
8553 } ;
8654
8755 return (
8856 < div className = "container mx-auto px-4 py-8" >
89- { data ?. cart ?. contents ?. nodes ?. length ? (
57+ { cart ?. products ?. length ? (
9058 < >
9159 < div className = "bg-white rounded-lg p-6 mb-8 md:w-full" >
92- { data . cart . contents . nodes . map ( ( item : IProductRootObject ) => (
60+ { cart . products . map ( ( item : Product ) => (
9361 < div
94- key = { item . key }
62+ key = { item . cartKey }
9563 className = "flex items-center border-b border-gray-200 py-4"
9664 >
9765 < div className = "flex-shrink-0 w-24 h-24 relative hidden md:block" >
9866 < Image
99- src = {
100- item . product . node . image ?. sourceUrl || '/placeholder.png'
101- }
102- alt = { item . product . node . name }
67+ src = { item . image ?. sourceUrl || '/placeholder.png' }
68+ alt = { item . name }
10369 layout = "fill"
10470 objectFit = "cover"
10571 className = "rounded"
10672 />
10773 </ div >
10874 < div className = "flex-grow ml-4" >
10975 < h2 className = "text-lg font-semibold" >
110- { item . product . node . name }
76+ { item . name }
11177 </ h2 >
11278 < p className = "text-gray-600" >
113- kr { getUnitPrice ( item . subtotal , item . quantity ) }
79+ kr { item . price }
11480 </ p >
11581 </ div >
11682 < div className = "flex items-center" >
11783 < input
11884 type = "number"
11985 min = "1"
120- value = { item . quantity }
121- onChange = { ( event ) => {
86+ value = { item . qty }
87+ onChange = { ( event : ChangeEvent < HTMLInputElement > ) => {
88+ const newQty = parseInt ( event . target . value , 10 ) ;
89+ if ( isNaN ( newQty ) || newQty < 1 ) return ;
90+
91+ // Update local state
92+ useCartStore . getState ( ) . updateProductQuantity ( item . cartKey , newQty ) ;
93+
94+ // Update remote state in background
12295 handleQuantityChange (
12396 event ,
124- item . key ,
125- data . cart . contents . nodes ,
126- updateCart ,
127- updateCartProcessing ,
97+ item . cartKey ,
98+ newQty ,
99+ updateCart
128100 ) ;
129101 } }
130102 className = "w-16 px-2 py-1 text-center border border-gray-300 rounded mr-2"
131103 />
132104 < Button
133- handleButtonClick = { ( ) =>
134- handleRemoveProductClick (
135- item . key ,
136- data . cart . contents . nodes ,
137- )
138- }
105+ handleButtonClick = { ( ) => handleRemoveProductClick ( item . cartKey ) }
139106 variant = "secondary"
140- buttonDisabled = { updateCartProcessing }
141107 >
142108 Fjern
143109 </ Button >
144110 </ div >
145111 < div className = "ml-4" >
146- < p className = "text-lg font-semibold" > { item . subtotal } </ p >
112+ < p className = "text-lg font-semibold" > { item . totalPrice } </ p >
147113 </ div >
148114 </ div >
149115 ) ) }
150116 </ div >
151117 < div className = "bg-white rounded-lg p-6 md:w-full" >
152118 < div className = "flex justify-end mb-4" >
153119 < span className = "font-semibold pr-2" > Subtotal:</ span >
154- < span > { cartTotal } </ span >
120+ < span > { cart . totalProductsPrice } </ span >
155121 </ div >
156122 { ! isCheckoutPage && (
157123 < div className = "flex justify-center mb-4" >
@@ -172,14 +138,6 @@ const CartContents = () => {
172138 </ Link >
173139 </ div >
174140 ) }
175- { updateCartProcessing && (
176- < div className = "fixed inset-0 flex items-center justify-center bg-black bg-opacity-50" >
177- < div className = "bg-white p-4 rounded-lg" >
178- < p className = "text-lg mb-2" > Oppdaterer handlekurv...</ p >
179- < LoadingSpinner />
180- </ div >
181- </ div >
182- ) }
183141 </ div >
184142 ) ;
185143} ;
0 commit comments