feat: Refine i18n content across multiple locales and improve LLM SEO data processing for catalog generation.

This commit is contained in:
sebseb7
2025-12-14 09:47:51 +01:00
parent 9df5642a6e
commit 57515bfb85
49 changed files with 528 additions and 479 deletions

View File

@@ -36,11 +36,11 @@ function getCachedCategoryData(categoryId, language = 'de') {
try {
const cacheKey = `categoryProducts_${categoryId}_${language}`;
const cachedData = window.productCache[cacheKey];
if (cachedData) {
const { timestamp } = cachedData;
const cacheAge = Date.now() - timestamp;
const tenMinutes = 10 * 60 * 1000;
const tenMinutes = 10 * 60 * 1000;
if (cacheAge < tenMinutes) {
return cachedData;
}
@@ -58,21 +58,21 @@ function getFilteredProducts(unfilteredProducts, attributes, t) {
const attributeSettings = getAllSettingsWithPrefix('filter_attribute_');
const manufacturerSettings = getAllSettingsWithPrefix('filter_manufacturer_');
const availabilitySettings = getAllSettingsWithPrefix('filter_availability_');
const attributeFilters = [];
Object.keys(attributeSettings).forEach(key => {
if (attributeSettings[key] === 'true') {
attributeFilters.push(key.split('_')[2]);
}
});
const manufacturerFilters = [];
Object.keys(manufacturerSettings).forEach(key => {
if (manufacturerSettings[key] === 'true') {
manufacturerFilters.push(key.split('_')[2]);
}
});
const availabilityFilters = [];
Object.keys(availabilitySettings).forEach(key => {
if (availabilitySettings[key] === 'true') {
@@ -82,9 +82,9 @@ function getFilteredProducts(unfilteredProducts, attributes, t) {
const uniqueAttributes = [...new Set((attributes || []).map(attr => attr.kMerkmalWert ? attr.kMerkmalWert.toString() : ''))];
const uniqueManufacturers = [...new Set((unfilteredProducts || []).filter(product => product.manufacturerId).map(product => product.manufacturerId ? product.manufacturerId.toString() : ''))];
const uniqueManufacturersWithName = [...new Set((unfilteredProducts || []).filter(product => product.manufacturerId).map(product => ({id:product.manufacturerId ? product.manufacturerId.toString() : '',value:product.manufacturer})))];
const uniqueManufacturersWithName = [...new Set((unfilteredProducts || []).filter(product => product.manufacturerId).map(product => ({ id: product.manufacturerId ? product.manufacturerId.toString() : '', value: product.manufacturer })))];
const activeAttributeFilters = attributeFilters.filter(filter => uniqueAttributes.includes(filter));
const activeManufacturerFilters = manufacturerFilters.filter(filter => uniqueManufacturers.includes(filter));
const activeManufacturerFilters = manufacturerFilters.filter(filter => uniqueManufacturers.includes(filter));
const attributeFiltersByGroup = {};
for (const filterId of activeAttributeFilters) {
const attribute = attributes.find(attr => attr.kMerkmalWert.toString() === filterId);
@@ -95,26 +95,26 @@ function getFilteredProducts(unfilteredProducts, attributes, t) {
attributeFiltersByGroup[attribute.cName].push(filterId);
}
}
let filteredProducts = (unfilteredProducts || []).filter(product => {
const availabilityFilter = sessionStorage.getItem('filter_availability');
let inStockMatch = availabilityFilter == 1 ? true : (product.available>0);
let inStockMatch = availabilityFilter == 1 ? true : (product.available > 0);
// Check if there are any new products in the entire set
const hasNewProducts = (unfilteredProducts || []).some(product => isNew(product.neu));
// Only apply the new filter if there are actually new products and the filter is active
const isNewMatch = availabilityFilters.includes('2') && hasNewProducts ? isNew(product.neu) : true;
let soonMatch = availabilityFilters.includes('3') ? !product.available && product.incoming : true;
const soon2Match = (availabilityFilter != 1)&&availabilityFilters.includes('3') ? (product.available) || (!product.available && product.incoming) : true;
if( (availabilityFilter != 1)&&availabilityFilters.includes('3') && ((product.available) || (!product.available && product.incoming))){
const soon2Match = (availabilityFilter != 1) && availabilityFilters.includes('3') ? (product.available) || (!product.available && product.incoming) : true;
if ((availabilityFilter != 1) && availabilityFilters.includes('3') && ((product.available) || (!product.available && product.incoming))) {
inStockMatch = true;
soonMatch = true;
console.log("soon2Match", product.cName);
}
const manufacturerMatch = activeManufacturerFilters.length === 0 ||
const manufacturerMatch = activeManufacturerFilters.length === 0 ||
(product.manufacturerId && activeManufacturerFilters.includes(product.manufacturerId.toString()));
if (Object.keys(attributeFiltersByGroup).length === 0) {
@@ -130,41 +130,41 @@ function getFilteredProducts(unfilteredProducts, attributes, t) {
});
return manufacturerMatch && attributeMatch && soon2Match && inStockMatch && soonMatch && isNewMatch;
});
const activeAttributeFiltersWithNames = activeAttributeFilters.map(filter => {
const attribute = attributes.find(attr => attr.kMerkmalWert.toString() === filter);
return {name: attribute.cName, value: attribute.cWert, id: attribute.kMerkmalWert};
return { name: attribute.cName, value: attribute.cWert, id: attribute.kMerkmalWert };
});
const activeManufacturerFiltersWithNames = activeManufacturerFilters.map(filter => {
const manufacturer = uniqueManufacturersWithName.find(manufacturer => manufacturer.id === filter);
return {name: manufacturer.value, value: manufacturer.id};
return { name: manufacturer.value, value: manufacturer.id };
});
// Extract active availability filters
const availabilityFilter = sessionStorage.getItem('filter_availability');
const activeAvailabilityFilters = [];
// Check if there are actually products with these characteristics
const hasNewProducts = (unfilteredProducts || []).some(product => isNew(product.neu));
const hasComingSoonProducts = (unfilteredProducts || []).some(product => !product.available && product.incoming);
// Check for "auf Lager" filter (in stock) - it's active when filter_availability is NOT set to '1'
if (availabilityFilter !== '1') {
activeAvailabilityFilters.push({id: '1', name: t ? t('product.inStock') : 'auf Lager'});
}
// Check for "Neu" filter (new) - only show if there are actually new products and filter is active
if (availabilityFilters.includes('2') && hasNewProducts) {
activeAvailabilityFilters.push({id: '2', name: t ? t('product.new') : 'Neu'});
}
// Check for "Bald verfügbar" filter (coming soon) - only show if there are actually coming soon products and filter is active
if (availabilityFilters.includes('3') && hasComingSoonProducts) {
activeAvailabilityFilters.push({id: '3', name: t ? t('product.comingSoon') : 'Bald verfügbar'});
activeAvailabilityFilters.push({ id: '1', name: t ? t('product.inStock') : 'auf Lager' });
}
return {filteredProducts,activeAttributeFilters:activeAttributeFiltersWithNames,activeManufacturerFilters:activeManufacturerFiltersWithNames,activeAvailabilityFilters};
// Check for "Neu" filter (new) - only show if there are actually new products and filter is active
if (availabilityFilters.includes('2') && hasNewProducts) {
activeAvailabilityFilters.push({ id: '2', name: t ? t('product.new') : 'Neu' });
}
// Check for "Bald verfügbar" filter (coming soon) - only show if there are actually coming soon products and filter is active
if (availabilityFilters.includes('3') && hasComingSoonProducts) {
activeAvailabilityFilters.push({ id: '3', name: t ? t('product.comingSoon') : 'Bald verfügbar' });
}
return { filteredProducts, activeAttributeFilters: activeAttributeFiltersWithNames, activeManufacturerFilters: activeManufacturerFiltersWithNames, activeAvailabilityFilters };
}
function setCachedCategoryData(categoryId, data, language = 'de') {
if (!window.productCache) {
@@ -176,7 +176,7 @@ function setCachedCategoryData(categoryId, data, language = 'de') {
try {
const cacheKey = `categoryProducts_${categoryId}_${language}`;
if(data.products) for(const product of data.products) {
if (data.products) for (const product of data.products) {
const productCacheKey = `product_${product.id}_${language}`;
window.productDetailCache[productCacheKey] = product;
}
@@ -195,7 +195,7 @@ class Content extends Component {
this.state = {
loaded: false,
categoryName: null,
categoryName: null,
unfilteredProducts: [],
filteredProducts: [],
attributes: [],
@@ -206,11 +206,13 @@ class Content extends Component {
componentDidMount() {
const currentLanguage = this.props.i18n?.language || 'de';
if(this.props.params.categoryId) {this.setState({loaded: false, unfilteredProducts: [], filteredProducts: [], attributes: [], categoryName: null, childCategories: [], lastFetchedLanguage: currentLanguage}, () => {
if (this.props.params.categoryId) {
this.setState({ loaded: false, unfilteredProducts: [], filteredProducts: [], attributes: [], categoryName: null, childCategories: [], lastFetchedLanguage: currentLanguage }, () => {
this.fetchCategoryData(this.props.params.categoryId);
})}
})
}
else if (this.props.searchParams?.get('q')) {
this.setState({loaded: false, unfilteredProducts: [], filteredProducts: [], attributes: [], categoryName: null, childCategories: [], lastFetchedLanguage: currentLanguage}, () => {
this.setState({ loaded: false, unfilteredProducts: [], filteredProducts: [], attributes: [], categoryName: null, childCategories: [], lastFetchedLanguage: currentLanguage }, () => {
this.fetchSearchData(this.props.searchParams?.get('q'));
})
}
@@ -220,29 +222,29 @@ class Content extends Component {
const currentLanguage = this.props.i18n?.language || 'de';
const categoryChanged = this.props.params.categoryId && (prevProps.params.categoryId !== this.props.params.categoryId);
const searchChanged = this.props.searchParams?.get('q') && (prevProps.searchParams?.get('q') !== this.props.searchParams?.get('q'));
if(categoryChanged) {
// Clear context for new category loading
if (this.props.categoryContext && this.props.categoryContext.setCurrentCategory) {
this.props.categoryContext.setCurrentCategory(null);
}
window.currentSearchQuery = null;
this.setState({loaded: false, unfilteredProducts: [], filteredProducts: [], attributes: [], categoryName: null, childCategories: [], lastFetchedLanguage: currentLanguage}, () => {
this.fetchCategoryData(this.props.params.categoryId);
});
return; // Don't check language change if category changed
}
if (categoryChanged) {
// Clear context for new category loading
if (this.props.categoryContext && this.props.categoryContext.setCurrentCategory) {
this.props.categoryContext.setCurrentCategory(null);
}
window.currentSearchQuery = null;
this.setState({ loaded: false, unfilteredProducts: [], filteredProducts: [], attributes: [], categoryName: null, childCategories: [], lastFetchedLanguage: currentLanguage }, () => {
this.fetchCategoryData(this.props.params.categoryId);
});
return; // Don't check language change if category changed
}
else if (searchChanged) {
this.setState({loaded: false, unfilteredProducts: [], filteredProducts: [], attributes: [], categoryName: null, childCategories: [], lastFetchedLanguage: currentLanguage}, () => {
this.setState({ loaded: false, unfilteredProducts: [], filteredProducts: [], attributes: [], categoryName: null, childCategories: [], lastFetchedLanguage: currentLanguage }, () => {
this.fetchSearchData(this.props.searchParams?.get('q'));
});
return; // Don't check language change if search changed
}
// Re-fetch products when language changes to get translated content
const languageChanged = currentLanguage !== this.state.lastFetchedLanguage;
console.log('Content componentDidUpdate:', {
languageChanged,
lastFetchedLang: this.state.lastFetchedLanguage,
@@ -252,27 +254,27 @@ class Content extends Component {
categoryId: this.props.params.categoryId,
hasSearchQuery: !!this.props.searchParams?.get('q')
});
if(languageChanged) {
if (languageChanged) {
console.log('Content: Language changed! Re-fetching data...');
// Re-fetch current data with new language
// Note: Language is now part of the cache key, so it will automatically fetch fresh data
if(this.props.params.categoryId) {
if (this.props.params.categoryId) {
// Re-fetch category data with new language
console.log('Content: Re-fetching category', this.props.params.categoryId);
this.setState({loaded: false, lastFetchedLanguage: currentLanguage}, () => {
this.setState({ loaded: false, lastFetchedLanguage: currentLanguage }, () => {
this.fetchCategoryData(this.props.params.categoryId);
});
} else if(this.props.searchParams?.get('q')) {
} else if (this.props.searchParams?.get('q')) {
// Re-fetch search data with new language
console.log('Content: Re-fetching search', this.props.searchParams?.get('q'));
this.setState({loaded: false, lastFetchedLanguage: currentLanguage}, () => {
this.setState({ loaded: false, lastFetchedLanguage: currentLanguage }, () => {
this.fetchSearchData(this.props.searchParams?.get('q'));
});
} else {
// If not viewing category or search, just re-filter existing products
console.log('Content: Just re-filtering existing products');
this.setState({lastFetchedLanguage: currentLanguage});
this.setState({ lastFetchedLanguage: currentLanguage });
this.filterProducts();
}
}
@@ -281,7 +283,7 @@ class Content extends Component {
processData(response) {
const rawProducts = response.products;
const currentLanguage = this.props.languageContext?.currentLanguage || this.props.i18n?.language || 'de';
if (!window.individualProductCache) {
window.individualProductCache = {};
}
@@ -289,10 +291,10 @@ class Content extends Component {
const unfilteredProducts = [];
//console.log("processData", rawProducts);
if(rawProducts) rawProducts.forEach(product => {
if (rawProducts) rawProducts.forEach(product => {
const effectiveProduct = product.translatedProduct || product;
const cacheKey = `${effectiveProduct.id}_${currentLanguage}`;
window.individualProductCache[cacheKey] = {
data: effectiveProduct,
timestamp: Date.now()
@@ -319,16 +321,16 @@ class Content extends Component {
categoryName: response.categoryName,
name: response.name
});
if (this.props.categoryContext && this.props.categoryContext.setCurrentCategory) {
if (response.categoryName || response.name) {
console.log('Content: Setting category context');
this.props.categoryContext.setCurrentCategory({
id: this.props.params.categoryId,
name: response.categoryName || response.name
});
console.log('Content: Setting category context');
this.props.categoryContext.setCurrentCategory({
id: this.props.params.categoryId,
name: response.categoryName || response.name
});
} else {
console.log('Content: No category name found to set in context');
console.log('Content: No category name found to set in context');
}
} else {
console.warn('Content: categoryContext prop is missing!');
@@ -352,7 +354,7 @@ class Content extends Component {
// Track if we've received the full response to ignore stub response if needed
let receivedFullResponse = false;
window.socketManager.on(`productList:${categoryId}`,(response) => {
window.socketManager.on(`productList:${categoryId}`, (response) => {
console.log("getCategoryProducts full response", response);
receivedFullResponse = true;
setCachedCategoryData(categoryId, response, currentLanguage);
@@ -382,7 +384,7 @@ class Content extends Component {
}
);
}
processDataWithCategoryTree(response, categoryId) {
console.log("---------------processDataWithCategoryTree", response, categoryId);
// Get child categories from the cached category tree
@@ -392,10 +394,10 @@ class Content extends Component {
const categoryTreeCache = window.categoryService.getSync(209, currentLanguage);
if (categoryTreeCache) {
// If categoryId is a string (SEO name), find by seoName, otherwise by ID
const targetCategory = typeof categoryId === 'string'
const targetCategory = typeof categoryId === 'string'
? this.findCategoryBySeoName(categoryTreeCache, categoryId)
: this.findCategoryById(categoryTreeCache, categoryId);
if (targetCategory && targetCategory.children) {
childCategories = targetCategory.children;
}
@@ -403,7 +405,7 @@ class Content extends Component {
} catch (err) {
console.error('Error getting child categories from tree:', err);
}
// Add child categories to the response
const enhancedResponse = {
...response,
@@ -412,42 +414,42 @@ class Content extends Component {
// Attempt to set category name from the tree if missing in response
if (!enhancedResponse.categoryName && !enhancedResponse.name) {
// Try to find name in the tree using the ID or SEO name
try {
const currentLanguage = this.props.languageContext?.currentLanguage || this.props.i18n?.language || 'de';
const categoryTreeCache = window.categoryService.getSync(209, currentLanguage);
if (categoryTreeCache) {
const targetCategory = typeof categoryId === 'string'
? this.findCategoryBySeoName(categoryTreeCache, categoryId)
: this.findCategoryById(categoryTreeCache, categoryId);
if (targetCategory && targetCategory.name) {
enhancedResponse.categoryName = targetCategory.name;
}
}
} catch (err) {
console.error('Error finding category name in tree:', err);
}
// Try to find name in the tree using the ID or SEO name
try {
const currentLanguage = this.props.languageContext?.currentLanguage || this.props.i18n?.language || 'de';
const categoryTreeCache = window.categoryService.getSync(209, currentLanguage);
if (categoryTreeCache) {
const targetCategory = typeof categoryId === 'string'
? this.findCategoryBySeoName(categoryTreeCache, categoryId)
: this.findCategoryById(categoryTreeCache, categoryId);
if (targetCategory && targetCategory.name) {
enhancedResponse.categoryName = targetCategory.name;
}
}
} catch (err) {
console.error('Error finding category name in tree:', err);
}
}
this.processData(enhancedResponse);
}
findCategoryById(category, targetId) {
if (!category) return null;
if (category.id === targetId) {
return category;
}
if (category.children) {
for (let child of category.children) {
const found = this.findCategoryById(child, targetId);
if (found) return found;
}
}
return null;
}
@@ -472,7 +474,7 @@ class Content extends Component {
}
filterProducts() {
this.setState({
this.setState({
...getFilteredProducts(
this.state.unfilteredProducts,
this.state.attributes,
@@ -484,25 +486,25 @@ class Content extends Component {
// Helper function to find category by seoName
findCategoryBySeoName = (categoryNode, seoName) => {
if (!categoryNode) return null;
if (categoryNode.seoName === seoName) {
return categoryNode;
}
if (categoryNode.children) {
for (const child of categoryNode.children) {
const found = this.findCategoryBySeoName(child, seoName);
if (found) return found;
}
}
return null;
}
// Helper function to get current category ID from seoName
getCurrentCategoryId = () => {
const seoName = this.props.params.categoryId;
// Get the category tree from cache
const currentLanguage = this.props.languageContext?.currentLanguage || this.props.i18n?.language || 'de';
const categoryTreeCache = window.categoryService.getSync(209, currentLanguage);
@@ -521,7 +523,7 @@ class Content extends Component {
renderParentCategoryNavigation = () => {
const currentCategoryId = this.getCurrentCategoryId();
if (!currentCategoryId) return null;
// Get the category tree from cache
const currentLanguage = this.props.languageContext?.currentLanguage || this.props.i18n?.language || 'de';
const categoryTreeCache = window.categoryService.getSync(209, currentLanguage);
@@ -558,289 +560,289 @@ class Content extends Component {
render() {
// console.log('Content props:', this.props);
// Check if we should show category boxes instead of product list
const showCategoryBoxes = this.state.loaded &&
this.state.unfilteredProducts.length === 0 &&
this.state.childCategories.length > 0;
const showCategoryBoxes = this.state.loaded &&
this.state.unfilteredProducts.length === 0 &&
this.state.childCategories.length > 0;
console.log("showCategoryBoxes", showCategoryBoxes, this.state.unfilteredProducts.length, this.state.childCategories.length);
return (
<Container maxWidth="xl" sx={{ py: { xs: 0, sm: 2 }, px: { xs: 0, sm: 3 }, flexGrow: 1, display: 'grid', gridTemplateRows: '1fr' }}>
{showCategoryBoxes ? (
// Show category boxes layout when no products but have child categories
<CategoryBoxGrid
<CategoryBoxGrid
categories={this.state.childCategories}
title={this.state.categoryName}
/>
) : (
<>
{/* Show subcategories above main layout when there are both products and child categories */}
{this.state.loaded &&
this.state.unfilteredProducts.length > 0 &&
this.state.childCategories.length > 0 && (
<Box sx={{ mb: 4 }}>
{(() => {
const parentCategory = this.renderParentCategoryNavigation();
if (parentCategory) {
// Show parent category to the left of subcategories
return (
<Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 3, flexWrap: 'wrap' }}>
{/* Parent Category Box */}
<Box sx={{ mt:2,position: 'relative', flexShrink: 0 }}>
<CategoryBox
id={parentCategory.id}
seoName={parentCategory.seoName}
name={parentCategory.name}
image={parentCategory.image}
height={130}
fontSize="1.0rem"
/>
{/* Up Arrow Overlay */}
<Box sx={{
position: 'absolute',
top: 8,
right: 8,
bgcolor: 'rgba(27, 94, 32, 0.8)',
borderRadius: '50%',
zIndex: 100,
width: 32,
height: 32,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
pointerEvents: 'none'
}}>
<KeyboardArrowUpIcon sx={{ color: 'white', fontSize: '1.2rem' }} />
{this.state.loaded &&
this.state.unfilteredProducts.length > 0 &&
this.state.childCategories.length > 0 && (
<Box sx={{ mb: 4 }}>
{(() => {
const parentCategory = this.renderParentCategoryNavigation();
if (parentCategory) {
// Show parent category to the left of subcategories
return (
<Box sx={{ display: 'flex', alignItems: 'flex-start', gap: 3, flexWrap: 'wrap' }}>
{/* Parent Category Box */}
<Box sx={{ mt: 2, position: 'relative', flexShrink: 0 }}>
<CategoryBox
id={parentCategory.id}
seoName={parentCategory.seoName}
name={parentCategory.name}
image={parentCategory.image}
height={130}
fontSize="1.0rem"
/>
{/* Up Arrow Overlay */}
<Box sx={{
position: 'absolute',
top: 8,
right: 8,
bgcolor: 'rgba(27, 94, 32, 0.8)',
borderRadius: '50%',
zIndex: 100,
width: 32,
height: 32,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
pointerEvents: 'none'
}}>
<KeyboardArrowUpIcon sx={{ color: 'white', fontSize: '1.2rem' }} />
</Box>
</Box>
{/* Subcategories Grid */}
<Box sx={{ flexGrow: 1 }}>
<CategoryBoxGrid categories={this.state.childCategories} />
</Box>
</Box>
{/* Subcategories Grid */}
<Box sx={{ flexGrow: 1 }}>
<CategoryBoxGrid categories={this.state.childCategories} />
</Box>
</Box>
);
} else {
// No parent category, just show subcategories
return <CategoryBoxGrid categories={this.state.childCategories} />;
}
})()}
</Box>
)}
);
} else {
// No parent category, just show subcategories
return <CategoryBoxGrid categories={this.state.childCategories} />;
}
})()}
</Box>
)}
{/* Show standalone parent category navigation when there are only products */}
{this.state.loaded &&
this.props.params.categoryId &&
!(this.state.unfilteredProducts.length > 0 && this.state.childCategories.length > 0) && (() => {
const parentCategory = this.renderParentCategoryNavigation();
if (parentCategory) {
return (
<Box sx={{ mb: 3 }}>
<Box sx={{ position: 'relative', width: 'fit-content' }}>
<CategoryBox
id={parentCategory.id}
seoName={parentCategory.seoName}
name={parentCategory.name}
image={parentCategory.image}
height={130}
fontSize="1.0rem"
/>
{/* Up Arrow Overlay */}
<Box sx={{
position: 'absolute',
top: 8,
right: 8,
bgcolor: 'rgba(27, 94, 32, 0.8)',
borderRadius: '50%',
zIndex: 100,
width: 32,
height: 32,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
pointerEvents: 'none'
}}>
<KeyboardArrowUpIcon sx={{ color: 'white', fontSize: '1.2rem' }} />
{this.state.loaded &&
this.props.params.categoryId &&
!(this.state.unfilteredProducts.length > 0 && this.state.childCategories.length > 0) && (() => {
const parentCategory = this.renderParentCategoryNavigation();
if (parentCategory) {
return (
<Box sx={{ mb: 3 }}>
<Box sx={{ position: 'relative', width: 'fit-content' }}>
<CategoryBox
id={parentCategory.id}
seoName={parentCategory.seoName}
name={parentCategory.name}
image={parentCategory.image}
height={130}
fontSize="1.0rem"
/>
{/* Up Arrow Overlay */}
<Box sx={{
position: 'absolute',
top: 8,
right: 8,
bgcolor: 'rgba(27, 94, 32, 0.8)',
borderRadius: '50%',
zIndex: 100,
width: 32,
height: 32,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
pointerEvents: 'none'
}}>
<KeyboardArrowUpIcon sx={{ color: 'white', fontSize: '1.2rem' }} />
</Box>
</Box>
</Box>
</Box>
);
}
return null;
})()}
);
}
return null;
})()}
{/* Show normal product list layout */}
<Box sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', sm: '1fr 2fr', md: '1fr 3fr', lg: '1fr 4fr', xl: '1fr 4fr' },
<Box sx={{
display: 'grid',
gridTemplateColumns: { xs: '1fr', sm: '1fr 2fr', md: '1fr 3fr', lg: '1fr 4fr', xl: '1fr 4fr' },
gap: { xs: 0, sm: 3 }
}}>
<Stack direction="row" spacing={0} sx={{
display: 'flex',
flexDirection: 'column',
minHeight: { xs: 'min-content', sm: '100%' }
}}>
<Box >
<ProductFilters
products={this.state.unfilteredProducts}
filteredProducts={this.state.filteredProducts}
attributes={this.state.attributes}
searchParams={this.props.searchParams}
onFilterChange={()=>{this.filterProducts()}}
dataType={this.state.dataType}
dataParam={this.state.dataParam}
categoryName={this.state.categoryName}
/>
</Box>
{(this.props.params.categoryId == 'Stecklinge' || this.props.params.categoryId == 'Seeds') &&
<Box sx={{ display: { xs: 'none', sm: 'block' } }}>
<Typography variant="h6" sx={{mt:3}}>
{this.props.t ? this.props.t('navigation.otherCategories') : 'Andere Kategorien'}
</Typography>
</Box>
}
{this.props.params.categoryId == 'Stecklinge' && <Paper
component={Link}
to="/Kategorie/Seeds"
sx={{
p:0,
mt: 1,
textDecoration: 'none',
color: 'text.primary',
borderRadius: 2,
overflow: 'hidden',
height: 300,
transition: 'all 0.3s ease',
boxShadow: 10,
display: { xs: 'none', sm: 'block' },
'&:hover': {
transform: 'translateY(-5px)',
boxShadow: 20
}
}}
>
{/* Image Container - Place your seeds image here */}
<Box sx={{
height: '100%',
bgcolor: '#e1f0d3',
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<img
src="/assets/images/seeds.avif"
alt="Seeds"
fetchPriority="high"
loading="eager"
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}}
/>
{/* Overlay text - optional */}
<Box sx={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
bgcolor: 'rgba(27, 94, 32, 0.8)',
p: 2,
<Stack direction="row" spacing={0} sx={{
display: 'flex',
flexDirection: 'column',
minHeight: { xs: 'min-content', sm: '100%' }
}}>
<Typography sx={{ fontSize: '1.3rem', color: 'white', fontFamily: 'SwashingtonCP' }}>
{this.props.t('sections.seeds')}
</Typography>
<Box >
<ProductFilters
products={this.state.unfilteredProducts}
filteredProducts={this.state.filteredProducts}
attributes={this.state.attributes}
searchParams={this.props.searchParams}
onFilterChange={() => { this.filterProducts() }}
dataType={this.state.dataType}
dataParam={this.state.dataParam}
categoryName={this.state.categoryName}
/>
</Box>
{(this.props.params.categoryId == 'Stecklinge___' || this.props.params.categoryId == 'Seeds___') &&
<Box sx={{ display: { xs: 'none', sm: 'block' } }}>
<Typography variant="h6" sx={{ mt: 3 }}>
{this.props.t ? this.props.t('navigation.otherCategories') : 'Andere Kategorien'}
</Typography>
</Box>
}
{this.props.params.categoryId == 'Stecklinge' && <Paper
component={Link}
to="/Kategorie/Seeds"
sx={{
p: 0,
mt: 1,
textDecoration: 'none',
color: 'text.primary',
borderRadius: 2,
overflow: 'hidden',
height: 300,
transition: 'all 0.3s ease',
boxShadow: 10,
display: { xs: 'none', sm: 'block' },
'&:hover': {
transform: 'translateY(-5px)',
boxShadow: 20
}
}}
>
{/* Image Container - Place your seeds image here */}
<Box sx={{
height: '100%',
bgcolor: '#e1f0d3',
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<img
src="/assets/images/seeds.avif"
alt="Seeds"
fetchPriority="high"
loading="eager"
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}}
/>
{/* Overlay text - optional */}
<Box sx={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
bgcolor: 'rgba(27, 94, 32, 0.8)',
p: 2,
}}>
<Typography sx={{ fontSize: '1.3rem', color: 'white', fontFamily: 'SwashingtonCP' }}>
{this.props.t('sections.seeds')}
</Typography>
</Box>
</Box>
</Paper>
}
{this.props.params.categoryId == 'Seeds___' && <Paper
component={Link}
to="/Kategorie/Stecklinge"
sx={{
p: 0,
mt: 1,
textDecoration: 'none',
color: 'text.primary',
borderRadius: 2,
overflow: 'hidden',
height: 300,
boxShadow: 10,
transition: 'all 0.3s ease',
display: { xs: 'none', sm: 'block' },
'&:hover': {
transform: 'translateY(-5px)',
boxShadow: 20
}
}}
>
{/* Image Container - Place your cutlings image here */}
<Box sx={{
height: '100%',
bgcolor: '#e8f5d6',
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<img
src="/assets/images/cutlings.avif"
alt="Stecklinge"
fetchPriority="high"
loading="eager"
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}}
/>
{/* Overlay text - optional */}
<Box sx={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
bgcolor: 'rgba(27, 94, 32, 0.8)',
p: 2,
}}>
<Typography sx={{ fontSize: '1.3rem', color: 'white', fontFamily: 'SwashingtonCP' }}>
{this.props.t('sections.stecklinge')}
</Typography>
</Box>
</Box>
</Paper>}
</Stack>
<Box>
<ProductList
totalProductCount={(this.state.unfilteredProducts || []).length}
products={this.state.filteredProducts || []}
activeAttributeFilters={this.state.activeAttributeFilters || []}
activeManufacturerFilters={this.state.activeManufacturerFilters || []}
activeAvailabilityFilters={this.state.activeAvailabilityFilters || []}
onFilterChange={() => { this.filterProducts() }}
dataType={this.state.dataType}
dataParam={this.state.dataParam}
/>
</Box>
</Box>
</Paper>
}
{this.props.params.categoryId == 'Seeds' && <Paper
component={Link}
to="/Kategorie/Stecklinge"
sx={{
p: 0,
mt: 1,
textDecoration: 'none',
color: 'text.primary',
borderRadius: 2,
overflow: 'hidden',
height: 300,
boxShadow: 10,
transition: 'all 0.3s ease',
display: { xs: 'none', sm: 'block' },
'&:hover': {
transform: 'translateY(-5px)',
boxShadow: 20
}
}}
>
{/* Image Container - Place your cutlings image here */}
<Box sx={{
height: '100%',
bgcolor: '#e8f5d6',
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<img
src="/assets/images/cutlings.avif"
alt="Stecklinge"
fetchPriority="high"
loading="eager"
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}}
/>
{/* Overlay text - optional */}
<Box sx={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
bgcolor: 'rgba(27, 94, 32, 0.8)',
p: 2,
}}>
<Typography sx={{ fontSize: '1.3rem', color: 'white', fontFamily: 'SwashingtonCP' }}>
{this.props.t('sections.stecklinge')}
</Typography>
</Box>
</Box>
</Paper>}
</Stack>
<Box>
<ProductList
totalProductCount={(this.state.unfilteredProducts || []).length}
products={this.state.filteredProducts || []}
activeAttributeFilters={this.state.activeAttributeFilters || []}
activeManufacturerFilters={this.state.activeManufacturerFilters || []}
activeAvailabilityFilters={this.state.activeAvailabilityFilters || []}
onFilterChange={()=>{this.filterProducts()}}
dataType={this.state.dataType}
dataParam={this.state.dataParam}
/>
</Box>
</Box>
</>
)}
</Container>

View File

@@ -156,7 +156,7 @@ const MainPageLayout = () => {
};
const allTitles = {
home: t('titles.home') ,
home: t('titles.home'),
aktionen: t('titles.aktionen'),
filiale: t('titles.filiale')
};
@@ -164,7 +164,7 @@ const MainPageLayout = () => {
const allContentBoxes = {
home: [
{ title: t('sections.seeds'), image: "/assets/images/seeds.avif", bgcolor: "#e1f0d3", link: "/Kategorie/Seeds" },
{ title: t('sections.stecklinge'), image: "/assets/images/cutlings.avif", bgcolor: "#e8f5d6", link: "/Kategorie/Stecklinge" }
{ title: t('sections.konfigurator'), image: "/assets/images/konfigurator.avif", bgcolor: "#e8f5d6", link: "/Konfigurator" }
],
aktionen: [
{ title: t('sections.oilPress'), image: "/assets/images/presse.jpg", bgcolor: "#e1f0d3", link: "/presseverleih" },
@@ -262,16 +262,16 @@ const MainPageLayout = () => {
position: pageType === "home" ? "relative" : "absolute", top: 0, left: 0, width: "100%", pointerEvents: getOpacity(pageType) === 1 ? "auto" : "none"
}}>
{contentBoxes.map((box, index) => (
<ContentBox
key={`${pageType}-${index}`}
box={box}
index={index}
pageType={pageType}
starHovered={starHovered}
setStarHovered={setStarHovered}
opacity={getOpacity(pageType)}
translatedContent={translatedContent}
/>
<ContentBox
key={`${pageType}-${index}`}
box={box}
index={index}
pageType={pageType}
starHovered={starHovered}
setStarHovered={setStarHovered}
opacity={getOpacity(pageType)}
translatedContent={translatedContent}
/>
))}
</Grid>
))}