Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/cart not reactive #20

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
324 changes: 170 additions & 154 deletions src/templates/_components/app/line-item-cart.twig
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
{% set minQty = lineItem.purchasable.minQty %}
{% set maxQty = lineItem.purchasable.maxQty %}
{% set stock = lineItem.purchasable.stock %}
{% set unlimitedStock = lineItem.purchasable.hasUnlimitedStock ? 1 : 0 %}
{% set lineSubtotal = lineItem.subtotalAsCurrency() %}

{# Get preview images for lineItems #}

{#
===============================================================================================================================
Commented out temporarily (It's currently difficult to tinker around i.e passing the lineItem variable from javascript to twig )
I can't think of anyother way we can be able to guarantee reactivity of all items in the cart without ensuring all items in the
Cart are controlled from Petite Vue
===============================================================================================================================

{% set imageUrl = null %}
{% set imageSrcSet = null %}
Expand All @@ -19,167 +22,180 @@
{% set imageUrl = previewImage.getUrl(preview) %}
{% set imageSrcSet = previewImage.getSrcSet(['80', '200']) %}
{% endif %}
#}

<article
v-scope="LineItem({ id: {{ lineItem.id }}, qty: {{ lineItem.qty }}, min: {{ minQty ?? 0 }}, max: {{ maxQty ?? 0 }}, stock: {{ stock }}, unlimitedStock: {{ unlimitedStock }}, lineSubtotal: '{{ lineSubtotal }}', showErrorMaxMessage: false, showErrorMinMessage: false, showErrorStockMessage: false })"
class="flex justify-start items-stretch gap-5 p-5 bg-gray-200 rounded-xl"
>

<div class="w-[80px] min-w-[80px] md:w-[200px]">
<figure class="rounded-lg overflow-hidden">
<img
src="{{ imageUrl ?? 'https://placehold.co/200x200?text=No+Image' }}"
srcset="{{ imageUrl ? imageSrcSet : '' }}"
sizes="(min-width: 768px) 200px, 80px"
width="200"
height="200"
alt="{{ 'Image of'|t('foster-checkout') ~ ' ' ~ lineItem.description }}"
/>
</figure>
</div>

<div class="flex flex-col justify-between items-stretch gap-10 flex-grow">

<div class="md:flex md:justify-between md:items-start">

<div>
<h3 class="font-semibold">{{ lineItem.description }}</h3>
<p class="mt-3 text-sm uppercase text-gray-500">{{ 'SKU'|t('foster-checkout') }}: {{ lineItem.sku }}</p>
{% if lineItem.purchasable.onPromotion %}
<p class="mt-3 text-sm uppercase text-gray-500">
<del
class="line-through">{{ lineItem.purchasable.priceAsCurrency }}</del> {{ lineItem.purchasable.salePriceAsCurrency }}
</p>
{% else %}
<p class="mt-3 text-sm uppercase text-gray-500">{{ lineItem.purchasable.priceAsCurrency }}</p>
{% endif %}
</div>
{% set imageUrl = null %}
{% set imageSrcSet = null %}

<div class="mt-3 md:flex md:flex-col-reverse md:justify-start md:items-end md:gap-3 md:mt-0">

<form id="lineItemQty-{{ lineItem.id }}" class="flex flex-col items-end gap-2" method="post">
{{ csrfInput() }}
{{ actionInput('commerce/cart/update-cart') }}
<div class="inline-flex bg-white border border-gray-300 rounded-lg overflow-hidden">

<button type="button"
class="flex justify-center items-center w-[38px] h-[38px] text-[var(--brandColor)]"
@click="decrement"
>
<span v-cloak v-if="qty <= 1">
<span class="sr-only">{{ 'Remove from cart'|t('foster-checkout') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" viewBox="0 0 18 20" class="fill-current">
<path
d="M3.47723 19.1494C3.0156 19.1494 2.61532 18.9806 2.27638 18.6428C1.93745 18.305 1.76798 17.9062 1.76798 17.4462V3.29781H0.641357V1.59454H5.59843V0.736938H12.3957V1.59454H17.3588V3.29781H16.2321V17.4462C16.2321 17.9062 16.0627 18.305 15.7237 18.6428C15.3848 18.9806 14.9845 19.1494 14.5229 19.1494H3.47723ZM6.09733 15.344H7.69898V5.36901H6.09733V15.344ZM10.3011 15.344H11.9088V5.36901H10.3011V15.344Z"/>
</svg>
</span>
<span v-else>
<span class="sr-only">{{ 'Decrement quantity'|t('foster-checkout') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="2" viewBox="0 0 16 2" class="fill-current">
<path d="M0.850586 1.85163V0.148376H15.1555V1.85163H0.850586Z"/>
</svg>
</span>
</button>
<li v-for="lineItem in App.cart.lineItems" :key="lineItem.id">
<article
v-scope="LineItem({ id: lineItem?.id, qty: lineItem?.qty, min: lineItem?.purchasable?.minQty ?? 0, max: lineItem?.purchasable?.maxQty ?? 0, stock: lineItem?.purchasable?.stock, unlimitedStock: lineItem?.purchasable?.hasUnlimitedStock ? 1 : 0 , lineSubtotal: lineItem.subtotalAsCurrency, showErrorMaxMessage: false, showErrorMinMessage: false, showErrorStockMessage: false })"
class="flex justify-start items-stretch gap-5 p-5 bg-gray-200 rounded-xl"
>
<div class="w-[80px] min-w-[80px] md:w-[200px]">
<figure class="rounded-lg overflow-hidden">
<img
src="{{ imageUrl ?? 'https://placehold.co/200x200?text=No+Image' }}"
srcset="{{ imageUrl ? imageSrcSet : '' }}"
sizes="(min-width: 768px) 200px, 80px"
width="200"
height="200"
alt="{{ 'Image of'|t('foster-checkout') ~ ' ' ~ "${lineItem.description}" }}"
/>
</figure>
</div>

<div class="flex flex-col justify-between items-stretch gap-10 flex-grow">

<div class="md:flex md:justify-between md:items-start">

<div>
<h3 v-text="lineItem.description" class="font-semibold"></h3>
<p class="mt-3 text-sm uppercase text-gray-500">{{ 'SKU'|t('foster-checkout') }}: ${ lineItem.sku }</p>
<template v-if="lineItem?.onPromotion">
<p v-text="lineItem.salePriceAsCurrency" class="mt-3 text-sm uppercase text-gray-500">
<del
class="line-through" v-text="lineItem.priceAsCurrency"></del>
</p>
</template>
<template v-else>
<p v-text="lineItem.priceAsCurrency" class="mt-3 text-sm uppercase text-gray-500"></p>
</template>
</div>

<label for="qty_{{ lineItem.id }}" class="sr-only">{{ 'Quantity'|t('foster-checkout') }}</label>
<input name="lineItems[{{ lineItem.id }}][qty]"
v-model="qty"
id="qty_{{ lineItem.id }}"
type="text"
inputmode="numeric"
pattern="[0-9]*"
class="w-[38px] h-[38px] px-0 text-center border-none"
@input="input"
@blur="blur"
/>

<button type="button"
class="flex justify-center items-center w-[38px] h-[38px] text-[var(--brandColor)]"
@click="increment"
>
<span class="sr-only">{{ 'Increment quantity'|t('foster-checkout') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"
class="fill-current">
<path
d="M7.14841 8.85162H0.850586V7.14837H7.14841V0.844543H8.85166V7.14837H15.1555V8.85162H8.85166V15.1494H7.14841V8.85162Z"/>
</svg>
<div class="mt-3 md:flex md:flex-col-reverse md:justify-start md:items-end md:gap-3 md:mt-0">

<form :id="'lineItemQty-'+lineItem.id" class="flex flex-col items-end gap-2" method="post">
{{ csrfInput() }}
{{ actionInput('commerce/cart/update-cart') }}
<div class="inline-flex bg-white border border-gray-300 rounded-lg overflow-hidden">

<button type="button"
class="flex justify-center items-center w-[38px] h-[38px] text-[var(--brandColor)]"
@click="decrement"
>
<span v-cloak v-if="qty <= 1">
<span class="sr-only">{{ 'Remove from cart'|t('foster-checkout') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" viewBox="0 0 18 20" class="fill-current">
<path
d="M3.47723 19.1494C3.0156 19.1494 2.61532 18.9806 2.27638 18.6428C1.93745 18.305 1.76798 17.9062 1.76798 17.4462V3.29781H0.641357V1.59454H5.59843V0.736938H12.3957V1.59454H17.3588V3.29781H16.2321V17.4462C16.2321 17.9062 16.0627 18.305 15.7237 18.6428C15.3848 18.9806 14.9845 19.1494 14.5229 19.1494H3.47723ZM6.09733 15.344H7.69898V5.36901H6.09733V15.344ZM10.3011 15.344H11.9088V5.36901H10.3011V15.344Z"/>
</svg>
</span>
<span v-else>
<span class="sr-only">{{ 'Decrement quantity'|t('foster-checkout') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="2" viewBox="0 0 16 2" class="fill-current">
<path d="M0.850586 1.85163V0.148376H15.1555V1.85163H0.850586Z"/>
</svg>
</span>
</button>

<label v-bind:for="'qty_'+lineItem.id" class="sr-only">{{ 'Quantity'|t('foster-checkout') }}</label>
<input :name="'lineItems['+lineItem.id+'][qty]'"
v-model="qty"
:id="'qty_'+lineItem.id"
type="text"
inputmode="numeric"
pattern="[0-9]*"
class="w-[38px] h-[38px] px-0 text-center border-none"
@input="input"
@blur="blur"
/>

<button type="button"
class="flex justify-center items-center w-[38px] h-[38px] text-[var(--brandColor)]"
@click="increment"
>
<span class="sr-only">{{ 'Increment quantity'|t('foster-checkout') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"
class="fill-current">
<path
d="M7.14841 8.85162H0.850586V7.14837H7.14841V0.844543H8.85166V7.14837H15.1555V8.85162H8.85166V15.1494H7.14841V8.85162Z"/>
</svg>
</button>

</div>

<button type="submit"
class="js-hide text-sm underline text-gray-500 hover:no-underline hover:text-gray-700">
Update
</button>

<div class="relative w-full w-full">
<p class="text-red-700 text-sm text-right absolute top-[100%] w-full" v-if="showErrorMinMessage"
v-cloak>{{ 'You must purchase at least ${min} of this item' | t('foster-checkout') }}</p>

<p class="text-red-700 text-sm text-right absolute top-[100%] w-full" v-if="showErrorMaxMessage"
v-cloak>{{ 'You may only purchase ${max} of this item' | t('foster-checkout') }}</p>

<p class="text-red-700 text-sm text-right absolute top-[100%] w-full"
v-if="showErrorStockMessage"
v-cloak>{{ 'Only ${stock} in stock' | t('foster-checkout') }}</p>
</div>
</form>

<div class="mt-3 md:mt-0">
<template v-if="lineItem?.onPromotion || lineItem?.discountAsCurrency !== '$0.00' || lineItem?.purchasable?.onPromotion">
<h4 v-text="lineItem.totalAsCurrency" class="font-semibold"></h4>
<h5 class="mt-1 text-sm text-gray-600 line-through"><span
v-text="lineSubtotal"></span></h5>
</template>
<template v-else>
<h4 class="font-semibold"><span v-text="lineSubtotal"></span>
</h4>
</template>
</div>

<button type="submit"
class="js-hide text-sm underline text-gray-500 hover:no-underline hover:text-gray-700">
Update
</button>

<div class="relative w-full w-full">
<p class="text-red-700 text-sm text-right absolute top-[100%] w-full" v-if="showErrorMinMessage"
v-cloak>{{ 'You must purchase at least {qty} of this item' | t('foster-checkout', params = { qty: minQty }) }}</p>

<p class="text-red-700 text-sm text-right absolute top-[100%] w-full" v-if="showErrorMaxMessage"
v-cloak>{{ 'You may only purchase {qty} of this item' | t('foster-checkout', params = { qty: maxQty}) }}</p>

<p class="text-red-700 text-sm text-right absolute top-[100%] w-full"
v-if="showErrorStockMessage"
v-cloak>{{ 'Only {qty} in stock' | t('foster-checkout', params = { qty: stock }) }}</p>
</div>
</form>

<div class="mt-3 md:mt-0">
{% if lineItem.onPromotion or lineItem.discount or lineItem.purchasable.onPromotion %}
<h4 class="font-semibold">{{ (lineItem.purchasable.promotionalPrice * lineItem.qty)|commerceCurrency(cart.paymentCurrency) }}</h4>
<h5 class="mt-1 text-sm text-gray-600 line-through"><span
v-text="lineSubtotal">{{ lineItem.subtotalAsCurrency() }}</span></h5>
{% else %}
<h4 class="font-semibold"><span v-text="lineSubtotal">{{ lineItem.subtotalAsCurrency() }}</span>
</h4>
{% endif %}
</div>

</div>

</div>
{#
======================================================================
Commented out temporarily (Most properties are only available in twig )
======================================================================
<footer class="flex flex-col justify-between items-start gap-3">
{% if not lineItem.purchasable.hasUnlimitedStock %}
<p class="text-sm font-medium text-gray-500">
{{ 'Only {qty} in stock'|t('foster-checkout', params = {
qty: lineItem.purchasable.stock
}) }}
</p>
{% endif %}

<footer class="flex flex-col justify-between items-start gap-3">
{% if not lineItem.purchasable.hasUnlimitedStock %}
<p class="text-sm font-medium text-gray-500">
{{ 'Only {qty} in stock'|t('foster-checkout', params = {
qty: lineItem.purchasable.stock
}) }}
</p>
{% endif %}

<div
class="flex flex-col justify-between items-start gap-2 sm:flex-row sm:justify-start sm:items-center sm:gap-8">

<button
class="inline-flex justify-start items-center gap-2 text-sm underline text-gray-500 hover:no-underline hover:text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14"
class="fill-current">
<path
d="M6.99605 13.1188L6.24497 12.4424C5.05921 11.3566 4.08101 10.4194 3.31035 9.63079C2.53971 8.84215 1.92528 8.13683 1.46707 7.51484C1.00885 6.89286 0.68807 6.32855 0.504736 5.82191C0.321403 5.31526 0.229736 4.8024 0.229736 4.28333C0.229736 3.2541 0.575147 2.39341 1.26597 1.70126C1.95679 1.0091 2.81126 0.663025 3.82939 0.663025C4.46006 0.663025 5.04418 0.809042 5.58174 1.10108C6.1193 1.39311 6.59074 1.81714 6.99605 2.37318C7.46803 1.78381 7.9638 1.35144 8.48337 1.07608C9.00294 0.800709 9.56272 0.663025 10.1627 0.663025C11.1835 0.663025 12.0399 1.0091 12.7321 1.70126C13.4243 2.39341 13.7703 3.2541 13.7703 4.28333C13.7703 4.8024 13.6787 5.3146 13.4953 5.81993C13.312 6.32524 12.9912 6.88888 12.533 7.51086C12.0748 8.13284 11.4597 8.83881 10.6877 9.62879C9.91574 10.4188 8.93688 11.3566 7.75112 12.4424L6.99605 13.1188Z"
fill="#6B7280"/>
</svg>
<span class="inline">{{ 'Save for later'|t('foster-checkout') }}</span>
</button>

<button
type="button"
class="inline-flex justify-start items-center gap-2 text-sm underline text-gray-500 hover:no-underline hover:text-gray-700"
@click="remove"
>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="14" viewBox="0 0 12 14"
class="fill-current">
<path
d="M2.31807 13.0996C2.01032 13.0996 1.74346 12.9871 1.51751 12.7619C1.29155 12.5367 1.17857 12.2708 1.17857 11.9641V2.5319H0.42749V1.39638H3.73221V0.824646H8.26372V1.39638H11.5724V2.5319H10.8213V11.9641C10.8213 12.2708 10.7084 12.5367 10.4824 12.7619C10.2565 12.9871 9.9896 13.0996 9.68184 13.0996H2.31807ZM4.06481 10.5627H5.13257V3.9127H4.06481V10.5627ZM6.86734 10.5627H7.93909V3.9127H6.86734V10.5627Z"
fill="#6B7280"/>
</svg>
<span class="inline">{{ 'Remove'|t('foster-checkout') }}</span>
</button>
</div>
</footer>
<div
class="flex flex-col justify-between items-start gap-2 sm:flex-row sm:justify-start sm:items-center sm:gap-8">

<button
class="inline-flex justify-start items-center gap-2 text-sm underline text-gray-500 hover:no-underline hover:text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14"
class="fill-current">
<path
d="M6.99605 13.1188L6.24497 12.4424C5.05921 11.3566 4.08101 10.4194 3.31035 9.63079C2.53971 8.84215 1.92528 8.13683 1.46707 7.51484C1.00885 6.89286 0.68807 6.32855 0.504736 5.82191C0.321403 5.31526 0.229736 4.8024 0.229736 4.28333C0.229736 3.2541 0.575147 2.39341 1.26597 1.70126C1.95679 1.0091 2.81126 0.663025 3.82939 0.663025C4.46006 0.663025 5.04418 0.809042 5.58174 1.10108C6.1193 1.39311 6.59074 1.81714 6.99605 2.37318C7.46803 1.78381 7.9638 1.35144 8.48337 1.07608C9.00294 0.800709 9.56272 0.663025 10.1627 0.663025C11.1835 0.663025 12.0399 1.0091 12.7321 1.70126C13.4243 2.39341 13.7703 3.2541 13.7703 4.28333C13.7703 4.8024 13.6787 5.3146 13.4953 5.81993C13.312 6.32524 12.9912 6.88888 12.533 7.51086C12.0748 8.13284 11.4597 8.83881 10.6877 9.62879C9.91574 10.4188 8.93688 11.3566 7.75112 12.4424L6.99605 13.1188Z"
fill="#6B7280"/>
</svg>
<span class="inline">{{ 'Save for later'|t('foster-checkout') }}</span>
</button>

<button
type="button"
class="inline-flex justify-start items-center gap-2 text-sm underline text-gray-500 hover:no-underline hover:text-gray-700"
@click="remove"
>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="14" viewBox="0 0 12 14"
class="fill-current">
<path
d="M2.31807 13.0996C2.01032 13.0996 1.74346 12.9871 1.51751 12.7619C1.29155 12.5367 1.17857 12.2708 1.17857 11.9641V2.5319H0.42749V1.39638H3.73221V0.824646H8.26372V1.39638H11.5724V2.5319H10.8213V11.9641C10.8213 12.2708 10.7084 12.5367 10.4824 12.7619C10.2565 12.9871 9.9896 13.0996 9.68184 13.0996H2.31807ZM4.06481 10.5627H5.13257V3.9127H4.06481V10.5627ZM6.86734 10.5627H7.93909V3.9127H6.86734V10.5627Z"
fill="#6B7280"/>
</svg>
<span class="inline">{{ 'Remove'|t('foster-checkout') }}</span>
</button>
</div>
</footer>
#}

</div>
</div>

</article>
</article>

</li>

Loading
Loading