mirror of
https://github.com/Fluffy-Bean/TastyBites.git
synced 2025-05-21 10:54:55 +00:00
Kinda working cart
This commit is contained in:
parent
f7321ed338
commit
67c8794427
6 changed files with 175 additions and 41 deletions
|
@ -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 Us</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>
|
</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 Us</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>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
</nav>
|
</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 { 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue