wip: shopping cart, product options

This commit is contained in:
Nikita Kiselev
2025-07-22 23:07:10 +03:00
parent 626ee6ecb0
commit db18f3ae16
21 changed files with 429 additions and 186 deletions

View File

@@ -34,57 +34,52 @@
</div>
</div>
<div v-if="product.id" class="px-4 pb-10 pt-4 fixed bottom-0 left-0 w-full bg-base-200 z-50 flex justify-between gap-2 border-t-1 border-t-base-300">
<div class="flex-1">
<button
class="btn btn-lg w-full"
:class="isInCartNow ? 'btn-success' : 'btn-primary'"
:disabled="canAddToCart === false"
@click="actionBtnClick"
>
<span>{{ buttonText }}</span><br>
</button>
<div v-if="canAddToCart === false" class="text-error text-center text-xs mt-1">
Выберите обязательные опции
</div>
<div v-if="product.id" class="fixed px-4 pb-10 pt-4 bottom-0 left-0 w-full bg-base-200 z-50 flex flex-col gap-2 border-t-1 border-t-base-300">
<div class="text-error">
{{ error }}
</div>
<Quantity
v-if="quantity > 0"
:modelValue="quantity"
@update:modelValue="setQuantity"
:max="10"
size="lg"
/>
<div v-if="canAddToCart === false" class="text-error text-center text-xs mt-1">
Выберите обязательные опции
</div>
<div class="flex gap-2">
<div class="flex-1">
<button
class="btn btn-primary btn-lg w-full"
:disabled="canAddToCart === false"
@click="actionBtnClick"
>
Купить
</button>
</div>
<Quantity
:modelValue="quantity"
@update:modelValue="setQuantity"
size="lg"
/>
</div>
</div>
</div>
</template>
<script setup>
import {computed, onMounted, onUnmounted, ref, watch, watchEffect} from "vue";
import {computed, onMounted, ref} from "vue";
import {$fetch} from "ofetch";
import {useRoute} from 'vue-router'
import {useRouter} from 'vue-router'
import ProductOptions from "../components/ProductOptions/ProductOptions.vue";
import {useCartStore} from "../stores/CartStore.js";
import ProductImageSwiper from "../components/ProductImageSwiper.vue";
import Quantity from "../components/Quantity.vue";
import {SUPPORTED_OPTION_TYPES} from "@/constants/options.js";
const route = useRoute();
const router = useRouter();
const productId = computed(() => route.params.id);
const product = ref({});
const cart = useCartStore();
const rowId = computed(() => cart.generateRowId(productId.value, product.value.options));
const buttonText = computed(() => {
const item = cart.getItem(rowId.value);
return item && item.quantity > 0
? `В корзине`
: 'Добавить в корзину'
});
const quantity = ref(1);
const error = ref('');
const canAddToCart = computed(() => {
if (!product.value || product.value.options === undefined || product.value.options?.length === 0) {
@@ -92,7 +87,7 @@ const canAddToCart = computed(() => {
}
const required = product.value.options.filter(item => {
return ['checkbox', 'radio', 'select', 'text', 'textarea'].indexOf(item.type) !== -1
return SUPPORTED_OPTION_TYPES.includes(item.type)
&& item.required === true
&& !item.value;
});
@@ -100,32 +95,21 @@ const canAddToCart = computed(() => {
return required.length === 0;
});
const isInCartNow = computed(() => {
return cart.hasItem(rowId.value);
});
const quantity = computed(() => {
return cart.getQuantity(rowId.value);
});
function actionBtnClick() {
if (cart.hasItem(rowId.value)) {
window.Telegram.WebApp.HapticFeedback.selectionChanged();
router.push({name: 'cart.show'});
} else {
cart.addProduct(productId.value, product.value.name, product.value.price, 1, product.value.options);
async function actionBtnClick() {
try {
error.value = '';
console.log(product.value);
await cart.addProduct(productId.value, product.value.name, product.value.price, quantity.value, product.value.options);
window.Telegram.WebApp.HapticFeedback.notificationOccurred('success');
} catch (e) {
await window.Telegram.WebApp.HapticFeedback.notificationOccurred('error');
error.value = e.message;
}
}
function setQuantity(newQuantity) {
if (newQuantity === 0) {
cart.removeItem(rowId.value);
window.Telegram.WebApp.HapticFeedback.notificationOccurred('warning');
} else {
cart.setQuantity(rowId.value, newQuantity);
window.Telegram.WebApp.HapticFeedback.selectionChanged();
}
quantity.value = newQuantity;
window.Telegram.WebApp.HapticFeedback.selectionChanged();
}
onMounted(async () => {