Skip to content

Commit

Permalink
feat: use SSR for shop pages
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreaDiotallevi committed Sep 28, 2024
1 parent 2fd90f8 commit 241a71a
Show file tree
Hide file tree
Showing 4 changed files with 340 additions and 22 deletions.
37 changes: 21 additions & 16 deletions astro/src/pages/shop/[category]/[slug].astro
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
---
export const prerender = false
import { Image } from "@unpic/astro"
import BaseLayout from "@layouts/BaseLayout.astro"
import Button from "@components/Button.astro"
import LocalisedPrice from "@components/LocalisedPrice.astro"
import { getActivePrices, type StripePrice } from "@utils/stripe"
import { getLocalCurrency } from "@utils/currency"
import { formatCurrency } from "@utils/intl"
import { getStripePrices } from "@utils/serverless"
import { type StripePrice } from "@utils/stripe"
export async function getStaticPaths() {
const prices = await getActivePrices()
const { slug } = Astro.params
const prices = await getStripePrices()
return prices.map(price => ({
params: {
slug: price.product.metadata.slug,
category: price.product.metadata.category,
},
props: { price },
}))
}
const price = prices.filter(price => price.product.metadata.slug === slug)[0]
const { price } = Astro.props
if (!price) return Astro.redirect("/404")
const sizeToDescription: Record<
StripePrice["product"]["metadata"]["size"],
Expand All @@ -28,6 +25,10 @@ const sizeToDescription: Record<
A2: "A2 (420 x 594 mm)",
A1: "A1 (594 x 841 mm)",
}
const currency = getLocalCurrency(
Astro.locals.netlify.context.geo.country?.name
)
---

<BaseLayout
Expand Down Expand Up @@ -147,9 +148,13 @@ const sizeToDescription: Record<
</div>
<div>
<h2 class="text-2xl font-semibold mb-2">
<LocalisedPrice
priceCurrencyOptions={price.currency_options}
/>
{
formatCurrency({
value: price.currency_options[currency]
.unit_amount,
currency,
})
}
</h2>
<p>Apply promotion codes at checkout.</p>
</div>
Expand Down
241 changes: 241 additions & 0 deletions astro/src/pages/shop/[category]/_ssg.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
---
import { Image } from "@unpic/astro"
import BaseLayout from "@layouts/BaseLayout.astro"
import Button from "@components/Button.astro"
import LocalisedPrice from "@components/LocalisedPrice.astro"
import { getActivePrices, type StripePrice } from "@utils/stripe"
export async function getStaticPaths() {
const prices = await getActivePrices()
return prices.map(price => ({
params: {
slug: price.product.metadata.slug,
category: price.product.metadata.category,
},
props: { price },
}))
}
const { price } = Astro.props
const sizeToDescription: Record<
StripePrice["product"]["metadata"]["size"],
string
> = {
A3: "A3 (297 x 420 mm)",
A2: "A2 (420 x 594 mm)",
A1: "A1 (594 x 841 mm)",
}
---

<BaseLayout
title={`${price.product.metadata.displayName} | Giclée Fine Art Print | Andrea Diotallevi Art`}
description={price.product.description}
image={price.product.images[0]}
type="product"
amount={(price.unit_amount / 100).toFixed(2)}
currency="gbp"
tags={[
price.product.metadata.displayName,
"Generative Art",
"p5.js",
"Processing",
"Procedural",
"Prints",
"Fine Art",
"Giclee",
"Hahnemühle photo rag",
]}
>
<div
class="flex flex-col md:flex-row items-center md:items-start px-4 py-8 max-w-screen-xl mx-auto"
>
<div class="w-full md:w-1/2 mb-6 md:mb-0 md:mr-8">
<div class="mb-5 relative">
{
price.product.images.map((src, index) => (
<Image
id={`main-image-${index}`}
width={1000}
height={1414}
src={src}
alt={price.product.name}
class={`w-full h-auto ${index === 0 ? "" : "absolute top-0 opacity-0"}`}
/>
))
}
</div>
<div class="grid grid-cols-4 gap-4">
{
price.product.images.map((img, index) => (
<Image
id={`thumbnail-${index}`}
src={img}
width={1000}
height={1414}
alt={`Thumbnail ${index + 1}`}
class={`w-full h-auto cursor-pointer border border-white border-dashed`}
/>
))
}
</div>
</div>

<form id="price-form" class="w-full md:w-1/2">
<h1 class="text-5xl font-bold mb-5">
{price.product.metadata.displayName}
</h1>

