From 5fb3e10598acfcab9740e4fbbf3855a25b44fe8b Mon Sep 17 00:00:00 2001 From: sebseb7 Date: Sat, 19 Jul 2025 11:23:31 +0200 Subject: [PATCH] Enhance product display in PrerenderProduct: Added a utility function to clean product names, improved layout with Box components for better styling, and formatted price display with tax. Updated product details section to include manufacturer, weight, and availability status, ensuring a more informative and visually appealing product presentation. --- src/PrerenderProduct.js | 290 +++++++++++++++++++++++++++------------- 1 file changed, 200 insertions(+), 90 deletions(-) diff --git a/src/PrerenderProduct.js b/src/PrerenderProduct.js index 0db1cc2..f6baa2e 100644 --- a/src/PrerenderProduct.js +++ b/src/PrerenderProduct.js @@ -14,18 +14,30 @@ const { const Footer = require('./components/Footer.js').default; const { Logo } = require('./components/header/index.js'); +// Utility function to clean product names by removing trailing number in parentheses +const cleanProductName = (name) => { + if (!name) return ""; + // Remove patterns like " (1)", " (3)", " (10)" at the end of the string + return name.replace(/\s*\(\d+\)\s*$/, "").trim(); +}; + class PrerenderProduct extends React.Component { render() { const { productData } = this.props; if (!productData) { return React.createElement( - Container, - { maxWidth: 'lg', sx: { py: 4 } }, + Box, + { sx: { p: 4, textAlign: "center" } }, React.createElement( Typography, - { variant: 'h4', component: 'h1', gutterBottom: true }, - 'Product not found' + { variant: 'h5', gutterBottom: true }, + 'Produkt nicht gefunden' + ), + React.createElement( + Typography, + null, + 'Das gesuchte Produkt existiert nicht oder wurde entfernt.' ) ); } @@ -36,6 +48,12 @@ class PrerenderProduct extends React.Component { ? `/assets/images/prod${product.pictureList.split(',')[0].trim()}.jpg` : '/assets/images/nopicture.jpg'; + // Format price with tax + const priceWithTax = new Intl.NumberFormat("de-DE", { + style: "currency", + currency: "EUR", + }).format(product.price); + return React.createElement( Box, { @@ -48,7 +66,7 @@ class PrerenderProduct extends React.Component { bgcolor: 'background.default' } }, - React.createElement( + React.createElement( AppBar, { position: 'sticky', color: 'primary', elevation: 0, sx: { zIndex: 1100 } }, React.createElement( @@ -62,18 +80,43 @@ class PrerenderProduct extends React.Component { ) ), React.createElement( - Container, - { maxWidth: 'lg', sx: { py: 4, flexGrow: 1 } }, + Box, + { + sx: { + p: { xs: 2, md: 2 }, + pb: { xs: 4, md: 8 }, + maxWidth: "1400px", + mx: "auto", + flexGrow: 1 + } + }, React.createElement( - Grid, - { container: true, spacing: 4 }, - // Product Image - React.createElement( - Grid, - { item: true, xs: 12, md: 6 }, + Box, + { + sx: { + display: "flex", + flexDirection: { xs: "column", md: "row" }, + gap: 4, + background: "#fff", + borderRadius: 2, + boxShadow: "0 2px 8px rgba(0,0,0,0.08)", + } + }, + // Product Image Section React.createElement( - Card, - { sx: { height: '100%' } }, + Box, + { + sx: { + width: { xs: "100%", sm: "555px" }, + maxWidth: "100%", + minHeight: "400px", + background: "#f8f8f8", + display: "flex", + flexDirection: "column", + alignItems: "center", + justifyContent: "center", + } + }, React.createElement( CardMedia, { @@ -84,108 +127,175 @@ class PrerenderProduct extends React.Component { sx: { objectFit: 'contain', p: 2 } } ) - ) - ), - // Product Details - React.createElement( - Grid, - { item: true, xs: 12, md: 6 }, + ), + // Product Details Section React.createElement( - Stack, - { spacing: 3 }, - React.createElement( - Typography, - { variant: 'h3', component: 'h1', gutterBottom: true }, - product.name - ), - React.createElement( - Typography, - { variant: 'h6', color: 'text.secondary' }, - (this.props.t ? this.props.t('product.articleNumber') : 'Artikelnummer')+': '+product.articleNumber+' '+(product.gtin ? ` | GTIN: ${product.gtin}` : "") - ), + Box, + { + sx: { + flex: "1 1 60%", + p: { xs: 2, md: 4 }, + display: "flex", + flexDirection: "column", + } + }, + // Product identifiers React.createElement( Box, - { sx: { mt: 1 } }, + { sx: { mb: 1 } }, React.createElement( - Typography, - { variant: 'h4', color: 'primary', fontWeight: 'bold' }, - new Intl.NumberFormat('de-DE', { - style: 'currency', - currency: 'EUR' - }).format(product.price) - ), - product.vat && React.createElement( Typography, { variant: 'body2', color: 'text.secondary' }, - `inkl. ${product.vat}% MwSt.` - ), - React.createElement( - Typography, - { - variant: 'body1', - color: product.available ? 'success.main' : 'error.main', - fontWeight: 'medium', - sx: { mt: 1 } - }, - product.available ? '✅ Verfügbar' : '❌ Nicht verfügbar' + (this.props.t ? this.props.t('product.articleNumber') : 'Artikelnummer')+': '+product.articleNumber+' '+(product.gtin ? ` | GTIN: ${product.gtin}` : "") ) ), - product.description && React.createElement( - Box, - { sx: { mt: 2 } }, - React.createElement( - Typography, - { variant: 'h6', gutterBottom: true }, - 'Beschreibung' - ), - React.createElement( - 'div', - { - dangerouslySetInnerHTML: { __html: product.description }, - style: { - fontFamily: '"Roboto","Helvetica","Arial",sans-serif', - fontSize: '1rem', - lineHeight: '1.5', - color: '#33691E' - } - } - ) - ), - // Product specifications + // Product title React.createElement( + Typography, + { + variant: 'h4', + component: 'h1', + gutterBottom: true, + sx: { fontWeight: 600, color: "#333" } + }, + cleanProductName(product.name) + ), + // Manufacturer if available + product.manufacturer && React.createElement( Box, - { sx: { mt: 2 } }, + { sx: { display: "flex", alignItems: "center", mb: 2 } }, React.createElement( Typography, - { variant: 'h6', gutterBottom: true }, - 'Produktdetails' - ), + { variant: 'body2', sx: { fontStyle: "italic" } }, + (this.props.t ? this.props.t('product.manufacturer') : 'Hersteller')+': '+product.manufacturer + ) + ), + // Product specifications (attributes) + attributes.length > 0 && React.createElement( + Box, + { sx: { mb: 2 } }, React.createElement( Stack, { direction: 'row', spacing: 1, flexWrap: 'wrap', gap: 1 }, - product.manufacturer && React.createElement( - Chip, - { label: `Hersteller: ${product.manufacturer}`, variant: 'outlined' } - ), - product.weight && product.weight > 0 && React.createElement( - Chip, - { label: `Gewicht: ${product.weight} kg`, variant: 'outlined' } - ), ...attributes.map((attr, index) => React.createElement( Chip, { key: index, label: `${attr.cName}: ${attr.cWert}`, - variant: 'outlined', - color: 'primary' + disabled: true, + sx: { mb: 1 } } ) ) ) + ), + // Weight + product.weight && product.weight > 0 && React.createElement( + Box, + { sx: { mb: 2 } }, + React.createElement( + Typography, + { variant: 'body2', color: 'text.secondary' }, + (this.props.t ? this.props.t('product.weight', { weight: product.weight.toFixed(1).replace(".", ",") }) : `Gewicht: ${product.weight.toFixed(1).replace(".", ",")} kg`) + ) + ), + // Price and availability section + React.createElement( + Box, + { + sx: { + mt: "auto", + p: 3, + background: "#f9f9f9", + borderRadius: 2, + } + }, + React.createElement( + Box, + { + sx: { + display: "flex", + flexDirection: { xs: "column", sm: "row" }, + justifyContent: "space-between", + alignItems: { xs: "flex-start", sm: "flex-start" }, + gap: 2, + } + }, + React.createElement( + Box, + null, + React.createElement( + Typography, + { + variant: "h4", + color: "primary", + sx: { fontWeight: "bold" } + }, + priceWithTax + ), + product.vat && React.createElement( + Typography, + { variant: 'body2', color: 'text.secondary' }, + (this.props.t ? this.props.t('product.inclVat', { vat: product.vat }) : `inkl. ${product.vat}% MwSt.`) + ), + product.versandklasse && + product.versandklasse != "standard" && + product.versandklasse != "kostenlos" && React.createElement( + Typography, + { variant: 'body2', color: 'text.secondary' }, + product.versandklasse + ), + React.createElement( + Typography, + { + variant: 'body1', + color: product.available ? 'success.main' : 'error.main', + fontWeight: 'medium', + sx: { mt: 1 } + }, + product.available ? '✅ Verfügbar' : '❌ Nicht verfügbar' + ) + ) + ) + ) + ) + ), + // Product full description + product.description && React.createElement( + Box, + { + sx: { + mt: 4, + p: 4, + background: "#fff", + borderRadius: 2, + boxShadow: "0 2px 8px rgba(0,0,0,0.08)", + } + }, + React.createElement( + Box, + { + sx: { + mt: 2, + lineHeight: 1.7, + "& p": { mt: 0, mb: 2 }, + "& strong": { fontWeight: 600 }, + } + }, + React.createElement( + 'div', + { + dangerouslySetInnerHTML: { __html: product.description }, + style: { + fontFamily: '"Roboto","Helvetica","Arial",sans-serif', + fontSize: '1rem', + lineHeight: '1.7', + color: '#333' + } + } ) ) - ) ) ), React.createElement(Footer)