🔥 Finish Cart implementation
- Use Select component in CartItem to change quantity - Visual update when removing or changing an item quantity - API: Remove Cart item action - API: Handle Cart item adding and updating (quantity)
This commit is contained in:
@@ -1,17 +1,21 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
// Components
|
||||||
|
import ButtonCircle from '$components/atoms/ButtonCircle.svelte'
|
||||||
|
import Select from '$components/molecules/Select.svelte'
|
||||||
|
|
||||||
export let item: any
|
export let item: any
|
||||||
|
export let index: number
|
||||||
|
|
||||||
// console.log(item)
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
const quantityLimit = 5
|
||||||
|
|
||||||
|
|
||||||
// When changing item quantity
|
// When changing item quantity
|
||||||
const updateQuantity = ({ target: { value }}: any) => {
|
const updateQuantity = ({ detail }: any) => {
|
||||||
dispatch('updatedQuantity', {
|
dispatch('updatedQuantity', {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
quantity: Number(value)
|
quantity: Number(detail)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,29 +25,39 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<aside class="cart-item shadow-small">
|
<div class="cart-item shadow-small">
|
||||||
<div class="cart-item__left">
|
<div class="cart-item__left">
|
||||||
<img
|
<img src={item.product.images[0].file.url} width={200} height={300} alt={item.product.name}>
|
||||||
src={item.product.images[0].file.url}
|
|
||||||
width={200}
|
|
||||||
height={300}
|
|
||||||
alt={item.product.name}
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="cart-item__right">
|
<div class="cart-item__right">
|
||||||
<h3>Poster</h3>
|
<h3>Poster</h3>
|
||||||
<p>{item.product.name} – {item.price_total}€</p>
|
<p>{item.product.name} – {item.price_total}€</p>
|
||||||
|
|
||||||
{#if item && item.product}
|
{#if item && item.quantity}
|
||||||
<div class="select">
|
<Select
|
||||||
<select on:change={updateQuantity}>
|
name="sort" id="filter_sort"
|
||||||
{#each Array(5) as _, index}
|
options={[...Array(item.quantity <= quantityLimit ? quantityLimit : item.quantity)].map((_, index) => {
|
||||||
<option value={index + 1} selected={item.quantity - 1 === index}>{index + 1}</option>
|
return {
|
||||||
{/each}
|
value: `${index + 1}`,
|
||||||
</select>
|
name: `${index + 1}`,
|
||||||
</div>
|
default: index === 0,
|
||||||
|
selected: index + 1 === item.quantity,
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
on:change={updateQuantity}
|
||||||
|
value={String(item.quantity)}
|
||||||
|
>
|
||||||
|
<span>Quantity:</span>
|
||||||
|
</Select>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<button on:click={removeItem}>Remove</button>
|
<ButtonCircle class="remove"
|
||||||
|
size="tiny" color="gray"
|
||||||
|
on:click={removeItem}
|
||||||
|
>
|
||||||
|
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.81 1.104a.647.647 0 1 0-.914-.915L4 3.085 1.104.19a.647.647 0 1 0-.915.915L3.085 4 .19 6.896a.647.647 0 1 0 .915.915L4 4.915 6.896 7.81a.647.647 0 1 0 .915-.915L4.915 4 7.81 1.104Z" fill="#666"/>
|
||||||
|
</svg>
|
||||||
|
</ButtonCircle>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</div>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { fade, fly } from 'svelte/transition'
|
import { fade, fly } from 'svelte/transition'
|
||||||
import { quartOut } from 'svelte/easing'
|
import { quartOut } from 'svelte/easing'
|
||||||
import { cartOpen, cartId, cartData, cartAmount } from '$utils/store'
|
import { cartOpen, cartId, cartData, cartAmount, cartIsUpdating } from '$utils/store'
|
||||||
// Components
|
// Components
|
||||||
import Button from '$components/atoms/Button.svelte'
|
import Button from '$components/atoms/Button.svelte'
|
||||||
import CartItem from '$components/molecules/CartItem.svelte'
|
import CartItem from '$components/molecules/CartItem.svelte'
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
const cart = await existantCart.json()
|
const cart = await existantCart.json()
|
||||||
$cartId = cart.id
|
$cartId = cart.id
|
||||||
$cartData = cart
|
$cartData = cart
|
||||||
console.log('fetched existant cart:', $cartId, $cartData)
|
// console.log('Fetched existant cart:', $cartId, $cartData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Cart doesn't exists
|
// Cart doesn't exists
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
const cart = await newCart.json()
|
const cart = await newCart.json()
|
||||||
$cartId = cart.id
|
$cartId = cart.id
|
||||||
$cartData = cart
|
$cartData = cart
|
||||||
console.log('new cart:', localStorage.getItem('cartId'))
|
// console.log('Created new cart:', localStorage.getItem('cartId'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -54,43 +54,53 @@
|
|||||||
|
|
||||||
// Item quantity changed
|
// Item quantity changed
|
||||||
const changedQuantity = async ({ detail: { id, quantity } }) => {
|
const changedQuantity = async ({ detail: { id, quantity } }) => {
|
||||||
// Update item in cart
|
// Cart is now updating
|
||||||
// const updatedCart = await swell.cart.updateItem(id, {
|
$cartIsUpdating = true
|
||||||
// quantity
|
|
||||||
// })
|
|
||||||
// if (updatedCart) {
|
|
||||||
// $cartData = updatedCart
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
// Get updated cart
|
||||||
const updatedCart = await fetch('/api/swell', {
|
const updatedCart = await fetch('/api/swell', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
action: 'updateCartItem',
|
action: 'updateCartItem',
|
||||||
cartId: $cartId,
|
cartId: $cartId,
|
||||||
productId: id,
|
productId: id,
|
||||||
quantity: quantity
|
quantity,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
if (updatedCart.ok) {
|
if (updatedCart.ok) {
|
||||||
// const cart = await updatedCart.json()
|
const cart = await updatedCart.json()
|
||||||
// $cartData = cart
|
$cartData = cart
|
||||||
// console.log('updated cart:', $cartData.items)
|
// Cart is updated
|
||||||
|
$cartIsUpdating = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Item removed
|
// Item removed
|
||||||
const removedItem = async ({ detail: id }) => {
|
const removedItem = async ({ detail: id }) => {
|
||||||
|
// Cart is now updating
|
||||||
|
$cartIsUpdating = true
|
||||||
|
|
||||||
// Remove item from cart
|
// Remove item from cart
|
||||||
// const removedItem = await swell.cart.removeItem(id)
|
const updatedCart = await fetch('/api/swell', {
|
||||||
// if (removedItem) {
|
method: 'POST',
|
||||||
// $cartData = removedItem
|
body: JSON.stringify({
|
||||||
// }
|
action: 'removeCartItem',
|
||||||
|
cartId: $cartId,
|
||||||
|
productId: id,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (updatedCart.ok) {
|
||||||
|
const cart = await updatedCart.json()
|
||||||
|
$cartData = cart
|
||||||
|
// Cart is updated
|
||||||
|
$cartIsUpdating = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $cartOpen}
|
{#if $cartOpen}
|
||||||
<aside class="cart shadow-box-dark"
|
<aside class="cart shadow-box-dark"
|
||||||
|
class:is-updating={$cartIsUpdating}
|
||||||
transition:fly={{ x: 48, duration: 600, easing: quartOut }}
|
transition:fly={{ x: 48, duration: 600, easing: quartOut }}
|
||||||
>
|
>
|
||||||
<header class="cart__heading">
|
<header class="cart__heading">
|
||||||
@@ -100,20 +110,28 @@
|
|||||||
|
|
||||||
<div class="cart__content">
|
<div class="cart__content">
|
||||||
{#if $cartAmount > 0}
|
{#if $cartAmount > 0}
|
||||||
{#each $cartData.items as item}
|
{#each $cartData.items as item, index}
|
||||||
<CartItem {item}
|
<CartItem {item} {index}
|
||||||
on:updatedQuantity={changedQuantity}
|
on:updatedQuantity={changedQuantity}
|
||||||
on:removed={removedItem}
|
on:removed={removedItem}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="cart__message shadow-small">
|
<div class="cart__empty shadow-small">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
|
<svg width="23" height="29" viewBox="0 0 23 29" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.95 5.83a4.94 4.94 0 0 1 1.23-3.42 3.8 3.8 0 0 1 2.8-1.2c2.07.02 4 1.67 4.04 4.62h4.13c.6 0 1.08.52 1.03 1.11l-.02.32 2.68 18.19a.94.94 0 0 1-1.26 1.02l-1.02-.38a.09.09 0 0 0-.08.01l-1.84 1.2c-.08.5-.5.88-1.02.88H1.78c-.6 0-1.07-.51-1.03-1.1l1.53-20.3c.04-.53.5-.95 1.03-.95h3.64Zm1.2 0c.01-1.2.4-2.05.9-2.6a2.6 2.6 0 0 1 1.93-.81c1.34 0 2.8 1.07 2.84 3.41H8.15Zm6.87 1.2h3.95l-.02.27-1.48 19.68H1.97l1.5-19.95h3.48v3.41a1.38 1.38 0 1 0 1.2 0v-3.4h5.67v3.4a1.38 1.38 0 1 0 1.2 0v-3.4Zm3.74 18.77.99-13.1 1.84 12.5-.62-.23c-.38-.14-.81-.1-1.15.13l-1.06.7ZM7.87 11.68a.33.33 0 1 1-.65 0 .33.33 0 0 1 .65 0Zm6.55.33a.33.33 0 1 0 0-.66.33.33 0 0 0 0 .66Z"/>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<p>Your cart is empty</p>
|
<p>Your cart is empty</p>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if !$cartData || $cartIsUpdating}
|
||||||
|
<div class="cart__update">
|
||||||
|
<p>Updating…</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="cart__total">
|
<footer class="cart__total">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { addToCart, createCart, fetchCart, getProduct, updateCartItem } from '$utils/swellFunctions'
|
import { addToCart, createCart, fetchCart, getProduct, removeCartItem, updateCartItem } from '$utils/swellFunctions'
|
||||||
|
|
||||||
|
|
||||||
// Block GET requests
|
// Block GET requests
|
||||||
@@ -41,11 +41,13 @@ export async function post ({ headers, query, body, params, ...rest }) {
|
|||||||
result = await updateCartItem(cartId, productId, bodyParsed.quantity)
|
result = await updateCartItem(cartId, productId, bodyParsed.quantity)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case 'removeCartItem': {
|
||||||
|
result = await removeCartItem(cartId, productId)
|
||||||
|
break
|
||||||
|
}
|
||||||
default: break
|
default: break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: 200,
|
status: 200,
|
||||||
body: result,
|
body: result,
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
// Cart item
|
// Cart item
|
||||||
.cart-item {
|
.cart-item {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: #fff;
|
|
||||||
color: $color-gray;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
border-radius: 6px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
background: #fff;
|
||||||
|
color: $color-gray;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: opacity 0.3s var(--ease-quart);
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
@@ -13,14 +16,14 @@
|
|||||||
|
|
||||||
// Left Image
|
// Left Image
|
||||||
&__left {
|
&__left {
|
||||||
margin-right: 20px;
|
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 150px;
|
height: 150px;
|
||||||
|
margin-right: 20px;
|
||||||
|
|
||||||
@include bp (sm) {
|
@include bp (sm) {
|
||||||
margin-right: 32px;
|
|
||||||
width: 124px;
|
width: 124px;
|
||||||
height: 180px;
|
height: 180px;
|
||||||
|
margin-right: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@@ -32,7 +35,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Details
|
||||||
&__right {
|
&__right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
// Poster Title
|
// Poster Title
|
||||||
h3 {
|
h3 {
|
||||||
font-family: $font-serif;
|
font-family: $font-serif;
|
||||||
@@ -45,14 +52,71 @@
|
|||||||
}
|
}
|
||||||
// Text
|
// Text
|
||||||
p {
|
p {
|
||||||
font-size: rem(12px);
|
|
||||||
line-height: 1.4;
|
|
||||||
max-width: 124px;
|
max-width: 124px;
|
||||||
margin: 8px 0 20px;
|
margin: 8px 0 20px;
|
||||||
|
font-size: rem(12px);
|
||||||
|
line-height: 1.4;
|
||||||
|
|
||||||
@include bp (sm) {
|
@include bp (sm) {
|
||||||
font-size: rem(13px);
|
font-size: rem(13px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Select
|
||||||
|
.select {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 28px;
|
||||||
|
margin-right: auto;
|
||||||
|
padding: 0 12px;
|
||||||
|
border: 1px solid rgba($color-lightgray, 0.3);
|
||||||
|
border-radius: 100vh;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.4s var(--ease-quart);
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
font-size: rem(12px);
|
||||||
|
color: $color-text;
|
||||||
|
|
||||||
|
& + span {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 8px;
|
||||||
|
height: 5px;
|
||||||
|
margin-left: 4px;
|
||||||
|
color: red;
|
||||||
|
background: url('data:image/svg+xml; utf8, <svg width="8" height="5" viewBox="0 0 8 5" fill="none" xmlns="http://www.w3.org/2000/svg">\
|
||||||
|
<path d="m1 1 3 3 3-3" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>\
|
||||||
|
</svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hover
|
||||||
|
&:hover {
|
||||||
|
border-color: $color-secondary-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove Icon
|
||||||
|
.remove {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
.cart {
|
.cart {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 20px 20px 24px;
|
||||||
background-color: $color-cream;
|
background-color: $color-cream;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 20px 20px 24px;
|
|
||||||
|
|
||||||
@include bp (sm) {
|
@include bp (sm) {
|
||||||
padding: 24px 32px;
|
padding: 24px 32px 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heading
|
// Heading
|
||||||
@@ -51,21 +52,10 @@
|
|||||||
|
|
||||||
// Content
|
// Content
|
||||||
&__content {
|
&__content {
|
||||||
|
position: relative;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message
|
|
||||||
&__message {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100%;
|
|
||||||
padding: 24px;
|
|
||||||
background: #fff;
|
|
||||||
color: $color-gray;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Total
|
// Total
|
||||||
&__total {
|
&__total {
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
@@ -73,7 +63,7 @@
|
|||||||
color: $color-gray;
|
color: $color-gray;
|
||||||
|
|
||||||
@include bp (md) {
|
@include bp (md) {
|
||||||
margin: 32px 0;
|
margin: 32px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum
|
// Sum
|
||||||
@@ -138,6 +128,67 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Empty content
|
||||||
|
&__empty {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
padding: 24px;
|
||||||
|
font-size: rem(20px);
|
||||||
|
font-weight: 200;
|
||||||
|
background: #fff;
|
||||||
|
color: $color-gray;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
color: #FF6C89;
|
||||||
|
background: $color-cream;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updating message
|
||||||
|
&__update {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: rem(20px);
|
||||||
|
color: $color-secondary;
|
||||||
|
transition: opacity 0.6s var(--ease-quart), transform 0.6s var(--ease-quart);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate3d(0, -8px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Updating state
|
||||||
|
&.is-updating {
|
||||||
|
.cart-item {
|
||||||
|
opacity: 0.1;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.cart__update {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate3d(0,0,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Overlay
|
// Overlay
|
||||||
&-overlay {
|
&-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@@ -3,10 +3,8 @@
|
|||||||
|
|
||||||
// Cart
|
// Cart
|
||||||
.cart {
|
.cart {
|
||||||
// display: flex;
|
|
||||||
// display: none;
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 100;
|
z-index: 101;
|
||||||
top: 72px;
|
top: 72px;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -25,7 +23,7 @@
|
|||||||
.shop-location {
|
.shop-location {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 20;
|
z-index: 100;
|
||||||
top: 18px;
|
top: 18px;
|
||||||
left: 20px;
|
left: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { writable, derived } from 'svelte/store'
|
|||||||
* Shop
|
* Shop
|
||||||
*/
|
*/
|
||||||
/** Open Cart state */
|
/** Open Cart state */
|
||||||
export const cartOpen = writable(true)
|
export const cartOpen = writable(false)
|
||||||
|
|
||||||
/** Current Cart ID */
|
/** Current Cart ID */
|
||||||
export const cartId = writable(null)
|
export const cartId = writable(null)
|
||||||
@@ -21,6 +21,9 @@ if (typeof localStorage !== 'undefined') {
|
|||||||
/** Raw Cart data */
|
/** Raw Cart data */
|
||||||
export const cartData = writable(null)
|
export const cartData = writable(null)
|
||||||
|
|
||||||
|
/** Cart data is being updated */
|
||||||
|
export const cartIsUpdating = writable(false)
|
||||||
|
|
||||||
/** Amount of products present in cart */
|
/** Amount of products present in cart */
|
||||||
export const cartAmount = derived(cartData, ($cart) => {
|
export const cartAmount = derived(cartData, ($cart) => {
|
||||||
return $cart && $cart.item_quantity > 0 ? $cart.item_quantity : 0
|
return $cart && $cart.item_quantity > 0 ? $cart.item_quantity : 0
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ swell.init(import.meta.env.VITE_SWELL_STORE_ID, import.meta.env.VITE_SWELL_API_T
|
|||||||
* Retrieve a product
|
* Retrieve a product
|
||||||
*/
|
*/
|
||||||
export const getProduct = async (id: string) => {
|
export const getProduct = async (id: string) => {
|
||||||
const product = await swell.get(`/products/${id}`)
|
const product = await swell.get('/products/{id}', {
|
||||||
|
id
|
||||||
|
})
|
||||||
|
|
||||||
if (product) {
|
if (product) {
|
||||||
return product
|
return product
|
||||||
@@ -21,7 +23,7 @@ export const getProduct = async (id: string) => {
|
|||||||
* Create a cart
|
* Create a cart
|
||||||
*/
|
*/
|
||||||
export const createCart = async () => {
|
export const createCart = async () => {
|
||||||
const cart = await swell.post('/carts', {})
|
const cart = await swell.post('/carts')
|
||||||
|
|
||||||
if (cart) {
|
if (cart) {
|
||||||
return cart
|
return cart
|
||||||
@@ -32,9 +34,9 @@ export const createCart = async () => {
|
|||||||
/**
|
/**
|
||||||
* Retrieve cart
|
* Retrieve cart
|
||||||
*/
|
*/
|
||||||
export const fetchCart = async (cartId: string) => {
|
export const fetchCart = async (id: string) => {
|
||||||
const cart = await swell.get('/carts/{id}', {
|
const cart = await swell.get('/carts/{id}', {
|
||||||
id: cartId,
|
id,
|
||||||
expand: [
|
expand: [
|
||||||
'items.product',
|
'items.product',
|
||||||
'items.variant',
|
'items.variant',
|
||||||
@@ -51,21 +53,26 @@ export const fetchCart = async (cartId: string) => {
|
|||||||
* Add product to cart
|
* Add product to cart
|
||||||
*/
|
*/
|
||||||
export const addToCart = async (cartId: string, productId: string, quantity: number) => {
|
export const addToCart = async (cartId: string, productId: string, quantity: number) => {
|
||||||
// TODO: Update current product quantity if adding again, otherwise add new product to existing items
|
// Fetch current cart data
|
||||||
|
const currentCart = await fetchCart(cartId)
|
||||||
|
|
||||||
|
// Updated cart with new items
|
||||||
const updatedCart = await swell.put('/carts/{id}', {
|
const updatedCart = await swell.put('/carts/{id}', {
|
||||||
id: cartId,
|
id: cartId,
|
||||||
items: [{
|
items: [
|
||||||
product_id: productId,
|
...currentCart.items || [],
|
||||||
quantity: quantity,
|
{
|
||||||
expand: [
|
product_id: productId,
|
||||||
'items.product',
|
quantity,
|
||||||
'items.variant',
|
}
|
||||||
]
|
],
|
||||||
}],
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (updatedCart) {
|
if (updatedCart) {
|
||||||
return updatedCart
|
// Fetch latest cart with updates
|
||||||
|
const cart = await fetchCart(cartId)
|
||||||
|
if (cart) {
|
||||||
|
return cart
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,26 +84,54 @@ export const updateCartItem = async (cartId: string, productId: string, quantity
|
|||||||
// Fetch current cart data
|
// Fetch current cart data
|
||||||
const currentCart = await fetchCart(cartId)
|
const currentCart = await fetchCart(cartId)
|
||||||
|
|
||||||
// Update cart
|
|
||||||
// const itemToUpdate = currentCart.items.find((item: any) => item.id === productId)
|
|
||||||
// itemToUpdate.quantity = quantity
|
|
||||||
|
|
||||||
// Updated items with replacing new item quantity
|
// Updated items with replacing new item quantity
|
||||||
const updatedCartItems = currentCart.items.map((item: any) => {
|
const updatedCartItems = currentCart.items.map((item: any) => {
|
||||||
console.log(item)
|
// Replace item quantity with selected one
|
||||||
|
if (item.id === productId) {
|
||||||
|
item.quantity = quantity
|
||||||
|
}
|
||||||
return item
|
return item
|
||||||
})
|
})
|
||||||
|
|
||||||
// const updatedCart = await swell.put('/carts/{id}', {
|
const updatedCart = await swell.put('/carts/{id}', {
|
||||||
// id: cartId,
|
id: cartId,
|
||||||
// items: updatedItems,
|
$set: {
|
||||||
// })
|
items: updatedCartItems,
|
||||||
|
}
|
||||||
// console.log(updatedCart)
|
})
|
||||||
|
if (updatedCart) {
|
||||||
return currentCart
|
// Fetch latest cart with updates
|
||||||
// if (updatedCart) {
|
const cart = await fetchCart(cartId)
|
||||||
// return {}
|
if (cart) {
|
||||||
// // return updatedCart
|
return cart
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove cart item
|
||||||
|
*/
|
||||||
|
export const removeCartItem = async (cartId: string, productId: string) => {
|
||||||
|
// Fetch current cart data
|
||||||
|
const currentCart = await fetchCart(cartId)
|
||||||
|
|
||||||
|
// Updated items and remove selected item
|
||||||
|
const updatedCartItems = [...currentCart.items.filter((item: any) => {
|
||||||
|
return item.id !== productId
|
||||||
|
})]
|
||||||
|
|
||||||
|
const updatedCart = await swell.put('/carts/{id}', {
|
||||||
|
id: cartId,
|
||||||
|
$set: {
|
||||||
|
items: updatedCartItems,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (updatedCart) {
|
||||||
|
// Fetch latest cart with updates
|
||||||
|
const cart = await fetchCart(cartId)
|
||||||
|
if (cart) {
|
||||||
|
return cart
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user