This commit is contained in:
seb
2026-08-05 07:25:40 +02:00
parent d87047bfe3
commit 89f8804a69

View File

@@ -27,6 +27,7 @@ import PointOfSaleIcon from '@mui/icons-material/PointOfSale';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import BackendError from './BackendError'; import BackendError from './BackendError';
import SingleLineTextEdit from './SingleLineTextEdit'; import SingleLineTextEdit from './SingleLineTextEdit';
import { StorageManagerContext } from '../api/storageManager';
import { import {
loadCurrentCompany, loadCurrentCompany,
selectCompanyStatus, selectCompanyStatus,
@@ -34,12 +35,9 @@ import {
updateCompany as updateCompanyThunk, updateCompany as updateCompanyThunk,
} from '../store/companySlice'; } from '../store/companySlice';
import { import {
loadPosterminals,
createPosterminal, createPosterminal,
deletePosterminal, deletePosterminal,
enableAllTerminalCategories, enableAllTerminalCategories,
selectPosterminals,
selectPosterminalStatus,
} from '../store/posterminalSlice'; } from '../store/posterminalSlice';
import { loadCategoryTree } from '../store/categorySlice'; import { loadCategoryTree } from '../store/categorySlice';
import { ISO639_OPTIONS, parseTaxRate } from '../utils/companyForm'; import { ISO639_OPTIONS, parseTaxRate } from '../utils/companyForm';
@@ -47,6 +45,8 @@ import { backendErrorFrom, isBackendFailure } from '../utils/backendError';
import { notifyError } from '../utils/notify'; import { notifyError } from '../utils/notify';
class CompanySettingsDialog extends Component { class CompanySettingsDialog extends Component {
static contextType = StorageManagerContext;
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@@ -59,11 +59,13 @@ class CompanySettingsDialog extends Component {
newTerminalName: '', newTerminalName: '',
creatingTerminal: false, creatingTerminal: false,
enableAllForNew: true, enableAllForNew: true,
terminals: [],
}; };
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.syncFormFromCompany = this.syncFormFromCompany.bind(this); this.syncFormFromCompany = this.syncFormFromCompany.bind(this);
this.handleCreateTerminal = this.handleCreateTerminal.bind(this); this.handleCreateTerminal = this.handleCreateTerminal.bind(this);
this.handleDeleteTerminal = this.handleDeleteTerminal.bind(this); this.handleDeleteTerminal = this.handleDeleteTerminal.bind(this);
this.loadTerminals = this.loadTerminals.bind(this);
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
@@ -75,10 +77,7 @@ class CompanySettingsDialog extends Component {
} else if (companyStatus !== 'loading') { } else if (companyStatus !== 'loading') {
void this.props.loadCurrentCompany(); void this.props.loadCurrentCompany();
} }
// Load posterminals when dialog opens void this.loadTerminals();
if (this.props.posterminalStatus !== 'loading') {
void this.props.loadPosterminals();
}
} }
if (open && company && company !== prevProps.company) { if (open && company && company !== prevProps.company) {
this.syncFormFromCompany(company); this.syncFormFromCompany(company);
@@ -94,6 +93,15 @@ class CompanySettingsDialog extends Component {
}); });
} }
async loadTerminals() {
try {
const terminals = await this.context.posterminalPromise;
this.setState({ terminals });
} catch (err) {
notifyError(err);
}
}
async handleCreateTerminal() { async handleCreateTerminal() {
const { newTerminalName, enableAllForNew } = this.state; const { newTerminalName, enableAllForNew } = this.state;
const trimmed = newTerminalName.trim(); const trimmed = newTerminalName.trim();
@@ -109,7 +117,8 @@ class CompanySettingsDialog extends Component {
this.props.loadCategoryTree(); this.props.loadCategoryTree();
} }
this.setState({ newTerminalName: '' }); const terminals = await this.context.updatePosterminal();
this.setState({ newTerminalName: '', terminals });
} catch (err) { } catch (err) {
notifyError(err); notifyError(err);
} finally { } finally {
@@ -120,6 +129,8 @@ class CompanySettingsDialog extends Component {
async handleDeleteTerminal(terminal) { async handleDeleteTerminal(terminal) {
try { try {
await this.props.deletePosterminal({ terminalId: terminal.id }).unwrap(); await this.props.deletePosterminal({ terminalId: terminal.id }).unwrap();
const terminals = await this.context.updatePosterminal();
this.setState({ terminals });
} catch (err) { } catch (err) {
notifyError(err); notifyError(err);
} }
@@ -262,73 +273,65 @@ class CompanySettingsDialog extends Component {
<Divider sx={{ my: 1 }} /> <Divider sx={{ my: 1 }} />
<Box> <Box>
{this.props.posterminalStatus === 'loading' ? ( <List dense sx={{ py: 0 }}>
<Box sx={{ display: 'flex', justifyContent: 'center', py: 2 }}> {this.state.terminals.map((terminal) => (
<CircularProgress size={24} /> <ListItem
</Box> key={terminal.id}
) : ( sx={{ px: 0, py: 0.5 }}
<> >
<List dense sx={{ py: 0 }}> <PointOfSaleIcon sx={{ mr: 1, color: 'text.secondary', fontSize: 20 }} />
{this.props.terminals.map((terminal) => ( <ListItemText
<ListItem primary={terminal.name}
key={terminal.id} secondary={`PIN: ${terminal.pairingpin}`}
sx={{ px: 0, py: 0.5 }}
>
<PointOfSaleIcon sx={{ mr: 1, color: 'text.secondary', fontSize: 20 }} />
<ListItemText
primary={terminal.name}
secondary={`PIN: ${terminal.pairingpin}`}
/>
<ListItemSecondaryAction>
<IconButton
edge="end"
size="small"
onClick={() => this.handleDeleteTerminal(terminal)}
disabled={busy || this.state.creatingTerminal}
>
<DeleteOutlinedIcon fontSize="small" />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
))}
</List>
<Box sx={{ mt: 1, display: 'flex', alignItems: 'center', gap: 1 }}>
<TextField
size="small"
placeholder="Neues Terminal..."
value={this.state.newTerminalName}
onChange={(e) => this.setState({ newTerminalName: e.target.value })}
disabled={busy || this.state.creatingTerminal}
autoComplete="off"
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
this.handleCreateTerminal();
}
}}
sx={{ flex: 1 }}
/> />
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}> <ListItemSecondaryAction>
<PointOfSaleIcon sx={{ fontSize: 18, color: 'text.secondary' }} /> <IconButton
<Switch edge="end"
size="small" size="small"
checked={this.state.enableAllForNew} onClick={() => this.handleDeleteTerminal(terminal)}
onChange={(e) => this.setState({ enableAllForNew: e.target.checked })}
disabled={busy || this.state.creatingTerminal} disabled={busy || this.state.creatingTerminal}
/> >
</Box> <DeleteOutlinedIcon fontSize="small" />
<Button </IconButton>
variant="contained" </ListItemSecondaryAction>
size="small" </ListItem>
onClick={this.handleCreateTerminal} ))}
disabled={busy || this.state.creatingTerminal || !this.state.newTerminalName.trim()} </List>
>
Hinzufügen <Box sx={{ mt: 1, display: 'flex', alignItems: 'center', gap: 1 }}>
</Button> <TextField
</Box> size="small"
</> placeholder="Neues Terminal..."
)} value={this.state.newTerminalName}
onChange={(e) => this.setState({ newTerminalName: e.target.value })}
disabled={busy || this.state.creatingTerminal}
autoComplete="off"
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
this.handleCreateTerminal();
}
}}
sx={{ flex: 1 }}
/>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<PointOfSaleIcon sx={{ fontSize: 18, color: 'text.secondary' }} />
<Switch
size="small"
checked={this.state.enableAllForNew}
onChange={(e) => this.setState({ enableAllForNew: e.target.checked })}
disabled={busy || this.state.creatingTerminal}
/>
</Box>
<Button
variant="contained"
size="small"
onClick={this.handleCreateTerminal}
disabled={busy || this.state.creatingTerminal || !this.state.newTerminalName.trim()}
>
Hinzufügen
</Button>
</Box>
</Box> </Box>
</Stack> </Stack>
)} )}
@@ -350,14 +353,11 @@ class CompanySettingsDialog extends Component {
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
company: selectCurrentCompany(state), company: selectCurrentCompany(state),
companyStatus: selectCompanyStatus(state), companyStatus: selectCompanyStatus(state),
terminals: selectPosterminals(state),
posterminalStatus: selectPosterminalStatus(state),
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
loadCurrentCompany: () => dispatch(loadCurrentCompany()), loadCurrentCompany: () => dispatch(loadCurrentCompany()),
updateCompany: (payload) => dispatch(updateCompanyThunk(payload)), updateCompany: (payload) => dispatch(updateCompanyThunk(payload)),
loadPosterminals: () => dispatch(loadPosterminals()),
createPosterminal: (payload) => dispatch(createPosterminal(payload)), createPosterminal: (payload) => dispatch(createPosterminal(payload)),
deletePosterminal: (payload) => dispatch(deletePosterminal(payload)), deletePosterminal: (payload) => dispatch(deletePosterminal(payload)),
enableAllTerminalCategories: (payload) => dispatch(enableAllTerminalCategories(payload)), enableAllTerminalCategories: (payload) => dispatch(enableAllTerminalCategories(payload)),