This commit is contained in:
seb
2026-08-01 03:37:40 +02:00
parent 4ea593a0c8
commit 41bc76303a
10 changed files with 904 additions and 68 deletions

View File

@@ -1,5 +1,6 @@
import { useRef, useState } from 'react';
import { Component, createRef } from 'react';
import ContentPasteIcon from '@mui/icons-material/ContentPaste';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import { article } from '../../api';
import { PanelTile } from '../panels';
import { requireObject } from '../../utils/apiShape';
@@ -8,22 +9,23 @@ import { prepareArticlePhoto } from '../../utils/prepareArticlePhoto';
import { pasteImageOrFallback } from '../../utils/pasteImage';
import { articleWithUploadedPhoto, primaryPhoto } from '../../utils/articleDetail';
import ArticlePhoto from './ArticlePhoto';
import ArticlePhotosDialog from './ArticlePhotosDialog';
export default function ArticlePhotoTile({
article: articleData,
onArticleUpdated,
wide = 1,
minHeight = 200,
sx,
tileKey,
}) {
const fileInputRef = useRef(null);
const [busy, setBusy] = useState(false);
const photo = primaryPhoto(articleData);
const hasPhoto = photo?.thumbHash != null;
class ArticlePhotoTile extends Component {
constructor(props) {
super(props);
this.fileInputRef = createRef();
this.state = { busy: false, editOpen: false };
this.handlePasteClick = this.handlePasteClick.bind(this);
this.handleFileChange = this.handleFileChange.bind(this);
this.handleEditOpen = this.handleEditOpen.bind(this);
this.handleEditClose = this.handleEditClose.bind(this);
this.uploadRawImage = this.uploadRawImage.bind(this);
}
const uploadRawImage = async (rawBlob) => {
setBusy(true);
async uploadRawImage(rawBlob) {
const { article: articleData, onArticleUpdated } = this.props;
this.setState({ busy: true });
try {
const file = await prepareArticlePhoto(rawBlob);
const res = await article.uploadImage(articleData.sku, file);
@@ -33,53 +35,88 @@ export default function ArticlePhotoTile({
} catch (err) {
notifyError(err);
} finally {
setBusy(false);
this.setState({ busy: false });
}
};
}
const handlePasteClick = () => {
if (busy) return;
handlePasteClick() {
if (this.state.busy) return;
void pasteImageOrFallback(() => {
fileInputRef.current?.click();
this.fileInputRef.current?.click();
}).then((image) => {
if (image) void uploadRawImage(image);
if (image) void this.uploadRawImage(image);
});
};
}
const handleFileChange = (event) => {
handleFileChange(event) {
const file = event.target.files?.[0];
event.target.value = '';
if (!file) return;
void uploadRawImage(file);
};
void this.uploadRawImage(file);
}
return (
<>
<PanelTile
wide={wide}
minHeight={minHeight}
sx={sx}
tileKey={tileKey}
action={
hasPhoto
? undefined
: {
label: 'Bild einfügen',
icon: ContentPasteIcon,
onClick: handlePasteClick,
busy,
}
}
>
<ArticlePhoto photo={photo} />
</PanelTile>
<input
ref={fileInputRef}
type="file"
accept="image/*"
hidden
onChange={handleFileChange}
/>
</>
);
handleEditOpen() {
this.setState({ editOpen: true });
}
handleEditClose() {
this.setState({ editOpen: false });
}
render() {
const {
article: articleData,
onArticleUpdated,
wide = 1,
minHeight = 200,
sx,
tileKey,
} = this.props;
const { busy, editOpen } = this.state;
const photo = primaryPhoto(articleData);
const hasPhoto = photo?.thumbHash != null || photo?.fullHash != null;
return (
<>
<PanelTile
wide={wide}
minHeight={minHeight}
sx={sx}
tileKey={tileKey}
action={
hasPhoto
? {
label: 'Bilder bearbeiten',
icon: EditOutlinedIcon,
onClick: this.handleEditOpen,
busy: false,
}
: {
label: 'Bild einfügen',
icon: ContentPasteIcon,
onClick: this.handlePasteClick,
busy,
}
}
>
<ArticlePhoto photo={photo} />
</PanelTile>
<input
ref={this.fileInputRef}
type="file"
accept="image/*"
hidden
onChange={this.handleFileChange}
/>
<ArticlePhotosDialog
open={editOpen}
article={articleData}
onClose={this.handleEditClose}
onArticleUpdated={onArticleUpdated}
/>
</>
);
}
}
export default ArticlePhotoTile;