feat: new price count

This commit is contained in:
Константин Уколов 2024-09-02 00:27:30 +03:00
parent 63d31fbe53
commit 0130b9aa0d
6 changed files with 91 additions and 79 deletions

View File

@ -1,3 +1,3 @@
export { ProductCard, ProductImage } from './ui' export { ProductCard, ProductImage, ProductPrice } from './ui'
export * as productModel from './model' export * as productModel from './model'

View File

@ -1,58 +1,63 @@
import { watchOnce } from '@vueuse/shared' import { useStorage } from '@vueuse/core'
import type { CrmVariant } from '~/src/shared/model' import type { CrmVariant } from '~/src/shared/model'
import { useCRMGetCart } from '~/src/shared/api/crm/crm'
export function useProductPrice() { export function useProductPrice(variants: CrmVariant[], id: string) {
const amount = ref(0) const amount = ref(0)
const currentUnitPrice = ref(0) const currentUnitPrice = ref(0)
const prevUnitPrice = ref() const prevUnitPrice = ref()
const variants = ref<CrmVariant[]>([]) const { mutateAsync, data } = useCRMGetCart()
const addedItems = useStorage<{
id: string
count: number
}[]>('added-items', [])
const currentPriceForAll = computed(() => currentUnitPrice.value * amount.value) const currentPriceForAll = computed(() => currentUnitPrice.value * amount.value)
const prevUnitPriceForAll = computed(() => prevUnitPrice.value * amount.value) const prevUnitPriceForAll = computed(() => prevUnitPrice.value * amount.value)
watch(amount, () => { const setInitCurrentPrice = () => {
updatePrices() currentUnitPrice.value = Number(variants[0].price) / 100
})
watchOnce(variants, () => {
updatePrices()
})
function updatePrices() {
if (!variants.value.length) {
return
} }
for (let i = 0; i < variants.value.length; i++) { watch(amount, async (value, oldValue) => {
const variant = variants.value[i] await mutateAsync({
data: [
let max = Number.POSITIVE_INFINITY {
let min = 0 count: String(value),
productId: id,
variant.properties?.forEach((property) => { },
if (property.name === 'min') { ],
min = Number(property.value)
}
if (property.name === 'max')
max = Number(property.value)
}) })
if (amount.value >= min && amount.value <= max) { const newCurrent = Number(data.value?.data.amount) / 100 || 0
currentUnitPrice.value = Number(variant.price) / 100 const newPrev = Number(data.value?.data.amountOld) / 100 || 0
if (i !== 0) { currentUnitPrice.value = newCurrent
prevUnitPrice.value = Number(variants.value[i - 1].price) / 100
if (newCurrent !== newPrev) {
prevUnitPrice.value = newPrev
} }
else { else {
prevUnitPrice.value = undefined prevUnitPrice.value = undefined
} }
return if (oldValue === 0 && value > 0) {
} addedItems.value.push({
id,
count: value,
})
} }
if (oldValue > 0 && value === 0) {
addedItems.value = addedItems.value.filter(item => item.id !== id)
setInitCurrentPrice()
} }
})
setInitCurrentPrice()
return { return {
amount, amount,
@ -60,6 +65,5 @@ export function useProductPrice() {
prevUnitPrice, prevUnitPrice,
currentPriceForAll, currentPriceForAll,
prevUnitPriceForAll, prevUnitPriceForAll,
variants,
} }
} }

View File

@ -8,11 +8,7 @@ const props = defineProps<{
product: CrmProduct product: CrmProduct
}>() }>()
const { amount, currentUnitPrice, prevUnitPriceForAll, prevUnitPrice, variants } = useProductPrice() const { amount, currentUnitPrice, prevUnitPriceForAll, prevUnitPrice } = useProductPrice(props.product.variants || [], props.product.id!)
if (props.product.variants) {
variants.value = props.product.variants
}
function onImageClick() { function onImageClick() {
navigateTo( navigateTo(
@ -33,7 +29,7 @@ function onImageClick() {
<div>{{ product.name }}</div> <div>{{ product.name }}</div>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div class="text-2xl font-bold" :class="{ 'text-pink-800': prevUnitPrice }"> <div class="text-2xl font-bold" :class="{ 'text-pink-800': prevUnitPrice }">
{{ currentUnitPrice * (amount || 1) }} {{ currentUnitPrice }}
</div> </div>
<div v-if="prevUnitPrice" class="line-through text-slate-400"> <div v-if="prevUnitPrice" class="line-through text-slate-400">
{{ prevUnitPriceForAll }} {{ prevUnitPriceForAll }}

View File

@ -0,0 +1,31 @@
<script setup lang="ts">
import { useProductPrice } from '../model'
import { InputNumber } from '~/src/shared/ui'
import type { CrmVariant } from '~/src/shared/model'
const props = defineProps<{
variants: CrmVariant[]
productId: string
}>()
const { amount, currentUnitPrice, prevUnitPrice, prevUnitPriceForAll } = useProductPrice(props.variants, props.productId)
</script>
<template>
<div class="bg-gray-50 rounded-2xl border border-slate-200 flex gap-5 justify-between p-5 items-center">
<div class="flex flex-col gap-1 flex-1">
<div class="text-2xl font-bold" :class="{ 'text-pink-800': prevUnitPrice }">
{{ currentUnitPrice }}
</div>
<div v-if="prevUnitPrice" class="line-through text-slate-400">
{{ prevUnitPriceForAll }}
</div>
</div>
<div class="flex-1">
<UButton v-if="!amount" class="w-full justify-center" size="xl" @click="amount = 1">
В корзину
</UButton>
<InputNumber v-else v-model="amount" />
</div>
</div>
</template>

View File

@ -1,2 +1,3 @@
export { default as ProductCard } from './ProductCard.vue' export { default as ProductCard } from './ProductCard.vue'
export { default as ProductImage } from './ProductImage.vue' export { default as ProductImage } from './ProductImage.vue'
export { default as ProductPrice } from './ProductPrice.vue'

View File

@ -1,22 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { watchOnce } from '@vueuse/shared' import { ProductImage, ProductPrice } from '~/src/entities/product'
import { ProductImage, productModel } from '~/src/entities/product'
import { useCRMGetProduct } from '~/src/shared/api/crm/crm' import { useCRMGetProduct } from '~/src/shared/api/crm/crm'
import { Header } from '~/src/widgets/header' import { Header } from '~/src/widgets/header'
import { InputNumber, StandardLayout } from '~/src/shared/ui' import { StandardLayout } from '~/src/shared/ui'
import { Footer } from '~/src/widgets/footer' import { Footer } from '~/src/widgets/footer'
const route = useRoute() const route = useRoute()
const { data } = useCRMGetProduct(route.params.id as string) const { data } = useCRMGetProduct(route.params.id as string)
const { amount, currentUnitPrice, prevUnitPrice, prevUnitPriceForAll, variants } = productModel.useProductPrice()
watchOnce(() => data.value?.data.product?.variants, (value) => {
if (value) {
variants.value = value
}
})
</script> </script>
<template> <template>
@ -38,22 +29,11 @@ watchOnce(() => data.value?.data.product?.variants, (value) => {
</div> </div>
</div> </div>
<div v-if="data?.data.product" class="bg-gray-50 rounded-2xl border border-slate-200 flex gap-5 justify-between p-5 items-center"> <ProductPrice
<div class="flex flex-col gap-1 flex-1"> v-if="data?.data.product?.id && data.data.product.variants"
<div class="text-2xl font-bold" :class="{ 'text-pink-800': prevUnitPrice }"> :product-id="data.data.product.id"
{{ currentUnitPrice * (amount || 1) }} :variants="data.data.product.variants"
</div> />
<div v-if="prevUnitPrice" class="line-through text-slate-400">
{{ prevUnitPriceForAll }}
</div>
</div>
<div class="flex-1">
<UButton v-if="!amount" class="w-full justify-center" size="xl" @click="amount = 1">
В корзину
</UButton>
<InputNumber v-else v-model="amount" />
</div>
</div>
</div> </div>
</div> </div>
<template #footer> <template #footer>