From dfb4f3e1898f9979852530eda876b64201ef614f Mon Sep 17 00:00:00 2001 From: sebseb7 Date: Sat, 19 Jul 2025 11:30:37 +0200 Subject: [PATCH] Refactor PrerenderProduct layout: Introduced a back button for navigation, improved styling with Box components, and ensured consistent heights for product details and price sections. Enhanced product display with fixed height placeholders and updated availability messaging for better user experience. --- src/PrerenderProduct.js | 443 ++++++++++++++++++++++++++-------------- 1 file changed, 294 insertions(+), 149 deletions(-) diff --git a/src/PrerenderProduct.js b/src/PrerenderProduct.js index f6baa2e..e80afdc 100644 --- a/src/PrerenderProduct.js +++ b/src/PrerenderProduct.js @@ -90,178 +90,322 @@ class PrerenderProduct extends React.Component { flexGrow: 1 } }, + // Back button (breadcrumbs section) React.createElement( Box, { sx: { + mb: 2, + position: ["-webkit-sticky", "sticky"], + top: { + xs: "80px", + sm: "80px", + md: "80px", + lg: "80px", + }, + left: 0, + width: "100%", display: "flex", - flexDirection: { xs: "column", md: "row" }, - gap: 4, - background: "#fff", - borderRadius: 2, - boxShadow: "0 2px 8px rgba(0,0,0,0.08)", + zIndex: 999, // Just below the AppBar + py: 0, + px: 2, } }, - // Product Image Section React.createElement( Box, { sx: { - width: { xs: "100%", sm: "555px" }, - maxWidth: "100%", - minHeight: "400px", - background: "#f8f8f8", - display: "flex", - flexDirection: "column", - alignItems: "center", - justifyContent: "center", + ml: { xs: 0, md: 0 }, + display: "inline-flex", + px: 0, + py: 1, + backgroundColor: "#2e7d32", // primary dark green + borderRadius: 1, } }, - React.createElement( - CardMedia, - { - component: 'img', - height: '400', - image: mainImage, - alt: product.name, - sx: { objectFit: 'contain', p: 2 } - } - ) - ), - // Product Details Section - React.createElement( - Box, - { - sx: { - flex: "1 1 60%", - p: { xs: 2, md: 4 }, - display: "flex", - flexDirection: "column", - } - }, - // Product identifiers - React.createElement( - Box, - { sx: { mb: 1 } }, - React.createElement( - Typography, - { variant: 'body2', color: 'text.secondary' }, - (this.props.t ? this.props.t('product.articleNumber') : 'Artikelnummer')+': '+product.articleNumber+' '+(product.gtin ? ` | GTIN: ${product.gtin}` : "") - ) - ), - // 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: { display: "flex", alignItems: "center", mb: 2 } }, + { variant: "body2", color: "text.secondary" }, React.createElement( - Typography, - { 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 }, - ...attributes.map((attr, index) => - React.createElement( - Chip, - { - key: index, - label: `${attr.cName}: ${attr.cWert}`, - 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, + 'a', { - sx: { - display: "flex", - flexDirection: { xs: "column", sm: "row" }, - justifyContent: "space-between", - alignItems: { xs: "flex-start", sm: "flex-start" }, - gap: 2, + href: "#", + onClick: (e) => { + e.preventDefault(); + if (window.history.length > 1) { + window.history.back(); + } else { + window.location.href = '/'; + } + }, + style: { + paddingLeft: 16, + paddingRight: 16, + paddingTop: 8, + paddingBottom: 8, + textDecoration: "none", + color: "#fff", + fontWeight: "bold", + cursor: "pointer" } }, - 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' - ) - ) + this.props.t ? this.props.t('common.back') : 'Zurück' ) ) ) ), - // Product full description + React.createElement( + 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( + Box, + { + sx: { + width: { xs: "100%", sm: "555px" }, + maxWidth: "100%", + minHeight: "400px", + height: "400px", // Fixed height to prevent shifts + background: "#f8f8f8", + display: "flex", + flexDirection: "column", + alignItems: "center", + justifyContent: "center", + } + }, + React.createElement( + CardMedia, + { + component: 'img', + height: '400', + image: mainImage, + alt: product.name, + sx: { + objectFit: 'contain', + p: 2, + width: '100%', + maxWidth: '100%' + } + } + ) + ), + // Product Details Section + React.createElement( + Box, + { + sx: { + flex: "1 1 60%", + p: { xs: 2, md: 4 }, + display: "flex", + flexDirection: "column", + minHeight: "400px", // Ensure consistent minimum height + } + }, + // Product identifiers - fixed height to prevent shifts + React.createElement( + Box, + { sx: { mb: 1, minHeight: "24px" } }, + React.createElement( + Typography, + { variant: 'body2', color: 'text.secondary' }, + (this.props.t ? this.props.t('product.articleNumber') : 'Artikelnummer')+': '+product.articleNumber+' '+(product.gtin ? ` | GTIN: ${product.gtin}` : "") + ) + ), + // Product title - reserve space for 2 lines + React.createElement( + Box, + { sx: { mb: 2, minHeight: "72px" } }, + React.createElement( + Typography, + { + variant: 'h4', + component: 'h1', + sx: { + fontWeight: 600, + color: "#333", + display: '-webkit-box', + WebkitLineClamp: 2, + WebkitBoxOrient: 'vertical', + overflow: 'hidden', + lineHeight: 1.2 + } + }, + cleanProductName(product.name) + ) + ), + // Manufacturer if available - fixed height placeholder + React.createElement( + Box, + { sx: { display: "flex", alignItems: "center", mb: 2, minHeight: "28px" } }, + product.manufacturer && React.createElement( + Typography, + { variant: 'body2', sx: { fontStyle: "italic" } }, + (this.props.t ? this.props.t('product.manufacturer') : 'Hersteller')+': '+product.manufacturer + ) + ), + // Product specifications (attributes) - fixed height container + React.createElement( + Box, + { sx: { mb: 2, minHeight: attributes.length > 0 ? "auto" : "0px" } }, + attributes.length > 0 && React.createElement( + Stack, + { direction: 'row', spacing: 1, flexWrap: 'wrap', gap: 1 }, + ...attributes.map((attr, index) => + React.createElement( + Chip, + { + key: index, + label: `${attr.cName}: ${attr.cWert}`, + disabled: true, + size: "small", + sx: { mb: 1 } + } + ) + ) + ) + ), + // Weight - fixed height placeholder + React.createElement( + Box, + { sx: { mb: 2, minHeight: "28px" } }, + product.weight && product.weight > 0 && 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 - positioned at bottom + React.createElement( + Box, + { + sx: { + mt: "auto", + p: 3, + background: "#f9f9f9", + borderRadius: 2, + minHeight: "120px", // Fixed minimum height for price section + } + }, + React.createElement( + Box, + { + sx: { + display: "flex", + flexDirection: { xs: "column", sm: "row" }, + justifyContent: "space-between", + alignItems: { xs: "flex-start", sm: "flex-start" }, + gap: 2, + } + }, + // Left side - Price information + React.createElement( + Box, + { sx: { flex: 1 } }, + React.createElement( + Typography, + { + variant: "h4", + color: "primary", + sx: { fontWeight: "bold", mb: 1 } + }, + priceWithTax + ), + // VAT info with fixed height + React.createElement( + Box, + { sx: { minHeight: "20px", mb: 1 } }, + 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.`) + ) + ), + // Shipping class with fixed height + React.createElement( + Box, + { sx: { minHeight: "20px", mb: 1 } }, + product.versandklasse && + product.versandklasse != "standard" && + product.versandklasse != "kostenlos" && React.createElement( + Typography, + { variant: 'body2', color: 'text.secondary' }, + product.versandklasse + ) + ) + ), + // Right side - Cart button area with availability info + React.createElement( + Box, + { + sx: { + display: "flex", + flexDirection: "column", + minWidth: { xs: "100%", sm: "200px" } + } + }, + // Placeholder for AddToCartButton area + React.createElement( + Box, + { + sx: { + minHeight: "48px", + mb: 1, + display: "flex", + alignItems: "center", + justifyContent: "center", + backgroundColor: "#f0f0f0", + borderRadius: 2, + border: "1px dashed #ccc" + } + }, + React.createElement( + Typography, + { + variant: 'body2', + color: 'text.secondary', + sx: { fontStyle: 'italic' } + }, + 'Add to Cart Button' + ) + ), + // Availability and delivery time info (matching ProductDetailPage) + React.createElement( + Typography, + { + variant: 'caption', + sx: { + fontStyle: "italic", + color: "text.secondary", + textAlign: "center", + minHeight: "28px", + display: "flex", + alignItems: "center", + justifyContent: "center" + } + }, + product.id && product.id.toString().endsWith("steckling") ? + (this.props.t ? this.props.t('delivery.times.cutting14Days') : "Lieferzeit: 14 Tage") : + product.available == 1 ? + (this.props.t ? this.props.t('delivery.times.standard2to3Days') : "Lieferzeit: 2-3 Tage") : + product.availableSupplier == 1 ? + (this.props.t ? this.props.t('delivery.times.supplier7to9Days') : "Lieferzeit: 7-9 Tage") : + (product.available ? '✅ Verfügbar' : '❌ Nicht verfügbar') + ) + ) + ) + ) + ) + ), + // Product full description - separate card product.description && React.createElement( Box, { @@ -271,6 +415,7 @@ class PrerenderProduct extends React.Component { background: "#fff", borderRadius: 2, boxShadow: "0 2px 8px rgba(0,0,0,0.08)", + minHeight: "100px" // Minimum height to prevent shifts } }, React.createElement(