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.

This commit is contained in:
sebseb7
2025-07-19 11:30:37 +02:00
parent 5fb3e10598
commit dfb4f3e189

View File

@@ -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(