first commit
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Bestellung erfolgreich"
|
||||
description="Vielen Dank für Ihre Bestellung bei place4bees."
|
||||
>
|
||||
<section class="mx-auto max-w-2xl px-4 sm:px-6 lg:px-8 py-16 text-center">
|
||||
<h1 class="text-3xl font-semibold text-brand-ink">Vielen Dank für Ihre Bestellung!</h1>
|
||||
<p id="order-summary" class="mt-4 text-brand-text">Bestellbestätigung wird geladen…</p>
|
||||
<a href="/shop" class="mt-8 inline-block text-brand-primary underline">Weiter einkaufen</a>
|
||||
</section>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
const raw = sessionStorage.getItem("last_order");
|
||||
const el = document.getElementById("order-summary");
|
||||
|
||||
if (raw && el) {
|
||||
const order = JSON.parse(raw);
|
||||
el.textContent = `Bestellnummer ${order.display_id ?? order.id}. Eine Bestätigung geht an ${order.email}.`;
|
||||
sessionStorage.removeItem("last_order");
|
||||
} else if (el) {
|
||||
el.textContent = "Keine aktuelle Bestellung gefunden.";
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Anfrage"
|
||||
description="Interesse an eigenen Bienenvölkern für Ihr Unternehmen? Jetzt unverbindlich anfragen."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16">
|
||||
<h1 class="text-3xl font-semibold text-brand-ink">Interesse?</h1>
|
||||
<p class="mt-4 text-brand-text">
|
||||
Schreiben Sie uns, wir melden uns mit einem individuellen Angebot für Ihren Standort.
|
||||
</p>
|
||||
<form class="mt-8 grid gap-4 max-w-md">
|
||||
<input type="text" name="company" placeholder="Unternehmen" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<input type="text" name="name" placeholder="Ansprechpartner" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<input type="email" name="email" placeholder="E-Mail" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<input type="text" name="location" placeholder="Standort (Stadt)" class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<textarea name="message" placeholder="Ihre Nachricht" rows="4" class="rounded-lg border border-brand-border px-4 py-2"></textarea>
|
||||
<button type="submit" class="rounded-full bg-brand-primary text-brand-ink px-6 py-3 text-sm font-semibold hover:bg-brand-primary-hover transition-colors">
|
||||
Anfrage senden
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Unser Angebot"
|
||||
description="Bienenvölker, professionelle Betreuung und Team-Erlebnisse für Unternehmen und Hotels."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16 prose prose-stone">
|
||||
<h1 class="text-3xl font-semibold text-brand-ink">Unser Angebot</h1>
|
||||
<p class="mt-4 text-brand-text">
|
||||
Wir bringen eigene Bienenvölker an Ihren Firmen- oder Hotelstandort und übernehmen die
|
||||
komplette fachliche Betreuung. Ihr Unternehmen profitiert von einem nachhaltigen Image,
|
||||
eigenem Honig als Geschenk oder Give-away, und einem greifbaren Beitrag zum Artenschutz –
|
||||
inklusive Erlebnisangeboten für Ihr Team vor Ort.
|
||||
</p>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Ihr Projekt"
|
||||
description="So funktioniert ein Unternehmensbienen-Projekt mit place4bees – von der Beratung bis zur Honigernte."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-brand-accent">Eigene Bienen vor Ort. Professionell betreut. Nachhaltig erlebbar.</p>
|
||||
<h1 class="mt-2 text-4xl text-brand-ink">Ihr Projekt</h1>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">So funktioniert's</h2>
|
||||
<p class="mt-4 text-brand-text normal-case">
|
||||
place4bees ermöglicht es Unternehmen, ohne imkerliche Erfahrung Bienenvölker auf dem
|
||||
Firmengelände anzusiedeln. Wir kümmern uns um die intensive Betreuung das ganze Jahr über,
|
||||
regeln alle Formalitäten und gesetzlichen Vorgaben und unterstützen bei der medialen
|
||||
Aufbereitung.
|
||||
</p>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Ablauf vor Projektstart</h2>
|
||||
<ol class="mt-4 space-y-2 text-brand-text normal-case list-decimal list-inside">
|
||||
<li>Kennenlernen & Beratungsgespräch</li>
|
||||
<li>Standortauswahl mit lokalem Imker vor Ort</li>
|
||||
<li>Individuelles Angebot</li>
|
||||
<li>Vorbereitung der Bienenvölker</li>
|
||||
<li>Die Bienen ziehen ein!</li>
|
||||
</ol>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Highlights</h2>
|
||||
<div class="mt-4 grid gap-6 sm:grid-cols-3">
|
||||
<div>
|
||||
<p class="font-semibold text-brand-ink normal-case">Honigernte</p>
|
||||
<p class="mt-1 text-sm text-brand-text normal-case">1–2 Mal jährlich eigenen Honig aus Ihrem direkten Umfeld, auf Wunsch mit individuellem Design.</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-brand-ink normal-case">PR & Media</p>
|
||||
<p class="mt-1 text-sm text-brand-text normal-case">Wir unterstützen bei der medialen Aufbereitung Ihres nachhaltigen Engagements.</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-brand-ink normal-case">Events</p>
|
||||
<p class="mt-1 text-sm text-brand-text normal-case">Regelmäßige Besuche der Imker:innen vor Ort sowie Workshops, Vorträge und Kurse.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Leistungen umfassen</h2>
|
||||
<ul class="mt-4 grid gap-2 sm:grid-cols-2 text-brand-text normal-case list-disc list-inside">
|
||||
<li>Bienenstand einrichten</li>
|
||||
<li>Honigernte und -verarbeitung</li>
|
||||
<li>Event-Organisation</li>
|
||||
<li>Übernahme aller Formalitäten</li>
|
||||
<li>Individueller Unternehmenshonig</li>
|
||||
<li>Ersatz für Verluste (versichert gegen Diebstahl und Vandalismus)</li>
|
||||
<li>Ganzjährige Betreuung</li>
|
||||
<li>PR & Social Media Support</li>
|
||||
<li>Rückholung der Bienen bei Projektende</li>
|
||||
</ul>
|
||||
|
||||
<a href="/business/anfrage" class="mt-10 inline-block rounded bg-brand-primary text-brand-ink px-7 py-3 text-sm font-semibold hover:bg-brand-primary-hover transition-colors">
|
||||
Interesse? Jetzt anfragen
|
||||
</a>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import BusinessHome from "../../components/sections/BusinessHome.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Bienenvölker für Unternehmen"
|
||||
description="place4bees betreut Bienenvölker direkt an Ihrem Firmen- oder Hotelstandort – professionell, nachhaltig und erlebbar."
|
||||
>
|
||||
<BusinessHome />
|
||||
</Layout>
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Kontakt"
|
||||
description="Holen Sie sich zusammen mit place4bees ein Stück Natur in Ihr Unternehmen."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-brand-accent">Partnerschaftliche vertrauensvolle Zusammenarbeit</p>
|
||||
<h1 class="mt-2 text-4xl text-brand-ink">Holen Sie sich zusammen mit uns ein Stück Natur in Ihr Unternehmen</h1>
|
||||
<p class="mt-4 text-brand-text normal-case">
|
||||
place4bees ist in Hamburg zuhause und arbeitet deutschlandweit und in der DACH-Region mit
|
||||
festen Vertragsimkern zusammen.
|
||||
</p>
|
||||
|
||||
<form class="mt-8 grid gap-4 max-w-md">
|
||||
<input type="text" name="name" placeholder="Name" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<input type="email" name="email" placeholder="E-Mail" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<textarea name="message" placeholder="Ihr Anliegen" rows="4" required class="rounded-lg border border-brand-border px-4 py-2"></textarea>
|
||||
<label class="flex items-start gap-2 text-sm text-brand-text-muted normal-case">
|
||||
<input type="checkbox" required class="mt-1" />
|
||||
Ich stimme der Datenschutzerklärung zu.
|
||||
</label>
|
||||
<button type="submit" class="rounded bg-brand-primary text-brand-ink px-6 py-3 text-sm font-semibold hover:bg-brand-primary-hover transition-colors">
|
||||
Senden
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="mt-10 text-sm text-brand-text-muted normal-case">
|
||||
<p>place4bees GmbH</p>
|
||||
<p>Isestr. 109, 20149 Hamburg</p>
|
||||
<p>kontakt@place4bees.com · +49 162-2 35 02 02</p>
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Philosophie"
|
||||
description="Verantwortung. Regionalität. Wertschätzung. Die Philosophie hinter place4bees."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-brand-accent">Verantwortung. Regionalität. Wertschätzung.</p>
|
||||
<h1 class="mt-2 text-4xl text-brand-ink">Was uns antreibt</h1>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Unsere Vision</h2>
|
||||
<p class="mt-4 text-brand-text normal-case">
|
||||
Als Hamburger Stadtimker möchten wir nicht nur möglichst viele artgerechte Lebensräume für
|
||||
die Honigbienen etablieren, sondern folgende Ziele verfolgen:
|
||||
</p>
|
||||
<ul class="mt-4 space-y-2 text-brand-text normal-case list-disc list-inside">
|
||||
<li>Aufmerksamkeit und Wertschätzung für eines der wichtigsten Nutztiere weltweit schaffen</li>
|
||||
<li>Unternehmen und Hotels eine besondere Möglichkeit bieten, sich im lokalen Umweltschutz zu engagieren</li>
|
||||
<li>Vielen Menschen Einblicke in die Welt der Bienen ermöglichen</li>
|
||||
<li>Durch die Honigbiene ein Bewusstsein für die Gefährdung von Wildbienenarten schaffen</li>
|
||||
</ul>
|
||||
|
||||
<div class="mt-10 rounded-2xl bg-white ring-1 ring-brand-border overflow-hidden grid sm:grid-cols-2 items-stretch">
|
||||
<img src="/images/beekeepers-quote.jpg" alt="Imker:innen von place4bees bei der Arbeit" class="w-full h-64 sm:h-full object-cover" />
|
||||
<div class="p-6 sm:p-8 flex flex-col justify-center">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-brand-accent">Was uns antreibt</p>
|
||||
<p class="mt-3 text-lg text-brand-ink normal-case italic">
|
||||
„Wir haben es uns zur Aufgabe gemacht, mithilfe von zukunftsorientierten Unternehmen und
|
||||
Hotels den heimischen Honigbienen artgerechte Lebensräume zu schaffen und sie so stark
|
||||
für die Zukunft zu machen."
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Starke Partner</h2>
|
||||
<p class="mt-4 text-brand-text normal-case">
|
||||
Wir setzen auf vertrauensvolle Partnerschaft und arbeiten nachhaltig mit regionalem Fokus.
|
||||
Mit über 20 Jahren Erfahrung in Unternehmenskommunikation unterstützen wir unsere Kunden
|
||||
dabei, gesunde, kräftige Bienenvölker aufzubauen.
|
||||
</p>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Unsere Werte</h2>
|
||||
<div class="mt-4 grid gap-6 sm:grid-cols-2">
|
||||
<div>
|
||||
<p class="font-semibold text-brand-ink normal-case">Die Tiere</p>
|
||||
<p class="mt-1 text-sm text-brand-text normal-case">Tierwohl hat oberste Priorität.</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-brand-ink normal-case">Die Imkerei</p>
|
||||
<p class="mt-1 text-sm text-brand-text normal-case">Moderne Ansätze mit Respekt vor konventioneller Imkerei.</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-brand-ink normal-case">Unser Netzwerk</p>
|
||||
<p class="mt-1 text-sm text-brand-text normal-case">Austausch mit Bienenexperten.</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-semibold text-brand-ink normal-case">Jedes Projekt</p>
|
||||
<p class="mt-1 text-sm text-brand-text normal-case">Maßgeschneiderte Konzepte für individuelle Bedürfnisse.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
|
||||
const artikel = [
|
||||
"noordish 2023",
|
||||
"green LIFESTYLE 2023",
|
||||
"Brigitte 2023",
|
||||
"Couch 2023",
|
||||
"Szene Hamburg Essen+Trinken 2023/2024",
|
||||
"Hamburger Morgenpost 2025",
|
||||
];
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Presse"
|
||||
description="Was man über place4bees schreibt und hört."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-brand-accent">Verantwortung. Regionalität. Wertschätzung.</p>
|
||||
<h1 class="mt-2 text-4xl text-brand-ink">Presse</h1>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Was man über uns schreibt</h2>
|
||||
<ul class="mt-4 space-y-2 text-brand-text normal-case list-disc list-inside">
|
||||
{artikel.map((a) => <li>{a}</li>)}
|
||||
</ul>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Hier kann man was über uns hören</h2>
|
||||
<p class="mt-4 text-brand-text normal-case">„Der Finanzgourmet – Dani Zastrow: Die Bienenkönigin" (Podcast)</p>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Was wir über uns schreiben</h2>
|
||||
<ul class="mt-4 space-y-2 text-brand-text normal-case list-disc list-inside">
|
||||
<li>Unsere Brand Story</li>
|
||||
<li>Unsere Gründerstory</li>
|
||||
</ul>
|
||||
|
||||
<p class="mt-10 text-sm text-brand-text-muted normal-case">
|
||||
place4bees GmbH · Isestr. 109 · 20149 Hamburg · kontakt@place4bees.com · +49 162-2 35 02 02
|
||||
</p>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
|
||||
const team = [
|
||||
{ name: "Dani Zastrow", role: "Co-Founder, Head of B2B" },
|
||||
{ name: "Björn Schumann", role: "Co-Founder, Head of Operations" },
|
||||
{ name: "Niklas Bartelmann", role: "Technischer Leiter & ausgebildeter Imker" },
|
||||
{ name: "Meike Fischer", role: "Backoffice & Marketing" },
|
||||
{ name: "Nico Göllnitz", role: "Assistenz Imkerei & Hamburger Standorte" },
|
||||
{ name: "Doro Scriba", role: "Verantwortliche Imkerin Düsseldorf" },
|
||||
{ name: "Sabine Schließer", role: "Imkerei Support & Allround Power" },
|
||||
{ name: "Klaus Bamberger", role: "Verantwortlicher Imker Detmold" },
|
||||
{ name: "Rudi", role: "Büro Wachdienst & Feel Good Manager" },
|
||||
];
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Über uns"
|
||||
description="Das Team hinter place4bees – moderne, gesunde Imkerei für Unternehmen und Hotels."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-brand-accent">Eigene Bienen vor Ort. Professionell betreut. Nachhaltig erlebbar.</p>
|
||||
<h1 class="mt-2 text-4xl text-brand-ink">Über uns</h1>
|
||||
|
||||
<p class="mt-6 text-brand-text normal-case">
|
||||
place4bees wurde gegründet, um moderne und gesunde Imkerei in urbanen und ländlichen
|
||||
Regionen zu fördern. Unser Team verfügt über umfangreiche Imkerei-Expertise sowie 24 Jahre
|
||||
Erfahrung in Banking, Marketing, Kommunikation und Nachhaltigkeitsmanagement bei großen
|
||||
Hamburger Unternehmen. Unsere gemeinsame Leidenschaft für Bienen motiviert uns, die Imkerei
|
||||
strukturell zu stärken. place4bees ist in Hamburg ansässig und arbeitet deutschlandweit
|
||||
sowie in der DACH-Region mit vertragsgebundenen Imkern zusammen.
|
||||
</p>
|
||||
|
||||
<h2 class="mt-10 text-2xl text-brand-ink">Unser Team</h2>
|
||||
<div class="mt-6 grid gap-6 sm:grid-cols-2">
|
||||
{team.map((member) => (
|
||||
<div class="rounded-lg bg-white ring-1 ring-brand-border p-4">
|
||||
<p class="font-semibold text-brand-ink normal-case">{member.name}</p>
|
||||
<p class="text-sm text-brand-text-muted normal-case">{member.role}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
export const prerender = false;
|
||||
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import PrivateHome from "../components/sections/PrivateHome.astro";
|
||||
import BusinessHome from "../components/sections/BusinessHome.astro";
|
||||
import { isBusinessHost } from "../lib/sections";
|
||||
|
||||
const hostname = Astro.request.headers.get("host") ?? Astro.url.hostname;
|
||||
const showBusiness = isBusinessHost(hostname);
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={showBusiness ? "Bienenvölker für Unternehmen" : "Regionaler Honig aus Hamburg"}
|
||||
description={
|
||||
showBusiness
|
||||
? "place4bees betreut Bienenvölker direkt an Ihrem Firmen- oder Hotelstandort – professionell, nachhaltig und erlebbar."
|
||||
: "place4bees: regionaler Honig, Bienenprodukte und Bienenpatenschaften aus Hamburg – auch mitten in der Stadt."
|
||||
}
|
||||
>
|
||||
{showBusiness ? <BusinessHome /> : <PrivateHome />}
|
||||
</Layout>
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { getCart, listShippingOptions } from "../lib/cart";
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
const cartId = Astro.cookies.get("cart_id")?.value;
|
||||
let cart = null;
|
||||
let shippingOptions: Awaited<ReturnType<typeof listShippingOptions>> = [];
|
||||
|
||||
if (cartId) {
|
||||
try {
|
||||
cart = await getCart(cartId);
|
||||
shippingOptions = await listShippingOptions(cartId);
|
||||
} catch {
|
||||
cart = null;
|
||||
}
|
||||
}
|
||||
|
||||
const items = cart?.items ?? [];
|
||||
---
|
||||
|
||||
<Layout title="Kasse" description="Bestellung bei place4bees abschließen.">
|
||||
<section class="mx-auto max-w-2xl px-4 sm:px-6 lg:px-8 py-12 sm:py-16">
|
||||
<h1 class="text-3xl font-semibold text-brand-ink">Zur Kasse</h1>
|
||||
|
||||
{items.length === 0 && (
|
||||
<p class="mt-6 text-brand-text">
|
||||
Ihr Warenkorb ist leer. <a href="/shop" class="text-brand-primary underline">Zum Shop</a>
|
||||
</p>
|
||||
)}
|
||||
|
||||
{items.length > 0 && (
|
||||
<form id="checkout-form" class="mt-8 grid gap-4">
|
||||
<input type="email" name="email" placeholder="E-Mail" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<input type="text" name="first_name" placeholder="Vorname" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<input type="text" name="last_name" placeholder="Nachname" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
</div>
|
||||
|
||||
<input type="text" name="address_1" placeholder="Straße und Hausnummer" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<input type="text" name="postal_code" placeholder="PLZ" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<input type="text" name="city" placeholder="Stadt" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="country_code" value="de" />
|
||||
|
||||
<fieldset class="mt-4">
|
||||
<legend class="font-medium text-brand-ink mb-2">Versand</legend>
|
||||
<div class="grid gap-2">
|
||||
{shippingOptions.map((option, index) => (
|
||||
<label class="flex items-center gap-2 text-sm text-brand-text">
|
||||
<input type="radio" name="shipping_option_id" value={option.id} required checked={index === 0} />
|
||||
{option.name} – {option.amount.toFixed(2)} €
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<p id="checkout-status" class="text-sm text-red-600 hidden"></p>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="mt-4 rounded-full bg-brand-primary text-brand-ink px-6 py-3 text-sm font-semibold hover:bg-brand-primary-hover transition-colors disabled:opacity-50"
|
||||
>
|
||||
Zahlungspflichtig bestellen
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
</section>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
import { getCartIdClient, clearCartIdClient } from "../lib/cartCookie";
|
||||
import { updateCart, addShippingMethod, createPaymentCollection, createPaymentSession, completeCart } from "../lib/cart";
|
||||
|
||||
const form = document.getElementById("checkout-form") as HTMLFormElement | null;
|
||||
const status = document.getElementById("checkout-status");
|
||||
|
||||
form?.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
const cartId = getCartIdClient();
|
||||
if (!cartId) return;
|
||||
|
||||
const submitButton = form.querySelector("button[type=submit]") as HTMLButtonElement;
|
||||
submitButton.disabled = true;
|
||||
status?.classList.add("hidden");
|
||||
|
||||
try {
|
||||
const data = new FormData(form);
|
||||
|
||||
await updateCart(cartId, {
|
||||
email: String(data.get("email")),
|
||||
shipping_address: {
|
||||
first_name: String(data.get("first_name")),
|
||||
last_name: String(data.get("last_name")),
|
||||
address_1: String(data.get("address_1")),
|
||||
postal_code: String(data.get("postal_code")),
|
||||
city: String(data.get("city")),
|
||||
country_code: String(data.get("country_code")),
|
||||
},
|
||||
});
|
||||
|
||||
await addShippingMethod(cartId, String(data.get("shipping_option_id")));
|
||||
|
||||
const paymentCollection = await createPaymentCollection(cartId);
|
||||
await createPaymentSession(paymentCollection.id, "pp_system_default");
|
||||
|
||||
const result = await completeCart(cartId);
|
||||
|
||||
if (result.type === "order") {
|
||||
sessionStorage.setItem("last_order", JSON.stringify(result.order));
|
||||
clearCartIdClient();
|
||||
window.location.href = "/bestellung/danke";
|
||||
} else {
|
||||
throw new Error(result.error?.message || "Bestellung konnte nicht abgeschlossen werden.");
|
||||
}
|
||||
} catch (err) {
|
||||
if (status) {
|
||||
status.textContent = err instanceof Error ? err.message : "Es ist ein Fehler aufgetreten.";
|
||||
status.classList.remove("hidden");
|
||||
}
|
||||
submitButton.disabled = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Kontakt"
|
||||
description="Kontaktieren Sie place4bees in Hamburg."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16">
|
||||
<h1 class="text-3xl font-semibold text-brand-ink">Kontakt</h1>
|
||||
<p class="mt-4 text-brand-text">Fragen zu unserem Honig oder den Patenschaften? Schreiben Sie uns.</p>
|
||||
<form class="mt-8 grid gap-4 max-w-md">
|
||||
<input type="text" name="name" placeholder="Name" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<input type="email" name="email" placeholder="E-Mail" required class="rounded-lg border border-brand-border px-4 py-2" />
|
||||
<textarea name="message" placeholder="Ihre Nachricht" rows="4" required class="rounded-lg border border-brand-border px-4 py-2"></textarea>
|
||||
<button type="submit" class="rounded-full bg-brand-primary text-brand-ink px-6 py-3 text-sm font-semibold hover:bg-brand-primary-hover transition-colors">
|
||||
Absenden
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import PrivateHome from "../components/sections/PrivateHome.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Regionaler Honig aus Hamburg"
|
||||
description="place4bees: regionaler Honig, Bienenprodukte und Bienenpatenschaften aus Hamburg – auch mitten in der Stadt."
|
||||
>
|
||||
<PrivateHome />
|
||||
</Layout>
|
||||
@@ -0,0 +1,146 @@
|
||||
---
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import AddToCartButton from "../../components/AddToCartButton.astro";
|
||||
import { getProductByHandle, getDefaultRegion } from "../../lib/medusa";
|
||||
import { formatEUR, formatGrundpreis } from "../../lib/format";
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
const { handle } = Astro.params;
|
||||
const region = await getDefaultRegion();
|
||||
const product = handle ? await getProductByHandle(handle, region.id) : null;
|
||||
|
||||
if (!product) {
|
||||
return Astro.redirect("/shop");
|
||||
}
|
||||
|
||||
const infoByVariant = Object.fromEntries(
|
||||
product.variants.map((variant) => [
|
||||
variant.id,
|
||||
{
|
||||
price: variant.calculated_price ? formatEUR(variant.calculated_price.calculated_amount) : "",
|
||||
grundpreis:
|
||||
variant.calculated_price && variant.metadata?.net_weight_grams
|
||||
? formatGrundpreis(variant.calculated_price.calculated_amount, variant.metadata.net_weight_grams)
|
||||
: null,
|
||||
},
|
||||
])
|
||||
);
|
||||
const initial = infoByVariant[product.variants[0]?.id] ?? { price: "", grundpreis: null };
|
||||
const deliveryTime = product.metadata?.delivery_time;
|
||||
|
||||
const gallery = (product.images?.length ? product.images.map((i) => i.url) : product.thumbnail ? [product.thumbnail] : []);
|
||||
---
|
||||
|
||||
<Layout title={product.title} description={product.description ?? product.title}>
|
||||
<section class="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8 py-8 sm:py-12">
|
||||
<nav class="flex items-center gap-2 text-sm text-brand-text-muted">
|
||||
<a href="/shop" class="hover:text-brand-primary transition-colors">Shop</a>
|
||||
<span>/</span>
|
||||
{product.metadata?.category && (
|
||||
<>
|
||||
<span>{product.metadata.category}</span>
|
||||
<span>/</span>
|
||||
</>
|
||||
)}
|
||||
<span class="text-brand-text">{product.title}</span>
|
||||
</nav>
|
||||
|
||||
<div class="mt-8 grid gap-12 sm:grid-cols-2">
|
||||
<div>
|
||||
<div id="main-image" class="aspect-square rounded-2xl bg-brand-surface overflow-hidden">
|
||||
{gallery[0] && <img src={gallery[0]} alt={product.title} class="h-full w-full object-cover" />}
|
||||
</div>
|
||||
{gallery.length > 1 && (
|
||||
<div class="mt-4 flex gap-3">
|
||||
{gallery.map((url, index) => (
|
||||
<button
|
||||
class:list={[
|
||||
"gallery-thumb h-16 w-16 rounded-lg overflow-hidden ring-2 transition-colors",
|
||||
index === 0 ? "ring-brand-primary" : "ring-transparent",
|
||||
]}
|
||||
data-src={url}
|
||||
>
|
||||
<img src={url} alt="" class="h-full w-full object-cover" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{product.metadata?.category && (
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-brand-accent">{product.metadata.category}</p>
|
||||
)}
|
||||
<h1 class="mt-2 text-3xl font-semibold text-brand-ink">{product.title}</h1>
|
||||
|
||||
<div class="mt-3 flex items-baseline gap-3">
|
||||
<p id="product-price" class="text-2xl font-semibold text-brand-primary">{initial.price}</p>
|
||||
<span class="text-sm text-brand-text-muted">inkl. MwSt.</span>
|
||||
</div>
|
||||
<p id="product-grundpreis" class="mt-1 text-sm text-brand-text-muted">{initial.grundpreis ?? ""}</p>
|
||||
|
||||
<p class="mt-6 text-brand-text whitespace-pre-line">{product.description}</p>
|
||||
|
||||
<div class="mt-8">
|
||||
<AddToCartButton variants={product.variants} regionId={region.id} />
|
||||
</div>
|
||||
|
||||
<div class="mt-8 grid gap-3 sm:grid-cols-2">
|
||||
{deliveryTime && (
|
||||
<p class="flex items-center gap-2 text-sm text-brand-text-muted">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
Lieferzeit: {deliveryTime}
|
||||
</p>
|
||||
)}
|
||||
<p class="flex items-center gap-2 text-sm text-brand-text-muted">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
Regional aus Hamburg
|
||||
</p>
|
||||
<p class="flex items-center gap-2 text-sm text-brand-text-muted">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
Nachhaltig produziert
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script type="application/json" id="variant-info" set:html={JSON.stringify(infoByVariant)} />
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
const priceEl = document.getElementById("product-price");
|
||||
const grundpreisEl = document.getElementById("product-grundpreis");
|
||||
const infoJson = document.getElementById("variant-info")?.textContent;
|
||||
|
||||
if (priceEl && grundpreisEl && infoJson) {
|
||||
const info: Record<string, { price: string; grundpreis: string | null }> = JSON.parse(infoJson);
|
||||
document.querySelectorAll<HTMLInputElement>('input[name="variant"]').forEach((input) => {
|
||||
input.addEventListener("change", () => {
|
||||
const entry = info[input.value];
|
||||
priceEl.textContent = entry?.price ?? "";
|
||||
grundpreisEl.textContent = entry?.grundpreis ?? "";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const mainImage = document.querySelector<HTMLImageElement>("#main-image img");
|
||||
document.querySelectorAll<HTMLButtonElement>(".gallery-thumb").forEach((thumb) => {
|
||||
thumb.addEventListener("click", () => {
|
||||
if (mainImage && thumb.dataset.src) mainImage.src = thumb.dataset.src;
|
||||
document.querySelectorAll(".gallery-thumb").forEach((t) => {
|
||||
t.classList.remove("ring-brand-primary");
|
||||
t.classList.add("ring-transparent");
|
||||
});
|
||||
thumb.classList.remove("ring-transparent");
|
||||
thumb.classList.add("ring-brand-primary");
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
export const prerender = false;
|
||||
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import { listProducts, getDefaultRegion } from "../../lib/medusa";
|
||||
import { formatEUR, formatGrundpreis } from "../../lib/format";
|
||||
|
||||
let products: Awaited<ReturnType<typeof listProducts>> = [];
|
||||
let loadError = false;
|
||||
|
||||
try {
|
||||
const region = await getDefaultRegion();
|
||||
products = await listProducts(region.id);
|
||||
} catch {
|
||||
loadError = true;
|
||||
}
|
||||
|
||||
function priceLabel(product: (typeof products)[number]) {
|
||||
const prices = product.variants
|
||||
.map((v) => v.calculated_price?.calculated_amount)
|
||||
.filter((amount): amount is number => amount != null);
|
||||
if (prices.length === 0) return null;
|
||||
const min = Math.min(...prices);
|
||||
return prices.length > 1 && new Set(prices).size > 1 ? `ab ${formatEUR(min)}` : formatEUR(min);
|
||||
}
|
||||
|
||||
function grundpreisLabel(product: (typeof products)[number]) {
|
||||
const variant = product.variants.find((v) => v.metadata?.net_weight_grams);
|
||||
if (!variant?.calculated_price || !variant.metadata?.net_weight_grams) return null;
|
||||
return formatGrundpreis(variant.calculated_price.calculated_amount, variant.metadata.net_weight_grams);
|
||||
}
|
||||
|
||||
const categories = [...new Set(products.map((p) => p.metadata?.category).filter(Boolean))] as string[];
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Shop"
|
||||
description="Regionaler Honig, Bienenwachsprodukte und Geschenkideen von place4bees direkt aus Hamburg bestellen."
|
||||
>
|
||||
<section class="bg-brand-surface">
|
||||
<div class="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8 py-16 sm:py-20">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.25em] text-brand-accent">Regional · Nachhaltig · Hamburg</p>
|
||||
<h1 class="mt-3 text-4xl sm:text-5xl text-brand-ink">Der Shop</h1>
|
||||
<p class="mt-4 text-brand-text max-w-xl normal-case">
|
||||
Regionaler Honig, Bienenprodukte und Geschenkideen direkt aus Hamburg. Alle Preise inkl. MwSt.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8 py-12 sm:py-16">
|
||||
{loadError && (
|
||||
<p class="rounded-lg bg-red-50 text-red-700 px-4 py-3 text-sm">
|
||||
Die Produkte konnten aktuell nicht geladen werden. Bitte später erneut versuchen.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{categories.length > 1 && (
|
||||
<div id="category-filters" class="flex flex-wrap gap-2">
|
||||
<button data-category="" class="category-pill rounded-full px-4 py-1.5 text-sm font-medium transition-colors bg-brand-ink text-brand-cream">
|
||||
Alle
|
||||
</button>
|
||||
{categories.map((category) => (
|
||||
<button
|
||||
data-category={category}
|
||||
class="category-pill rounded-full px-4 py-1.5 text-sm font-medium transition-colors bg-brand-surface text-brand-text hover:bg-brand-surface-strong"
|
||||
>
|
||||
{category}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div id="product-grid" class="mt-10 grid gap-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{products.map((product) => {
|
||||
const price = priceLabel(product);
|
||||
const grundpreis = grundpreisLabel(product);
|
||||
return (
|
||||
<a
|
||||
href={`/shop/${product.handle}`}
|
||||
data-category={product.metadata?.category ?? ""}
|
||||
class="product-card group block rounded-2xl bg-white shadow-sm ring-1 ring-brand-border overflow-hidden transition-all hover:-translate-y-1 hover:shadow-xl"
|
||||
>
|
||||
<div class="aspect-square bg-brand-surface relative overflow-hidden">
|
||||
{product.metadata?.category && (
|
||||
<span class="absolute top-3 left-3 rounded-full bg-brand-ink/80 text-brand-cream text-xs font-medium px-3 py-1 backdrop-blur-sm">
|
||||
{product.metadata.category}
|
||||
</span>
|
||||
)}
|
||||
{product.thumbnail && (
|
||||
<img src={product.thumbnail} alt={product.title} class="h-full w-full object-cover group-hover:scale-105 transition-transform duration-300" />
|
||||
)}
|
||||
</div>
|
||||
<div class="p-5">
|
||||
<h2 class="font-semibold text-brand-ink leading-snug">{product.title}</h2>
|
||||
<div class="mt-2 flex items-baseline justify-between gap-2">
|
||||
{price && <span class="font-semibold text-brand-primary">{price}</span>}
|
||||
{grundpreis && <span class="text-xs text-brand-text-muted">{grundpreis}</span>}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{!loadError && products.length === 0 && (
|
||||
<p class="mt-10 text-brand-text-muted">Aktuell sind keine Produkte verfügbar.</p>
|
||||
)}
|
||||
</section>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
const pills = document.querySelectorAll<HTMLButtonElement>(".category-pill");
|
||||
const cards = document.querySelectorAll<HTMLAnchorElement>(".product-card");
|
||||
|
||||
pills.forEach((pill) => {
|
||||
pill.addEventListener("click", () => {
|
||||
const category = pill.dataset.category ?? "";
|
||||
|
||||
pills.forEach((p) => {
|
||||
const active = p === pill;
|
||||
p.classList.toggle("bg-brand-ink", active);
|
||||
p.classList.toggle("text-brand-cream", active);
|
||||
p.classList.toggle("bg-brand-surface", !active);
|
||||
p.classList.toggle("text-brand-text", !active);
|
||||
});
|
||||
|
||||
cards.forEach((card) => {
|
||||
const matches = !category || card.dataset.category === category;
|
||||
card.classList.toggle("hidden", !matches);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Über uns"
|
||||
description="place4bees betreut Bienenvölker in und um Hamburg – auch mitten in der Stadt."
|
||||
>
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-16 prose prose-stone">
|
||||
<h1 class="text-3xl font-semibold text-brand-ink">Über uns</h1>
|
||||
<p class="mt-4 text-brand-text">
|
||||
place4bees produziert regionalen Honig in und um Hamburg – einige unserer Völker stehen
|
||||
mitten in der Stadt. Neben Honig in verschiedenen Sorten bieten wir Bienenwachsprodukte,
|
||||
Schnupperkurse und Bienenpatenschaften an.
|
||||
</p>
|
||||
<p class="mt-4 text-brand-text">
|
||||
Unseren Honig und weitere regionale Produkte gibt es außerdem an mehreren
|
||||
24/7-Verkaufsautomaten in Hamburg.
|
||||
</p>
|
||||
</section>
|
||||
</Layout>
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import { getCart } from "../lib/cart";
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
const cartId = Astro.cookies.get("cart_id")?.value;
|
||||
let cart = null;
|
||||
|
||||
if (cartId) {
|
||||
try {
|
||||
cart = await getCart(cartId);
|
||||
} catch {
|
||||
cart = null;
|
||||
}
|
||||
}
|
||||
|
||||
const items = cart?.items ?? [];
|
||||
---
|
||||
|
||||
<Layout title="Warenkorb" description="Ihr Warenkorb bei place4bees.">
|
||||
<section class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 py-12 sm:py-16">
|
||||
<h1 class="text-3xl font-semibold text-brand-ink">Warenkorb</h1>
|
||||
|
||||
{items.length === 0 && (
|
||||
<p class="mt-6 text-brand-text">
|
||||
Ihr Warenkorb ist leer. <a href="/shop" class="text-brand-primary underline">Zum Shop</a>
|
||||
</p>
|
||||
)}
|
||||
|
||||
{items.length > 0 && (
|
||||
<>
|
||||
<ul class="mt-8 divide-y divide-brand-border">
|
||||
{items.map((item) => (
|
||||
<li class="py-4 flex items-center gap-4" data-line-item-id={item.id}>
|
||||
<div class="h-16 w-16 rounded-lg bg-brand-surface overflow-hidden shrink-0">
|
||||
{item.thumbnail && <img src={item.thumbnail} alt={item.title} class="h-full w-full object-cover" />}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="font-medium text-brand-ink">{item.title}</p>
|
||||
<p class="text-sm text-brand-text-muted">{item.unit_price.toFixed(2)} € / Stück</p>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
value={item.quantity}
|
||||
class="line-item-qty w-16 rounded-lg border border-brand-border px-2 py-1"
|
||||
/>
|
||||
<button class="remove-line-item text-sm text-brand-text-muted hover:text-red-600">Entfernen</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<div class="mt-8 flex items-center justify-between">
|
||||
<p class="text-lg font-semibold text-brand-ink">Summe: {(cart?.item_total ?? 0).toFixed(2)} €</p>
|
||||
<a
|
||||
href="/kasse"
|
||||
class="rounded-full bg-brand-primary text-brand-ink px-6 py-3 text-sm font-semibold hover:bg-brand-primary-hover transition-colors"
|
||||
>
|
||||
Zur Kasse
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
import { getCartIdClient } from "../lib/cartCookie";
|
||||
import { updateLineItem, removeLineItem } from "../lib/cart";
|
||||
|
||||
const cartId = getCartIdClient();
|
||||
|
||||
document.querySelectorAll<HTMLInputElement>(".line-item-qty").forEach((input) => {
|
||||
input.addEventListener("change", async () => {
|
||||
const li = input.closest<HTMLElement>("[data-line-item-id]");
|
||||
const lineId = li?.dataset.lineItemId;
|
||||
if (!cartId || !lineId) return;
|
||||
await updateLineItem(cartId, lineId, Number(input.value));
|
||||
window.dispatchEvent(new CustomEvent("cart:updated"));
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll<HTMLButtonElement>(".remove-line-item").forEach((button) => {
|
||||
button.addEventListener("click", async () => {
|
||||
const li = button.closest<HTMLElement>("[data-line-item-id]");
|
||||
const lineId = li?.dataset.lineItemId;
|
||||
if (!cartId || !lineId) return;
|
||||
await removeLineItem(cartId, lineId);
|
||||
window.dispatchEvent(new CustomEvent("cart:updated"));
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user