111 lines
3.1 KiB
TypeScript
111 lines
3.1 KiB
TypeScript
import Image from 'next/image'
|
|
import Link from 'next/link'
|
|
import { notFound } from 'next/navigation'
|
|
import { getPayload } from 'payload'
|
|
import React from 'react'
|
|
|
|
import config from '@/payload.config'
|
|
import type { Media, Product } from '@/payload-types'
|
|
import { cestaKSouboru, formatujCenu, popisStavu } from '@/lib/format'
|
|
import '../../styles.css'
|
|
|
|
export const dynamic = 'force-dynamic'
|
|
|
|
type Props = { params: Promise<{ slug: string }> }
|
|
|
|
export async function generateMetadata({ params }: Props) {
|
|
const polozka = await najdiPolozku((await params).slug)
|
|
if (!polozka) return { title: 'Položka nenalezena' }
|
|
|
|
return {
|
|
title: `${polozka.nazev} — Reiner zbraně`,
|
|
description: polozka.popis ?? undefined,
|
|
}
|
|
}
|
|
|
|
export default async function DetailPolozky({ params }: Props) {
|
|
const polozka = await najdiPolozku((await params).slug)
|
|
if (!polozka) notFound()
|
|
|
|
const obrazky = (polozka.obrazky ?? [])
|
|
.map((radek) => radek.obrazek)
|
|
.filter((o): o is Media => typeof o === 'object' && o !== null)
|
|
|
|
return (
|
|
<article className="stranka detail">
|
|
<p className="zpet">
|
|
{typeof polozka.kategorie === 'object' && polozka.kategorie !== null ? (
|
|
<Link href={`/kategorie/${polozka.kategorie.slug}`}>
|
|
← Zpět na {polozka.kategorie.nazev}
|
|
</Link>
|
|
) : (
|
|
<Link href="/">← Zpět na nabídku</Link>
|
|
)}
|
|
</p>
|
|
|
|
<h1>{polozka.nazev}</h1>
|
|
|
|
<p className="detail__cena">
|
|
{formatujCenu(polozka.cena)}
|
|
<span className={`znacka-stavu znacka-stavu--${polozka.stav}`}>
|
|
{popisStavu(polozka.stav)}
|
|
</span>
|
|
</p>
|
|
|
|
{obrazky.length > 0 && (
|
|
<div className="galerie">
|
|
{obrazky.map((obrazek) => {
|
|
const varianta = obrazek.sizes?.detail
|
|
const url = varianta?.url ?? obrazek.url
|
|
const width = varianta?.width ?? obrazek.width
|
|
const height = varianta?.height ?? obrazek.height
|
|
if (!url || !width || !height) return null
|
|
|
|
return (
|
|
<Image
|
|
key={obrazek.id}
|
|
alt={obrazek.alt ?? polozka.nazev}
|
|
src={cestaKSouboru(url)}
|
|
width={width}
|
|
height={height}
|
|
sizes="(max-width: 900px) 100vw, 800px"
|
|
/>
|
|
)
|
|
})}
|
|
</div>
|
|
)}
|
|
|
|
{polozka.parametry && polozka.parametry.length > 0 && (
|
|
<table className="parametry">
|
|
<tbody>
|
|
{polozka.parametry.map((parametr) => (
|
|
<tr key={parametr.id}>
|
|
<th scope="row">{parametr.nazev}</th>
|
|
<td>{parametr.hodnota}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
)}
|
|
|
|
{polozka.popis && <div className="popis">{polozka.popis}</div>}
|
|
</article>
|
|
)
|
|
}
|
|
|
|
async function najdiPolozku(slug: string): Promise<Product | null> {
|
|
const payload = await getPayload({ config: await config })
|
|
|
|
const { docs } = await payload.find({
|
|
collection: 'products',
|
|
where: {
|
|
slug: { equals: slug },
|
|
skryto: { not_equals: true },
|
|
},
|
|
depth: 1,
|
|
limit: 1,
|
|
})
|
|
|
|
return docs[0] ?? null
|
|
}
|