This commit is contained in:
seb
2026-10-30 17:40:15 +01:00
parent 56d376c9bd
commit 9cb82745e3

View File

@@ -5,19 +5,18 @@ import Chip from '@mui/material/Chip';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'; import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward'; import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
import CheckIcon from '@mui/icons-material/Check'; import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from '@mui/icons-material/Close';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined'; import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import LocalPrintshopOutlinedIcon from '@mui/icons-material/LocalPrintshopOutlined'; import LocalPrintshopOutlinedIcon from '@mui/icons-material/LocalPrintshopOutlined';
import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined'; import CheckCircleOutlinedIcon from '@mui/icons-material/CheckCircleOutlined';
import HourglassEmptyIcon from '@mui/icons-material/HourglassEmpty'; import HourglassEmptyIcon from '@mui/icons-material/HourglassEmpty';
import QRCode from 'qrcode';
import { enqueueSnackbar } from 'notistack'; import { enqueueSnackbar } from 'notistack';
import BackendError from '../BackendError'; import BackendError from '../BackendError';
import companyAutomat from '../../automats/companyAutomat'; import companyAutomat from '../../automats/companyAutomat';
@@ -41,6 +40,80 @@ function formatDateTime(val) {
} }
} }
class AgentQrCode extends PureComponent {
constructor(props) {
super(props);
this.state = { dataUrl: null };
}
componentDidMount() {
this.generateQr();
}
componentDidUpdate(prevProps) {
if (prevProps.value !== this.props.value || prevProps.size !== this.props.size) {
this.generateQr();
}
}
async generateQr() {
const { value, size = 110 } = this.props;
if (!value) {
this.setState({ dataUrl: null });
return;
}
try {
const dataUrl = await QRCode.toDataURL(value, {
width: size,
margin: 1,
color: {
dark: '#000000',
light: '#ffffff',
},
errorCorrectionLevel: 'M',
});
this.setState({ dataUrl });
} catch (err) {
console.error('Failed to generate QR code:', err);
}
}
render() {
const { size = 110 } = this.props;
const { dataUrl } = this.state;
if (!dataUrl) {
return (
<Box
sx={{
width: size,
height: size,
bgcolor: 'action.hover',
borderRadius: 1,
}}
/>
);
}
return (
<Box
component="img"
src={dataUrl}
alt="Pairing QR Code"
sx={{
width: size,
height: size,
borderRadius: 1,
border: '1px solid',
borderColor: 'divider',
bgcolor: '#fff',
p: 0.5,
display: 'block',
flexShrink: 0,
}}
/>
);
}
}
export default class PrinterAgentSettingsPanel extends PureComponent { export default class PrinterAgentSettingsPanel extends PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
@@ -385,7 +458,6 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
<Typography variant="subtitle1" fontWeight={600}> <Typography variant="subtitle1" fontWeight={600}>
{agent.name} {agent.name}
</Typography> </Typography>
<Tooltip title="Name bearbeiten">
<IconButton <IconButton
size="small" size="small"
onClick={() => this.handleStartRename(agent)} onClick={() => this.handleStartRename(agent)}
@@ -394,7 +466,6 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
> >
<EditOutlinedIcon sx={{ fontSize: 16 }} /> <EditOutlinedIcon sx={{ fontSize: 16 }} />
</IconButton> </IconButton>
</Tooltip>
</Box> </Box>
)} )}
@@ -433,33 +504,47 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
</Box> </Box>
</Box> </Box>
{/* Body: Pairing details or PIN info */} {/* Body: Pairing details with QR code or Paired status info */}
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
alignItems: 'center', flexDirection: 'column',
justifyContent: 'space-between', gap: 1.5,
flexWrap: 'wrap',
gap: 2,
pt: 0.5, pt: 0.5,
}} }}
> >
{!isPaired ? ( {!isPaired ? (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, flexWrap: 'wrap' }}> (() => {
<Typography variant="body2" color="text.secondary"> const domain = typeof window !== 'undefined' ? window.location.host : '';
const qrPayload = JSON.stringify({
domain,
pin: String(agent.pairingpin || ''),
});
return (
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 2,
flexWrap: 'wrap',
bgcolor: 'action.hover',
p: 1.5,
borderRadius: 1.5,
border: '1px solid',
borderColor: 'warning.light',
}}
>
<Box sx={{ display: 'inline-flex' }}>
<AgentQrCode value={qrPayload} size={110} />
</Box>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1, flex: 1, minWidth: 220 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>
<Typography variant="body2" color="text.secondary" sx={{ fontWeight: 500 }}>
Kopplungs-PIN: Kopplungs-PIN:
</Typography> </Typography>
<Tooltip title="PIN in die Zwischenablage kopieren">
<Chip <Chip
icon={<ContentCopyIcon sx={{ fontSize: 14 }} />}
label={agent.pairingpin || '—'} label={agent.pairingpin || '—'}
onClick={() => {
if (agent.pairingpin) {
navigator.clipboard?.writeText(agent.pairingpin);
enqueueSnackbar('PIN in Zwischenablage kopiert.', { variant: 'info' });
}
}}
clickable
color="warning" color="warning"
variant="filled" variant="filled"
sx={{ sx={{
@@ -470,11 +555,23 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
px: 0.5, px: 0.5,
}} }}
/> />
</Tooltip>
<Typography variant="caption" color="text.secondary">
Geben Sie diesen PIN auf dem Drucker-Agent-Gerät ein.
</Typography>
</Box> </Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>
<Typography variant="body2" color="text.secondary" sx={{ fontWeight: 500 }}>
Domain:
</Typography>
<Chip
label={domain}
size="small"
variant="outlined"
sx={{ fontFamily: 'monospace', fontSize: '0.8rem' }}
/>
</Box>
</Box>
</Box>
);
})()
) : ( ) : (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, flexWrap: 'wrap' }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, flexWrap: 'wrap' }}>
{agent.clientserial ? ( {agent.clientserial ? (
@@ -513,12 +610,11 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
</Box> </Box>
)} )}
{/* Sort Order Controls */} {/* Row with Sort Order Controls */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, ml: 'auto' }}> <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: 0.5, pt: 0.5 }}>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
Reihenfolge: Reihenfolge:
</Typography> </Typography>
<Tooltip title="Nach oben verschieben">
<span> <span>
<IconButton <IconButton
size="small" size="small"
@@ -529,8 +625,7 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
<ArrowUpwardIcon sx={{ fontSize: 16 }} /> <ArrowUpwardIcon sx={{ fontSize: 16 }} />
</IconButton> </IconButton>
</span> </span>
</Tooltip>
<Tooltip title="Nach unten verschieben">
<span> <span>
<IconButton <IconButton
size="small" size="small"
@@ -541,7 +636,6 @@ export default class PrinterAgentSettingsPanel extends PureComponent {
<ArrowDownwardIcon sx={{ fontSize: 16 }} /> <ArrowDownwardIcon sx={{ fontSize: 16 }} />
</IconButton> </IconButton>
</span> </span>
</Tooltip>
<TextField <TextField
type="number" type="number"
size="small" size="small"