mirror of
https://github.com/Fluffy-Bean/TastyBites.git
synced 2025-01-29 17:48:28 +00:00
Kinda working cart
This commit is contained in:
parent
f7321ed338
commit
67c8794427
|
@ -17,7 +17,7 @@
|
|||
|
||||
let cartItemCount = 0;
|
||||
Cart.subscribe(() => {
|
||||
cartItemCount = Cart.getLength();
|
||||
cartItemCount = Cart.getTotalLength();
|
||||
});
|
||||
|
||||
let scrollY = 0;
|
||||
|
@ -72,14 +72,14 @@
|
|||
<span class="nav-logo"><img src={Logo} alt="TastyBites"></span>
|
||||
<ul style="justify-content: flex-start">
|
||||
<li use:active={links.contact}><a href="/contact" use:link>Contact Us</a></li>
|
||||
<li use:active={links.cart}><a href="/cart" use:link>Cart <span class="nav-basket">{cartItemCount}</span></a></li>
|
||||
<li use:active={links.cart}><a href="/cart" use:link>Cart <span class="nav-basket">{cartItemCount}</span></a></li>
|
||||
</ul>
|
||||
{:else}
|
||||
<ul>
|
||||
<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.contact}><a href="/contact" use:link>Contact Us</a></li>
|
||||
<li use:active={links.cart}><a href="/cart" use:link>Cart <span class="nav-basket">{cartItemCount}</span></a></li>
|
||||
<li use:active={links.cart}><a href="/cart" use:link>Cart <span class="nav-basket">{cartItemCount}</span></a></li>
|
||||
</ul>
|
||||
{/if}
|
||||
</nav>
|
||||
|
|
69
front/src/components/BasketItem.svelte
Normal file
69
front/src/components/BasketItem.svelte
Normal 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>
|
|
@ -1,5 +1,9 @@
|
|||
import { get, writable } from "svelte/store";
|
||||
|
||||
import type { CartItem } from './types';
|
||||
import { getItemByUUID } from "./test-api";
|
||||
|
||||
|
||||
// Load content from localstorage
|
||||
let local = [];
|
||||
try {
|
||||
|
@ -12,10 +16,10 @@ try {
|
|||
function createCartStore() {
|
||||
const cart = writable(local);
|
||||
|
||||
function addToCart(uuid: string, amount: number) {
|
||||
async function addToCart(uuid: string, amount: number) {
|
||||
let found = false;
|
||||
|
||||
get(cart).forEach((item) => {
|
||||
get(cart).forEach((item: CartItem) => {
|
||||
if (item.uuid === uuid) {
|
||||
item.amount += amount;
|
||||
found = true;
|
||||
|
@ -23,24 +27,33 @@ function createCartStore() {
|
|||
});
|
||||
|
||||
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
|
||||
cart.update((cart) => cart.filter((item) => item.amount > 0))
|
||||
}
|
||||
|
||||
function getLength() {
|
||||
function getUniqueLength() {
|
||||
return get(cart).length;
|
||||
}
|
||||
|
||||
function getByUUID(uuid: string) {
|
||||
function getTotalLength() {
|
||||
let amounts = get(cart).map((item) => item.amount);
|
||||
return amounts.reduce((a, b) => a + b, 0);
|
||||
}
|
||||
|
||||
function getTotalPrice() {
|
||||
let price = 0;
|
||||
get(cart).forEach((item) => {
|
||||
if (item.uuid === uuid) {
|
||||
return item;
|
||||
}
|
||||
price += item.amount * item.data.price;
|
||||
})
|
||||
return {};
|
||||
return price;
|
||||
}
|
||||
|
||||
function removeByUUID(uuid: string) {
|
||||
|
@ -50,8 +63,9 @@ function createCartStore() {
|
|||
return {
|
||||
...cart,
|
||||
addToCart,
|
||||
getLength,
|
||||
getByUUID,
|
||||
getUniqueLength,
|
||||
getTotalLength,
|
||||
getTotalPrice,
|
||||
removeByUUID,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ const TestData: Item[] = [
|
|||
name: "GwaGwa",
|
||||
price: 69,
|
||||
labels: [Labels.nut],
|
||||
image: "/dab.jpg",
|
||||
// image: "/dab.jpg",
|
||||
},
|
||||
{
|
||||
uuid: "hogmelon",
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
export enum Labels {
|
||||
vegan = "VEGAN",
|
||||
fish = "FISH",
|
||||
nut = "NUT",
|
||||
spicy = "SPICY",
|
||||
gluten = "GLUTEN",
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
uuid: string,
|
||||
name: string,
|
||||
|
@ -7,10 +15,10 @@ export interface Item {
|
|||
image?: string,
|
||||
}
|
||||
|
||||
export enum Labels {
|
||||
vegan = "VEGAN",
|
||||
fish = "FISH",
|
||||
nut = "NUT",
|
||||
spicy = "SPICY",
|
||||
gluten = "GLUTEN",
|
||||
// UUID is stored in both Item and CartItem, this isn't the best, I don't like it
|
||||
// But it's the simplest way of doing this shit
|
||||
export interface CartItem {
|
||||
uuid: string,
|
||||
amount: number,
|
||||
data: Item,
|
||||
}
|
||||
|
|
|
@ -1,32 +1,75 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import { link } from 'svelte-spa-router';
|
||||
|
||||
import { getItemsByUUID } from "../lib/test-api";
|
||||
import { getPopularToday } from "../lib/test-api";
|
||||
import Cart from "../lib/cart";
|
||||
import LoadingBar from "../components/LoadingBar.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>
|
||||
|
||||
<h1>Shopping Cart</h1>
|
||||
<h1>Cart</h1>
|
||||
|
||||
{#await items}
|
||||
<LoadingBar />
|
||||
{:then items}
|
||||
{#if items.length}
|
||||
<MenuList items={items} />
|
||||
{:else}
|
||||
<p>Empty.....</p>
|
||||
{/if}
|
||||
<button id="checkout-button">Checkout</button>
|
||||
<h2>Order total: £{totalPrice}</h2>
|
||||
|
||||
<ul>
|
||||
{#each items as item}
|
||||
<li>
|
||||
<button on:click={() => {Cart.removeByUUID(item.uuid)}}>Yeet {item.name}</button>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{#if items.length > 0}
|
||||
{#each items as item}
|
||||
<div class="basket-item">
|
||||
<BasketItem item={item}/>
|
||||
</div>
|
||||
{/each}
|
||||
{: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}
|
||||
|
||||
<div class="spacer" />
|
||||
|
||||
<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>
|
Loading…
Reference in a new issue