mirror of
https://github.com/KevinMidboe/planetposen-frontend.git
synced 2025-10-29 13:10:12 +00:00
Patch: Receipt page (#7)
* OrderSection receipts list of lineItems instead of always getting cart * Hide express checkout behind feature flag * Add torn receipt paper css look to order list * Re-use OrderSection on receipt page * Linting * Reduced max font from 130->120%, now only applies scaling on div.main Reducing relative font size for the largest screen width. Scaling only applies to main container, not header and footer. * Minor header size changes * Set max-width to login input elements on desktop * Prettier doesn't liek shorthand props
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
|
||||
<footer>
|
||||
<section>
|
||||
<h2>Personvern og vilkår</h2>
|
||||
<h1>Personvern og vilkår</h1>
|
||||
<ul>
|
||||
<li><LinkArrow /><a href="/terms-and-conditions">Betingelser og vilkår</a></li>
|
||||
<li><LinkArrow /><a href="/privacy-policy">Personvernerklæring</a></li>
|
||||
@@ -31,7 +31,7 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Kontakt</h2>
|
||||
<h1>Kontakt</h1>
|
||||
<ul>
|
||||
<li>Epost: <a class="link" href="mailto:post@planetposen.no">post@planetposen.no</a></li>
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
Kode: <a
|
||||
class="link"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://github.com/search?q=user%3Akevinmidboe+sort%3Aupdated+planetposen&type=repositories"
|
||||
>github.com</a
|
||||
>
|
||||
@@ -60,10 +61,6 @@
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
|
||||
h2 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
section {
|
||||
width: 30%;
|
||||
padding: 2rem;
|
||||
@@ -97,7 +94,7 @@
|
||||
flex-direction: column;
|
||||
padding: 3rem 0.5rem;
|
||||
|
||||
h2 {
|
||||
h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import CheckoutButton from '$lib/components/Button.svelte';
|
||||
import StripeCard from '$lib/components/StripeCard.svelte';
|
||||
import ErrorStack from '$lib/components/ErrorStack.svelte';
|
||||
import { cart } from '$lib/cartStore';
|
||||
import { cart, subTotal } from '$lib/cartStore';
|
||||
import stripeApi from '$lib/stripe/index';
|
||||
import { OrderSubmitUnsuccessfullError } from '$lib/errors/OrderErrors';
|
||||
import Loading from '$lib/components/loading/index.svelte';
|
||||
@@ -28,6 +28,7 @@
|
||||
let card: StripeCardElement;
|
||||
let form: HTMLFormElement;
|
||||
let errors: string[] = [];
|
||||
let showExpressCheckout = false;
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
let resolvePaymentPromise: (value: any) => void;
|
||||
@@ -147,13 +148,15 @@
|
||||
|
||||
<form class="checkout" bind:this="{form}" on:submit|preventDefault="{postOrder}">
|
||||
<div class="main">
|
||||
<section class="express-checkout" style="display: block;">
|
||||
<h2>Hurtigkasse</h2>
|
||||
{#if showExpressCheckout}
|
||||
<section class="express-checkout" style="display: block;">
|
||||
<h2>Hurtigkasse</h2>
|
||||
|
||||
<ExpressSection />
|
||||
<ExpressSection />
|
||||
|
||||
<p style="margin: 0 0 -0.5rem 0.5rem; text-align: left; color: rgba(0,0,0,0.5);">eller</p>
|
||||
</section>
|
||||
<p style="margin: 0 0 -0.5rem 0.5rem; text-align: left; color: rgba(0,0,0,0.5);">eller</p>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<section id="delivery">
|
||||
<h2>Leveringsaddresse</h2>
|
||||
@@ -178,7 +181,7 @@
|
||||
<aside class="sidebar">
|
||||
<section id="order">
|
||||
<h2>Din ordre</h2>
|
||||
<OrderSection />
|
||||
<OrderSection lineItems="{$cart}" subTotal="{$subTotal}" />
|
||||
</section>
|
||||
</aside>
|
||||
</form>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Vipps from '$lib/icons/Vipps.svelte';
|
||||
import ShopPay from '$lib/icons/ShopPay.svelte';
|
||||
import ApplePay from '$lib/icons/ApplePay.svelte';
|
||||
import PayPal from '$lib/icons/PayPal.svelte';
|
||||
import GooglePay from '$lib/icons/GooglePay.svelte';
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
<script lang="ts">
|
||||
import OrderTotalSection from './OrderTotalSection.svelte';
|
||||
import QuantitySelect from '$lib/components/QuantitySelect.svelte';
|
||||
import type ICart from '$lib/interfaces/ICart';
|
||||
|
||||
import { cart, subTotal } from '$lib/cartStore';
|
||||
import { decrementProductInCart, incrementProductInCart } from '$lib/websocketCart';
|
||||
|
||||
const shippingPrice = 75;
|
||||
$: totalPrice = $subTotal + shippingPrice;
|
||||
|
||||
function lineItemClass(id: number) {
|
||||
return `lineitem-${id}`;
|
||||
}
|
||||
export let lineItems: ICart[];
|
||||
export let subTotal: number;
|
||||
</script>
|
||||
|
||||
<div class="order-summary">
|
||||
@@ -26,7 +19,7 @@
|
||||
</thead>
|
||||
|
||||
<tbody data-order-summary-section="line-items">
|
||||
{#each $cart as cartItem}
|
||||
{#each lineItems as lineItem}
|
||||
<tr
|
||||
class="product"
|
||||
data-product-id="6718367989809"
|
||||
@@ -40,18 +33,18 @@
|
||||
<img
|
||||
alt="Black Googly Eye Puff Print Logo Tee - XS"
|
||||
class="product-thumbnail__image"
|
||||
src="{cartItem.image}"
|
||||
src="{lineItem.image}"
|
||||
data-src="//cdn.shopify.com/s/files/1/0023/3789/8540/products/20220718_A24_GooglyEye_Tee_Black_15991x1gray_small.jpg?v=1659020903"
|
||||
/>
|
||||
</div>
|
||||
<span class="product-thumbnail__quantity" aria-hidden="true">{cartItem.quantity}</span
|
||||
<span class="product-thumbnail__quantity" aria-hidden="true">{lineItem.quantity}</span
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
<th class="product__description" scope="row">
|
||||
<span class="product__description__name order-summary__emphasis">{cartItem.name}</span>
|
||||
<span class="product__description__name order-summary__emphasis">{lineItem.name}</span>
|
||||
<span class="product__description__variant order-summary__small-text"
|
||||
>{cartItem.size}</span
|
||||
>{lineItem.size}</span
|
||||
>
|
||||
</th>
|
||||
<td class="product__quantity">
|
||||
@@ -59,7 +52,7 @@
|
||||
</td>
|
||||
<td class="product__price">
|
||||
<p class="order-summary__emphasis skeleton-while-loading">
|
||||
NOK {cartItem.quantity * cartItem.price}
|
||||
NOK {lineItem.quantity * lineItem.price}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -68,7 +61,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<OrderTotalSection />
|
||||
<OrderTotalSection subTotal="{subTotal}" />
|
||||
</div>
|
||||
|
||||
<style lang="scss" module="scoped">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { subTotal } from '$lib/cartStore';
|
||||
export let subTotal: number;
|
||||
</script>
|
||||
|
||||
<div class="total">
|
||||
@@ -19,7 +19,7 @@
|
||||
class="order-summary__emphasis skeleton-while-loading"
|
||||
data-checkout-subtotal-price-target="4000"
|
||||
>
|
||||
Nok {$subTotal}
|
||||
Nok {subTotal}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -58,7 +58,7 @@
|
||||
<td class="price payment-due" data-presentment-currency="NOK">
|
||||
<span class="payment-due__currency remove-while-loading">Nok</span>
|
||||
<span class="price skeleton-while-loading--lg" data-checkout-payment-due-target="4000">
|
||||
{$subTotal + 75}
|
||||
{subTotal + 75}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -62,13 +62,14 @@
|
||||
<style lang="scss" module="scoped">
|
||||
@import '../../styles/media-queries.scss';
|
||||
|
||||
@include desktop {
|
||||
section {
|
||||
margin: 20% 2rem;
|
||||
width: 60%;
|
||||
section {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
|
||||
@include desktop {
|
||||
margin: 20% auto;
|
||||
}
|
||||
}
|
||||
|
||||
.signin-button {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export const load: PageServerLoad = async ({ fetch, params }) => {
|
||||
const { id } = params;
|
||||
|
||||
const res = await fetch(`/api/v1/order/${id}`);
|
||||
const orderResponse = await res.json();
|
||||
const orderResponse: IOrderDTO = await res.json();
|
||||
|
||||
if (orderResponse?.success == false || orderResponse?.order === undefined) {
|
||||
console.log('throwing error', orderResponse);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
import type { Actions } from './$types';
|
||||
|
||||
export const actions: Actions = {
|
||||
default: async ({ request }) => {
|
||||
@@ -10,8 +10,6 @@ export const actions: Actions = {
|
||||
|
||||
const receiptUrl = `/receipt/${orderId}?email=${email}`;
|
||||
throw redirect(303, receiptUrl);
|
||||
|
||||
return { success: false };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,17 +2,11 @@
|
||||
import { page } from '$app/stores';
|
||||
import CircleCheckmark from '$lib/components/loading/CircleCheckmark.svelte';
|
||||
import CircleError from '$lib/components/loading/CircleError.svelte';
|
||||
import OrderSection from '../../checkout/OrderSection.svelte';
|
||||
|
||||
import type { PageServerData } from './$types';
|
||||
import type { ILineItem, IOrder } from '$lib/interfaces/IOrder';
|
||||
import type { IOrder } from '$lib/interfaces/IOrder';
|
||||
import CircleWarning from '$lib/components/loading/CircleWarning.svelte';
|
||||
|
||||
function subTotal(lineItems: Array<ILineItem> = []) {
|
||||
let total = 0;
|
||||
lineItems.forEach((lineItem) => (total = total + lineItem.price * lineItem.quantity));
|
||||
return total;
|
||||
}
|
||||
|
||||
let id: string;
|
||||
let email: string;
|
||||
let order: IOrder;
|
||||
@@ -23,6 +17,8 @@
|
||||
email = data.email || (data?.order?.customer?.email as string);
|
||||
order = data.order as IOrder;
|
||||
}
|
||||
|
||||
$: subTotal = Math.round((order?.payment?.amount || 1) / 100);
|
||||
</script>
|
||||
|
||||
<section class="order-confirmation">
|
||||
@@ -49,21 +45,9 @@
|
||||
</div>
|
||||
|
||||
<div class="order-receipt">
|
||||
{#each order?.lineItems as lineItem}
|
||||
<p>
|
||||
<code>{lineItem.name} x{lineItem.quantity}</code>
|
||||
<code>NOK {lineItem.price * lineItem.quantity}</code>
|
||||
</p>
|
||||
{/each}
|
||||
<p>
|
||||
<code>Shipping</code>
|
||||
<code>NOK 75</code>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<code>Total</code>
|
||||
<code>NOK {subTotal(order?.lineItems)}</code>
|
||||
</p>
|
||||
<div class="receipt-box">
|
||||
<OrderSection lineItems="{order?.lineItems}" subTotal="{subTotal}" } />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -75,30 +59,52 @@
|
||||
}
|
||||
|
||||
.order-receipt {
|
||||
background-color: #f7f7f7;
|
||||
max-width: 500px;
|
||||
--receipt_color: #f7f7f7;
|
||||
--tearOffHeight: 8px;
|
||||
background-color: var(--receipt_color);
|
||||
max-width: 800px;
|
||||
width: calc(100% - 4rem);
|
||||
padding: 2rem;
|
||||
font-family: monospace;
|
||||
position: relative;
|
||||
|
||||
p {
|
||||
margin: 0.8rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid lightgrey;
|
||||
/* Paper background effect */
|
||||
.receipt-box {
|
||||
height: auto;
|
||||
overflow: hidden;
|
||||
padding: 1rem;
|
||||
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.05);
|
||||
|
||||
&:last-of-type {
|
||||
padding-top: 1.5rem;
|
||||
border-width: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
opacity: 0.4;
|
||||
font-size: 1rem;
|
||||
|
||||
&:first-of-type {
|
||||
font-weight: 600;
|
||||
&::after {
|
||||
content: '';
|
||||
height: var(--tearOffHeight);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: calc(var(--tearOffHeight) * -1);
|
||||
background-color: var(--receipt_color);
|
||||
clip-path: polygon(
|
||||
0% 0%,
|
||||
5% 100%,
|
||||
10% 0%,
|
||||
15% 100%,
|
||||
20% 0%,
|
||||
25% 100%,
|
||||
30% 0%,
|
||||
35% 100%,
|
||||
40% 0%,
|
||||
45% 100%,
|
||||
50% 0%,
|
||||
55% 100%,
|
||||
60% 0%,
|
||||
65% 100%,
|
||||
70% 0%,
|
||||
75% 100%,
|
||||
80% 0%,
|
||||
85% 100%,
|
||||
90% 0%,
|
||||
95% 100%,
|
||||
100% 0%
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import { onMount } from 'svelte';
|
||||
import CircleLoading from '$lib/components/loading/CircleLoading.svelte';
|
||||
import { buildApiUrl } from '$lib/utils/apiUrl';
|
||||
import type { PageServerData } from './$types';
|
||||
|
||||
const { data } = $page;
|
||||
const id = data?.id as string;
|
||||
@@ -22,7 +21,7 @@
|
||||
goto(url);
|
||||
}
|
||||
|
||||
function checkOrder() {
|
||||
async function checkOrder() {
|
||||
const url = buildApiUrl(`/api/v1/order/${id}`);
|
||||
return fetch(url)
|
||||
.then((resp) => resp.json())
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import ProductTile from '$lib/components/ProductTile.svelte';
|
||||
import ProductVariationSelect from '$lib/components/ProductVariationSelect.svelte';
|
||||
import QuantitySelect from '$lib/components/QuantitySelect.svelte';
|
||||
import SizesSection from './SizesSection.svelte';
|
||||
@@ -98,7 +97,7 @@
|
||||
|
||||
.details {
|
||||
.name {
|
||||
font-size: 2rem;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.description {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
html {
|
||||
body .app main {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
@@ -56,11 +56,11 @@ a.link {
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1rem;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.no-scroll {
|
||||
@@ -104,12 +104,12 @@ button:focus:not(:focus-visible) {
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1500px) {
|
||||
html {
|
||||
body .app main {
|
||||
font-size: 110%;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 2000px) {
|
||||
html {
|
||||
font-size: 130%;
|
||||
body .app main {
|
||||
font-size: 125%;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user