<script setup>
import Header from '@/components/Header.vue'
import Drawer from "@/components/Drawer.vue";
import axios from "axios";
import {onMounted, reactive, ref, watch, provide, computed} from "vue";
const cart = ref([])
const drawerOpen = ref(false)
const closeDrawer = () => drawerOpen.value = false
const openDrawer = () => drawerOpen.value = true
const totalPrice = computed(() => cart.value.reduce((total, item) => total + item.price, 0))
const salePrice = computed(() => Math.round(totalPrice.value * 5) / 100)
const addToCart = (item) => {
cart.value.push(item)
item.isAdded = true
}
const removeFromCart = (item) => {
cart.value.splice(cart.value.indexOf(item), 1)
item.isAdded = false
}
provide('cart', {
cart,
closeDrawer,
openDrawer,
addToCart,
removeFromCart
})
</script>
<template>
<Drawer
v-if="drawerOpen"
:total-price="totalPrice"
:sale-price="salePrice"
/>
<div class="w-4/5 m-auto bg-white rounded-3xl mt-10 mb-10" style="box-shadow: 0px 0px 14px 0px #003319; min-height: 90vh;">
<Header :total-price="totalPrice" @openDrawer="openDrawer"/>
<div class="p-10">
<router-view></router-view>
</div>
</div>
</template>
<style>
.router-link-active span {
color: #003319;
text-decoration: underline;
}
</style>
<script setup>
import DrawerHead from "@/components/DrawerHead.vue";
import CartItemList from "@/components/CartItemList.vue";
import InfoBlock from "@/components/infoBlock.vue";
import axios from "axios";
import {inject, ref} from "vue";
const props = defineProps({
totalPrice: Number,
salePrice: Number,
})
const orderId = ref(null)
const { cart } = inject('cart')
const { closeDrawer } = inject('cart')
const createOrder = async () => {
try {
const { data } = await axios.post(`https://34402a52ffa89b7c.mokky.dev/orders`, {
items: cart.value,
totalPrice: props.totalPrice - props.salePrice
})
cart.value = []
orderId.value = data.id
} catch (e) {
console.error(e)
}
}
const cleanCart = () => {
cart.value = []
}
const currentDate = new Date(),
day = currentDate.getDate(),
year = currentDate.getFullYear(),
month = currentDate.getMonth() >= 10 ? currentDate.getMonth() + 1 : `0${currentDate.getMonth() + 1}`
</script>
<template>
<div>
<div
@click="() => closeDrawer()"
class="fixed top-0 left-0 h-full w-full bg-black z-30 opacity-70"></div>
<div class="bg-white w-1/2 h-full fixed top-0 right-0 z-30 p-8 flex flex-col">
<DrawerHead />
<div v-if="!totalPrice || orderId" class="flex h-full items-center m-auto">
<InfoBlock
v-if="!totalPrice && !orderId"
title="Корзина пустая"
description="Добавьте хотя бы одну пару кроссовок, чтобы сделать заказ."
image-url="./img/package-icon.png"
/>
<InfoBlock
v-if="orderId"
title="Заказ оформлен!"
:description="`Ваш заказ №${orderId} от ${day}.${month}.${year} скоро будет передан курьерской доставке.`"
image-url="./img/order-success-icon.png"
/>
</div>
<CartItemList />
<div v-if="totalPrice" class="flex flex-col gap-5 mt-10">
<div class="flex gap-2">
<span>Итого:</span>
<div class="flex-1 border-b border-slate-300 border-dashed"></div>
<b>{{ totalPrice }} ₽</b>
</div>
<button
@click="cleanCart"
class="w-full rounded-xl mt-4 py-3 text-white bg-rose-500 transition hover:bg-rose-600 active:bg-rose-700 disabled:bg-slate-400">Очистить корзину</button>
<button
:disabled="totalPrice ? false : true"
@click="createOrder"
class="w-full rounded-xl mt-0 py-3 text-white bg-lime-500 transition hover:bg-lime-600 active:bg-lime-700 disabled:bg-slate-400">Оформить заказ</button>
</div>
</div>
</div>
</template>
<script setup>
import CartItem from "@/components/CartItem.vue";
import {inject} from "vue";
const { cart, removeFromCart } = inject('cart')
</script>
<template>
<div
v-auto-animate
class="flex flex-col gap-4 flex-1"
style="overflow-y: auto">
<CartItem
:title="item.title"
:price="item.price"
:image-url="item.imageUrl"
v-for="item in cart"
:key="item.id"
@onClickRemove="() => removeFromCart(item)"
/>
</div>
</template>
<script setup>
import {computed, ref, watch} from "vue";
const props = defineProps({
id: Number,
title: String,
price: Number,
imageUrl: String,
quantity: Number,
maxValue: Number,
finalPrice: Number,
})
const quantity = ref(1)
const maxValue = 50
const finalPrice = computed(() => (quantity.value * props.price))
const errorMsg = `Максимальное количество: ${maxValue}`
const isError = ref(false)
watch(quantity, (newValue) => {
if (newValue === '') {
quantity.value = 1
isError.value = false
} else if (newValue >= maxValue) {
quantity.value = maxValue
isError.value = true
}
})
const emit = defineEmits(['onClickRemove'])
</script>
<template>
<div class="flex items-center border border-slate-200 p-4 rounded-xl gap-4">
<img
class="w-40 h-40"
:src="imageUrl"
:alt="title"
/>
<div class="flex flex-col w-full">
<b class="">{{ title }}</b>
<div class="flex flex-col gap-2 mt-8">
<div>Стоимость: <b>{{ price }} ₽</b></div>
<div>Осталось: <b>{{ maxValue }} шт.</b></div>
<label for="" class="flex gap-4 items-center">
Количество:
<input
v-model="quantity"
class="border border-black px-2 py-1 text-black rounded-xl outline-none focus:border-lime-500 font-bold text-center"
type="number"
min="1"
max="100"
maxlength="3"
placeholder="1"
>
<span class="text-rose-500 text-xs font-bold" v-if="isError">{{ errorMsg }}</span>
</label>
<div>Итог: <b>{{ finalPrice }} ₽</b></div>
<img
width="36"
height="36"
@click="emit('onClickRemove')"
title="Удалить из корзины"
class="cursor-pointer absolute transition self-end"
src="@/assets/img/close.svg" alt="close">
</div>
</div>
</div>
</template>
item.isAdded = true
const quantity = ref(1)
const quantity = defineModel('quantity');
<CartItem
v-for="n in cart"
v-bind="n"
:key="n.id"
@update:quantity="updateQuantity(n, $event)"
@remove="removeFromCart(n)"
/>
const updateQuantity = (item, quantity) => item.quantity = quantity;
const totalPrice = computed(() => cart.value.reduce((acc, n) => acc + n.price * n.quantity, 0));