file api
This commit is contained in:
@@ -9,8 +9,7 @@ import Paper from '@mui/material/Paper';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import SearchIcon from '@mui/icons-material/Search';
|
||||
import ClearIcon from '@mui/icons-material/Clear';
|
||||
import { StorageManagerContext } from '../../api/storageManagerContext';
|
||||
import { StorageManagerContext, getStorageManager } from '../../api/storageManagerContext';
|
||||
import BackendError from '../../components/BackendError';
|
||||
import { formatPrice } from '../../utils/price';
|
||||
import {
|
||||
@@ -83,6 +82,10 @@ function initialSearchState(searchParams) {
|
||||
class ArtikelSearchPage extends Component {
|
||||
static contextType = StorageManagerContext;
|
||||
|
||||
get storageManager() {
|
||||
return this.context || getStorageManager();
|
||||
}
|
||||
|
||||
state = initialSearchState(this.props.searchParams);
|
||||
listSlotRef = { current: null };
|
||||
rowMeasureRef = { current: null };
|
||||
@@ -171,7 +174,7 @@ class ArtikelSearchPage extends Component {
|
||||
|
||||
// Kick off initial search (empty input = show all products).
|
||||
const { input } = this.state;
|
||||
this.context.doSearch({
|
||||
this.storageManager?.doSearch({
|
||||
target: input,
|
||||
filter: this.props.searchParams.get('filter') || undefined,
|
||||
offset: 0,
|
||||
@@ -220,7 +223,7 @@ class ArtikelSearchPage extends Component {
|
||||
const value = event.target.value;
|
||||
this.setState({ input: value });
|
||||
|
||||
this.context.doSearch({
|
||||
this.storageManager?.doSearch({
|
||||
target: value,
|
||||
filter: this.props.searchParams.get('filter') || undefined,
|
||||
offset: 0,
|
||||
@@ -240,7 +243,7 @@ class ArtikelSearchPage extends Component {
|
||||
|
||||
// Delegate fetch + debounce to the global StorageManager.
|
||||
// The callback pushes results into local component state.
|
||||
this.context.doSearch({
|
||||
this.storageManager?.doSearch({
|
||||
target: trimmed,
|
||||
filter: filter || undefined,
|
||||
offset,
|
||||
|
||||
@@ -28,7 +28,8 @@ import { backendErrorFrom } from '../../utils/backendError';
|
||||
import { notifyError } from '../../utils/notify';
|
||||
import { generatePdfThumbnail } from '../../utils/pdfThumbnail';
|
||||
import { extractPdfText } from '../../utils/pdfText';
|
||||
import { deliveryEditorAutomat } from '../../automats/deliveryEditorAutomat';
|
||||
import { getDeliveryEditorAutomat } from '../../automats/deliveryEditorAutomat';
|
||||
import { delivery as deliveryApi } from '../../api';
|
||||
|
||||
class LieferungNeuPage extends PureComponent {
|
||||
static contextType = StorageManagerContext;
|
||||
@@ -36,9 +37,10 @@ class LieferungNeuPage extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.cfg = manifestConfig('delivery');
|
||||
this.automat = getDeliveryEditorAutomat(props.docId);
|
||||
this.state = {
|
||||
...deliveryEditorAutomat.state,
|
||||
status: 'loadingParties',
|
||||
...this.automat.state,
|
||||
status: props.docId != null ? 'loading' : 'loadingParties',
|
||||
error: null,
|
||||
partiesLoading: true,
|
||||
saving: false,
|
||||
@@ -66,32 +68,38 @@ class LieferungNeuPage extends PureComponent {
|
||||
this.handleAttachmentClick = this.handleAttachmentClick.bind(this);
|
||||
this.handleCloseTextEditor = this.handleCloseTextEditor.bind(this);
|
||||
this.handleSaveTextEditor = this.handleSaveTextEditor.bind(this);
|
||||
this.handleTextEditorContentLoaded = this.handleTextEditorContentLoaded.bind(this);
|
||||
this.ensureAttachmentFile = this.ensureAttachmentFile.bind(this);
|
||||
this.handleSkuBlur = this.handleSkuBlur.bind(this);
|
||||
this.handleCreateArticleForLine = this.handleCreateArticleForLine.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.unsubscribe = deliveryEditorAutomat.subscribe(this);
|
||||
this.unsubscribe = this.automat.subscribe(this);
|
||||
this._cancelled = false;
|
||||
if (this.props.docId != null) {
|
||||
void this.loadEdit();
|
||||
} else {
|
||||
void this.loadPartiesOnly();
|
||||
if (this.props.initialDelivery) {
|
||||
deliveryEditorAutomat.actions.setDelivery(this.props.initialDelivery);
|
||||
} else {
|
||||
deliveryEditorAutomat.actions.resetDelivery();
|
||||
this.automat.actions.setDelivery(this.props.initialDelivery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.docId !== this.props.docId) {
|
||||
this.unsubscribe?.();
|
||||
this.automat = getDeliveryEditorAutomat(this.props.docId);
|
||||
this.unsubscribe = this.automat.subscribe(this);
|
||||
this.setState({ ...this.automat.state });
|
||||
if (this.props.docId != null) {
|
||||
void this.loadEdit();
|
||||
} else {
|
||||
void this.loadPartiesOnly();
|
||||
deliveryEditorAutomat.actions.resetDelivery();
|
||||
if (this.props.initialDelivery) {
|
||||
this.automat.actions.setDelivery(this.props.initialDelivery);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +118,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
try {
|
||||
const parties = await loadParties('delivery', this.context);
|
||||
if (this._cancelled) return;
|
||||
deliveryEditorAutomat.actions.setDeliveryEntities(parties);
|
||||
this.automat.actions.setDeliveryEntities(parties);
|
||||
this.setState({
|
||||
status: 'ready',
|
||||
partiesLoading: false,
|
||||
@@ -145,7 +153,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
]);
|
||||
if (this._cancelled) return;
|
||||
|
||||
deliveryEditorAutomat.actions.setDeliveryEntities(parties);
|
||||
this.automat.actions.setDeliveryEntities(parties);
|
||||
|
||||
requireObject(docRes, cfg.getPathLabel);
|
||||
requireObject(docRes[cfg.docField], cfg.docField);
|
||||
@@ -154,17 +162,17 @@ class LieferungNeuPage extends PureComponent {
|
||||
const lines =
|
||||
apiLines.length > 0 ? apiLines.map(lineFromApi) : [emptyLine()];
|
||||
|
||||
deliveryEditorAutomat.actions.setId(doc.id ?? docId);
|
||||
deliveryEditorAutomat.actions.setDate(dateInputValue(doc.date));
|
||||
if (doc[cfg.partyField] != null) deliveryEditorAutomat.actions.setDeliveryEntity(doc[cfg.partyField]);
|
||||
if (doc.number != null) deliveryEditorAutomat.actions.setNumber(doc.number);
|
||||
if (doc.externalNumber != null) deliveryEditorAutomat.actions.setExternalNumber(String(doc.externalNumber));
|
||||
deliveryEditorAutomat.actions.setLineitems(lines);
|
||||
this.automat.actions.setId(doc.id ?? docId);
|
||||
this.automat.actions.setDate(dateInputValue(doc.date));
|
||||
if (doc[cfg.partyField] != null) this.automat.actions.setDeliveryEntity(doc[cfg.partyField]);
|
||||
if (doc.number != null) this.automat.actions.setNumber(doc.number);
|
||||
if (doc.externalNumber != null) this.automat.actions.setExternalNumber(String(doc.externalNumber));
|
||||
this.automat.actions.setLineitems(lines);
|
||||
|
||||
// Restore attachments with thumbnails
|
||||
const apiFiles = doc.files ?? [];
|
||||
const attachments = await restoreAttachmentsFromApi(apiFiles, this.state.attachments);
|
||||
deliveryEditorAutomat.actions.setAttachments(attachments);
|
||||
this.automat.actions.setAttachments(attachments);
|
||||
|
||||
this.setState({
|
||||
status: 'ready',
|
||||
@@ -186,19 +194,19 @@ class LieferungNeuPage extends PureComponent {
|
||||
}
|
||||
|
||||
handlePartyChange(partyId) {
|
||||
deliveryEditorAutomat.actions.setDeliveryEntity(partyId);
|
||||
this.automat.actions.setDeliveryEntity(partyId);
|
||||
}
|
||||
|
||||
handleDateChange(date) {
|
||||
deliveryEditorAutomat.actions.setDate(date);
|
||||
this.automat.actions.setDate(date);
|
||||
}
|
||||
|
||||
handleNumberChange(number) {
|
||||
deliveryEditorAutomat.actions.setNumber(number);
|
||||
this.automat.actions.setNumber(number);
|
||||
}
|
||||
|
||||
handleExternalNumberChange(externalNumber) {
|
||||
deliveryEditorAutomat.actions.setExternalNumber(externalNumber);
|
||||
this.automat.actions.setExternalNumber(externalNumber);
|
||||
}
|
||||
|
||||
findLineIndex(key) {
|
||||
@@ -214,7 +222,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
|
||||
handleLineChange(key, field, value) {
|
||||
const index = this.findLineIndex(key);
|
||||
deliveryEditorAutomat.actions.updateLineitem({
|
||||
this.automat.actions.updateLineitem({
|
||||
index,
|
||||
key,
|
||||
[field]: value,
|
||||
@@ -229,7 +237,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
}
|
||||
this._skuDebounceTimers[key] = setTimeout(() => {
|
||||
if (this._skuDebounceTimers) delete this._skuDebounceTimers[key];
|
||||
deliveryEditorAutomat.actions.fetchSupplierArticleForSku(value, key);
|
||||
this.automat.actions.fetchSupplierArticleForSku(value, key);
|
||||
}, 350);
|
||||
}
|
||||
}
|
||||
@@ -239,7 +247,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
clearTimeout(this._skuDebounceTimers[key]);
|
||||
delete this._skuDebounceTimers[key];
|
||||
}
|
||||
deliveryEditorAutomat.actions.fetchSupplierArticleForSku(value, key);
|
||||
this.automat.actions.fetchSupplierArticleForSku(value, key);
|
||||
}
|
||||
|
||||
async handleCreateArticleForLine(line) {
|
||||
@@ -294,7 +302,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
|
||||
// Keep the supplier SKU in the delivery line, but refresh supplier article data
|
||||
// using the supplier SKU (not the internal SKU)
|
||||
deliveryEditorAutomat.actions.fetchSupplierArticleForSku(supplierSku, line.key);
|
||||
this.automat.actions.fetchSupplierArticleForSku(supplierSku, line.key);
|
||||
|
||||
enqueueSnackbar(`Artikel "${internalSku}" erstellt und Lieferanten-Artikel "${supplierSku}" zugeordnet.`, { variant: 'success' });
|
||||
} catch (err) {
|
||||
@@ -304,69 +312,105 @@ class LieferungNeuPage extends PureComponent {
|
||||
}
|
||||
|
||||
handleAddLine() {
|
||||
deliveryEditorAutomat.actions.addLineitem();
|
||||
this.automat.actions.addLineitem();
|
||||
}
|
||||
|
||||
handleRemoveLine(key) {
|
||||
const index = this.findLineIndex(key);
|
||||
deliveryEditorAutomat.actions.removeLineitem(index >= 0 ? index : key);
|
||||
this.automat.actions.removeLineitem(index >= 0 ? index : key);
|
||||
}
|
||||
|
||||
async handlePdfUpload(file) {
|
||||
if (!file || this.state.pdfUploading) return;
|
||||
|
||||
// 1. Generate thumbnail for PDF
|
||||
let thumbnail = null;
|
||||
try {
|
||||
thumbnail = await generatePdfThumbnail(file);
|
||||
} catch (err) {
|
||||
console.error('Fehler beim Erstellen des PDF-Thumbnails:', err);
|
||||
}
|
||||
const isPdf =
|
||||
file.type === 'application/pdf' || file.name?.toLowerCase().endsWith('.pdf');
|
||||
const isCsv =
|
||||
file.type === 'text/csv' || file.name?.toLowerCase().endsWith('.csv');
|
||||
|
||||
const pdfId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
const pdfAttachment = {
|
||||
id: pdfId,
|
||||
file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: 'application/pdf',
|
||||
thumbnail,
|
||||
uploadedAt: new Date().toISOString(),
|
||||
};
|
||||
deliveryEditorAutomat.actions.addAttachment(pdfAttachment);
|
||||
if (isPdf) {
|
||||
// 1. Generate thumbnail for PDF
|
||||
let thumbnail = null;
|
||||
try {
|
||||
thumbnail = await generatePdfThumbnail(file);
|
||||
} catch (err) {
|
||||
console.error('Fehler beim Erstellen des PDF-Thumbnails:', err);
|
||||
}
|
||||
|
||||
// 2. Extract text using pdftotext-wasm to create 2nd file (textfile)
|
||||
try {
|
||||
const text = await extractPdfText(file, { layout: true });
|
||||
const txtName = file.name.replace(/\.pdf$/i, '') + '.txt';
|
||||
const txtFile = new File([text], txtName, { type: 'text/plain;charset=utf-8' });
|
||||
const txtAttachment = {
|
||||
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
||||
file: txtFile,
|
||||
name: txtFile.name,
|
||||
size: txtFile.size,
|
||||
type: 'text/plain',
|
||||
text,
|
||||
parentPdfId: pdfId,
|
||||
const pdfId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
const pdfAttachment = {
|
||||
id: pdfId,
|
||||
file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: 'application/pdf',
|
||||
thumbnail,
|
||||
uploadedAt: new Date().toISOString(),
|
||||
};
|
||||
deliveryEditorAutomat.actions.addAttachment(txtAttachment);
|
||||
} catch (txtErr) {
|
||||
console.error('Fehler beim Extrahieren von Text mit pdftotext-wasm:', txtErr);
|
||||
this.automat.actions.addAttachment(pdfAttachment);
|
||||
|
||||
// 2. Extract text using pdftotext-wasm to create 2nd file (textfile)
|
||||
try {
|
||||
const text = await extractPdfText(file, { layout: true });
|
||||
const txtName = file.name.replace(/\.pdf$/i, '') + '.txt';
|
||||
const txtFile = new File([text], txtName, { type: 'text/plain;charset=utf-8' });
|
||||
const txtAttachment = {
|
||||
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
||||
file: txtFile,
|
||||
name: txtFile.name,
|
||||
size: txtFile.size,
|
||||
type: 'text/plain',
|
||||
text,
|
||||
parentPdfId: pdfId,
|
||||
uploadedAt: new Date().toISOString(),
|
||||
};
|
||||
this.automat.actions.addAttachment(txtAttachment);
|
||||
} catch (txtErr) {
|
||||
console.error('Fehler beim Extrahieren von Text mit pdftotext-wasm:', txtErr);
|
||||
}
|
||||
} else {
|
||||
// Direct text / CSV attachment
|
||||
let text = '';
|
||||
try {
|
||||
text = await file.text();
|
||||
} catch (err) {
|
||||
console.error('Fehler beim Lesen der Datei:', err);
|
||||
}
|
||||
const attachmentId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
const textAttachment = {
|
||||
id: attachmentId,
|
||||
file,
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
type: isCsv ? 'text/csv' : 'text/plain',
|
||||
text,
|
||||
uploadedAt: new Date().toISOString(),
|
||||
};
|
||||
this.automat.actions.addAttachment(textAttachment);
|
||||
}
|
||||
|
||||
// 3. Run SSE parsing with backend
|
||||
await this.runPdfParse(file);
|
||||
// 3. Run SSE parsing with backend (POST /api/delivery/parse)
|
||||
await this.runParse(file);
|
||||
}
|
||||
|
||||
async handlePdfRescan(attachment) {
|
||||
if (!attachment?.file || this.state.pdfUploading) return;
|
||||
if (!attachment || this.state.pdfUploading) return;
|
||||
|
||||
let targetAttachment = attachment;
|
||||
if (!targetAttachment.file || targetAttachment.file.size === 0) {
|
||||
const file = await this.ensureAttachmentFile(targetAttachment);
|
||||
if (!file || file.size === 0) {
|
||||
enqueueSnackbar('Datei konnte nicht geladen werden', { variant: 'error' });
|
||||
return;
|
||||
}
|
||||
targetAttachment = { ...targetAttachment, file };
|
||||
}
|
||||
|
||||
// Refresh textfile upon rescan for PDF
|
||||
const isPdf = attachment.type === 'application/pdf' || attachment.name.toLowerCase().endsWith('.pdf');
|
||||
const isPdf = targetAttachment.type === 'application/pdf' || targetAttachment.name.toLowerCase().endsWith('.pdf');
|
||||
if (isPdf) {
|
||||
try {
|
||||
const text = await extractPdfText(attachment.file, { layout: true });
|
||||
const text = await extractPdfText(targetAttachment.file, { layout: true });
|
||||
const txtName = attachment.name.replace(/\.pdf$/i, '') + '.txt';
|
||||
const txtFile = new File([text], txtName, { type: 'text/plain;charset=utf-8' });
|
||||
|
||||
@@ -374,7 +418,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
(a) => a.parentPdfId === attachment.id || a.name === txtName,
|
||||
);
|
||||
if (existingTxt) {
|
||||
deliveryEditorAutomat.actions.updateAttachment({
|
||||
this.automat.actions.updateAttachment({
|
||||
id: existingTxt.id,
|
||||
file: txtFile,
|
||||
size: txtFile.size,
|
||||
@@ -382,7 +426,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
isDirty: true,
|
||||
});
|
||||
} else {
|
||||
deliveryEditorAutomat.actions.addAttachment({
|
||||
this.automat.actions.addAttachment({
|
||||
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
||||
file: txtFile,
|
||||
name: txtFile.name,
|
||||
@@ -403,7 +447,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
|
||||
handlePdfDelete(attachment) {
|
||||
if (!attachment?.id) return;
|
||||
deliveryEditorAutomat.actions.removeAttachment(attachment.id);
|
||||
this.automat.actions.removeAttachment(attachment.id);
|
||||
}
|
||||
|
||||
async runParse(file) {
|
||||
@@ -500,24 +544,24 @@ class LieferungNeuPage extends PureComponent {
|
||||
if (matched) supplierId = matched.id;
|
||||
}
|
||||
|
||||
if (docDate) deliveryEditorAutomat.actions.setDate(docDate);
|
||||
if (supplierId != null) deliveryEditorAutomat.actions.setDeliveryEntity(supplierId);
|
||||
if (docDate) this.automat.actions.setDate(docDate);
|
||||
if (supplierId != null) this.automat.actions.setDeliveryEntity(supplierId);
|
||||
if (extNum != null) {
|
||||
deliveryEditorAutomat.actions.setExternalNumber(String(extNum));
|
||||
this.automat.actions.setExternalNumber(String(extNum));
|
||||
}
|
||||
if (docType) deliveryEditorAutomat.actions.setType(docType);
|
||||
if (docType) this.automat.actions.setType(docType);
|
||||
if (newLines && newLines.length > 0) {
|
||||
deliveryEditorAutomat.actions.setLineitems(newLines);
|
||||
this.automat.actions.setLineitems(newLines);
|
||||
}
|
||||
if (notes.length > 0) {
|
||||
deliveryEditorAutomat.actions.setNotes(notes);
|
||||
this.automat.actions.setNotes(notes);
|
||||
}
|
||||
|
||||
// Supply whole article list to GET /supplier/{id}/articles
|
||||
const effectiveSupplierId = supplierId ?? deliveryEditorAutomat.state.deliveryEntity ?? deliveryEditorAutomat.state.partyId;
|
||||
const effectiveLines = (newLines && newLines.length > 0) ? newLines : deliveryEditorAutomat.state.lines;
|
||||
const effectiveSupplierId = supplierId ?? this.automat.state.deliveryEntity ?? this.automat.state.partyId;
|
||||
const effectiveLines = (newLines && newLines.length > 0) ? newLines : this.automat.state.lines;
|
||||
if (effectiveSupplierId != null && effectiveLines && effectiveLines.length > 0) {
|
||||
deliveryEditorAutomat.actions.fetchSupplierArticles(effectiveSupplierId, effectiveLines);
|
||||
this.automat.actions.fetchSupplierArticles(effectiveSupplierId, effectiveLines);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -567,6 +611,74 @@ class LieferungNeuPage extends PureComponent {
|
||||
this.setState({ pdfDialogOpen: false });
|
||||
}
|
||||
|
||||
async ensureAttachmentFile(attachment) {
|
||||
if (!attachment) return null;
|
||||
const hasContent =
|
||||
(attachment.file instanceof Blob || attachment.file instanceof File) &&
|
||||
attachment.file.size > 0;
|
||||
if (hasContent) {
|
||||
return attachment.file;
|
||||
}
|
||||
|
||||
const docId = this.props.docId ?? attachment.manifestId ?? this.state.id;
|
||||
const fileId = attachment.fileId ?? attachment.id;
|
||||
if (docId == null || fileId == null) {
|
||||
return attachment.file || null;
|
||||
}
|
||||
|
||||
try {
|
||||
const getFile =
|
||||
this.context?.delivery?.getFile?.bind(this.context.delivery) ||
|
||||
deliveryApi.getFile;
|
||||
const blob = await getFile(docId, fileId);
|
||||
const filename = attachment.name || 'Dokument';
|
||||
const mimetype = attachment.type || blob.type || 'application/octet-stream';
|
||||
const file = new File([blob], filename, { type: mimetype });
|
||||
|
||||
let text = attachment.text;
|
||||
const isPdf =
|
||||
mimetype === 'application/pdf' || filename.toLowerCase().endsWith('.pdf');
|
||||
const isText =
|
||||
!isPdf &&
|
||||
(mimetype.startsWith('text/') ||
|
||||
filename.toLowerCase().endsWith('.txt') ||
|
||||
filename.toLowerCase().endsWith('.csv'));
|
||||
|
||||
if (isText && typeof text !== 'string') {
|
||||
try {
|
||||
text = await blob.text();
|
||||
} catch (e) {
|
||||
console.error('Fehler beim Dekodieren des Texts:', e);
|
||||
}
|
||||
}
|
||||
|
||||
this.automat.actions.updateAttachment({
|
||||
id: attachment.id,
|
||||
file,
|
||||
size: blob.size,
|
||||
...(typeof text === 'string' ? { text } : {}),
|
||||
});
|
||||
|
||||
return file;
|
||||
} catch (err) {
|
||||
console.error('Fehler beim Laden der Dateiinhalte:', err);
|
||||
notifyError(err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
handleTextEditorContentLoaded(attachment, text, blob) {
|
||||
const file = new File([blob], attachment.name || 'Dokument.txt', {
|
||||
type: attachment.type || 'text/plain;charset=utf-8',
|
||||
});
|
||||
this.automat.actions.updateAttachment({
|
||||
id: attachment.id,
|
||||
file,
|
||||
size: blob.size,
|
||||
text,
|
||||
});
|
||||
}
|
||||
|
||||
handleAttachmentClick(attachment) {
|
||||
if (!attachment) return;
|
||||
const isPdf =
|
||||
@@ -575,19 +687,55 @@ class LieferungNeuPage extends PureComponent {
|
||||
const isText =
|
||||
!isPdf &&
|
||||
(attachment.type?.startsWith('text/') ||
|
||||
attachment.name?.toLowerCase().endsWith('.txt'));
|
||||
attachment.name?.toLowerCase().endsWith('.txt') ||
|
||||
attachment.name?.toLowerCase().endsWith('.csv'));
|
||||
|
||||
if (isText) {
|
||||
this.setState({
|
||||
textEditorOpen: true,
|
||||
textEditorAttachment: attachment,
|
||||
});
|
||||
} else if (attachment.file instanceof Blob || attachment.file instanceof File) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPdf) {
|
||||
if (
|
||||
(attachment.file instanceof Blob || attachment.file instanceof File) &&
|
||||
attachment.file.size > 0
|
||||
) {
|
||||
const url = URL.createObjectURL(attachment.file);
|
||||
window.open(url, '_blank');
|
||||
return;
|
||||
}
|
||||
|
||||
const docId = this.props.docId ?? attachment.manifestId ?? this.state.id;
|
||||
const fileId = attachment.fileId ?? attachment.id;
|
||||
if (docId != null && fileId != null) {
|
||||
window.open(
|
||||
`/api/delivery/${encodeURIComponent(docId)}/file/${encodeURIComponent(fileId)}`,
|
||||
'_blank',
|
||||
);
|
||||
void this.ensureAttachmentFile(attachment);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (attachment.file instanceof Blob || attachment.file instanceof File) {
|
||||
if (attachment.file.size > 0) {
|
||||
const url = URL.createObjectURL(attachment.file);
|
||||
window.open(url, '_blank');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const docId = this.props.docId ?? attachment.manifestId ?? this.state.id;
|
||||
const fileId = attachment.fileId ?? attachment.id;
|
||||
if (docId != null && fileId != null) {
|
||||
window.open(
|
||||
`/api/delivery/${encodeURIComponent(docId)}/file/${encodeURIComponent(fileId)}`,
|
||||
'_blank',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleCloseTextEditor() {
|
||||
@@ -605,7 +753,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
type: 'text/plain;charset=utf-8',
|
||||
});
|
||||
|
||||
deliveryEditorAutomat.actions.updateAttachment({
|
||||
this.automat.actions.updateAttachment({
|
||||
id: attachment.id,
|
||||
file: newFile,
|
||||
size: newFile.size,
|
||||
@@ -657,7 +805,7 @@ class LieferungNeuPage extends PureComponent {
|
||||
await this.context[cfg.updateCache]();
|
||||
if (this._cancelled) return;
|
||||
enqueueSnackbar(cfg.createdMsg, { variant: 'success' });
|
||||
deliveryEditorAutomat.actions.resetDelivery();
|
||||
this.automat.actions.resetDelivery();
|
||||
this.props.navigate(cfg.editPath(data[cfg.docField].id));
|
||||
} else {
|
||||
const data = await this.context[cfg.api].update(docId, body);
|
||||
@@ -670,17 +818,17 @@ class LieferungNeuPage extends PureComponent {
|
||||
const apiLines = requireArray(doc.lines, `${cfg.docField}.lines`);
|
||||
const lines = apiLines.length > 0 ? apiLines.map(lineFromApi) : [emptyLine()];
|
||||
|
||||
deliveryEditorAutomat.actions.setId(doc.id ?? docId);
|
||||
deliveryEditorAutomat.actions.setDate(dateInputValue(doc.date));
|
||||
if (doc[cfg.partyField] != null) deliveryEditorAutomat.actions.setDeliveryEntity(doc[cfg.partyField]);
|
||||
if (doc.number != null) deliveryEditorAutomat.actions.setNumber(doc.number);
|
||||
if (doc.externalNumber != null) deliveryEditorAutomat.actions.setExternalNumber(String(doc.externalNumber));
|
||||
deliveryEditorAutomat.actions.setLineitems(lines);
|
||||
this.automat.actions.setId(doc.id ?? docId);
|
||||
this.automat.actions.setDate(dateInputValue(doc.date));
|
||||
if (doc[cfg.partyField] != null) this.automat.actions.setDeliveryEntity(doc[cfg.partyField]);
|
||||
if (doc.number != null) this.automat.actions.setNumber(doc.number);
|
||||
if (doc.externalNumber != null) this.automat.actions.setExternalNumber(String(doc.externalNumber));
|
||||
this.automat.actions.setLineitems(lines);
|
||||
|
||||
// Restore attachments with thumbnails
|
||||
const apiFiles = doc.files ?? [];
|
||||
const attachments = await restoreAttachmentsFromApi(apiFiles, this.state.attachments);
|
||||
deliveryEditorAutomat.actions.setAttachments(attachments);
|
||||
this.automat.actions.setAttachments(attachments);
|
||||
|
||||
enqueueSnackbar(cfg.savedMsg, { variant: 'success' });
|
||||
this.setState({ saving: false });
|
||||
@@ -807,9 +955,11 @@ class LieferungNeuPage extends PureComponent {
|
||||
/>
|
||||
<TextEditorDialog
|
||||
open={this.state.textEditorOpen}
|
||||
docId={this.props.docId ?? this.state.id}
|
||||
attachment={this.state.textEditorAttachment}
|
||||
onClose={this.handleCloseTextEditor}
|
||||
onSave={this.handleSaveTextEditor}
|
||||
onContentLoad={this.handleTextEditorContentLoaded}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user