checkout + moved cart to only show on product relevant pages
This commit is contained in:
parent
bc75aef3c6
commit
a362c9a7ce
6 changed files with 229 additions and 139 deletions
213
src/lib/components/checkout.svelte
Normal file
213
src/lib/components/checkout.svelte
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cart } from '$lib/stores/cart';
|
||||||
|
|
||||||
|
let formData = {
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
email: '',
|
||||||
|
country: '',
|
||||||
|
phoneNumber: '',
|
||||||
|
district: '',
|
||||||
|
block: '',
|
||||||
|
street: '',
|
||||||
|
avenue: '',
|
||||||
|
buildingNumber: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
// Here you'll integrate payment processing later
|
||||||
|
console.log('Form submitted:', formData);
|
||||||
|
console.log('Cart items:', $cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateTotal(items: any[]) {
|
||||||
|
return items.reduce((sum, item) =>
|
||||||
|
sum + (item.variant.calculated_price.calculated_amount * item.quantity), 0
|
||||||
|
).toFixed(2);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="min-h-screen bg-base-100">
|
||||||
|
<div class="container mx-auto px-4 py-8">
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||||
|
<!-- Order Summary -->
|
||||||
|
<div class="lg:col-span-1 h-fit bg-base-200 rounded-lg p-6">
|
||||||
|
<h2 class="text-xl font-bold mb-4">Order Summary</h2>
|
||||||
|
<div class="space-y-3 mb-4">
|
||||||
|
{#each $cart as item}
|
||||||
|
<div class="flex justify-between items-start text-sm border-b border-base-300 pb-2">
|
||||||
|
<div class="flex-1">
|
||||||
|
<p class="font-medium">{item.product.title}</p>
|
||||||
|
<p class="text-xs text-base-content/70">
|
||||||
|
{item.variant.title} × {item.quantity}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p class="font-medium ml-4">{(item.variant.calculated_price.calculated_amount * item.quantity).toFixed(2)} €</p>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center pt-4">
|
||||||
|
<span class="text-lg font-bold">Total:</span>
|
||||||
|
<span class="text-lg font-bold">{calculateTotal($cart)} €</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Shipping Details Form -->
|
||||||
|
<form class="lg:col-span-2 space-y-6 bg-base-200 rounded-lg p-6" on:submit|preventDefault={handleSubmit}>
|
||||||
|
<h2 class="text-xl font-bold">Shipping Details</h2>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="firstName">
|
||||||
|
<span class="label-text">First Name</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="firstName"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.firstName}
|
||||||
|
placeholder="John"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="lastName">
|
||||||
|
<span class="label-text">Last Name</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="lastName"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.lastName}
|
||||||
|
placeholder="Doe"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="email">
|
||||||
|
<span class="label-text">Email</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
id="email"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.email}
|
||||||
|
placeholder="john.doe@example.com"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="country">
|
||||||
|
<span class="label-text">Country</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="country"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.country}
|
||||||
|
placeholder="Kuwait"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="phoneNumber">
|
||||||
|
<span class="label-text">Phone Number</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="tel"
|
||||||
|
id="phoneNumber"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.phoneNumber}
|
||||||
|
placeholder="+96596596596"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="district">
|
||||||
|
<span class="label-text">District</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="district"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.district}
|
||||||
|
placeholder="Al-Rai"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="block">
|
||||||
|
<span class="label-text">Block</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="block"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.block}
|
||||||
|
placeholder="2"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="street">
|
||||||
|
<span class="label-text">Street</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="street"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.street}
|
||||||
|
placeholder="203"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="avenue">
|
||||||
|
<span class="label-text">Avenue (optional)</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="avenue"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.avenue}
|
||||||
|
placeholder="31"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label" for="buildingNumber">
|
||||||
|
<span class="label-text">Building Number</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="buildingNumber"
|
||||||
|
class="input input-bordered w-full"
|
||||||
|
bind:value={formData.buildingNumber}
|
||||||
|
placeholder="12"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary w-full">
|
||||||
|
Continue to Payment
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -59,7 +59,7 @@ function createCartStore() {
|
||||||
autoCloseTimeout = window.setTimeout(() => {
|
autoCloseTimeout = window.setTimeout(() => {
|
||||||
isOpenStore.set(false);
|
isOpenStore.set(false);
|
||||||
autoCloseTimeout = undefined;
|
autoCloseTimeout = undefined;
|
||||||
}, 2000);
|
}, 800);
|
||||||
},
|
},
|
||||||
updateQuantity: (index: number, quantity: number) => {
|
updateQuantity: (index: number, quantity: number) => {
|
||||||
update(items => {
|
update(items => {
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import Header from '$lib/components/Header.svelte';
|
import Header from '$lib/components/Header.svelte';
|
||||||
import Footer from '$lib/components/Footer.svelte';
|
import Footer from '$lib/components/Footer.svelte';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import MiniCart from '$lib/components/mini-cart.svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
@ -18,9 +17,6 @@
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
||||||
<!-- Mini Cart -->
|
|
||||||
<MiniCart />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -1,136 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cart } from '$lib/stores/cart';
|
import Checkout from '$lib/components/checkout.svelte';
|
||||||
|
|
||||||
let formData = {
|
|
||||||
name: '',
|
|
||||||
email: '',
|
|
||||||
country: '',
|
|
||||||
address: '',
|
|
||||||
city: '',
|
|
||||||
postalCode: ''
|
|
||||||
};
|
|
||||||
|
|
||||||
function handleSubmit() {
|
|
||||||
// Here you'll integrate payment processing later
|
|
||||||
console.log('Form submitted:', formData);
|
|
||||||
console.log('Cart items:', $cart);
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateTotal(items: any[]) {
|
|
||||||
return items.reduce((sum, item) =>
|
|
||||||
sum + (item.variant.calculated_price.calculated_amount * item.quantity), 0
|
|
||||||
).toFixed(2);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container mx-auto px-4 py-8">
|
<div class="container mx-auto px-4 py-8">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
<Checkout />
|
||||||
<!-- Order Summary -->
|
|
||||||
<div class="space-y-4">
|
|
||||||
<h2 class="text-2xl font-bold">Order Summary</h2>
|
|
||||||
{#each $cart as item}
|
|
||||||
<div class="flex justify-between items-center p-4 bg-base-200 rounded-lg">
|
|
||||||
<div>
|
|
||||||
<h3 class="font-bold">{item.product.title}</h3>
|
|
||||||
<p class="text-sm">{item.variant.title}</p>
|
|
||||||
<p class="text-sm">Quantity: {item.quantity}</p>
|
|
||||||
</div>
|
|
||||||
<p class="font-bold">{(item.variant.calculated_price.calculated_amount * item.quantity).toFixed(2)} €</p>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
|
|
||||||
<div class="flex justify-between items-center p-4 bg-base-300 rounded-lg">
|
|
||||||
<span class="font-bold">Total:</span>
|
|
||||||
<span class="font-bold">{calculateTotal($cart)} €</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Shipping Details Form -->
|
|
||||||
<form class="space-y-4" on:submit|preventDefault={handleSubmit}>
|
|
||||||
<h2 class="text-2xl font-bold">Shipping Details</h2>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label" for="name">
|
|
||||||
<span class="label-text">Full Name</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="name"
|
|
||||||
class="input input-bordered"
|
|
||||||
bind:value={formData.name}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label" for="email">
|
|
||||||
<span class="label-text">Email</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
id="email"
|
|
||||||
class="input input-bordered"
|
|
||||||
bind:value={formData.email}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label" for="country">
|
|
||||||
<span class="label-text">Country</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="country"
|
|
||||||
class="input input-bordered"
|
|
||||||
bind:value={formData.country}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label" for="address">
|
|
||||||
<span class="label-text">Address</span>
|
|
||||||
</label>
|
|
||||||
<textarea
|
|
||||||
id="address"
|
|
||||||
class="textarea textarea-bordered"
|
|
||||||
bind:value={formData.address}
|
|
||||||
required
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-4">
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label" for="city">
|
|
||||||
<span class="label-text">City</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="city"
|
|
||||||
class="input input-bordered"
|
|
||||||
bind:value={formData.city}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label" for="postalCode">
|
|
||||||
<span class="label-text">Postal Code</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="postalCode"
|
|
||||||
class="input input-bordered"
|
|
||||||
bind:value={formData.postalCode}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary w-full">
|
|
||||||
Continue to Payment
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
10
src/routes/products/+layout.svelte
Normal file
10
src/routes/products/+layout.svelte
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import MiniCart from '$lib/components/mini-cart.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="min-h-screen bg-base-100">
|
||||||
|
<slot />
|
||||||
|
|
||||||
|
<!-- Mini Cart - only shows on products pages -->
|
||||||
|
<MiniCart />
|
||||||
|
</div>
|
|
@ -1,9 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from './$types';
|
|
||||||
import Footer from '$lib/components/Footer.svelte';
|
|
||||||
import SingleProduct from '$lib/components/single-product.svelte';
|
import SingleProduct from '$lib/components/single-product.svelte';
|
||||||
|
import type { MedusaResponse } from '$lib/types/medusa';
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: MedusaResponse;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="container mx-auto px-4 py-8">
|
<div class="container mx-auto px-4 py-8">
|
||||||
|
|
Loading…
Reference in a new issue