mirror of
https://github.com/Fluffy-Bean/TastyBites.git
synced 2024-12-28 18:36:25 +00:00
Finalise Checkout page design
Make CheckoutProgress type, hopefully to use with the checkout API thang fix banner loading stuff
This commit is contained in:
parent
d1b35005d4
commit
e3e4e482cc
|
@ -27,8 +27,13 @@
|
||||||
|
|
||||||
border-radius: $border-radius-large;
|
border-radius: $border-radius-large;
|
||||||
|
|
||||||
background: linear-gradient(to right, $color-background 8%, rgba($color-dark, 0.3) 38%, $color-background 54%);
|
background: linear-gradient(
|
||||||
background-size: 1000px 100%;
|
to right,
|
||||||
|
rgba($color-dark, 0) 8%,
|
||||||
|
rgba($color-dark, 0.3) 38%,
|
||||||
|
rgba($color-dark, 0) 54%
|
||||||
|
) no-repeat;
|
||||||
|
background-size: 1500px 100%;
|
||||||
animation: loading 1s infinite linear;
|
animation: loading 1s infinite linear;
|
||||||
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -43,7 +48,10 @@
|
||||||
left: $padding;
|
left: $padding;
|
||||||
|
|
||||||
border-radius: calc($border-radius-large - $padding);
|
border-radius: calc($border-radius-large - $padding);
|
||||||
background-color: rgba($color-background, 0.9);
|
background-color: darken($color-background, 10%);
|
||||||
|
background-image: url("/assets/Noise.png");
|
||||||
|
|
||||||
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,10 +65,10 @@
|
||||||
|
|
||||||
@keyframes loading{
|
@keyframes loading{
|
||||||
0%{
|
0%{
|
||||||
background-position: -500px 0
|
background-position: -750px 0
|
||||||
}
|
}
|
||||||
100%{
|
100%{
|
||||||
background-position: 500px 0
|
background-position: 750px 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -12,7 +12,7 @@ export async function getAnnouncements(): Promise<{ image: string }> {
|
||||||
cache["announcement_banner"] = {
|
cache["announcement_banner"] = {
|
||||||
image: "/banner_images/BannerExampleImage.jpg",
|
image: "/banner_images/BannerExampleImage.jpg",
|
||||||
};
|
};
|
||||||
await fakeDelay(200);
|
await fakeDelay(2000);
|
||||||
}
|
}
|
||||||
return cache["announcement_banner"];
|
return cache["announcement_banner"];
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ export async function getAnnouncements(): Promise<{ image: string }> {
|
||||||
export async function getPopularToday(): Promise<Item[]> {
|
export async function getPopularToday(): Promise<Item[]> {
|
||||||
if (cache["popular_today"] === undefined) {
|
if (cache["popular_today"] === undefined) {
|
||||||
cache["popular_today"] = TestData;
|
cache["popular_today"] = TestData;
|
||||||
await fakeDelay(200);
|
await fakeDelay(2000);
|
||||||
}
|
}
|
||||||
return cache["popular_today"];
|
return cache["popular_today"];
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ export async function getItemsByUUID(items: string[]): Promise<Item[]> {
|
||||||
|
|
||||||
if (data.length === 0) throw new Error("Resource could not be found");
|
if (data.length === 0) throw new Error("Resource could not be found");
|
||||||
|
|
||||||
await fakeDelay(200);
|
await fakeDelay(2000);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ export async function postContactEmail(
|
||||||
reason: string,
|
reason: string,
|
||||||
message: string
|
message: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
await fakeDelay(200);
|
await fakeDelay(2000);
|
||||||
|
|
||||||
if (!name) throw new Error("Name missing");
|
if (!name) throw new Error("Name missing");
|
||||||
if (!email) throw new Error("Email missing");
|
if (!email) throw new Error("Email missing");
|
||||||
|
|
|
@ -19,7 +19,7 @@ const TestData: Item[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uuid: "brick",
|
uuid: "brick",
|
||||||
availability: true,
|
availability: false,
|
||||||
name: "Brick",
|
name: "Brick",
|
||||||
price: 0,
|
price: 0,
|
||||||
description: `Example`,
|
description: `Example`,
|
||||||
|
@ -44,14 +44,14 @@ const TestData: Item[] = [
|
||||||
{
|
{
|
||||||
uuid: "mouldy_bread",
|
uuid: "mouldy_bread",
|
||||||
availability: true,
|
availability: true,
|
||||||
name: "half eaten mouldy bread",
|
name: "Singular slice of bread",
|
||||||
price: 0.39,
|
price: 0.39,
|
||||||
description: `Example`,
|
description: `Example`,
|
||||||
labels: [Labels.nut],
|
labels: [Labels.nut],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uuid: "cup_cake_leg",
|
uuid: "cup_cake_leg",
|
||||||
availability: false,
|
availability: true,
|
||||||
name: "Eated Cupcake",
|
name: "Eated Cupcake",
|
||||||
price: 1.69,
|
price: 1.69,
|
||||||
description: `
|
description: `
|
||||||
|
@ -68,15 +68,15 @@ Contains:
|
||||||
"/item_images/cupcake.jpg",
|
"/item_images/cupcake.jpg",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
uuid: "gwagwa",
|
// uuid: "gwagwa",
|
||||||
availability: false,
|
// availability: false,
|
||||||
name: "GwaGwa",
|
// name: "GwaGwa",
|
||||||
price: 69,
|
// price: 69,
|
||||||
description: `Example`,
|
// description: `Example`,
|
||||||
labels: [Labels.nut],
|
// labels: [Labels.nut],
|
||||||
images: ["/item_images/dab.jpg"],
|
// images: ["/item_images/dab.jpg"],
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
uuid: "hogmelon",
|
uuid: "hogmelon",
|
||||||
availability: true,
|
availability: true,
|
||||||
|
|
|
@ -23,6 +23,20 @@ export type CartItem = {
|
||||||
|
|
||||||
export type CartRecord = Record<string, CartItem>;
|
export type CartRecord = Record<string, CartItem>;
|
||||||
|
|
||||||
|
export type Checkout = {
|
||||||
|
personal: {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
phone?: number;
|
||||||
|
};
|
||||||
|
address: {
|
||||||
|
line1: string;
|
||||||
|
line2?: string;
|
||||||
|
town: string;
|
||||||
|
postcode: string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export type JSONResponse = {
|
export type JSONResponse = {
|
||||||
data?: {
|
data?: {
|
||||||
item: Item[]; // Todo Make this not just item type
|
item: Item[]; // Todo Make this not just item type
|
||||||
|
|
|
@ -1,72 +1,179 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { link } from "svelte-spa-router";
|
import { link } from "svelte-spa-router";
|
||||||
import { ArrowLeft, ArrowRight, Basket } from "phosphor-svelte";
|
import { ArrowLeft, SealWarning, ArrowRight } from "phosphor-svelte";
|
||||||
|
|
||||||
import PaymentForm from "./Checkout/PaymentForm.svelte";
|
import { type Checkout } from '../lib/types';
|
||||||
import LeFinal from "./Checkout/LeFinal.svelte";
|
import Cart from "../lib/cart";
|
||||||
|
|
||||||
export let params: {
|
const CheckoutData: Checkout = {
|
||||||
progress?: string;
|
personal: {
|
||||||
};
|
name: "",
|
||||||
|
email: "",
|
||||||
|
},
|
||||||
|
address: {
|
||||||
|
line1: "",
|
||||||
|
line2: "",
|
||||||
|
town: "",
|
||||||
|
postcode: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
$: nameValid = CheckoutData.personal.name.length > 1
|
||||||
|
$: emailValid = CheckoutData.personal.email.length > 1
|
||||||
|
$: phoneValid = isNaN(CheckoutData.personal.phone)
|
||||||
|
|
||||||
|
$: items = Cart.getEntries();
|
||||||
|
$: totalPrice = Cart.getTotalPrice();
|
||||||
|
|
||||||
|
let unavailableItems = false;
|
||||||
|
Cart.getEntries().forEach(([_, item]) => {
|
||||||
|
if (!item.data.availability) unavailableItems = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
function onSubmit() {
|
||||||
|
console.log(CheckoutData);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id="checkoutHeader">
|
<a href="/cart" use:link id="cancel-button"><ArrowLeft /> Cancel</a>
|
||||||
<a href="/cart" use:link id="cancel-button"><ArrowLeft /> Cancel</a>
|
<div class="spacer half" />
|
||||||
</div>
|
<div class="checkout">
|
||||||
|
<div id="form-container">
|
||||||
|
<h2>Checkout</h2>
|
||||||
|
<form on:submit|preventDefault={onSubmit} id="form">
|
||||||
|
<div class="form-element">
|
||||||
|
<label class="form-label" for="name">Name</label>
|
||||||
|
<input
|
||||||
|
bind:value={CheckoutData.personal.name}
|
||||||
|
type="text"
|
||||||
|
id="name"
|
||||||
|
class="form-input"
|
||||||
|
/>
|
||||||
|
<span class="form-notice error">
|
||||||
|
{#if !nameValid}Enter a name{/if}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="spacer half" />
|
||||||
|
<div class="form-element">
|
||||||
|
<label class="form-label" for="email">Email</label>
|
||||||
|
<input
|
||||||
|
bind:value={CheckoutData.personal.email}
|
||||||
|
type="text"
|
||||||
|
id="email"
|
||||||
|
class="form-input"
|
||||||
|
/>
|
||||||
|
<span class="form-notice error">
|
||||||
|
{#if !emailValid}Email not valid{/if}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="spacer half" />
|
||||||
|
<div class="form-element">
|
||||||
|
<label class="form-label" for="phone">Phone Number</label>
|
||||||
|
<input
|
||||||
|
bind:value={CheckoutData.personal.phone}
|
||||||
|
type="number"
|
||||||
|
id="phone"
|
||||||
|
class="form-input"
|
||||||
|
/>
|
||||||
|
<span class="form-notice error">
|
||||||
|
{#if !phoneValid}Phone Number not valid{/if}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{#if params.progress === "1"}
|
<div class="spacer" />
|
||||||
<PaymentForm />
|
<div class="spacer" />
|
||||||
<div id="checkoutFooter">
|
|
||||||
<div />
|
<div class="form-element">
|
||||||
<a href="/cart/checkout/2" use:link id="navigation-button">Order <ArrowRight /></a>
|
<label class="form-label" for="line1">Address Line 1</label>
|
||||||
|
<input
|
||||||
|
bind:value={CheckoutData.address.line1}
|
||||||
|
type="text"
|
||||||
|
id="line1"
|
||||||
|
class="form-input"
|
||||||
|
/>
|
||||||
|
<span class="form-notice error">Line 1 required</span>
|
||||||
|
</div>
|
||||||
|
<div class="spacer half" />
|
||||||
|
<div class="form-element">
|
||||||
|
<label class="form-label" for="line2">Address Line 2</label>
|
||||||
|
<input
|
||||||
|
bind:value={CheckoutData.address.line2}
|
||||||
|
type="text"
|
||||||
|
id="line2"
|
||||||
|
class="form-input"
|
||||||
|
/>
|
||||||
|
<span class="form-notice error"></span>
|
||||||
|
</div>
|
||||||
|
<div class="spacer half" />
|
||||||
|
<div class="form-element">
|
||||||
|
<label class="form-label" for="town">Town</label>
|
||||||
|
<input
|
||||||
|
bind:value={CheckoutData.address.town}
|
||||||
|
type="text"
|
||||||
|
id="town"
|
||||||
|
class="form-input"
|
||||||
|
/>
|
||||||
|
<span class="form-notice error">Town name required</span>
|
||||||
|
</div>
|
||||||
|
<div class="spacer half" />
|
||||||
|
<div class="spacer half" />
|
||||||
|
<div class="form-element">
|
||||||
|
<label class="form-label" for="postcode">Postcode</label>
|
||||||
|
<input
|
||||||
|
bind:value={CheckoutData.address.postcode}
|
||||||
|
type="text"
|
||||||
|
id="postcode"
|
||||||
|
class="form-input"
|
||||||
|
/>
|
||||||
|
<span class="form-notice error">Postcode required</span>
|
||||||
|
</div>
|
||||||
|
<div class="spacer half" />
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{:else if params.progress === "2"}
|
<div class="spacer" />
|
||||||
<LeFinal />
|
<div id="cart">
|
||||||
<div id="checkoutFooter">
|
<div class="container">
|
||||||
<a href="/cart/checkout/1" use:link id="navigation-button"><ArrowLeft /> Payment</a>
|
{#if unavailableItems}
|
||||||
<a href="/cart/checkout/3" use:link id="navigation-button">Confirm Purchase <ArrowRight /></a>
|
<div class="unavailable-items-banner">
|
||||||
|
<SealWarning weight="fill" /> <span>Order contains unavailable items</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="header">
|
||||||
|
<h2>Cart Total: ${totalPrice}</h2>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="section">
|
||||||
|
<div class="table">
|
||||||
|
<table>
|
||||||
|
<tr><th>Price</th><th>Item Name</th><th>Amount</th></tr>
|
||||||
|
{#each items as [_, item]}
|
||||||
|
<tr class:table-row-error={!item.data.availability}>
|
||||||
|
<td>£{item.data.price * item.amount} (£{item.data.price})</td>
|
||||||
|
<td>{item.data.name}</td>
|
||||||
|
<td>{item.amount}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div class="section">
|
||||||
|
<p>To make any changes to your order, <a href="/cart" use:link>return to the cart</a>.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="spacer half" />
|
||||||
|
<button id="checkout-button" form="form">Checkout <ArrowRight /></button>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
</div>
|
||||||
<div id="checkoutLost">
|
|
||||||
<h1>Something went wrong! <Basket weight="fill" /></h1>
|
|
||||||
<p>Return <a href="/cart/checkout/1" use:link>to checkout</a>.</p>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../styles/vars";
|
@import "../styles/vars";
|
||||||
|
|
||||||
#checkoutHeader {
|
#name { width: 300px; }
|
||||||
padding-bottom: $spacing-normal;
|
#email { width: 300px; }
|
||||||
|
#line1, #line2 { width: 400px; }
|
||||||
display: flex;
|
#town { width: 250px; }
|
||||||
flex-direction: row;
|
#postcode { width: 200px; }
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
> p {
|
|
||||||
padding: 0 $spacing-small;
|
|
||||||
|
|
||||||
width: max-content;
|
|
||||||
height: 30px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
font-size: $font-size-p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#checkoutFooter {
|
|
||||||
padding-top: $spacing-normal;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#cancel-button {
|
#cancel-button {
|
||||||
padding: 0 $spacing-small;
|
padding: 0 $spacing-small;
|
||||||
|
@ -82,7 +189,7 @@
|
||||||
font-size: $font-size-p;
|
font-size: $font-size-p;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
border-radius: 9999px;
|
border-radius: $border-radius-circle;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: $color-on-background;
|
color: $color-on-background;
|
||||||
|
|
||||||
|
@ -91,31 +198,8 @@
|
||||||
color: $color-on-error;
|
color: $color-on-error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#navigation-button {
|
|
||||||
padding: 0 $spacing-small;
|
|
||||||
|
|
||||||
width: max-content;
|
#checkoutError {
|
||||||
height: 30px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
font-size: $font-size-p;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
border-radius: 9999px;
|
|
||||||
background-color: $color-light;
|
|
||||||
color: $color-on-light;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: $color-dark;
|
|
||||||
color: $color-on-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#checkoutLost {
|
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
|
||||||
|
@ -140,16 +224,33 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice {
|
#checkout-button {
|
||||||
margin-right: auto;
|
padding: 0 $spacing-normal;
|
||||||
margin-bottom: $spacing-large;
|
|
||||||
margin-left: auto;
|
|
||||||
|
|
||||||
max-width: $sizing-default-width;
|
width: 100%;
|
||||||
height: 40px;
|
height: 35px;
|
||||||
|
|
||||||
position: sticky;
|
display: flex;
|
||||||
top: calc($spacing-small + $sizing-navigation-height);
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
font-size: $font-size-p;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
border-radius: $border-radius-circle;
|
||||||
|
border: 0 solid transparent;
|
||||||
|
background-color: $color-primary;
|
||||||
|
color: $color-on-primary;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $color-dark;
|
||||||
|
color: $color-on-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unavailable-items-banner {
|
||||||
|
height: 30px;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -157,15 +258,88 @@
|
||||||
|
|
||||||
font-size: $font-size-p;
|
font-size: $font-size-p;
|
||||||
|
|
||||||
border-radius: $border-radius-large;
|
background: $color-error;
|
||||||
background: $color-dark;
|
color: $color-on-error;
|
||||||
color: $color-on-dark;
|
|
||||||
|
|
||||||
box-shadow: 0 1px 0.5px rgba(#000, 0.3);
|
box-shadow: 0 1px 0.5px rgba(#000, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
&.error {
|
.table {
|
||||||
background: $color-error;
|
border-radius: $border-radius-normal;
|
||||||
color: $color-on-error;
|
border: 1px solid rgba($color-dark, 0.2);
|
||||||
|
background-color: $color-light;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
tr {
|
||||||
|
border-bottom: 1px solid rgba($color-dark, 0.2);
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
border: 0 solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.table-row-error {
|
||||||
|
background-color: $color-error;
|
||||||
|
color: $color-on-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: $spacing-xsmall $spacing-small;
|
||||||
|
font-size: $font-size-small;
|
||||||
|
border-right: 1px solid rgba($color-dark, 0.2);
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
border: 0 solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
font-weight: $font-weight-bolder;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
font-weight: $font-weight-normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkout {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: normal;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#form-container {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cart {
|
||||||
|
min-width: calc(400px - $spacing-normal);
|
||||||
|
width: 100%;
|
||||||
|
max-width: calc(400px - $spacing-normal);
|
||||||
|
|
||||||
|
position: sticky;
|
||||||
|
top: calc($sizing-navigation-height + $spacing-normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 900px) {
|
||||||
|
.checkout {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cart {
|
||||||
|
max-width: unset;
|
||||||
|
position: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -1,104 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { link } from "svelte-spa-router";
|
|
||||||
import { SealWarning } from "phosphor-svelte";
|
|
||||||
|
|
||||||
import Cart from "../../lib/cart";
|
|
||||||
|
|
||||||
let items = Cart.getEntries();
|
|
||||||
let totalPrice = Cart.getTotalPrice();
|
|
||||||
|
|
||||||
let unavailableItems = false;
|
|
||||||
Cart.getEntries().forEach(([_, item]) => {
|
|
||||||
if (!item.data.availability) unavailableItems = true;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<h1>Checkout > Order</h1>
|
|
||||||
<div class="container">
|
|
||||||
{#if unavailableItems}
|
|
||||||
<div class="unavailable-items-banner">
|
|
||||||
<SealWarning weight="fill" /> <span>Order contains an item that is no-longer available</span>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<div class="section small">
|
|
||||||
<div class="table">
|
|
||||||
<table>
|
|
||||||
<tr><th>Price (each)</th><th>Item Name</th><th>Amount</th></tr>
|
|
||||||
{#each items as [_, item]}
|
|
||||||
<tr>
|
|
||||||
<td>£{item.data.price * item.amount} (£{item.data.price})</td>
|
|
||||||
<td>{item.data.name}</td>
|
|
||||||
<td>{item.amount}</td>
|
|
||||||
</tr>
|
|
||||||
{/each}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="spacer half" />
|
|
||||||
|
|
||||||
<p>Total: ${totalPrice}</p>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="section small">
|
|
||||||
<p>To make any changes to your order, <a href="/cart" use:link>please go back to your cart</a>.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../../styles/vars";
|
|
||||||
|
|
||||||
.container {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unavailable-items-banner {
|
|
||||||
height: 30px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
font-size: $font-size-p;
|
|
||||||
|
|
||||||
background: $color-error;
|
|
||||||
color: $color-on-error;
|
|
||||||
|
|
||||||
box-shadow: 0 1px 0.5px rgba(#000, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
border-radius: $border-radius-normal;
|
|
||||||
border: 1px solid rgba($color-dark, 0.3);
|
|
||||||
background-color: $color-light;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
|
|
||||||
tr {
|
|
||||||
border-bottom: 1px solid rgba($color-dark, 0.3);
|
|
||||||
|
|
||||||
&:last-of-type {
|
|
||||||
border: 0 solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
th, td {
|
|
||||||
padding: $spacing-xsmall $spacing-small;
|
|
||||||
border-right: 1px solid rgba($color-dark, 0.3);
|
|
||||||
|
|
||||||
&:last-of-type {
|
|
||||||
border: 0 solid transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
font-weight: $font-weight-bolder;
|
|
||||||
}
|
|
||||||
td {
|
|
||||||
font-weight: $font-weight-normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,66 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { SealCheck } from "phosphor-svelte";
|
|
||||||
|
|
||||||
let name = "";
|
|
||||||
let email = "";
|
|
||||||
|
|
||||||
let nameValid = true;
|
|
||||||
let emailValid = true;
|
|
||||||
|
|
||||||
function validateName() { nameValid = name.length > 1 }
|
|
||||||
function validateEmail() { emailValid = email.length > 1 }
|
|
||||||
|
|
||||||
function onSubmit() {
|
|
||||||
validateName();
|
|
||||||
validateEmail();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<h1>Checkout > Payment</h1>
|
|
||||||
<form on:submit|preventDefault={onSubmit}>
|
|
||||||
<div class="form-element">
|
|
||||||
<label class="form-label" for="name">Name</label>
|
|
||||||
<input
|
|
||||||
bind:value={name}
|
|
||||||
on:blur={validateName}
|
|
||||||
on:input={validateName}
|
|
||||||
type="text"
|
|
||||||
id="name"
|
|
||||||
name="name"
|
|
||||||
class="form-input"
|
|
||||||
/>
|
|
||||||
<span class="form-notice error">
|
|
||||||
{#if !nameValid}
|
|
||||||
Enter a name
|
|
||||||
{/if}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="spacer half" />
|
|
||||||
|
|
||||||
<div class="form-element">
|
|
||||||
<label class="form-label" for="email">Email</label>
|
|
||||||
<input
|
|
||||||
bind:value={email}
|
|
||||||
on:blur={validateEmail}
|
|
||||||
on:input={validateEmail}
|
|
||||||
type="text"
|
|
||||||
id="email"
|
|
||||||
name="email"
|
|
||||||
class="form-input"
|
|
||||||
/>
|
|
||||||
<span class="form-notice error">
|
|
||||||
{#if !emailValid}
|
|
||||||
Email not valid
|
|
||||||
{/if}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="spacer half" />
|
|
||||||
|
|
||||||
<p class="form-message success"><SealCheck weight="fill" /> GwaGwa</p>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "../../styles/vars";
|
|
||||||
</style>
|
|
|
@ -40,11 +40,11 @@ const routes = {
|
||||||
conditions: [],
|
conditions: [],
|
||||||
userData: { showNavBar: true, fullWidth: false },
|
userData: { showNavBar: true, fullWidth: false },
|
||||||
}),
|
}),
|
||||||
"/cart/checkout/:progress?": wrap({
|
"/cart/checkout": wrap({
|
||||||
asyncComponent: () => import("./pages/Checkout.svelte"),
|
asyncComponent: () => import("./pages/Checkout.svelte"),
|
||||||
loadingComponent: PageLoading,
|
loadingComponent: PageLoading,
|
||||||
conditions: [],
|
conditions: [],
|
||||||
userData: { showNavBar: true, fullWidth: false },
|
userData: { showNavBar: true, fullWidth: true },
|
||||||
}),
|
}),
|
||||||
"/booking": wrap({
|
"/booking": wrap({
|
||||||
asyncComponent: () => import("./pages/Booking.svelte"),
|
asyncComponent: () => import("./pages/Booking.svelte"),
|
||||||
|
|
Loading…
Reference in a new issue