refactor(lists): use shared RecordList from dashgui
Replace duplicated table/list markup in the Kunde list page and Manifest list with the shared dashgui RecordList component, and document dashgui/lists in the README.
This commit is contained in:
@@ -34,6 +34,8 @@ Reusable custom GUI class components live in the **`dashgui`** package
|
|||||||
so source imports are reflected instantly.
|
so source imports are reflected instantly.
|
||||||
|
|
||||||
- `dashgui/panels` — `PanelTile`, `PanelTileGrid`, `EditablePanelTile`, layout helpers
|
- `dashgui/panels` — `PanelTile`, `PanelTileGrid`, `EditablePanelTile`, layout helpers
|
||||||
|
- `dashgui/lists` — `RecordList`, the generic presentational list used by the
|
||||||
|
Lieferungen / Angebote / Bestellungen / Kunden list pages
|
||||||
- `dashgui/tiles` — base `Tile` (extended by `src/components/tiles/*`)
|
- `dashgui/tiles` — base `Tile` (extended by `src/components/tiles/*`)
|
||||||
- `dashgui/SingleLineTextEdit`, `dashgui/ElevatedPill`
|
- `dashgui/SingleLineTextEdit`, `dashgui/ElevatedPill`
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,7 @@
|
|||||||
import { PureComponent } from 'react';
|
import { PureComponent } from 'react';
|
||||||
import Box from '@mui/material/Box';
|
|
||||||
import Button from '@mui/material/Button';
|
|
||||||
import CircularProgress from '@mui/material/CircularProgress';
|
|
||||||
import IconButton from '@mui/material/IconButton';
|
|
||||||
import Stack from '@mui/material/Stack';
|
|
||||||
import Table from '@mui/material/Table';
|
|
||||||
import TableBody from '@mui/material/TableBody';
|
|
||||||
import TableCell from '@mui/material/TableCell';
|
|
||||||
import TableContainer from '@mui/material/TableContainer';
|
|
||||||
import TableHead from '@mui/material/TableHead';
|
|
||||||
import TableRow from '@mui/material/TableRow';
|
|
||||||
import Typography from '@mui/material/Typography';
|
|
||||||
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
|
|
||||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import BackendError from '../BackendError';
|
import BackendError from '../BackendError';
|
||||||
import { PanelTile, PanelTileGrid } from 'dashgui/panels';
|
import { RecordList } from 'dashgui/lists';
|
||||||
import { StorageManagerContext } from '../../api/storageManagerContext';
|
import { StorageManagerContext } from '../../api/storageManagerContext';
|
||||||
import { backendErrorFrom } from '../../utils/backendError';
|
import { backendErrorFrom } from '../../utils/backendError';
|
||||||
import { notifyError } from '../../utils/notify';
|
import { notifyError } from '../../utils/notify';
|
||||||
@@ -133,98 +119,43 @@ class ManifestList extends PureComponent {
|
|||||||
const cfg = this.cfg;
|
const cfg = this.cfg;
|
||||||
const partyField = cfg.partyField;
|
const partyField = cfg.partyField;
|
||||||
|
|
||||||
if (status === 'loading') {
|
const columns = [{ key: 'number', label: 'Nummer' }];
|
||||||
return (
|
if (cfg.externalNumber) {
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 6 }}>
|
columns.push({
|
||||||
<CircularProgress />
|
key: 'externalNumber',
|
||||||
</Box>
|
label: 'Referenz',
|
||||||
);
|
render: (row) => numberDisplay(row.externalNumber),
|
||||||
}
|
});
|
||||||
|
|
||||||
if (status === 'failed') {
|
|
||||||
return <BackendError error={error} onRetry={this.handleRetry} />;
|
|
||||||
}
|
}
|
||||||
|
columns.push(
|
||||||
|
{
|
||||||
|
key: 'date',
|
||||||
|
label: cfg.dateLabel,
|
||||||
|
render: (row) => formatDate(row.date),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: partyField,
|
||||||
|
label: cfg.partyLabel,
|
||||||
|
render: (row) => this.partyName(row[partyField]),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelTileGrid>
|
<RecordList
|
||||||
<PanelTile wide={3} minHeight={240} color={cfg.listColor}>
|
status={status}
|
||||||
<Stack spacing={2}>
|
error={<BackendError error={error} onRetry={this.handleRetry} />}
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
|
rows={docs}
|
||||||
<Button
|
columns={columns}
|
||||||
type="button"
|
createLabel={cfg.createButton}
|
||||||
variant="contained"
|
onCreate={this.handleCreate}
|
||||||
size="small"
|
onEdit={this.handleEdit}
|
||||||
onClick={this.handleCreate}
|
onDelete={this.handleDelete}
|
||||||
>
|
deleteDisabled={busyId != null}
|
||||||
{cfg.createButton}
|
emptyMessage={cfg.emptyList}
|
||||||
</Button>
|
color={cfg.listColor}
|
||||||
</Box>
|
getEditLabel={(row) => `„${row.number}“ bearbeiten`}
|
||||||
|
getDeleteLabel={(row) => `„${row.number}“ löschen`}
|
||||||
{docs.length === 0 ? (
|
/>
|
||||||
<Typography variant="body2" color="text.secondary">
|
|
||||||
{cfg.emptyList}
|
|
||||||
</Typography>
|
|
||||||
) : (
|
|
||||||
<TableContainer>
|
|
||||||
<Table size="small">
|
|
||||||
<TableHead>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell>Nummer</TableCell>
|
|
||||||
{cfg.externalNumber ? (
|
|
||||||
<TableCell>Referenz</TableCell>
|
|
||||||
) : null}
|
|
||||||
<TableCell>{cfg.dateLabel}</TableCell>
|
|
||||||
<TableCell>{cfg.partyLabel}</TableCell>
|
|
||||||
<TableCell padding="checkbox" />
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
<TableBody>
|
|
||||||
{docs.map((row) => (
|
|
||||||
<TableRow
|
|
||||||
key={row.id}
|
|
||||||
hover
|
|
||||||
sx={{ cursor: 'pointer' }}
|
|
||||||
onClick={() => this.handleEdit(row)}
|
|
||||||
>
|
|
||||||
<TableCell>{row.number}</TableCell>
|
|
||||||
{cfg.externalNumber ? (
|
|
||||||
<TableCell>
|
|
||||||
{numberDisplay(row.externalNumber)}
|
|
||||||
</TableCell>
|
|
||||||
) : null}
|
|
||||||
<TableCell>{formatDate(row.date)}</TableCell>
|
|
||||||
<TableCell>{this.partyName(row[partyField])}</TableCell>
|
|
||||||
<TableCell
|
|
||||||
padding="checkbox"
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
type="button"
|
|
||||||
size="small"
|
|
||||||
aria-label={`„${row.number}“ bearbeiten`}
|
|
||||||
onClick={() => this.handleEdit(row)}
|
|
||||||
>
|
|
||||||
<EditOutlinedIcon fontSize="small" />
|
|
||||||
</IconButton>
|
|
||||||
<IconButton
|
|
||||||
type="button"
|
|
||||||
size="small"
|
|
||||||
aria-label={`„${row.number}“ löschen`}
|
|
||||||
disabled={busyId != null}
|
|
||||||
onClick={() => void this.handleDelete(row)}
|
|
||||||
>
|
|
||||||
<DeleteOutlinedIcon fontSize="small" />
|
|
||||||
</IconButton>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</TableContainer>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</PanelTile>
|
|
||||||
</PanelTileGrid>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,7 @@
|
|||||||
import { PureComponent } from 'react';
|
import { PureComponent } from 'react';
|
||||||
import Box from '@mui/material/Box';
|
|
||||||
import Button from '@mui/material/Button';
|
|
||||||
import CircularProgress from '@mui/material/CircularProgress';
|
|
||||||
import IconButton from '@mui/material/IconButton';
|
|
||||||
import Stack from '@mui/material/Stack';
|
|
||||||
import Table from '@mui/material/Table';
|
|
||||||
import TableBody from '@mui/material/TableBody';
|
|
||||||
import TableCell from '@mui/material/TableCell';
|
|
||||||
import TableContainer from '@mui/material/TableContainer';
|
|
||||||
import TableHead from '@mui/material/TableHead';
|
|
||||||
import TableRow from '@mui/material/TableRow';
|
|
||||||
import Typography from '@mui/material/Typography';
|
|
||||||
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
|
|
||||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
|
||||||
import { enqueueSnackbar } from 'notistack';
|
import { enqueueSnackbar } from 'notistack';
|
||||||
import BackendError from '../../components/BackendError';
|
import BackendError from '../../components/BackendError';
|
||||||
import { PanelTile, PanelTileGrid } from 'dashgui/panels';
|
import { RecordList } from 'dashgui/lists';
|
||||||
import { StorageManagerContext } from '../../api/storageManagerContext';
|
import { StorageManagerContext } from '../../api/storageManagerContext';
|
||||||
import { router } from '../../appRouter';
|
import { router } from '../../appRouter';
|
||||||
import { backendErrorFrom } from '../../utils/backendError';
|
import { backendErrorFrom } from '../../utils/backendError';
|
||||||
@@ -119,86 +105,47 @@ class KundeListePage extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { status, error, entities, busyId } = this.state;
|
const { status, error, entities, groupsById, busyId } = this.state;
|
||||||
|
|
||||||
if (status === 'loading') {
|
|
||||||
return (
|
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 6 }}>
|
|
||||||
<CircularProgress />
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status === 'failed') {
|
if (status === 'failed') {
|
||||||
return <BackendError error={error} onRetry={this.handleRetry} />;
|
return <BackendError error={error} onRetry={this.handleRetry} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const columns = [
|
||||||
<PanelTileGrid>
|
{ key: 'number', label: 'Kundennummer' },
|
||||||
<PanelTile wide={3} minHeight={240} color="#bfdbfe">
|
{ key: 'name', label: 'Name' },
|
||||||
<Stack spacing={2}>
|
{ key: 'firstName', label: 'Vorname' },
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
|
{
|
||||||
<Button variant="contained" size="small" onClick={this.handleCreate}>
|
key: 'customergroupId',
|
||||||
Neuer Kunde
|
label: 'Gruppe',
|
||||||
</Button>
|
render: (row) => this.groupName(row.customergroupId),
|
||||||
</Box>
|
},
|
||||||
|
{
|
||||||
|
key: 'createdAt',
|
||||||
|
label: 'Erstellt am',
|
||||||
|
render: (row) => formatDate(row.createdAt),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
{entities.length === 0 ? (
|
const label = (row) =>
|
||||||
<Typography variant="body2" color="text.secondary">
|
[row.firstName, row.name].filter(Boolean).join(' ') || String(row.number);
|
||||||
Noch keine Kunden.
|
|
||||||
</Typography>
|
return (
|
||||||
) : (
|
<RecordList
|
||||||
<TableContainer>
|
status={status}
|
||||||
<Table size="small">
|
error={<BackendError error={error} onRetry={this.handleRetry} />}
|
||||||
<TableHead>
|
rows={entities}
|
||||||
<TableRow>
|
columns={columns}
|
||||||
<TableCell>Kundennummer</TableCell>
|
createLabel="Neuer Kunde"
|
||||||
<TableCell>Name</TableCell>
|
onCreate={this.handleCreate}
|
||||||
<TableCell>Vorname</TableCell>
|
onEdit={this.handleEdit}
|
||||||
<TableCell>Gruppe</TableCell>
|
onDelete={this.handleDelete}
|
||||||
<TableCell>Erstellt am</TableCell>
|
deleteDisabled={busyId != null}
|
||||||
<TableCell padding="checkbox" />
|
emptyMessage="Noch keine Kunden."
|
||||||
</TableRow>
|
color="#bfdbfe"
|
||||||
</TableHead>
|
getEditLabel={(row) => `„${label(row)}“ bearbeiten`}
|
||||||
<TableBody>
|
getDeleteLabel={(row) => `„${label(row)}“ löschen`}
|
||||||
{entities.map((row) => (
|
/>
|
||||||
<TableRow
|
|
||||||
key={row.id}
|
|
||||||
hover
|
|
||||||
sx={{ cursor: 'pointer' }}
|
|
||||||
onClick={() => this.handleEdit(row)}
|
|
||||||
>
|
|
||||||
<TableCell>{row.number}</TableCell>
|
|
||||||
<TableCell>{row.name}</TableCell>
|
|
||||||
<TableCell>{row.firstName}</TableCell>
|
|
||||||
<TableCell>{this.groupName(row.customergroupId)}</TableCell>
|
|
||||||
<TableCell>{formatDate(row.createdAt)}</TableCell>
|
|
||||||
<TableCell padding="checkbox" onClick={(e) => e.stopPropagation()}>
|
|
||||||
<IconButton
|
|
||||||
size="small"
|
|
||||||
aria-label={`„${row.name}“ bearbeiten`}
|
|
||||||
onClick={() => this.handleEdit(row)}
|
|
||||||
>
|
|
||||||
<EditOutlinedIcon fontSize="small" />
|
|
||||||
</IconButton>
|
|
||||||
<IconButton
|
|
||||||
size="small"
|
|
||||||
aria-label={`„${row.name}“ löschen`}
|
|
||||||
disabled={busyId != null}
|
|
||||||
onClick={() => void this.handleDelete(row)}
|
|
||||||
>
|
|
||||||
<DeleteOutlinedIcon fontSize="small" />
|
|
||||||
</IconButton>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</TableContainer>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</PanelTile>
|
|
||||||
</PanelTileGrid>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user