Skip to content

Commit 62e0b77

Browse files
authored
Merge pull request #1485 from w3bdesign/develop
Quantity input change
2 parents 46378d6 + 69c4a1f commit 62e0b77

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed

components/Cart/CartContents.vue

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
:key="product.key"
1616
:product="product"
1717
@remove="handleRemoveProduct"
18+
@update-quantity="handleUpdateQuantity"
1819
/>
1920
</section>
2021
<CommonButton v-if="showCheckoutButton" link-to="/checkout" center-button>
@@ -73,6 +74,20 @@ onMounted(async () => {
7374
isLoading.value = false;
7475
}
7576
});
77+
78+
/**
79+
* Handles updating the quantity of a cart item.
80+
*
81+
* @param {{ key: string, quantity: number }} payload
82+
*/
83+
const handleUpdateQuantity = async ({ key, quantity }) => {
84+
try {
85+
await cart.updateCartItemQuantity(key, quantity);
86+
} catch (error) {
87+
console.error("Error updating cart item quantity:", error);
88+
// Optionally, add user notification here
89+
}
90+
};
7691
</script>
7792

7893
<style scoped>

components/Cart/CartItem.vue

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@
2020
<div class="item">
2121
<span class="block mt-2 font-extrabold">Quantity: <br /></span>
2222
<span class="item-content">
23-
{{ product.quantity }}
23+
<CommonInput
24+
:model-value="localQuantity"
25+
:min="1"
26+
:loading="isUpdating"
27+
@update:modelValue="onQuantityChange"
28+
/>
2429
</span>
2530
</div>
2631
<div class="item">
@@ -46,10 +51,19 @@
4651
* @emits CartItem#remove - Emitted when the remove button is clicked.
4752
*/
4853
49-
import { ref } from "vue";
54+
import { ref, watch } from "vue";
5055
import { formatPrice } from "@/utils/functions";
5156
5257
const isRemoving = ref(false);
58+
const isUpdating = ref(false);
59+
const localQuantity = ref(props.product.quantity);
60+
61+
watch(
62+
() => props.product.quantity,
63+
(newVal) => {
64+
localQuantity.value = newVal;
65+
}
66+
);
5367
5468
const props = defineProps({
5569
product: {
@@ -58,7 +72,7 @@ const props = defineProps({
5872
},
5973
});
6074
61-
const emit = defineEmits(["remove"]);
75+
const emit = defineEmits(["remove", "update-quantity"]);
6276
6377
/**
6478
* Emits a "remove" event with the product's key as the payload.
@@ -67,6 +81,16 @@ const emitRemove = () => {
6781
isRemoving.value = true;
6882
emit("remove", props.product.key);
6983
};
84+
85+
const onQuantityChange = (newQuantity) => {
86+
if (newQuantity === props.product.quantity || isUpdating.value) return;
87+
isUpdating.value = true;
88+
emit("update-quantity", { key: props.product.key, quantity: newQuantity });
89+
// UI disables controls while updating; parent resets isUpdating via prop or reactivity
90+
setTimeout(() => {
91+
isUpdating.value = false;
92+
}, 1000);
93+
};
7094
</script>
7195

7296
<style scoped>

components/common/CommonInput.vue

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<template>
2+
<div class="flex items-center space-x-2">
3+
<button
4+
class="px-2 py-1 bg-gray-200 rounded disabled:opacity-50"
5+
:disabled="loading || value <= min"
6+
@click="updateValue(value - 1)"
7+
aria-label="Decrease quantity"
8+
>
9+
-
10+
</button>
11+
<input
12+
type="number"
13+
:value="value"
14+
:min="min"
15+
:max="max"
16+
class="w-12 text-center border rounded"
17+
:disabled="loading"
18+
@input="onInput"
19+
/>
20+
<button
21+
class="px-2 py-1 bg-gray-200 rounded disabled:opacity-50"
22+
:disabled="loading || (max !== null && value >= max)"
23+
@click="updateValue(value + 1)"
24+
aria-label="Increase quantity"
25+
>
26+
+
27+
</button>
28+
</div>
29+
</template>
30+
31+
<script setup>
32+
import { computed } from "vue";
33+
34+
const props = defineProps({
35+
modelValue: {
36+
type: Number,
37+
required: true,
38+
},
39+
min: {
40+
type: Number,
41+
default: 1,
42+
},
43+
max: {
44+
type: Number,
45+
default: null,
46+
},
47+
loading: {
48+
type: Boolean,
49+
default: false,
50+
},
51+
});
52+
53+
const emit = defineEmits(["update:modelValue"]);
54+
55+
const value = computed(() => props.modelValue);
56+
57+
function updateValue(newValue) {
58+
if (props.loading) return;
59+
if (props.max !== null && newValue > props.max) return;
60+
if (newValue < props.min) return;
61+
emit("update:modelValue", newValue);
62+
}
63+
64+
function onInput(e) {
65+
const newValue = Number(e.target.value);
66+
updateValue(newValue);
67+
}
68+
</script>

0 commit comments

Comments
 (0)