import React, { Component } from 'react';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Grid';
import Pagination from '@mui/material/Pagination';
import FormControl from '@mui/material/FormControl';
import InputLabel from '@mui/material/InputLabel';
import Select from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';
import Product from './Product.js';
import { removeSessionSetting } from '../utils/sessionStorage.js';
// Sort products by fuzzy similarity to their name/description
function sortProductsByFuzzySimilarity(products, searchTerm) {
console.log('sortProductsByFuzzySimilarity',products,searchTerm);
// Create an array that preserves the product object and its searchable text
const productsWithText = products.map(product => {
const searchableText = `${product.name || ''} ${product.description || ''}`;
return { product, searchableText };
});
// Sort products based on their searchable text similarity
productsWithText.sort((a, b) => {
const scoreA = getFuzzySimilarityScore(a.searchableText, searchTerm);
const scoreB = getFuzzySimilarityScore(b.searchableText, searchTerm);
return scoreB - scoreA; // Higher scores first
});
// Return just the sorted product objects
return productsWithText.map(item => item.product);
}
// Calculate a similarity score between text and search term
function getFuzzySimilarityScore(text, searchTerm) {
const searchWords = searchTerm.toLowerCase().split(/\W+/).filter(Boolean);
const textWords = text.toLowerCase().split(/\W+/).filter(Boolean);
let totalScore = 0;
for (let searchWord of searchWords) {
// Exact matches get highest priority
if (textWords.includes(searchWord)) {
totalScore += 2;
continue;
}
// Partial matches get scored based on similarity
let bestMatch = 0;
for (let textWord of textWords) {
if (textWord.includes(searchWord) || searchWord.includes(textWord)) {
const similarity = Math.min(searchWord.length, textWord.length) /
Math.max(searchWord.length, textWord.length);
if (similarity > bestMatch) bestMatch = similarity;
}
}
totalScore += bestMatch;
}
return totalScore;
}
class ProductList extends Component {
constructor(props) {
super(props);
this.state = {
viewMode: window.productListViewMode || 'grid',
products:[],
page: window.productListPage || 1,
itemsPerPage: window.productListItemsPerPage || 20,
sortBy: window.currentSearchQuery ? 'searchField' : 'name'
};
}
componentDidMount() {
this.handleSearchQuery = () => {
this.setState({ sortBy: window.currentSearchQuery ? 'searchField' : 'name' });
};
window.addEventListener('search-query-change', this.handleSearchQuery);
}
componentWillUnmount() {
window.removeEventListener('search-query-change', this.handleSearchQuery);
}
handleViewModeChange = (viewMode) => {
this.setState({ viewMode });
window.productListViewMode = viewMode;
}
handlePageChange = (event, value) => {
this.setState({ page: value });
window.productListPage = value;
}
componentDidUpdate() {
const currentPageCapacity = this.state.itemsPerPage === 'all' ? Infinity : this.state.itemsPerPage;
if(this.props.products.length > 0 ) if (this.props.products.length < (currentPageCapacity * (this.state.page-1)) ) {
if(this.state.page != 1) this.setState({ page: 1 });
window.productListPage = 1;
}
}
handleProductsPerPageChange = (event) => {
const newItemsPerPage = event.target.value;
const newState = { itemsPerPage: newItemsPerPage };
window.productListItemsPerPage = newItemsPerPage;
if(newItemsPerPage!=='all'){
const newTotalPages = Math.ceil(this.props.products.length / newItemsPerPage);
if (this.state.page > newTotalPages) {
newState.page = newTotalPages;
window.productListPage = newTotalPages;
}
}
this.setState(newState);
}
handleSortChange = (event) => {
const sortBy = event.target.value;
this.setState({ sortBy });
}
renderPagination = (pages, page) => {
return (
{(this.state.itemsPerPage==='all')?null:
= 600}
showLastButton={window.innerWidth >= 600}
sx={{
'& .MuiPagination-ul': {
flexWrap: 'nowrap',
overflowX: 'auto',
maxWidth: '100%'
}
}}
/>
}
);
}
render() {
//console.log('products',this.props.activeAttributeFilters,this.props.activeManufacturerFilters,window.currentSearchQuery,this.state.sortBy);
const filteredProducts = (this.state.sortBy==='searchField')&&(window.currentSearchQuery)?sortProductsByFuzzySimilarity(this.props.products, window.currentSearchQuery):this.state.sortBy==='name'?this.props.products:this.props.products.sort((a,b)=>{
if(this.state.sortBy==='price-low-high'){
return a.price-b.price;
}
if(this.state.sortBy==='price-high-low'){
return b.price-a.price;
}
});
const products = this.state.itemsPerPage==='all'?[...filteredProducts]:filteredProducts.slice((this.state.page - 1) * this.state.itemsPerPage , this.state.page * this.state.itemsPerPage);
return (
{this.props.activeAttributeFilters.map((filter,index) => (
{
removeSessionSetting(`filter_attribute_${filter.id}`);
this.props.onFilterChange();
}}
onDelete={() => {
removeSessionSetting(`filter_attribute_${filter.id}`);
this.props.onFilterChange();
}}
clickable
/>
))}
{this.props.activeManufacturerFilters.map((filter,index) => (
{
removeSessionSetting(`filter_manufacturer_${filter.value}`);
this.props.onFilterChange();
}}
onDelete={() => {
removeSessionSetting(`filter_manufacturer_${filter.value}`);
this.props.onFilterChange();
}}
clickable
/>
))}
{/* Sort Dropdown */}
Sortierung
{/* Per Page Dropdown */}
pro Seite
{/* Product count info - mobile only */}
{
this.props.totalProductCount==this.props.products.length && this.props.totalProductCount>0 ?
`${this.props.totalProductCount} Produkte`
:
`${this.props.products.length} von ${this.props.totalProductCount} Produkte`
}
{ this.renderPagination(Math.ceil(filteredProducts.length / this.state.itemsPerPage), this.state.page) }
{/*this.props.dataType == 'category' && (<>Kategorie: {this.props.dataParam}>)}*/}
{this.props.dataType == 'search' && (<>Suchergebnisse für: "{this.props.dataParam}">)}
{
this.props.totalProductCount==this.props.products.length && this.props.totalProductCount>0 ?
`${this.props.totalProductCount} Produkte`
:
`${this.props.products.length} von ${this.props.totalProductCount} Produkte`
}
{products.map((product, index) => (
))}
{/* Bottom pagination */}
{this.renderPagination(Math.ceil(filteredProducts.length / this.state.itemsPerPage), this.state.page)}
);
}
}
export default ProductList;