<div class="space-y-6">
<div>
<h2 class="text-2xl font-semibold mb-2">Size</h2>
<select
id="price-id"
name="price-id"
class="w-full px-3 py-3 border border-gray-800 rounded-md mb-2"
>
<option value={price.id}>
{sizeToDescription[price.product.metadata.size]}
</option>
</select>
<p>The image is printed full bleed with no border.</p>
</div>
<div>
<h2 class="text-2xl font-semibold mb-2">
100% cotton paper
</h2>
<p>
The artwork is printed on a white cotton paper called
Hahnemühle photo rag 308gsm. With its characteristic,
wonderfully soft feel, it boasts a lightly defined felt
structure, lending each artwork a three-dimensional
appearance and impressive pictorial depth.
</p>
</div>
<div>
<h2 class="text-2xl font-semibold mb-2">
Premium print quality
</h2>
<p>
The print is crafted using premium, pigment-based inks
that are fade-resistant and can endure for up to 200
years. This technique, called Giclée, makes the print
stand apart with its extremely high level of quality,
longevity and value compared to a standard print.
</p>
</div>
<div>
<h2 class="text-2xl font-semibold mb-2">Free shipping</h2>
<p>
Shipping is handled by The Print Space in London through
First Class Tracked Mail (typically 6-10 days). This is
an extremely more secure option than regular post for
sending art prints.
</p>
</div>
<div>
<h2 class="text-2xl font-semibold mb-2">
No custom charges for UK, EU and US orders
</h2>
<p>
With production in the UK, USA & Germany, The Print
Space guarantees no extra customs charges on UK-EU-US
orders.
</p>
</div>
<div>
<h2 class="text-2xl font-semibold mb-2">
<LocalisedPrice
priceCurrencyOptions={price.currency_options}
/>
</h2>
<p>Apply promotion codes at checkout.</p>
</div>
<Button
id="submit-button"
buttonText="Continue to checkout"
errorMessage="There was an error creating your session. Please try again."
/>
</div>
</form>
</div>
</BaseLayout>

<script>
import { sendGA4BeginCheckoutEvent } from "@utils/ga4"
import { createCheckoutSession, getLocaleCurrency } from "@utils/serverless"

document.addEventListener("astro:page-load", async () => {
const priceForm = document.querySelector("#price-form") as HTMLElement

if (!priceForm) return

const button = document.querySelector(
"#submit-button"
) as HTMLButtonElement

const spinner = document.getElementById("loading-spinner")!
const errorMessage = document.getElementById("error-message")!

priceForm.addEventListener("submit", async e => {
e.preventDefault()

button.disabled = true
spinner.classList.remove("hidden")
errorMessage.classList.add("hidden")

const priceId = (
document.getElementById("price-id") as HTMLInputElement
).value

const session = await createCheckoutSession({
line_items: [{ price: priceId, quantity: 1 }],
success_url: `${window.location.origin}/shop/checkout/success`,
currency: await getLocaleCurrency(),
})

if (!session) {
errorMessage.classList.remove("hidden")
spinner.classList.add("hidden")
button.disabled = false
return
}

sendGA4BeginCheckoutEvent({ session })
window.location.href = `/shop/checkout?clientSecret=${session.client_secret}`
})
})
</script>

<script>
document.addEventListener("astro:page-load", () => {
const mainImages = document.querySelectorAll('[id^="main-image-"]')
const thumbnails = document.querySelectorAll('[id^="thumbnail-"]')

if (!mainImages.length || !thumbnails.length) return

let selectedThumbnail = thumbnails[0]
selectedThumbnail.classList.replace("border-white", "border-black")

thumbnails.forEach((thumbnail, index) => {
thumbnail.addEventListener("click", () => {
mainImages.forEach((img, i) => {
if (i === index) {
img.classList.remove("absolute", "top-0", "opacity-0")
} else {
img.classList.add("absolute", "top-0", "opacity-0")
}
})

selectedThumbnail.classList.replace(
"border-black",
"border-white"
)
thumbnail.classList.replace("border-white", "border-black")
selectedThumbnail = thumbnail
})
})
})
</script>
64 changes: 64 additions & 0 deletions astro/src/pages/shop/_index-ssg.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
import { Image } from "@unpic/astro"
import BaseLayout from "@layouts/BaseLayout.astro"
import LocalisedPrice from "@components/LocalisedPrice.astro"
import { getActivePrices } from "@utils/stripe"
const prices = await getActivePrices()
---

<BaseLayout
title="Shop | Giclée Fine Art Prints | Andrea Diotallevi Art"
description="Archival quality giclée generative art prints, on vegan certified Hahnemühle photo rag 308gsm matte paper, delivered in a cardboard tube with recycled plastic ends."
image={prices[0].product.images[0]}
tags={[
"Generative Art",
"p5.js",
"Processing",
"Procedural",
"Prints",
"Fine Art",
"Giclee",
"Hahnemühle photo rag",
]}
>
<div class="max-w-screen-xl mx-auto px-4 py-8">
<div class="text-center mb-8">
<h1 class="text-5xl font-bold mb-6">Shop</h1>
<p class="max-w-[600px] mx-auto">
Archival quality giclée generative art prints, on vegan
certified Hahnemühle photo rag 308gsm matte paper, delivered in
recycled packaging
</p>
</div>

<div class="grid grid-cols-2 md:grid-cols-4 gap-4 md:gap-6">
{
prices.map(price => (
<a
href={`/shop/${price.product.metadata.category}/${price.product.metadata.slug}`}
class="flex flex-col no-underline text-black hover:underline"
data-astro-prefetch
>
<Image
alt={price.product.name}
src={price.product.images[0]}
width={1000}
height={1414}
class="w-full h-auto object-contain"
/>
<h2 class="text-2xl font-semibold mt-4">
{price.product.metadata.displayName}
</h2>
<p class="text-lg font-medium mt-2">
<LocalisedPrice
priceCurrencyOptions={price.currency_options}
/>
</p>
</a>
))
}
</div>
</div>
</BaseLayout>
Loading

0 comments on commit 241a71a

Please sign in to comment.