Fix cart rendering crash from nested ref access

This commit is contained in:
Ruslan Bakiev
2026-04-03 08:48:20 +07:00
parent 88e5c248f4
commit 4f14c24e46
2 changed files with 27 additions and 18 deletions

View File

@@ -6,13 +6,22 @@ import { useCounterpartyProfile } from '~/composables/useCounterpartyProfile';
const { isComplete: isCounterpartyComplete, loading: counterpartyLoading } = useCounterpartyProfile(); const { isComplete: isCounterpartyComplete, loading: counterpartyLoading } = useCounterpartyProfile();
const submitMutation = useMutation(SubmitCalculationOrderDocument, { throws: 'never' }); const submitMutation = useMutation(SubmitCalculationOrderDocument, { throws: 'never' });
const cart = useClientCart(); const {
items: cartItems,
totalPositions,
totalItems,
totalVolume,
incrementQuantity,
decrementQuantity,
removeProduct,
clearCart,
} = useClientCart();
const sending = ref(false); const sending = ref(false);
const success = ref(''); const success = ref('');
const errorMessage = ref(''); const errorMessage = ref('');
function lineVolume(productId: string) { function lineVolume(productId: string) {
const item = cart.items.value.find((entry) => entry.productId === productId); const item = cartItems.value.find((entry) => entry.productId === productId);
if (!item) { if (!item) {
return 0; return 0;
} }
@@ -23,19 +32,19 @@ function lineVolume(productId: string) {
function increment(productId: string) { function increment(productId: string) {
success.value = ''; success.value = '';
errorMessage.value = ''; errorMessage.value = '';
cart.incrementQuantity(productId); incrementQuantity(productId);
} }
function decrement(productId: string) { function decrement(productId: string) {
success.value = ''; success.value = '';
errorMessage.value = ''; errorMessage.value = '';
cart.decrementQuantity(productId); decrementQuantity(productId);
} }
function removeFromCart(productId: string) { function removeFromCart(productId: string) {
success.value = ''; success.value = '';
errorMessage.value = ''; errorMessage.value = '';
cart.removeProduct(productId); removeProduct(productId);
} }
async function submitCart() { async function submitCart() {
@@ -47,7 +56,7 @@ async function submitCart() {
return; return;
} }
if (cart.items.value.length < 1) { if (cartItems.value.length < 1) {
errorMessage.value = 'Добавьте хотя бы одну позицию в корзину.'; errorMessage.value = 'Добавьте хотя бы одну позицию в корзину.';
return; return;
} }
@@ -55,7 +64,7 @@ async function submitCart() {
sending.value = true; sending.value = true;
const createdCodes: string[] = []; const createdCodes: string[] = [];
for (const item of cart.items.value) { for (const item of cartItems.value) {
const result = await submitMutation.mutate({ const result = await submitMutation.mutate({
input: { input: {
productName: item.productName, productName: item.productName,
@@ -79,7 +88,7 @@ async function submitCart() {
} }
sending.value = false; sending.value = false;
cart.clearCart(); clearCart();
success.value = `Отправлено заявок: ${createdCodes.length}. Статус: уточнение цены.`; success.value = `Отправлено заявок: ${createdCodes.length}. Статус: уточнение цены.`;
} }
</script> </script>
@@ -100,13 +109,13 @@ async function submitCart() {
<div class="rounded-2xl border border-base-300 bg-base-100 p-4"> <div class="rounded-2xl border border-base-300 bg-base-100 p-4">
<h2 class="text-lg font-bold text-[#123824]">Список позиций</h2> <h2 class="text-lg font-bold text-[#123824]">Список позиций</h2>
<div v-if="cart.items.length === 0" class="alert mt-3"> <div v-if="cartItems.length === 0" class="alert mt-3">
Корзина пока пустая. Добавьте товар из каталога. Корзина пока пустая. Добавьте товар из каталога.
</div> </div>
<ul v-else class="mt-3 space-y-2"> <ul v-else class="mt-3 space-y-2">
<li <li
v-for="item in cart.items" v-for="item in cartItems"
:key="item.productId" :key="item.productId"
class="flex flex-col gap-3 rounded-xl border border-[#d6ebde] bg-white/75 px-3 py-3 md:flex-row md:items-center md:justify-between" class="flex flex-col gap-3 rounded-xl border border-[#d6ebde] bg-white/75 px-3 py-3 md:flex-row md:items-center md:justify-between"
> >
@@ -135,22 +144,22 @@ async function submitCart() {
<ul class="mt-3 space-y-2 text-sm text-[#214735]"> <ul class="mt-3 space-y-2 text-sm text-[#214735]">
<li class="flex items-center justify-between"> <li class="flex items-center justify-between">
<span>Позиций</span> <span>Позиций</span>
<span class="font-semibold">{{ cart.totalPositions }}</span> <span class="font-semibold">{{ totalPositions }}</span>
</li> </li>
<li class="flex items-center justify-between"> <li class="flex items-center justify-between">
<span>Количество, шт.</span> <span>Количество, шт.</span>
<span class="font-semibold">{{ cart.totalItems }}</span> <span class="font-semibold">{{ totalItems }}</span>
</li> </li>
<li class="flex items-center justify-between"> <li class="flex items-center justify-between">
<span>Суммарный объем</span> <span>Суммарный объем</span>
<span class="font-semibold">{{ cart.totalVolume }}</span> <span class="font-semibold">{{ totalVolume }}</span>
</li> </li>
</ul> </ul>
</div> </div>
<button <button
class="btn w-full border-0 bg-[#139957] text-white hover:bg-[#0d854a]" class="btn w-full border-0 bg-[#139957] text-white hover:bg-[#0d854a]"
:disabled="sending || counterpartyLoading.value || !isCounterpartyComplete || cart.items.length === 0" :disabled="sending || counterpartyLoading.value || !isCounterpartyComplete || cartItems.length === 0"
@click="submitCart" @click="submitCart"
> >
{{ sending ? 'Отправляем…' : 'Оформить заявку' }} {{ sending ? 'Отправляем…' : 'Оформить заявку' }}

View File

@@ -6,7 +6,7 @@ import { useClientCart } from '~/composables/useClientCart';
const { result, loading, error } = useQuery(ClientProductsDocument); const { result, loading, error } = useQuery(ClientProductsDocument);
const search = ref(''); const search = ref('');
const stockFilter = ref<'ALL' | 'CUSTOM' | 'STANDARD'>('ALL'); const stockFilter = ref<'ALL' | 'CUSTOM' | 'STANDARD'>('ALL');
const cart = useClientCart(); const { addProduct, getQuantity, totalItems } = useClientCart();
const coverPresets = [ const coverPresets = [
['#e9fbe5', '#acfcd5', '#7be9aa'], ['#e9fbe5', '#acfcd5', '#7be9aa'],
@@ -58,7 +58,7 @@ const filteredProducts = computed(() => {
}); });
function addProductToCart(product: ClientProductsQuery['clientProducts'][number]) { function addProductToCart(product: ClientProductsQuery['clientProducts'][number]) {
cart.addProduct({ addProduct({
id: product.id, id: product.id,
name: product.name, name: product.name,
sku: product.sku, sku: product.sku,
@@ -75,7 +75,7 @@ function addProductToCart(product: ClientProductsQuery['clientProducts'][number]
<div class="flex flex-wrap items-center justify-between gap-3"> <div class="flex flex-wrap items-center justify-between gap-3">
<p class="text-sm text-base-content/75">Добавляй позиции и оформляй заявку в корзине.</p> <p class="text-sm text-base-content/75">Добавляй позиции и оформляй заявку в корзине.</p>
<NuxtLink to="/cart" class="btn btn-outline btn-sm"> <NuxtLink to="/cart" class="btn btn-outline btn-sm">
Корзина: {{ cart.totalItems }} Корзина: {{ totalItems }}
</NuxtLink> </NuxtLink>
</div> </div>
</div> </div>
@@ -138,7 +138,7 @@ function addProductToCart(product: ClientProductsQuery['clientProducts'][number]
<h2 class="text-lg font-bold text-[#133826]">{{ product.name }}</h2> <h2 class="text-lg font-bold text-[#133826]">{{ product.name }}</h2>
<p class="text-xs text-base-content/65">SKU: {{ product.sku }}</p> <p class="text-xs text-base-content/65">SKU: {{ product.sku }}</p>
<div class="mt-3 flex items-center justify-between"> <div class="mt-3 flex items-center justify-between">
<span class="badge badge-outline">В корзине: {{ cart.getQuantity(product.id) }}</span> <span class="badge badge-outline">В корзине: {{ getQuantity(product.id) }}</span>
<button <button
class="btn btn-circle btn-sm border-0 bg-[#139957] text-white hover:bg-[#0d854a]" class="btn btn-circle btn-sm border-0 bg-[#139957] text-white hover:bg-[#0d854a]"
@click="addProductToCart(product)" @click="addProductToCart(product)"