u
This commit is contained in:
@@ -8,10 +8,14 @@ import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import ContentPasteIcon from '@mui/icons-material/ContentPaste';
|
||||
import UploadFileIcon from '@mui/icons-material/UploadFile';
|
||||
import ImageSearchIcon from '@mui/icons-material/ImageSearch';
|
||||
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { StorageManagerContext } from '../../api/storageManagerContext';
|
||||
import artikelAutomat from '../../automats/artikelAutomat';
|
||||
import { requireArray, requireObject } from '../../utils/apiShape';
|
||||
import {
|
||||
articleWithPhotoOrder,
|
||||
@@ -22,9 +26,10 @@ import {
|
||||
sortedPhotos,
|
||||
} from '../../utils/articleDetail';
|
||||
import { notifyError } from '../../utils/notify';
|
||||
import { pasteImageOrFallback } from '../../utils/pasteImage';
|
||||
import { readClipboardImage } from '../../utils/pasteImage';
|
||||
import { prepareArticlePhoto } from '../../utils/prepareArticlePhoto';
|
||||
import ArticlePhoto from './ArticlePhoto';
|
||||
import ArticleImageSearchDialog from './ArticleImageSearchDialog';
|
||||
|
||||
const overlayChipSx = {
|
||||
height: 22,
|
||||
@@ -46,9 +51,12 @@ class ArticlePhotosDialog extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.fileInputRef = createRef();
|
||||
this.state = { busy: false };
|
||||
this.state = { busy: false, searchOpen: false };
|
||||
this.handleClose = this.handleClose.bind(this);
|
||||
this.handlePasteClick = this.handlePasteClick.bind(this);
|
||||
this.handleUploadClick = this.handleUploadClick.bind(this);
|
||||
this.handleSearchOpen = this.handleSearchOpen.bind(this);
|
||||
this.handleSearchClose = this.handleSearchClose.bind(this);
|
||||
this.handleFileChange = this.handleFileChange.bind(this);
|
||||
this.uploadRawImage = this.uploadRawImage.bind(this);
|
||||
}
|
||||
@@ -72,7 +80,9 @@ class ArticlePhotosDialog extends Component {
|
||||
});
|
||||
requireObject(res, 'POST /api/article/:sku/image');
|
||||
requireObject(res.image, 'image');
|
||||
onArticleUpdated?.(articleWithUploadedPhoto(articleData, res.image));
|
||||
const updated = articleWithUploadedPhoto(articleData, res.image);
|
||||
artikelAutomat.actions.setArticle(updated);
|
||||
onArticleUpdated?.(updated);
|
||||
} catch (err) {
|
||||
notifyError(err);
|
||||
} finally {
|
||||
@@ -80,13 +90,33 @@ class ArticlePhotosDialog extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
handlePasteClick() {
|
||||
async handlePasteClick() {
|
||||
if (this.state.busy) return;
|
||||
void pasteImageOrFallback(() => {
|
||||
this.fileInputRef.current?.click();
|
||||
}).then((image) => {
|
||||
if (image) void this.uploadRawImage(image);
|
||||
});
|
||||
try {
|
||||
const image = await readClipboardImage();
|
||||
if (image) {
|
||||
await this.uploadRawImage(image);
|
||||
} else {
|
||||
enqueueSnackbar('Kein Bild in der Zwischenablage gefunden.', { variant: 'info' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Clipboard read error:', err);
|
||||
enqueueSnackbar('Zugriff auf Zwischenablage nicht möglich.', { variant: 'warning' });
|
||||
}
|
||||
}
|
||||
|
||||
handleUploadClick() {
|
||||
if (this.state.busy) return;
|
||||
this.fileInputRef.current?.click();
|
||||
}
|
||||
|
||||
handleSearchOpen() {
|
||||
if (this.state.busy) return;
|
||||
this.setState({ searchOpen: true });
|
||||
}
|
||||
|
||||
handleSearchClose() {
|
||||
this.setState({ searchOpen: false });
|
||||
}
|
||||
|
||||
handleFileChange(event) {
|
||||
@@ -101,7 +131,9 @@ class ArticlePhotosDialog extends Component {
|
||||
this.setState({ busy: true });
|
||||
try {
|
||||
await this.context.article.deleteImage(articleData.sku, fullHash);
|
||||
onArticleUpdated?.(articleWithoutPhoto(articleData, fullHash));
|
||||
const updated = articleWithoutPhoto(articleData, fullHash);
|
||||
artikelAutomat.actions.setArticle(updated);
|
||||
onArticleUpdated?.(updated);
|
||||
} catch (err) {
|
||||
notifyError(err);
|
||||
} finally {
|
||||
@@ -126,7 +158,9 @@ class ArticlePhotosDialog extends Component {
|
||||
const res = await this.context.article.orderImages(articleData.sku, { fullHashes });
|
||||
requireObject(res, 'PUT /api/article/:sku/images/order');
|
||||
requireArray(res.fullHashes, 'fullHashes');
|
||||
onArticleUpdated?.(articleWithPhotoOrder(articleData, res.fullHashes));
|
||||
const updated = articleWithPhotoOrder(articleData, res.fullHashes);
|
||||
artikelAutomat.actions.setArticle(updated);
|
||||
onArticleUpdated?.(updated);
|
||||
} catch (err) {
|
||||
notifyError(err);
|
||||
} finally {
|
||||
@@ -250,16 +284,37 @@ class ArticlePhotosDialog extends Component {
|
||||
</Box>
|
||||
)}
|
||||
</DialogContent>
|
||||
<DialogActions sx={{ px: 3, py: 2, justifyContent: 'space-between' }}>
|
||||
<Button
|
||||
type="button"
|
||||
startIcon={<ContentPasteIcon />}
|
||||
onClick={this.handlePasteClick}
|
||||
disabled={busy}
|
||||
>
|
||||
Bild einfügen
|
||||
</Button>
|
||||
<Button type="button" onClick={this.handleClose} disabled={busy}>
|
||||
<DialogActions sx={{ px: 3, py: 2, justifyContent: 'space-between', flexWrap: 'wrap', gap: 1 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outlined"
|
||||
startIcon={<ContentPasteIcon />}
|
||||
onClick={this.handlePasteClick}
|
||||
disabled={busy}
|
||||
>
|
||||
Bild einfügen
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outlined"
|
||||
startIcon={<UploadFileIcon />}
|
||||
onClick={this.handleUploadClick}
|
||||
disabled={busy}
|
||||
>
|
||||
Bild hochladen
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="contained"
|
||||
startIcon={<ImageSearchIcon />}
|
||||
onClick={this.handleSearchOpen}
|
||||
disabled={busy}
|
||||
>
|
||||
Bild suchen
|
||||
</Button>
|
||||
</Box>
|
||||
<Button type="button" onClick={this.handleClose} disabled={busy} color="inherit">
|
||||
Schließen
|
||||
</Button>
|
||||
</DialogActions>
|
||||
@@ -271,6 +326,12 @@ class ArticlePhotosDialog extends Component {
|
||||
hidden
|
||||
onChange={this.handleFileChange}
|
||||
/>
|
||||
<ArticleImageSearchDialog
|
||||
open={this.state.searchOpen}
|
||||
article={articleData}
|
||||
onClose={this.handleSearchClose}
|
||||
onArticleUpdated={this.props.onArticleUpdated}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user