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.
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user