This commit is contained in:
seb
2026-10-06 11:20:11 +02:00
parent ee49ed29de
commit 03608017f3
3 changed files with 165 additions and 22 deletions

View File

@@ -97,14 +97,19 @@ function scheduleRebuild() {
*/ */
function toIndexRecord(article, categoryId) { function toIndexRecord(article, categoryId) {
const eans = article.eans ?? article.eanCodes ?? article.ean ?? null; const eans = article.eans ?? article.eanCodes ?? article.ean ?? null;
const childCount = Number(article.childCount) || 0;
const price = article.price ?? article.net ?? article.vknetto ?? null;
return { return {
...article, ...article,
id: article.id, id: article.id,
sku: article.sku, sku: article.sku,
name: article.name, name: article.name,
price,
net: article.net ?? price,
eans: Array.isArray(eans) ? eans.filter(Boolean) : eans ? [eans] : [], eans: Array.isArray(eans) ? eans.filter(Boolean) : eans ? [eans] : [],
categories: categoryId != null ? String(categoryId) : null, categories: categoryId != null ? String(categoryId) : null,
isParent: Boolean(article.isParent ?? article.is_parent), isParent: Boolean(article.isParent ?? article.is_parent ?? (childCount > 0)),
childCount,
}; };
} }
@@ -135,7 +140,20 @@ export function buildArticleIndex(views) {
ids.add(String(categoryId)); ids.add(String(categoryId));
existing.categories = Array.from(ids).join(','); existing.categories = Array.from(ids).join(',');
} }
existing.isParent = Boolean(existing.isParent || (article.isParent ?? article.is_parent)); const childCount = Number(article.childCount) || 0;
if (childCount > (Number(existing.childCount) || 0)) {
existing.childCount = childCount;
}
existing.isParent = Boolean(
existing.isParent ||
(article.isParent ?? article.is_parent) ||
(childCount > 0)
);
if (existing.price == null && (article.price != null || article.net != null)) {
const p = article.price ?? article.net ?? article.vknetto;
existing.price = p;
existing.net = article.net ?? p;
}
} }
} }

View File

