Kinda working cart

This commit is contained in:
Michał Gdula 2024-05-03 11:34:44 +01:00
parent f7321ed338
commit 67c8794427
6 changed files with 175 additions and 41 deletions

View file

@ -17,7 +17,7 @@
let cartItemCount = 0; let cartItemCount = 0;
Cart.subscribe(() => { Cart.subscribe(() => {
cartItemCount = Cart.getLength(); cartItemCount = Cart.getTotalLength();
}); });
let scrollY = 0; let scrollY = 0;
@ -72,14 +72,14 @@
<span class="nav-logo"><img src={Logo} alt="TastyBites"></span> <span class="nav-logo"><img src={Logo} alt="TastyBites"></span>
<ul style="justify-content: flex-start"> <ul style="justify-content: flex-start">
<li use:active={links.contact}><a href="/contact" use:link>Contact&nbsp;Us</a></li> <li use:active={links.contact}><a href="/contact" use:link>Contact&nbsp;Us</a></li>
<li use:active={links.cart}><a href="/cart" use:link>Cart&nbsp;<span class="nav-basket">{cartItemCount}</span></a></li> <li use:active={links.cart}><a href="/cart" use:link>Cart&nbsp;&nbsp;<span class="nav-basket">{cartItemCount}</span></a></li>
</ul> </ul>
{:else} {:else}
<ul> <ul>
<li use:active={links.home}><a href="/" use:link>Home</a></li> <li use:active={links.home}><a href="/" use:link>Home</a></li>
<li use:active={links.menu}><a href="/menu" use:link>Menu</a></li> <li use:active={links.menu}><a href="/menu" use:link>Menu</a></li>
<li use:active={links.contact}><a href="/contact" use:link>Contact&nbsp;Us</a></li> <li use:active={links.contact}><a href="/contact" use:link>Contact&nbsp;Us</a></li>
<li use:active={links.cart}><a href="/cart" use:link>Cart&nbsp;<span class="nav-basket">{cartItemCount}</span></a></li> <li use:active={links.cart}><a href="/cart" use:link>Cart&nbsp;&nbsp;<span class="nav-basket">{cartItemCount}</span></a></li>
</ul> </ul>
{/if} {/if}
</nav> </nav>

View file

@ -0,0 +1,69 @@
<script lang="ts">
import type { CartItem } from "../lib/types";
import Cart from "../lib/cart";
export let item: CartItem;
</script>
<div class="container">
{#if item.data.image}
<img src="{item.data.image}" alt="Item" class="basket-item-image">
{:else}
<img src="/MenuItemLoadingAlt.svg" alt="Item" class="basket-item-image">
{/if}
<ul>
<li class="basket-item-name">{item.data.name}</li>
<li class="basket-item-controls">
<button on:click={() => { Cart.addToCart(item.uuid, -1) }}>-</button>
<input type="number" bind:value={item.amount}>
<button on:click={() => { Cart.addToCart(item.uuid, 1) }}>+</button>
</li>
<li class="basket-item-price">£{item.data.price * item.amount}{item.data.price})</li>
</ul>
</div>
<style lang="scss">
@import "../styles/vars";
.container {
display: flex;
flex-direction: row;
overflow: hidden;
ul {
margin: $spacing-small;
padding: 0;
display: flex;
flex-direction: column;
li {
padding-bottom: $spacing-small;
list-style: none;
}
}
}
.basket-item-image {
margin: $spacing-small;
width: 140px;
height: 140px;
border-radius: $border-radius-normal;
object-fit: cover;
}
.basket-item-name {
font-size: $font-size-h2;
}
.basket-item-controls {
display: flex;
flex-direction: row;
}
.basket-item-price {
font-size: $font-size-p;
}
</style>

View file

