140 lines
4.1 KiB
JavaScript
140 lines
4.1 KiB
JavaScript
import { PureComponent } from 'react';
|
|
import Table from '@mui/material/Table';
|
|
import TableBody from '@mui/material/TableBody';
|
|
import TableCell from '@mui/material/TableCell';
|
|
import TableHead from '@mui/material/TableHead';
|
|
import TableRow from '@mui/material/TableRow';
|
|
import { articleHistoryAutomat } from '../../../automats/articleDetailAutomat';
|
|
import sseAutomat from '../../../automats/sseAutomat';
|
|
import { notifyError } from '../../../utils/notify';
|
|
import ResultsPagination from '../ResultsPagination';
|
|
|
|
const PAGE_SIZE = 20;
|
|
|
|
function formatDate(iso) {
|
|
return new Date(iso).toLocaleString('de-DE');
|
|
}
|
|
|
|
export default class ArticleHistoryTab extends PureComponent {
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = { all: [], skip: 0 };
|
|
this.handlePageChange = this.handlePageChange.bind(this);
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.watch();
|
|
void articleHistoryAutomat.load(String(this.props.sku)).catch((err) => {
|
|
if (this.unsub) notifyError(err);
|
|
});
|
|
}
|
|
|
|
componentDidUpdate(prevProps) {
|
|
if (prevProps.sku !== this.props.sku) {
|
|
this.watch();
|
|
void articleHistoryAutomat.load(String(this.props.sku)).catch((err) => {
|
|
if (this.unsub) notifyError(err);
|
|
});
|
|
}
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.unsub?.();
|
|
this.unsub = null;
|
|
this.unwatchSignal?.();
|
|
this.unwatchSignal = null;
|
|
}
|
|
|
|
/**
|
|
* Subscribes to the keyed history cache and to the article SSE signal.
|
|
* The backend re-emits `article-<sku>` whenever the article changes, and
|
|
* `sseAutomat` reloads the history key for us.
|
|
*/
|
|
watch() {
|
|
this.unsub?.();
|
|
const handle = articleHistoryAutomat.key(String(this.props.sku));
|
|
this.unsub = handle.subscribe(this, (item) => {
|
|
const all = Array.isArray(item.data) ? item.data : [];
|
|
this.setState({ all });
|
|
});
|
|
|
|
this.unwatchSignal?.();
|
|
this.unwatchSignal = sseAutomat.actions.watchArticle(String(this.props.sku), () => {
|
|
void articleHistoryAutomat.reload(String(this.props.sku)).catch(() => {});
|
|
});
|
|
}
|
|
|
|
/** Client-side pagination over the full history list. */
|
|
pageOf(all, skip) {
|
|
return all.slice(skip, skip + PAGE_SIZE);
|
|
}
|
|
|
|
handlePageChange(_event, page) {
|
|
this.setState({ skip: (page - 1) * PAGE_SIZE });
|
|
}
|
|
|
|
render() {
|
|
const { all, skip } = this.state;
|
|
const total = all.length;
|
|
const history = this.pageOf(all, skip);
|
|
|
|
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"
|
|
sx={{
|
|
'& td': { borderBottom: 'none', bgcolor: 'transparent' },
|
|
'& th': { bgcolor: 'transparent' },
|
|
}}
|
|
>
|
|
<TableHead>
|
|
<TableRow>
|
|
<TableCell
|
|
sx={{
|
|
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)',
|
|
verticalAlign: 'middle',
|
|
}}
|
|
>
|
|
{showPagination ? (
|
|
<ResultsPagination
|
|
offset={skip}
|
|
totalCount={total}
|
|
pageSize={PAGE_SIZE}
|
|
pageCount={pageCount}
|
|
currentPage={currentPage}
|
|
onPageChange={this.handlePageChange}
|
|
/>
|
|
) : null}
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{history.map((entry) => (
|
|
<TableRow key={entry.id}>
|
|
<TableCell
|
|
sx={{ verticalAlign: 'top', whiteSpace: 'nowrap', width: '1%' }}
|
|
>
|
|
{formatDate(entry.date)}
|
|
</TableCell>
|
|
<TableCell sx={{ whiteSpace: 'pre-wrap' }}>{entry.text}</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
);
|
|
}
|
|
}
|