u
This commit is contained in:
@@ -14,10 +14,14 @@ import SettingsIcon from '@mui/icons-material/Settings';
|
||||
import {
|
||||
ARTICLE_TAB,
|
||||
DEFAULT_ARTICLE_TAB,
|
||||
artikelDetailPath,
|
||||
articleShowsCompoundTab,
|
||||
articleTabFromPathname,
|
||||
readPreferredArticleTab,
|
||||
resolveArticleTab,
|
||||
writePreferredArticleTab,
|
||||
} from '../../pages/artikel/articleRoute';
|
||||
import { router } from '../../appRouter';
|
||||
import { PanelTile } from '../panels';
|
||||
import { PANEL_TILE_BORDER_RADIUS, responsiveColumnSpan } from '../panels/panelTileLayout';
|
||||
import ArticleAttributesTab from './tabs/ArticleAttributesTab';
|
||||
@@ -69,30 +73,70 @@ function visibleTabs(article) {
|
||||
return tabs;
|
||||
}
|
||||
|
||||
function readRouteTab() {
|
||||
return articleTabFromPathname(router.state.location.pathname);
|
||||
}
|
||||
|
||||
class ArticleTileTab extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
preferredTab: readPreferredArticleTab(),
|
||||
tabParam: readRouteTab(),
|
||||
};
|
||||
this.handleTabChange = this.handleTabChange.bind(this);
|
||||
this.handlePinDefault = this.handlePinDefault.bind(this);
|
||||
this.syncTabFromRouter = this.syncTabFromRouter.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.unsubRouter = router.subscribe(this.syncTabFromRouter);
|
||||
this.ensureValidTab();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.article !== this.props.article) {
|
||||
this.ensureValidTab();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsubRouter?.();
|
||||
this.unsubRouter = null;
|
||||
}
|
||||
|
||||
syncTabFromRouter() {
|
||||
const tabParam = readRouteTab();
|
||||
if (tabParam !== this.state.tabParam) {
|
||||
this.setState({ tabParam }, () => this.ensureValidTab());
|
||||
}
|
||||
}
|
||||
|
||||
ensureValidTab() {
|
||||
const { article } = this.props;
|
||||
const { tabParam } = this.state;
|
||||
if (!article) return;
|
||||
const resolved = resolveArticleTab(tabParam, article);
|
||||
if (tabParam !== resolved) {
|
||||
void router.navigate(artikelDetailPath(article, resolved), { replace: true });
|
||||
}
|
||||
}
|
||||
|
||||
handleTabChange(_event, tab) {
|
||||
this.props.onTabChange?.(tab);
|
||||
const { article } = this.props;
|
||||
void router.navigate(artikelDetailPath(article, tab));
|
||||
}
|
||||
|
||||
handlePinDefault() {
|
||||
const { tab } = this.props;
|
||||
const tab = resolveArticleTab(this.state.tabParam, this.props.article);
|
||||
if (!tab) return;
|
||||
writePreferredArticleTab(tab);
|
||||
this.setState({ preferredTab: tab });
|
||||
}
|
||||
|
||||
renderPanel() {
|
||||
renderPanel(tab) {
|
||||
const { article: articleData, onArticleDeleted } = this.props;
|
||||
switch (this.props.tab) {
|
||||
switch (tab) {
|
||||
case ARTICLE_TAB.history:
|
||||
return <ArticleHistoryTab sku={articleData.sku} />;
|
||||
case ARTICLE_TAB.supplier:
|
||||
@@ -123,9 +167,11 @@ class ArticleTileTab extends PureComponent {
|
||||
wide = 3,
|
||||
minHeight = 200,
|
||||
sx,
|
||||
tab = DEFAULT_ARTICLE_TAB,
|
||||
} = this.props;
|
||||
const { preferredTab } = this.state;
|
||||
const { preferredTab, tabParam } = this.state;
|
||||
const tab = resolveArticleTab(tabParam, articleData);
|
||||
if (tabParam !== tab) return null;
|
||||
|
||||
const tabs = visibleTabs(articleData);
|
||||
const active =
|
||||
tabs.find((row) => row.id === tab) ??
|
||||
@@ -270,7 +316,7 @@ class ArticleTileTab extends PureComponent {
|
||||
...sx,
|
||||
}}
|
||||
>
|
||||
{this.renderPanel()}
|
||||
{this.renderPanel(tab)}
|
||||
</PanelTile>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component } from 'react';
|
||||
import { PureComponent } from 'react';
|
||||
import { PanelTileGrid } from '../panels';
|
||||
import { StorageManagerContext } from '../../api/storageManagerContext';
|
||||
import withNavigate from '../withNavigate';
|
||||
@@ -6,10 +6,6 @@ import {
|
||||
buildCategoryPath,
|
||||
defaultCategoryPath,
|
||||
} from '../../pages/artikel/categoryRoute';
|
||||
import {
|
||||
artikelDetailPath,
|
||||
resolveArticleTab,
|
||||
} from '../../pages/artikel/articleRoute';
|
||||
|
||||
import ArticleTileTab from './ArticleTileTab';
|
||||
import ArticlePhotoTile from './ArticlePhotoTile';
|
||||
@@ -23,7 +19,7 @@ import ArticleViewLists from './boxes/ArticleViewLists';
|
||||
/** Stable prop so PureComponent photo tile does not see a new sx each render. */
|
||||
const PHOTO_TILE_SX = { minHeight: 0 };
|
||||
|
||||
class ArticleView extends Component {
|
||||
class ArticleView extends PureComponent {
|
||||
static contextType = StorageManagerContext;
|
||||
|
||||
constructor(props, context) {
|
||||
@@ -36,13 +32,11 @@ class ArticleView extends Component {
|
||||
);
|
||||
this.state = { article };
|
||||
this.unwatchArticle = unwatch;
|
||||
this.handleTabChange = this.handleTabChange.bind(this);
|
||||
this.handleArticleDeleted = this.handleArticleDeleted.bind(this);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { sku, tab, navigate } = this.props;
|
||||
const { article } = this.state;
|
||||
const { sku } = this.props;
|
||||
|
||||
if (prevProps.sku !== sku) {
|
||||
this.unwatchArticle?.();
|
||||
@@ -52,13 +46,6 @@ class ArticleView extends Component {
|
||||
);
|
||||
this.unwatchArticle = unwatch;
|
||||
this.setState({ article: next });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!article) return;
|
||||
const resolved = resolveArticleTab(tab, article);
|
||||
if (tab !== resolved) {
|
||||
navigate(artikelDetailPath(article, resolved), { replace: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,14 +68,7 @@ class ArticleView extends Component {
|
||||
navigate(defaultCategoryPath());
|
||||
}
|
||||
|
||||
handleTabChange(nextTab) {
|
||||
const { navigate } = this.props;
|
||||
const { article } = this.state;
|
||||
navigate(artikelDetailPath(article, nextTab));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { tab } = this.props;
|
||||
const { article } = this.state;
|
||||
const categoryState = this.context.getCategoryState();
|
||||
const categories = categoryState?.categories ?? null;
|
||||
@@ -96,9 +76,6 @@ class ArticleView extends Component {
|
||||
|
||||
if (!article || categories == null || rootCategoryId == null) return null;
|
||||
|
||||
const resolvedTab = resolveArticleTab(tab, article);
|
||||
if (tab !== resolvedTab) return null;
|
||||
|
||||
return (
|
||||
<PanelTileGrid>
|
||||
<ArticleViewName article={article} />
|
||||
@@ -122,8 +99,6 @@ class ArticleView extends Component {
|
||||
wide={3}
|
||||
minHeight={200}
|
||||
article={article}
|
||||
tab={resolvedTab}
|
||||
onTabChange={this.handleTabChange}
|
||||
onArticleDeleted={this.handleArticleDeleted}
|
||||
/>
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ import TableCell from '@mui/material/TableCell';
|
||||
import TableHead from '@mui/material/TableHead';
|
||||
import TableRow from '@mui/material/TableRow';
|
||||
import { StorageManagerContext } from '../../../api/storageManagerContext';
|
||||
import ResultsPagination from '../../../pages/artikel/ResultsPagination';
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
|
||||
function formatDate(iso) {
|
||||
return new Date(iso).toLocaleString('de-DE');
|
||||
@@ -15,25 +18,46 @@ export default class ArticleHistoryTab extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { history: null };
|
||||
this.state = {
|
||||
history: null,
|
||||
total: null,
|
||||
skip: 0,
|
||||
};
|
||||
this.unwatchHistory = null;
|
||||
this.setSkipAndOffset = null;
|
||||
this.handlePageChange = this.handlePageChange.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.unwatchHistory = this.context.article.historyWatch(
|
||||
const { unwatch, setSkipAndOffset } = this.context.article.historyWatch(
|
||||
this.props.sku,
|
||||
(history) => this.setState({ history }),
|
||||
(history, total) => this.setState({ history, total }),
|
||||
);
|
||||
this.unwatchHistory = unwatch;
|
||||
this.setSkipAndOffset = setSkipAndOffset;
|
||||
setSkipAndOffset(0, PAGE_SIZE);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unwatchHistory?.();
|
||||
this.unwatchHistory = null;
|
||||
this.setSkipAndOffset = null;
|
||||
}
|
||||
|
||||
handlePageChange(_event, page) {
|
||||
const skip = (page - 1) * PAGE_SIZE;
|
||||
this.setSkipAndOffset?.(skip, PAGE_SIZE);
|
||||
this.setState({ skip });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { history } = this.state;
|
||||
if (history == null) return null;
|
||||
const { history, total, skip } = this.state;
|
||||
if (history == null || total == null) return null;
|
||||
|
||||
const pageCount = Math.max(1, Math.ceil(total / PAGE_SIZE));
|
||||
const currentPage = Math.floor(skip / PAGE_SIZE) + 1;
|
||||
const showPagination = total > PAGE_SIZE;
|
||||
|
||||
return (
|
||||
<Table
|
||||
size="small"
|
||||
@@ -49,13 +73,28 @@ export default class ArticleHistoryTab extends Component {
|
||||
borderBottom: '1px solid rgba(0, 0, 0, 0.35)',
|
||||
width: '1%',
|
||||
whiteSpace: 'nowrap',
|
||||
verticalAlign: 'middle',
|
||||
}}
|
||||
>
|
||||
Datum
|
||||
</TableCell>
|
||||
<TableCell
|
||||
sx={{ borderBottom: '1px solid rgba(0, 0, 0, 0.35)' }}
|
||||
/>
|
||||
sx={{
|
||||
borderBottom: '1px solid rgba(0, 0, 0, 0.35)',
|
||||
verticalAlign: 'middle',
|
||||
}}
|
||||
>
|
||||
{showPagination ? (
|
||||
<ResultsPagination
|
||||
offset={skip}
|
||||
totalCount={total}
|
||||
pageSize={PAGE_SIZE}
|
||||
pageCount={pageCount}
|
||||
currentPage={currentPage}
|
||||
onPageChange={this.handlePageChange}
|
||||
/>
|
||||
) : null}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
|
||||
Reference in New Issue
Block a user