@ -1,5 +1,9 @@
import { get, writable } from "svelte/store"; import { get, writable } from "svelte/store";
import type { CartItem } from './types';
import { getItemByUUID } from "./test-api";
// Load content from localstorage // Load content from localstorage
let local = []; let local = [];
try { try {
@ -12,10 +16,10 @@ try {
function createCartStore() { function createCartStore() {
const cart = writable(local); const cart = writable(local);
function addToCart(uuid: string, amount: number) { async function addToCart(uuid: string, amount: number) {
let found = false; let found = false;
get(cart).forEach((item) => { get(cart).forEach((item: CartItem) => {
if (item.uuid === uuid) { if (item.uuid === uuid) {
item.amount += amount; item.amount += amount;
found = true; found = true;
@ -23,24 +27,33 @@ function createCartStore() {
}); });
if (!found) { if (!found) {
cart.update((cart) => [...cart, {uuid:uuid,amount:amount}]); const newItem: CartItem = {
uuid: uuid,
amount: amount,
data: await getItemByUUID(uuid),
};
cart.update((cart: CartItem[]) => [...cart, newItem]);
} }
// Remove items that have an amount of 0 or lower // Remove items that have an amount of 0 or lower
cart.update((cart) => cart.filter((item) => item.amount > 0)) cart.update((cart) => cart.filter((item) => item.amount > 0))
} }
function getLength() { function getUniqueLength() {
return get(cart).length; return get(cart).length;
} }
function getByUUID(uuid: string) { function getTotalLength() {
get(cart).forEach((item) => { let amounts = get(cart).map((item) => item.amount);
if (item.uuid === uuid) { return amounts.reduce((a, b) => a + b, 0);
return item;
} }
function getTotalPrice() {
let price = 0;
get(cart).forEach((item) => {
price += item.amount * item.data.price;
}) })
return {}; return price;
} }
function removeByUUID(uuid: string) { function removeByUUID(uuid: string) {
@ -50,8 +63,9 @@ function createCartStore() {
return { return {
...cart, ...cart,
addToCart, addToCart,
getLength, getUniqueLength,
getByUUID, getTotalLength,
getTotalPrice,
removeByUUID, removeByUUID,
} }
} }

View file

@ -49,7 +49,7 @@ const TestData: Item[] = [
name: "GwaGwa", name: "GwaGwa",
price: 69, price: 69,
labels: [Labels.nut], labels: [Labels.nut],
image: "/dab.jpg", // image: "/dab.jpg",
}, },
{ {
uuid: "hogmelon", uuid: "hogmelon",

View file

@ -1,3 +1,11 @@
export enum Labels {
vegan = "VEGAN",
fish = "FISH",
nut = "NUT",
spicy = "SPICY",
gluten = "GLUTEN",
}
export interface Item { export interface Item {
uuid: string, uuid: string,
name: string, name: string,
@ -7,10 +15,10 @@ export interface Item {
image?: string, image?: string,
} }
export enum Labels { // UUID is stored in both Item and CartItem, this isn't the best, I don't like it
vegan = "VEGAN", // But it's the simplest way of doing this shit
fish = "FISH", export interface CartItem {
nut = "NUT", uuid: string,
spicy = "SPICY", amount: number,
gluten = "GLUTEN", data: Item,
} }

View file

@ -1,32 +1,75 @@
<script> <script lang="ts">
import { link } from 'svelte-spa-router'; import { link } from 'svelte-spa-router';
import { getItemsByUUID } from "../lib/test-api"; import { getPopularToday } from "../lib/test-api";
import Cart from "../lib/cart"; import Cart from "../lib/cart";
import LoadingBar from "../components/LoadingBar.svelte";
import MenuList from "../components/MenuList.svelte"; import MenuList from "../components/MenuList.svelte";
import BasketItem from "../components/BasketItem.svelte";
$: items = getItemsByUUID($Cart.map((item) => item.uuid)); let popularToday = getPopularToday();
$: items = $Cart;
$: totalPrice = $Cart.map((item) => item.amount * item.data.price).reduce((a, b) => a + b, 0);
</script> </script>
<h1>Shopping Cart</h1> <h1>Cart</h1>
{#await items} <button id="checkout-button">Checkout</button>
<LoadingBar /> <h2>Order total: £{totalPrice}</h2>
{:then items}
{#if items.length}
<MenuList items={items} />
{:else}
<p>Empty.....</p>
{/if}
<ul> {#if items.length > 0}
{#each items as item} {#each items as item}
<li> <div class="basket-item">
<button on:click={() => {Cart.removeByUUID(item.uuid)}}>Yeet {item.name}</button> <BasketItem item={item}/>
</li> </div>
{/each} {/each}
</ul> {:else}
<p>Empty.....</p>
{/if}
<div class="spacer" />
<h2>Looking for something more?</h2>
{#await popularToday}
<p>Loading</p>
{:then popularToday}
<MenuList items={popularToday} />
{/await} {/await}
<div class="spacer" />
<p>Looking past orders? Check out the <a href="/contact" use:link>commonly asked questions</a></p> <p>Looking past orders? Check out the <a href="/contact" use:link>commonly asked questions</a></p>
<style lang="scss">
@import "../styles/vars";
.basket-item {
margin-bottom: $spacing-normal;
}
#checkout-button {
padding: 0 $spacing-normal;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
text-shadow: 0 1px 0.5px rgba($color-dark, 0.3);;
border: 0 solid transparent;
border-radius: 9999px;
background-color: $color-primary;
color: $color-on-primary;
float: right;
&:hover, &:focus {
border: 0 solid transparent;
background-color: $color-dark;
color: $color-on-dark;
outline: 0 solid transparent
}
}
</style>