u
This commit is contained in:
@@ -32,23 +32,46 @@ import {
|
||||
formatCategoryList,
|
||||
formatStock,
|
||||
getCategoryDepth,
|
||||
getCategoryBreadcrumbLabel,
|
||||
parseFilter,
|
||||
} from '../components/article/searchFormat';
|
||||
import { preserveSearchFocus } from '../components/article/searchFocus';
|
||||
import { artikelDetailPath } from '../components/article/articleRoute';
|
||||
import { buildCategoryPath } from '../components/category/categoryRoute';
|
||||
import withSearchParams from '../components/article/withSearchParams';
|
||||
import { setLastArticleSku, setLastSearchTerm, navigationAutomat } from '../automats';
|
||||
import {
|
||||
setLastArticleSku,
|
||||
setLastSearchTerm,
|
||||
setLastCategoryId,
|
||||
navigationAutomat,
|
||||
categoryAutomat,
|
||||
} from '../automats';
|
||||
import { BrandLabel } from '../components/brand';
|
||||
|
||||
const resultRowSx = {
|
||||
alignItems: 'center',
|
||||
py: 1.5,
|
||||
minHeight: 64,
|
||||
maxHeight: 64,
|
||||
height: 64,
|
||||
boxSizing: 'border-box',
|
||||
py: 0,
|
||||
// Keep every row one line so sample height matches real rows.
|
||||
'& .MuiListItemText-root': { minWidth: 0 },
|
||||
'& .MuiListItemText-primary, & .MuiListItemText-secondary': {
|
||||
'& .MuiListItemText-root': { minWidth: 0, my: 0 },
|
||||
'& .MuiListItemText-primary': {
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
lineHeight: '22px',
|
||||
height: '22px',
|
||||
},
|
||||
'& .MuiListItemText-secondary': {
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
lineHeight: '20px',
|
||||
height: '20px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -68,7 +91,7 @@ function ResultRowMeasureSample() {
|
||||
<ListItemText
|
||||
primary={'\u00A0'}
|
||||
secondary={
|
||||
<Typography component="span" variant="body2" sx={{ visibility: 'hidden' }} noWrap>
|
||||
<Typography component="span" variant="body2" sx={{ visibility: 'hidden', lineHeight: '20px', height: '20px' }} noWrap>
|
||||
|
||||
</Typography>
|
||||
}
|
||||
@@ -111,6 +134,28 @@ function initialSearchState(searchParams) {
|
||||
};
|
||||
}
|
||||
|
||||
function getCategoryTreeOrder(categoriesMap, rootCategoryId) {
|
||||
const order = new Map();
|
||||
let index = 0;
|
||||
|
||||
function traverse(parentId) {
|
||||
const parentKey = String(parentId);
|
||||
const children = Object.values(categoriesMap || {})
|
||||
.filter((item) => item && item.parentId != null && String(item.parentId) === parentKey)
|
||||
.sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0) || Number(a.id) - Number(b.id));
|
||||
|
||||
for (const child of children) {
|
||||
order.set(String(child.id), index++);
|
||||
traverse(child.id);
|
||||
}
|
||||
}
|
||||
|
||||
const rootId = rootCategoryId ?? 1;
|
||||
traverse(rootId);
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
class ArtikelSearchPage extends Component {
|
||||
state = initialSearchState(this.props.searchParams);
|
||||
paginationRef = createRef();
|
||||
@@ -154,8 +199,22 @@ class ArtikelSearchPage extends Component {
|
||||
this.unsubSearch = articleSearchAutomat.subscribe(this, (state) => state.result);
|
||||
|
||||
// Initial search: kicks off index loading if idle and derives current items
|
||||
const { filter, offset } = queryFromParams(this.props.searchParams);
|
||||
const { filter: urlFilter, offset } = queryFromParams(this.props.searchParams);
|
||||
const hasFilterInUrl = this.props.searchParams.has('filter');
|
||||
const navCategory = navigationAutomat.state.lastCategoryId;
|
||||
const filter = hasFilterInUrl ? urlFilter : (navCategory || urlFilter);
|
||||
const activeTarget = this.state.input;
|
||||
|
||||
if (!hasFilterInUrl && navCategory) {
|
||||
const syncedUrl = buildSearchUrl(activeTarget, filter, offset);
|
||||
setLastSearchTerm(activeTarget, syncedUrl);
|
||||
this.props.navigate(syncedUrl, { replace: true });
|
||||
} else if (hasFilterInUrl) {
|
||||
const selectedCats = parseFilter(urlFilter);
|
||||
const primaryCatId = selectedCats.length > 0 ? selectedCats[0] : null;
|
||||
setLastCategoryId(primaryCatId);
|
||||
}
|
||||
|
||||
setLastSearchTerm(activeTarget, buildSearchUrl(activeTarget, filter, offset));
|
||||
void articleSearchAutomat.actions.search({
|
||||
target: activeTarget,
|
||||
@@ -213,6 +272,20 @@ class ArtikelSearchPage extends Component {
|
||||
});
|
||||
const nextUrl = buildSearchUrl(nextTarget, nextFilter, nextOffset);
|
||||
setLastSearchTerm(nextTarget, nextUrl);
|
||||
|
||||
// Synchronize category with navigationAutomat and /kategorien/
|
||||
const selectedCats = parseFilter(nextFilter);
|
||||
const primaryCatId = selectedCats.length > 0 ? selectedCats[0] : null;
|
||||
const categoriesMap = categoryAutomat.state?.categories;
|
||||
const rootCategoryId = categoryAutomat.state?.rootCategoryId;
|
||||
const isRoot = !primaryCatId || (rootCategoryId != null && String(primaryCatId) === String(rootCategoryId));
|
||||
const activeId = isRoot ? null : String(primaryCatId);
|
||||
const catPath = activeId && categoriesMap && rootCategoryId != null
|
||||
? buildCategoryPath(categoriesMap, rootCategoryId, activeId)
|
||||
: '/kategorien';
|
||||
|
||||
setLastCategoryId(activeId, catPath);
|
||||
|
||||
this.props.navigate(nextUrl, {
|
||||
replace: true,
|
||||
});
|
||||
@@ -275,16 +348,37 @@ class ArtikelSearchPage extends Component {
|
||||
const categories = parseFilter(filterParam);
|
||||
const rows = recordset ?? [];
|
||||
|
||||
const categoriesMap = categoryAutomat.state?.categories;
|
||||
const rootCategoryId = categoryAutomat.state?.rootCategoryId;
|
||||
const treeOrder = getCategoryTreeOrder(categoriesMap, rootCategoryId);
|
||||
|
||||
const facetEntries = categoryFacets
|
||||
? Object.entries(categoryFacets)
|
||||
.filter(([, meta]) => meta?.name)
|
||||
.filter(([id, meta]) => {
|
||||
if (!meta?.name) return false;
|
||||
if (String(id) === '1' || (rootCategoryId != null && String(id) === String(rootCategoryId))) {
|
||||
return false;
|
||||
}
|
||||
const lower = meta.name.trim().toLowerCase();
|
||||
if (lower === 'kategorie 1' || lower === 'category 1' || lower === 'home') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(([id, { count, name }]) => ({
|
||||
id,
|
||||
count,
|
||||
name,
|
||||
depth: getCategoryDepth(id, categoryFacets),
|
||||
}))
|
||||
.sort((a, b) => Number(a.id) - Number(b.id))
|
||||
.sort((a, b) => {
|
||||
const orderA = treeOrder.get(String(a.id));
|
||||
const orderB = treeOrder.get(String(b.id));
|
||||
if (orderA != null && orderB != null) return orderA - orderB;
|
||||
if (orderA != null) return -1;
|
||||
if (orderB != null) return 1;
|
||||
return Number(a.id) - Number(b.id);
|
||||
})
|
||||
: [];
|
||||
|
||||
const showPagination =
|
||||
@@ -338,11 +432,16 @@ class ArtikelSearchPage extends Component {
|
||||
</Button>
|
||||
)}
|
||||
{categories.map((catId) => {
|
||||
const catName = categoryFacets?.[catId]?.name ?? `Kategorie ${catId}`;
|
||||
const label = getCategoryBreadcrumbLabel(
|
||||
catId,
|
||||
categoriesMap,
|
||||
rootCategoryId,
|
||||
categoryFacets,
|
||||
);
|
||||
return (
|
||||
<Chip
|
||||
key={catId}
|
||||
label={catName}
|
||||
label={label}
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
onDelete={() => {
|
||||
@@ -482,7 +581,14 @@ class ArtikelSearchPage extends Component {
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
noWrap
|
||||
sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.5, maxWidth: '100%' }}
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: 0.5,
|
||||
maxWidth: '100%',
|
||||
lineHeight: '20px',
|
||||
height: '20px',
|
||||
}}
|
||||
>
|
||||
{(row.brand?.name || row.brandName) && (
|
||||
<>
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
import categoryAutomat from '../../automats/categoryAutomat';
|
||||
import posterminalAutomat from '../../automats/posterminalAutomat';
|
||||
import companyAutomat from '../../automats/companyAutomat';
|
||||
import { setLastArticleSku, setLastCategorySlug } from '../../automats';
|
||||
import { setLastArticleSku, setLastCategorySlug, setLastCategoryId } from '../../automats';
|
||||
import {
|
||||
categoryDisplayName,
|
||||
getCategoryBreadcrumbs,
|
||||
@@ -225,8 +225,13 @@ class ArtikelKategorienPage extends PureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
const isRoot = rootCategoryId != null && String(resolvedId) === String(rootCategoryId);
|
||||
const activeCatId = isRoot ? null : String(resolvedId);
|
||||
const fullCatPath = isRoot ? '/kategorien' : buildCategoryPath(categories, rootCategoryId, resolvedId);
|
||||
setLastCategoryId(activeCatId, fullCatPath);
|
||||
|
||||
if (hasLegacyHomePrefix) {
|
||||
navigate(buildCategoryPath(categories, rootCategoryId, resolvedId), { replace: true });
|
||||
navigate(fullCatPath, { replace: true });
|
||||
}
|
||||
|
||||
const nextHandle = categoryAutomat.key(categorySlugPath ?? '');
|
||||
|
||||
@@ -97,6 +97,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
this.handleExternalNumberChange = this.handleExternalNumberChange.bind(this);
|
||||
this.handleLineChange = this.handleLineChange.bind(this);
|
||||
this.handleAddLine = this.handleAddLine.bind(this);
|
||||
this.handleAddArticleLine = this.handleAddArticleLine.bind(this);
|
||||
this.handleRemoveLine = this.handleRemoveLine.bind(this);
|
||||
this.handleRemoveAllLines = this.handleRemoveAllLines.bind(this);
|
||||
this.handleSave = this.handleSave.bind(this);
|
||||
@@ -506,6 +507,35 @@ class LieferungNeuPage extends PureComponent {
|
||||
this.automat.actions.addLineitem();
|
||||
}
|
||||
|
||||
handleAddArticleLine(article) {
|
||||
if (!article) return;
|
||||
const netVal =
|
||||
article.price != null
|
||||
? String(article.price)
|
||||
: article.vknetto != null
|
||||
? String(article.vknetto)
|
||||
: article.net != null
|
||||
? String(article.net)
|
||||
: '';
|
||||
const taxVal =
|
||||
article.taxrate != null
|
||||
? String(article.taxrate)
|
||||
: article.tax != null
|
||||
? String(article.tax)
|
||||
: '';
|
||||
|
||||
this.automat.actions.addLineitem({
|
||||
amount: 1,
|
||||
sku: article.sku || '',
|
||||
name: article.name || '',
|
||||
tax: taxVal,
|
||||
taxrate: taxVal,
|
||||
net: netVal,
|
||||
netprice: netVal,
|
||||
pu: 1,
|
||||
});
|
||||
}
|
||||
|
||||
handleRemoveLine(key) {
|
||||
const index = this.findLineIndex(key);
|
||||
this.automat.actions.removeLineitem(index >= 0 ? index : key);
|
||||
@@ -1307,6 +1337,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
onLineChange={this.handleLineChange}
|
||||
onSkuBlur={this.handleSkuBlur}
|
||||
onAddLine={this.handleAddLine}
|
||||
onAddArticleLine={this.handleAddArticleLine}
|
||||
onRemoveLine={this.handleRemoveLine}
|
||||
onRemoveAllLines={this.handleRemoveAllLines}
|
||||
onSave={() => void this.handleSave()}
|
||||
|
||||
Reference in New Issue
Block a user