@@ -28,7 +28,7 @@ import { BrandLabel } from '../brand';
import { formatPrice } from '../../utils/price'; import { formatPrice } from '../../utils/price';
import { formatStock } from './searchFormat'; import { formatStock } from './searchFormat';
import ResultsPagination from './ResultsPagination'; import ResultsPagination from './ResultsPagination';
import { BORDER } from '../../colors'; import { BORDER, SCRIM_LABEL } from '../../colors';
const searchResultRowSx = { const searchResultRowSx = {
alignItems: 'center', alignItems: 'center',
@@ -45,6 +45,8 @@ const searchResultRowSx = {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
lineHeight: '22px', lineHeight: '22px',
height: '22px', height: '22px',
display: 'flex',
alignItems: 'center',
}, },
'& .MuiListItemText-secondary': { '& .MuiListItemText-secondary': {
overflow: 'hidden', overflow: 'hidden',
@@ -512,7 +514,52 @@ export default class ArticleSearch extends PureComponent {
</ListItemAvatar> </ListItemAvatar>
<ListItemText <ListItemText
primary={article.name || '–'} primary={
<Box
component="span"
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: 0.75,
maxWidth: '100%',
}}
>
<Box
component="span"
sx={{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
>
{article.name || '–'}
</Box>
{Boolean(article.isParent || article.is_parent || (Number(article.childCount) > 0)) && (
<Box
component="span"
title={`${Number(article.childCount) || 0} Varianten`}
sx={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
px: 0.75,
py: 0.25,
borderRadius: 999,
bgcolor: SCRIM_LABEL,
color: 'common.white',
fontSize: 11,
fontWeight: 600,
lineHeight: 1.2,
whiteSpace: 'nowrap',
flexShrink: 0,
pointerEvents: 'none',
}}
>
{Number(article.childCount) || 0}
</Box>
)}
</Box>
}
secondary={ secondary={
<Typography <Typography
component="span" component="span"
@@ -772,6 +819,30 @@ export default class ArticleSearch extends PureComponent {
<Typography variant="body2" fontWeight={600} noWrap sx={{ flex: 1 }}> <Typography variant="body2" fontWeight={600} noWrap sx={{ flex: 1 }}>
{article.name || '–'} {article.name || '–'}
</Typography> </Typography>
{Boolean(article.isParent || article.is_parent || (Number(article.childCount) > 0)) && (
<Box
component="span"
title={`${Number(article.childCount) || 0} Varianten`}
sx={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
px: 0.75,
py: 0.2,
borderRadius: 999,
bgcolor: SCRIM_LABEL,
color: 'common.white',
fontSize: 11,
fontWeight: 600,
lineHeight: 1.2,
whiteSpace: 'nowrap',
flexShrink: 0,
pointerEvents: 'none',
}}
>
{Number(article.childCount) || 0}
</Box>
)}
</Box> </Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: 0.25, height: 18, minHeight: 18 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: 0.25, height: 18, minHeight: 18 }}>
{(article.brand?.name || article.brandName) && ( {(article.brand?.name || article.brandName) && (

View File

@@ -48,6 +48,7 @@ import {
categoryAutomat, categoryAutomat,
} from '../automats'; } from '../automats';
import { BrandLabel } from '../components/brand'; import { BrandLabel } from '../components/brand';
import { SCRIM_LABEL } from '../colors';
// #endregion // #endregion
// #region Styles & Measure Sample // #region Styles & Measure Sample
@@ -66,6 +67,8 @@ const resultRowSx = {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
lineHeight: '22px', lineHeight: '22px',
height: '22px', height: '22px',
display: 'flex',
alignItems: 'center',
}, },
'& .MuiListItemText-secondary': { '& .MuiListItemText-secondary': {
overflow: 'hidden', overflow: 'hidden',
@@ -579,7 +582,12 @@ class ArtikelSearchPage extends Component {
<Box> <Box>
{rows.length > 0 && ( {rows.length > 0 && (
<List component={Paper} variant="outlined" disablePadding> <List component={Paper} variant="outlined" disablePadding>
{rows.map((row, index) => ( {rows.map((row, index) => {
const isParent = Boolean(row.isParent || row.is_parent);
const childCount = Number(row.childCount) || 0;
const showChildBadge = isParent || childCount > 0;
const price = row.price ?? row.net ?? row.vknetto;
return (
<ListItemButton <ListItemButton
key={row.id} key={row.id}
type="button" type="button"
@@ -593,7 +601,52 @@ class ArtikelSearchPage extends Component {
sx={resultRowSx} sx={resultRowSx}
> >
<ListItemText <ListItemText
primary={row.name} primary={
<Box
component="span"
sx={{
display: 'inline-flex',
alignItems: 'center',
gap: 0.75,
maxWidth: '100%',
}}
>
<Box
component="span"
sx={{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
>
{row.name}
</Box>
{showChildBadge && (
<Box
component="span"
title={`${childCount} Varianten`}
sx={{
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
px: 0.75,
py: 0.25,
borderRadius: 999,
bgcolor: SCRIM_LABEL,
color: 'common.white',
fontSize: 11,
fontWeight: 600,
lineHeight: 1.2,
whiteSpace: 'nowrap',
flexShrink: 0,
pointerEvents: 'none',
}}
>
{childCount}
</Box>
)}
</Box>
}
secondary={ secondary={
<Typography <Typography
component="span" component="span"
@@ -641,10 +694,11 @@ class ArtikelSearchPage extends Component {
variant="body2" variant="body2"
sx={{ fontWeight: 600, flexShrink: 0, ml: 2 }} sx={{ fontWeight: 600, flexShrink: 0, ml: 2 }}
> >
{row.price != null ? formatPrice(row.price) : '—'} {price != null ? formatPrice(price) : '—'}
</Typography> </Typography>
</ListItemButton> </ListItemButton>
))} );
})}
</List> </List>
)} )}
</Box> </Box>