mirror of
				https://github.com/KevinMidboe/planetposen-frontend.git
				synced 2025-10-29 13:10:12 +00:00 
			
		
		
		
	Polls for order status & displays loading while status=initiated
This is the page sent to after the payment is verified clientside at /checkout. While status is only initiated and not updated from stripe webhook we display spinner. TODO should still timeout to content message
This commit is contained in:
		| @@ -1,10 +1,33 @@ | ||||
| import validOrderId from '$lib/utils/validOrderId'; | ||||
| import type { PageServerLoad } from './$types'; | ||||
|  | ||||
| export const load: PageServerLoad = ({ params }) => { | ||||
| export const load: PageServerLoad = async ({ fetch, params, url }) => { | ||||
|   const { id } = params; | ||||
|   const email = url.searchParams.get('email'); | ||||
|  | ||||
|   let order = null; | ||||
|  | ||||
|   try { | ||||
|     const res = await fetch(`/api/v1/order/${id}`); | ||||
|     if (res?.status === 404) { | ||||
|       return { | ||||
|         id, | ||||
|         email, | ||||
|         order: null | ||||
|       }; | ||||
|     } | ||||
|     const orderResponse = await res.json(); | ||||
|  | ||||
|     if (orderResponse?.order && orderResponse?.order?.lineItems?.length > 0) { | ||||
|       order = orderResponse?.order; | ||||
|     } | ||||
|   } catch (error) { | ||||
|     console.error('unable to parse order response'); | ||||
|     throw error; | ||||
|   } | ||||
|  | ||||
|   return { | ||||
|     id, | ||||
|     isValidReceipt: validOrderId(id) | ||||
|     email, | ||||
|     order | ||||
|   }; | ||||
| }; | ||||
|   | ||||
| @@ -1,14 +1,27 @@ | ||||
| <script lang="ts"> | ||||
|   import PoolInitiatedOrder from './PoolInitiatedOrder.svelte'; | ||||
|   import ReceiptNotFound from './ReceiptNotFound.svelte'; | ||||
|   import BadgeType from '$lib/interfaces/BadgeType'; | ||||
|  | ||||
|   import type { PageData } from './$types'; | ||||
|   import PageMeta from '$lib/components/PageMeta.svelte'; | ||||
|  | ||||
|   export let data: PageData; | ||||
|   const isValidReceipt = data.isValidReceipt as boolean; | ||||
|   const id = data.id as string; | ||||
|   let orderStatus: BadgeType = BadgeType.NOT_FOUND; | ||||
|  | ||||
|   if (data?.order) { | ||||
|     orderStatus = data.order?.status; | ||||
|   } | ||||
|  | ||||
|   const id = data?.id as string; | ||||
| </script> | ||||
|  | ||||
| {#if isValidReceipt} | ||||
|   <slot /> | ||||
| {:else} | ||||
| <PageMeta title="Kvittering" description="Søk og finn din ordre kvittering" /> | ||||
|  | ||||
| {#if orderStatus === BadgeType.NOT_FOUND} | ||||
|   <ReceiptNotFound id="{id}" /> | ||||
| {:else if orderStatus === BadgeType.INITIATED} | ||||
|   <PoolInitiatedOrder /> | ||||
| {:else} | ||||
|   <slot /> | ||||
| {/if} | ||||
|   | ||||
| @@ -1,17 +1,6 @@ | ||||
| import { redirect } from '@sveltejs/kit'; | ||||
| import validOrderId from '$lib/utils/validOrderId'; | ||||
| import type { Actions, PageServerLoad } from './$types'; | ||||
|  | ||||
| export const load: PageServerLoad = ({ params, url }) => { | ||||
|   const { id } = params; | ||||
|   const email = url.searchParams.get('email'); | ||||
|  | ||||
|   return { | ||||
|     id, | ||||
|     email | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export const actions: Actions = { | ||||
|   default: async ({ request }) => { | ||||
|     const data = await request.formData(); | ||||
| @@ -19,12 +8,8 @@ export const actions: Actions = { | ||||
|     const orderId = data.get('order-id'); | ||||
|     const email = data.get('order-email'); | ||||
|  | ||||
|     // TODO replace with posting form (json) to backend to check?? | ||||
|     // also return statusCode from the backend directly. | ||||
|     if (validOrderId(String(orderId)) && email) { | ||||
|       const receiptUrl = `/receipt/${orderId}?email=${email}`; | ||||
|       throw redirect(303, receiptUrl); | ||||
|     } | ||||
|     const receiptUrl = `/receipt/${orderId}?email=${email}`; | ||||
|     throw redirect(303, receiptUrl); | ||||
|  | ||||
|     return { success: false }; | ||||
|   } | ||||
|   | ||||
| @@ -1,8 +1,11 @@ | ||||
| <script lang="ts"> | ||||
|   import CircleCheckmark from '$lib/icons/CircleCheckmark.svelte'; | ||||
|   import { page } from '$app/stores'; | ||||
|   import CircleCheckmark from '$lib/components/loading/CircleCheckmark.svelte'; | ||||
|   import CircleError from '$lib/components/loading/CircleError.svelte'; | ||||
|  | ||||
|   import type { PageServerData } from './$types'; | ||||
|   import type { ILineItem, IOrder } from '$lib/interfaces/IOrder'; | ||||
|   import CircleWarning from '$lib/components/loading/CircleWarning.svelte'; | ||||
|  | ||||
|   function subTotal(lineItems: Array<ILineItem> = []) { | ||||
|     let total = 0; | ||||
| @@ -10,20 +13,32 @@ | ||||
|     return total; | ||||
|   } | ||||
|  | ||||
|   export let data: PageServerData; | ||||
|   const id = data.id as string; | ||||
|   const email = data.email as string; | ||||
|   const order = data.order as IOrder; | ||||
|   let id: string; | ||||
|   let email: string; | ||||
|   let order: IOrder; | ||||
|  | ||||
|   // export let currentRoute; | ||||
|   // const id = currentRoute?.namedParams?.id; | ||||
|   // const email = currentRoute?.queryParams?.email; | ||||
|   const { data } = $page; | ||||
|   if (data) { | ||||
|     id = data.id as string; | ||||
|     email = data.email || (data?.order?.customer?.email as string); | ||||
|     order = data.order as IOrder; | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <section class="order-confirmation"> | ||||
|   <CircleCheckmark /> | ||||
|   {#if order.status === 'SUCCESS' || order.status === 'CONFIRMED'} | ||||
|     <CircleCheckmark /> | ||||
|   {:else if order.status === 'CANCELLED' || order.status === 'REJECTED'} | ||||
|     <CircleError /> | ||||
|   {:else} | ||||
|     <CircleWarning /> | ||||
|   {/if} | ||||
|  | ||||
|   <h1>Takk for din bestilling!</h1> | ||||
|   {#if order.status === 'SUCCESS' || order.status === 'CONFIRMED'} | ||||
|     <h1>Takk for din bestilling!</h1> | ||||
|   {:else} | ||||
|     <h1>Bestilling ikke gjennomført!</h1> | ||||
|   {/if} | ||||
|  | ||||
|   <div class="order-description"> | ||||
|     <p> | ||||
| @@ -42,7 +57,7 @@ | ||||
|     {/each} | ||||
|     <p> | ||||
|       <code>Shipping</code> | ||||
|       <code>NOK 79</code> | ||||
|       <code>NOK 75</code> | ||||
|     </p> | ||||
|  | ||||
|     <p> | ||||
| @@ -55,6 +70,10 @@ | ||||
| <style lang="scss"> | ||||
|   @import './styles-receipt-page.scss'; | ||||
|  | ||||
|   .order-description .underline { | ||||
|     text-decoration: underline; | ||||
|   } | ||||
|  | ||||
|   .order-receipt { | ||||
|     background-color: #f7f7f7; | ||||
|     max-width: 500px; | ||||
|   | ||||
							
								
								
									
										60
									
								
								src/routes/receipt/[[id]]/PoolInitiatedOrder.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/routes/receipt/[[id]]/PoolInitiatedOrder.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| <script lang="ts"> | ||||
|   import { page } from '$app/stores'; | ||||
|   import { goto } from '$app/navigation'; | ||||
|   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; | ||||
|  | ||||
|   let maxPoolTime: Date = new Date(); | ||||
|   maxPoolTime.setSeconds(maxPoolTime.getSeconds() + 15); | ||||
|  | ||||
|   if (!id) { | ||||
|     console.log('no id found after all:('); | ||||
|   } | ||||
|  | ||||
|   function redirect() { | ||||
|     const url = `/receipt/${id}`; | ||||
|     window.location.href = url; | ||||
|     goto(url); | ||||
|   } | ||||
|  | ||||
|   function checkOrder() { | ||||
|     const url = buildApiUrl(`/api/v1/order/${id}`); | ||||
|     return fetch(url) | ||||
|       .then((resp) => resp.json()) | ||||
|       .then((response) => { | ||||
|         response?.order?.status !== 'INITIATED' ? redirect() : null; | ||||
|       }); | ||||
|   } | ||||
|  | ||||
|   function pool() { | ||||
|     if (new Date() < maxPoolTime) { | ||||
|       setTimeout(() => checkOrder().then(() => pool()), 1500); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   onMount(pool); | ||||
| </script> | ||||
|  | ||||
| <section class="order-confirmation"> | ||||
|   <CircleLoading /> | ||||
|  | ||||
|   <h1>Bestillingen din behandles</h1> | ||||
|  | ||||
|   <div class="order-description"> | ||||
|     <p>Vent noen sekunder mens betalingen din blir godkjent</p> | ||||
|   </div> | ||||
| </section> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   @import './styles-receipt-page.scss'; | ||||
|  | ||||
|   h1 { | ||||
|     text-align: center; | ||||
|   } | ||||
| </style> | ||||
| @@ -1,33 +1,16 @@ | ||||
| <script lang="ts"> | ||||
|   import Input from '$lib/components/Input.svelte'; | ||||
|   import PlanetButton from '$lib/components/Button.svelte'; | ||||
|   import CircleError from '$lib/icons/CircleError.svelte'; | ||||
|   import CircleWarning from '$lib/icons/CircleWarning.svelte'; | ||||
|  | ||||
|   const CircleComponent = Math.random() > 0.5 ? CircleWarning : CircleError; | ||||
|   import CircleWarning from '$lib/components/loading/CircleWarning.svelte'; | ||||
|  | ||||
|   export let id: string; | ||||
|  | ||||
|   // async function handleSubmit(event) { | ||||
|   //   const data = new FormData(this); | ||||
|   //   console.log('formdata::', data); | ||||
|  | ||||
|   //   const orderId = data.get('order-id'); | ||||
|   //   const orderEmail = data.get('order-email'); | ||||
|  | ||||
|   //   console.log('orderId:', orderId) | ||||
|   //   console.log('orderEmail:', orderEmail) | ||||
|  | ||||
|   //   const url = `/receipt/${orderId}?email=${orderEmail}`; | ||||
|   //   goto(url); | ||||
|   // } | ||||
|  | ||||
|   let searchOrderNumber: string; | ||||
|   let searchOrderEmail: string; | ||||
| </script> | ||||
|  | ||||
| <section class="order-confirmation"> | ||||
|   <svelte:component this="{CircleComponent}" /> | ||||
|   <CircleWarning /> | ||||
|  | ||||
|   <h1>Fant ikke din bestilling!</h1> | ||||
|  | ||||
| @@ -40,7 +23,8 @@ | ||||
|   <form class="order-search" method="POST"> | ||||
|     <span>Du kan forsøke søke opp din ordre her:</span> | ||||
|  | ||||
|     <Input name="order-id" label="Ordre id (hex)" bind:value="{searchOrderNumber}" /> | ||||
|     <Input name="order-id" label="Ordre id " bind:value="{searchOrderNumber}" /> | ||||
|     <br /> | ||||
|     <Input name="order-email" label="Epost adresse" bind:value="{searchOrderEmail}" /> | ||||
|  | ||||
|     <PlanetButton text="Søk" /> | ||||
| @@ -62,6 +46,10 @@ | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .underline { | ||||
|     text-decoration: underline; | ||||
|   } | ||||
|  | ||||
|   :global(.order-search button) { | ||||
|     margin-top: 1rem; | ||||
|   } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| @import '../../../styles/media-queries.scss'; | ||||
|  | ||||
| .order-confirmation { | ||||
|   margin: 6rem auto 0; | ||||
|   margin: 10rem auto 0; | ||||
|   display: grid; | ||||
|   place-items: center; | ||||
|   padding: 0 0.5rem; | ||||
| @@ -10,8 +10,6 @@ | ||||
|     margin-top: 3rem; | ||||
|   } | ||||
|  | ||||
|   // @include pageMargin; | ||||
|  | ||||
|   @include tablet { | ||||
|     padding: 0 1rem; | ||||
|   } | ||||
| @@ -31,8 +29,4 @@ | ||||
|   padding: 1rem; | ||||
|   margin: 1rem 0; | ||||
|   text-align: center; | ||||
|  | ||||
|   .underline { | ||||
|     text-decoration: underline; | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user