mirror of
https://github.com/KevinMidboe/planetposen-frontend.git
synced 2025-10-29 13:10:12 +00:00
Compare commits
4 Commits
ci/ghcr-pu
...
b56be97f86
| Author | SHA1 | Date | |
|---|---|---|---|
| b56be97f86 | |||
| 6d2550f2f3 | |||
| 71e053297e | |||
| 63a1107427 |
113
.drone.yml
113
.drone.yml
@@ -1,53 +1,130 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Lint and build project
|
||||
name: Build
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: Build project
|
||||
image: node:18
|
||||
- name: Install dependencies
|
||||
image: node:21-alpine3.17
|
||||
commands:
|
||||
- yarn
|
||||
- yarn build
|
||||
|
||||
- name: Lint project
|
||||
image: node:18
|
||||
image: node:21-alpine3.17
|
||||
commands:
|
||||
- yarn
|
||||
- yarn lint
|
||||
|
||||
- name: Build
|
||||
image: node:21-alpine3.17
|
||||
commands:
|
||||
- yarn build
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Compile docker image
|
||||
name: Publish
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: Build
|
||||
image: node:18
|
||||
commands:
|
||||
- yarn
|
||||
- yarn build
|
||||
|
||||
depends_on:
|
||||
- Lint and build project
|
||||
- name: Publish to ghcr
|
||||
image: plugins/docker
|
||||
settings:
|
||||
registry: ghcr.io
|
||||
repo: ghcr.io/kevinmidboe/${DRONE_REPO_NAME}
|
||||
dockerfile: Dockerfile
|
||||
username:
|
||||
from_secret: GITHUB_USERNAME
|
||||
password:
|
||||
from_secret: GHCR_UPLOAD_TOKEN
|
||||
tags:
|
||||
- latest
|
||||
- ${DRONE_COMMIT_SHA}
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
include:
|
||||
- push
|
||||
exclude:
|
||||
- pull_request
|
||||
branch:
|
||||
- main
|
||||
|
||||
depends_on:
|
||||
- Build
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: Deploy
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: Prepare kubernetes environment
|
||||
image: alpine/k8s:1.25.15
|
||||
environment:
|
||||
VAULT_TOKEN:
|
||||
from_secret: VAULT_TOKEN
|
||||
VAULT_HOST:
|
||||
from_secret: VAULT_HOST
|
||||
commands:
|
||||
- mkdir -p /root/.kube
|
||||
- echo "IMAGE=ghcr.io/kevinmidboe/${DRONE_REPO_NAME}:${DRONE_COMMIT_SHA}" > /root/.kube/.env
|
||||
- echo "NAMESPACE=${DRONE_REPO_NAME}" >> /root/.kube/.env
|
||||
- 'curl -s
|
||||
-H "X-Vault-Token: $VAULT_TOKEN"
|
||||
$VAULT_HOST/v1/schleppe/data/kazan/_infra
|
||||
| jq -r ".data.data.KUBE_CONFIG" > /root/.kube/config'
|
||||
- 'curl -s
|
||||
-H "X-Vault-Token: $VAULT_TOKEN"
|
||||
$VAULT_HOST/v1/schleppe/data/kazan/_infra
|
||||
| jq -cr ".data.data | .[\"ghcr-login-secret\"] | @base64" > /root/.kube/dockerconfig.json'
|
||||
- echo "DOCKER_CONFIG=$(cat /root/.kube/dockerconfig.json)" >> /root/.kube/.env
|
||||
- sed -i '/^$/!s/^/export /' /root/.kube/.env
|
||||
volumes:
|
||||
- name: kube-config
|
||||
path: /root/.kube
|
||||
|
||||
- name: Deploy to kubernetes
|
||||
image: alpine/k8s:1.25.15
|
||||
commands:
|
||||
- source /root/.kube/.env > /dev/null 2>&1
|
||||
- cat .kubernetes/*.yml
|
||||
| envsubst
|
||||
| kubectl --kubeconfig=/root/.kube/config apply -f -
|
||||
volumes:
|
||||
- name: kube-config
|
||||
path: /root/.kube
|
||||
|
||||
trigger:
|
||||
event:
|
||||
include:
|
||||
- push
|
||||
exclude:
|
||||
- pull_request
|
||||
branch:
|
||||
- main
|
||||
|
||||
depends_on:
|
||||
- Build
|
||||
- Publish
|
||||
|
||||
volumes:
|
||||
- name: kube-config
|
||||
temp: {}
|
||||
|
||||
---
|
||||
kind: signature
|
||||
hmac: 84765f19d995d66f1d3409c4eddd1f68d1f2d297d65cd9e2612e6bb13e8ecb94
|
||||
hmac: 1e803c7610cc5d3b586af3f10228a4a3477d877538813dee6c366c952771e3e0
|
||||
|
||||
...
|
||||
|
||||
7
.kubernetes/0-Namespace.yml
Normal file
7
.kubernetes/0-Namespace.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: planet
|
||||
labels:
|
||||
name: planet
|
||||
41
.kubernetes/deployment.yml
Normal file
41
.kubernetes/deployment.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
app: planet-frontend
|
||||
name: planet-frontend
|
||||
namespace: planet
|
||||
spec:
|
||||
progressDeadlineSeconds: 600
|
||||
replicas: 2
|
||||
revisionHistoryLimit: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app: planet-frontend
|
||||
strategy:
|
||||
rollingUpdate:
|
||||
maxSurge: 25%
|
||||
maxUnavailable: 25%
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: planet-frontend
|
||||
spec:
|
||||
containers:
|
||||
- image: ${IMAGE}
|
||||
imagePullPolicy: Always
|
||||
name: planet-frontend
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
imagePullSecrets:
|
||||
- name: ghcr-login-secret
|
||||
dnsPolicy: ClusterFirst
|
||||
restartPolicy: Always
|
||||
schedulerName: default-scheduler
|
||||
securityContext: {}
|
||||
terminationGracePeriodSeconds: 30
|
||||
|
||||
19
.kubernetes/ingress.yml
Normal file
19
.kubernetes/ingress.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: planet-frontend-ingress
|
||||
namespace: planet
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: planet.kazan.schleppe.cloud
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: planet-frontend-service
|
||||
port:
|
||||
number: 80
|
||||
path: /
|
||||
pathType: Prefix
|
||||
18
.kubernetes/service.yml
Normal file
18
.kubernetes/service.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: planet-frontend
|
||||
name: planet-frontend-service
|
||||
namespace: planet
|
||||
spec:
|
||||
selector:
|
||||
app: planet-frontend
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 3000
|
||||
sessionAffinity: None
|
||||
|
||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
# Build the project
|
||||
FROM node:18-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN yarn
|
||||
RUN yarn build
|
||||
|
||||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /app/build build/
|
||||
COPY --from=builder /app/node_modules node_modules/
|
||||
COPY package.json .
|
||||
|
||||
EXPOSE 3000
|
||||
ENV NODE_ENV=production
|
||||
|
||||
CMD [ "node", "build" ]
|
||||
@@ -12,6 +12,7 @@
|
||||
"format": "prettier --plugin-search-dir . --write src"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-node": "^4.0.1",
|
||||
"@sveltejs/adapter-static": "1.0.0",
|
||||
"@sveltejs/kit": "1.0.1",
|
||||
"@types/cookie": "0.5.1",
|
||||
@@ -34,4 +35,4 @@
|
||||
"dependencies": {
|
||||
"@stripe/stripe-js": "1.46.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { env } from '$env/dynamic/private';
|
||||
import type { HandleFetch } from '@sveltejs/kit';
|
||||
|
||||
export const handleFetch: HandleFetch = async ({ request, fetch }) => {
|
||||
const { origin } = new URL(request.url);
|
||||
const host = env?.API_HOST || 'http://localhost:30010';
|
||||
|
||||
if (request.url.startsWith(`${origin}/api`)) {
|
||||
// clone the original request, but change the URL
|
||||
request = new Request(request.url.replace(origin, 'http://localhost:30010'), request);
|
||||
request = new Request(request.url.replace(origin, host), request);
|
||||
}
|
||||
|
||||
return fetch(request);
|
||||
|
||||
@@ -10,19 +10,20 @@
|
||||
|
||||
const textImages: Array<IFrontTextImage> = [
|
||||
{
|
||||
title: 'Vårt oppdrag',
|
||||
text: 'The new fabulous museum at Kistefos, designed by world renowned architect Bjarke Ingels Group, BIG, opened Wednesday September 18th, 2019. The building has been named the top architectural museum project in the world to open in 2019, by both the Daily Telegraph and Bloomberg.',
|
||||
title: 'Our story',
|
||||
text: 'I started making fabric gift bags as a way to combat the wastefulness of traditional paper packaging. As a lifelong crafter and DIY enthusiast, I wanted to create a product that was both beautiful and sustainable. After experimenting with different materials and designs, I landed on the perfect formula for a reusable fabric gift bag that was both eco-friendly and functional.',
|
||||
image: 'https://storage.googleapis.com/planetposen-images/front-kf-1.jpg'
|
||||
},
|
||||
{
|
||||
title: 'Paper waste and the planet',
|
||||
text: "As the 50th artwork to be included in the park, a site-specific new commission by French artist Pierre Huyghe (b. 1962, Paris) was opened on the 12th of June. The vast permanent work will be the artist's largest site-specific work to date and the most ambitious to ever be conceived for Kistefos.",
|
||||
title: 'Eco-Friendly Materials',
|
||||
text: 'Our bags are made from organic cotton or recycled fabric, both of which are sustainably sourced and responsibly produced. By choosing to use our bags instead of disposable paper or plastic packaging, you are making a positive impact on the environment and reducing your carbon footprint.',
|
||||
imageRight: true,
|
||||
image: 'https://storage.googleapis.com/planetposen-images/front-kf-2.jpg'
|
||||
// image: 'https://storage.googleapis.com/planetposen-images/front-kf-2.jpg'
|
||||
image: 'https://storage.googleapis.com/planetposen-images/bags_backyard-upscaled-2.jpeg'
|
||||
},
|
||||
{
|
||||
title: 'Our goal',
|
||||
text: 'The scenic sculpture park has an impressive collection of works by internationally renowned contemporary artists including Anish Kapoor, Jeppe Hein, Tony Cragg, Olafur Eliasson, Fernando Bottero and Elmgreen & Dragset. The sculpture park focus is sight specific and international contemporary works of art and is available all year.',
|
||||
title: 'Gift Ideas',
|
||||
text: "Whether you're looking for a birthday present, a wedding gift, or a holiday surprise, our fabric gift bags are the perfect way to add a personal touch to any occasion. Use our bags to wrap a variety of gifts, from jewelry and accessories to small electronics and gadgets. Not sure where to start? Check out our gallery for inspiration!",
|
||||
image: 'https://storage.googleapis.com/planetposen-images/front-kf-3.jpg'
|
||||
},
|
||||
{
|
||||
@@ -32,8 +33,8 @@
|
||||
image: 'https://storage.googleapis.com/planetposen-images/front-bee-1.jpg'
|
||||
},
|
||||
{
|
||||
title: 'Sculpture park of international standing',
|
||||
text: 'The scenic sculpture park has an impressive collection of works by internationally renowned contemporary artists including Anish Kapoor, Jeppe Hein, Tony Cragg, Olafur Eliasson, Fernando Bottero and Elmgreen & Dragset. The sculpture park focus is sight specific and international contemporary works of art and is available all year.',
|
||||
title: 'Gift Ideas',
|
||||
text: '',
|
||||
imageRight: false,
|
||||
image: 'https://storage.googleapis.com/planetposen-images/front-bee-2.jpg'
|
||||
}
|
||||
@@ -42,12 +43,12 @@
|
||||
const textTitle: Array<IFrontText> = [
|
||||
{
|
||||
title: 'Katy Vandekerckhove:',
|
||||
text: 'Kistefos was really a jewel on earth with high level art in fantastic surroundings',
|
||||
text: 'Give a gift that keeps on giving - our fabric gift bags are reusable, eco-friendly, and stylish.',
|
||||
color: '#27615d'
|
||||
},
|
||||
{
|
||||
title: 'Katy Vandekerckhove:',
|
||||
text: 'Kistefos was really a jewel on earth with high level art in fantastic surroundings',
|
||||
text: 'Wrap it up in style and sustainability with planetposen fabric gift bags.',
|
||||
color: 'orange'
|
||||
}
|
||||
];
|
||||
@@ -104,7 +105,10 @@
|
||||
<FrontText data="{textTitle[0]}" />
|
||||
|
||||
<FrontTextImage data="{textImages[3]}" />
|
||||
|
||||
<!--
|
||||
<FrontTextImage data="{textImages[4]}" />
|
||||
-->
|
||||
|
||||
<FrontText data="{textTitle[1]}" />
|
||||
</section>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
1
src/routes/_health/+server.ts
Normal file
1
src/routes/_health/+server.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const GET = () => new Response('ok');
|
||||
@@ -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%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import adapter from '@sveltejs/adapter-node';
|
||||
import preprocess from 'svelte-preprocess';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
@@ -7,6 +8,7 @@ const config = {
|
||||
preprocess: preprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
csrf: {
|
||||
checkOrigin: false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user