u
This commit is contained in:
@@ -84,6 +84,19 @@ export const delivery = {
|
|||||||
},
|
},
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DELETE /api/delivery/:id/file/:fileId
|
||||||
|
* Deletes delivery file attachment.
|
||||||
|
* @param {number|string} id Delivery ID
|
||||||
|
* @param {number|string} fileId File ID
|
||||||
|
* → 204 void
|
||||||
|
*/
|
||||||
|
// #region DELETE /api/delivery/:id/file/:fileId — deleteFile
|
||||||
|
deleteFile(id, fileId) {
|
||||||
|
return http(`/api/delivery/${id}/file/${fileId}`, { method: 'DELETE' });
|
||||||
|
},
|
||||||
|
// #endregion
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /api/delivery/parse — multipart/form-data, field "file"
|
* POST /api/delivery/parse — multipart/form-data, field "file"
|
||||||
* Accepts PDF, TXT or CSV document (max 50 MB)
|
* Accepts PDF, TXT or CSV document (max 50 MB)
|
||||||
|
|||||||
@@ -62,4 +62,17 @@ export const order = {
|
|||||||
return http(`/api/order/${id}`, { method: 'DELETE' });
|
return http(`/api/order/${id}`, { method: 'DELETE' });
|
||||||
},
|
},
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DELETE /api/order/:id/file/:fileId
|
||||||
|
* Deletes order file attachment.
|
||||||
|
* @param {number|string} id Order ID
|
||||||
|
* @param {number|string} fileId File ID
|
||||||
|
* → 204 void
|
||||||
|
*/
|
||||||
|
// #region DELETE /api/order/:id/file/:fileId — deleteFile
|
||||||
|
deleteFile(id, fileId) {
|
||||||
|
return http(`/api/order/${id}/file/${fileId}`, { method: 'DELETE' });
|
||||||
|
},
|
||||||
|
// #endregion
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ export function getManifestDirtyDetails(current, baseline) {
|
|||||||
const count = dirtyLineKeys.length;
|
const count = dirtyLineKeys.length;
|
||||||
summary.push(count > 0 ? `${count} Artikelzeile${count === 1 ? '' : 'n'}` : 'Artikelzeilen');
|
summary.push(count > 0 ? `${count} Artikelzeile${count === 1 ? '' : 'n'}` : 'Artikelzeilen');
|
||||||
}
|
}
|
||||||
if (fields.attachments) summary.push('Dateien');
|
if (fields.attachments && current.kind !== 'quote') summary.push('Dateien');
|
||||||
|
|
||||||
const isDirty = summary.length > 0;
|
const isDirty = summary.length > 0;
|
||||||
|
|
||||||
@@ -455,6 +455,16 @@ export function createManifestEditAutomat({ kind, name }) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setAttachments(attachments) {
|
||||||
|
const list = Array.isArray(attachments) ? attachments : [];
|
||||||
|
const base = automat.state.baseline;
|
||||||
|
const nextBaseline = base ? { ...base, attachments: [...list] } : null;
|
||||||
|
automat.setState({
|
||||||
|
attachments: list,
|
||||||
|
baseline: nextBaseline,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
restoreBaseline() {
|
restoreBaseline() {
|
||||||
if (!automat.state.baseline) return;
|
if (!automat.state.baseline) return;
|
||||||
const base = automat.state.baseline;
|
const base = automat.state.baseline;
|
||||||
|
|||||||
@@ -66,19 +66,37 @@ class AppSidebar extends PureComponent {
|
|||||||
<Box
|
<Box
|
||||||
component="nav"
|
component="nav"
|
||||||
sx={(theme) => ({
|
sx={(theme) => ({
|
||||||
width: SIDEBAR_WIDTH,
|
width: { xs: '100%', lg: SIDEBAR_WIDTH },
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: { xs: 'row', lg: 'column' },
|
||||||
|
alignItems: { xs: 'center', lg: 'stretch' },
|
||||||
backgroundColor: theme.nav.backgroundColor || NAV_SURFACE,
|
backgroundColor: theme.nav.backgroundColor || NAV_SURFACE,
|
||||||
background: theme.nav.background,
|
background: theme.nav.background,
|
||||||
position: 'sticky',
|
position: 'sticky',
|
||||||
top: 0,
|
top: 0,
|
||||||
|
zIndex: theme.zIndex.appBar || 1100,
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
height: 'var(--df-vh, 100vh)',
|
height: { xs: 52, sm: 56, lg: 'var(--df-vh, 100vh)' },
|
||||||
|
px: { xs: 1, sm: 1.5, lg: 0 },
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
boxShadow: { xs: '0 2px 8px rgba(0,0,0,0.18)', lg: 'none' },
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<List disablePadding sx={{ flexGrow: 1 }}>
|
<List
|
||||||
|
disablePadding
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: { xs: 'row', lg: 'column' },
|
||||||
|
alignItems: 'center',
|
||||||
|
height: { xs: '100%', lg: 'auto' },
|
||||||
|
overflowX: { xs: 'auto', lg: 'visible' },
|
||||||
|
scrollbarWidth: 'none',
|
||||||
|
'&::-webkit-scrollbar': { display: 'none' },
|
||||||
|
gap: { xs: 0.5, sm: 1, lg: 0 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
{NAV_ITEMS.map(({ path, label, help, icon: Icon }) => {
|
{NAV_ITEMS.map(({ path, label, help, icon: Icon }) => {
|
||||||
const active = path === activeNav;
|
const active = path === activeNav;
|
||||||
|
|
||||||
@@ -110,12 +128,21 @@ class AppSidebar extends PureComponent {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
sx={(theme) => ({
|
sx={(theme) => ({
|
||||||
borderRadius: 0,
|
borderRadius: { xs: 1, lg: 0 },
|
||||||
px: 1.5,
|
width: { xs: 'auto', lg: '100%' },
|
||||||
py: 1.25,
|
height: { xs: '100%', lg: 'auto' },
|
||||||
borderLeft: '3px solid transparent',
|
px: { xs: 1.25, sm: 1.5 },
|
||||||
|
py: { xs: 0.75, sm: 1, lg: 1.25 },
|
||||||
|
borderLeft: { xs: 'none', lg: '3px solid transparent' },
|
||||||
|
borderBottom: { xs: '3px solid transparent', lg: 'none' },
|
||||||
color: theme.nav.item,
|
color: theme.nav.item,
|
||||||
'& .MuiListItemIcon-root': { color: 'inherit' },
|
whiteSpace: 'nowrap',
|
||||||
|
flexShrink: 0,
|
||||||
|
'& .MuiListItemIcon-root': {
|
||||||
|
color: 'inherit',
|
||||||
|
minWidth: { xs: 'auto', lg: 36 },
|
||||||
|
mr: { xs: 0.75, lg: 0 },
|
||||||
|
},
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
bgcolor: theme.nav.itemHover,
|
bgcolor: theme.nav.itemHover,
|
||||||
color: theme.nav.itemHoverText,
|
color: theme.nav.itemHoverText,
|
||||||
@@ -124,7 +151,8 @@ class AppSidebar extends PureComponent {
|
|||||||
bgcolor: theme.nav.itemActive,
|
bgcolor: theme.nav.itemActive,
|
||||||
color: theme.nav.itemActiveText,
|
color: theme.nav.itemActiveText,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
borderLeftColor: theme.nav.itemActiveAccent,
|
borderLeftColor: { xs: 'transparent', lg: theme.nav.itemActiveAccent },
|
||||||
|
borderBottomColor: { xs: theme.nav.itemActiveAccent, lg: 'transparent' },
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
bgcolor: theme.nav.itemActive,
|
bgcolor: theme.nav.itemActive,
|
||||||
color: theme.nav.itemActiveText,
|
color: theme.nav.itemActiveText,
|
||||||
@@ -132,18 +160,28 @@ class AppSidebar extends PureComponent {
|
|||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<ListItemIcon sx={{ minWidth: 36 }}>
|
<ListItemIcon>
|
||||||
<HelpBadge title={label} help={help} placement="right">
|
<HelpBadge title={label} help={help} placement="right">
|
||||||
<Icon />
|
<Icon />
|
||||||
</HelpBadge>
|
</HelpBadge>
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={label} />
|
<ListItemText
|
||||||
|
primary={label}
|
||||||
|
primaryTypographyProps={{
|
||||||
|
fontSize: { xs: '0.8rem', sm: '0.875rem' },
|
||||||
|
fontWeight: active ? 600 : 500,
|
||||||
|
noWrap: true,
|
||||||
|
}}
|
||||||
|
sx={{ m: 0 }}
|
||||||
|
/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</List>
|
</List>
|
||||||
|
|
||||||
<UserMenu />
|
<Box sx={{ ml: { xs: 'auto', lg: 0 }, flexShrink: 0, display: 'flex', alignItems: 'center' }}>
|
||||||
|
<UserMenu />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -187,10 +225,11 @@ class AppSubNav extends PureComponent {
|
|||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: SUB_NAV_WIDTH,
|
width: { xs: 0, lg: SUB_NAV_WIDTH },
|
||||||
|
display: { xs: 'none', lg: 'block' },
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
ml: 3,
|
ml: { xs: 0, lg: 3 },
|
||||||
mr: 2,
|
mr: { xs: 0, lg: 2 },
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -201,19 +240,23 @@ class AppSubNav extends PureComponent {
|
|||||||
component="nav"
|
component="nav"
|
||||||
aria-label="Unternavigation"
|
aria-label="Unternavigation"
|
||||||
sx={{
|
sx={{
|
||||||
width: SUB_NAV_WIDTH,
|
width: { xs: 60, sm: 72, md: SUB_NAV_WIDTH },
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: 1.5,
|
gap: 1.5,
|
||||||
position: 'sticky',
|
position: 'sticky',
|
||||||
top: 0,
|
top: { xs: 52, sm: 56, lg: 0 },
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
height: 'var(--df-vh, 100vh)',
|
height: {
|
||||||
py: 4,
|
xs: 'calc(var(--df-vh, 100vh) - 52px)',
|
||||||
ml: 3,
|
sm: 'calc(var(--df-vh, 100vh) - 56px)',
|
||||||
mr: 2,
|
lg: 'var(--df-vh, 100vh)',
|
||||||
|
},
|
||||||
|
py: { xs: 2, lg: 4 },
|
||||||
|
ml: { xs: 1, sm: 2, lg: 3 },
|
||||||
|
mr: { xs: 1, sm: 1.5, lg: 2 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{subNav.map(({ segment, label, title, help, icon: Icon }) => {
|
{subNav.map(({ segment, label, title, help, icon: Icon }) => {
|
||||||
@@ -247,7 +290,7 @@ class AppSubNav extends PureComponent {
|
|||||||
navigate(segment ? `${activeNav}/${segment}` : activeNav);
|
navigate(segment ? `${activeNav}/${segment}` : activeNav);
|
||||||
}}
|
}}
|
||||||
sx={(theme) => ({
|
sx={(theme) => ({
|
||||||
width: SUB_NAV_WIDTH,
|
width: { xs: 60, sm: 72, md: SUB_NAV_WIDTH },
|
||||||
py: 1,
|
py: 1,
|
||||||
px: 0.5,
|
px: 0.5,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
@@ -271,14 +314,14 @@ class AppSubNav extends PureComponent {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<HelpBadge title={title || label} help={help} placement="right">
|
<HelpBadge title={title || label} help={help} placement="right">
|
||||||
<Icon sx={{ fontSize: 32 }} />
|
<Icon sx={{ fontSize: { xs: 24, sm: 28, md: 32 } }} />
|
||||||
</HelpBadge>
|
</HelpBadge>
|
||||||
{label ? (
|
{label ? (
|
||||||
<Typography
|
<Typography
|
||||||
variant="caption"
|
variant="caption"
|
||||||
noWrap
|
noWrap
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: '0.68rem',
|
fontSize: { xs: '0.62rem', sm: '0.68rem' },
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
lineHeight: 1.2,
|
lineHeight: 1.2,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
@@ -303,26 +346,43 @@ export default function AppShell() {
|
|||||||
const activeSub = activeNav ? resolveActiveSub(pathname, activeNav) : null;
|
const activeSub = activeNav ? resolveActiveSub(pathname, activeNav) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', minHeight: 'var(--df-vh, 100vh)', bgcolor: 'background.default' }}>
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: { xs: 'column', lg: 'row' },
|
||||||
|
minHeight: 'var(--df-vh, 100vh)',
|
||||||
|
bgcolor: 'background.default',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<AppSidebar activeNav={activeNav} navigate={navigate} />
|
<AppSidebar activeNav={activeNav} navigate={navigate} />
|
||||||
<AppSubNav
|
|
||||||
activeNav={activeNav}
|
|
||||||
activeSub={activeSub}
|
|
||||||
navigate={navigate}
|
|
||||||
/>
|
|
||||||
<Box
|
<Box
|
||||||
component="main"
|
sx={{
|
||||||
sx={(theme) => ({
|
|
||||||
flexGrow: 1,
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'row',
|
||||||
py: 4,
|
flexGrow: 1,
|
||||||
pr: 3,
|
|
||||||
bgcolor: theme.nav.mainBackground,
|
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
})}
|
}}
|
||||||
>
|
>
|
||||||
<Outlet />
|
<AppSubNav
|
||||||
|
activeNav={activeNav}
|
||||||
|
activeSub={activeSub}
|
||||||
|
navigate={navigate}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
component="main"
|
||||||
|
sx={(theme) => ({
|
||||||
|
flexGrow: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
py: { xs: 2, md: 3, lg: 4 },
|
||||||
|
pr: { xs: 1.5, sm: 2, lg: 3 },
|
||||||
|
pl: { xs: 1.5, sm: 2, lg: 0 },
|
||||||
|
bgcolor: theme.nav.mainBackground,
|
||||||
|
minWidth: 0,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Outlet />
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<ChatFab />
|
<ChatFab />
|
||||||
<ChatDrawer />
|
<ChatDrawer />
|
||||||
|
|||||||
@@ -110,9 +110,21 @@ class UserMenu extends PureComponent {
|
|||||||
return `data:${mime};base64,${pic}`;
|
return `data:${mime};base64,${pic}`;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
const isTop = Boolean(
|
||||||
|
anchorEl && typeof anchorEl.getBoundingClientRect === 'function' && anchorEl.getBoundingClientRect().top < 200
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box sx={{ px: 1.5, py: 1.5, alignSelf: 'flex-start' }}>
|
<Box
|
||||||
|
sx={{
|
||||||
|
px: { xs: 0.5, sm: 1, lg: 1.5 },
|
||||||
|
py: { xs: 0.5, lg: 1.5 },
|
||||||
|
alignSelf: { xs: 'center', lg: 'flex-start' },
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={this.handleOpenMenu}
|
onClick={this.handleOpenMenu}
|
||||||
onContextMenu={this.handleContextMenu}
|
onContextMenu={this.handleContextMenu}
|
||||||
@@ -138,8 +150,14 @@ class UserMenu extends PureComponent {
|
|||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={this.handleCloseMenu}
|
onClose={this.handleCloseMenu}
|
||||||
anchorOrigin={{ vertical: 'top', horizontal: 'left' }}
|
anchorOrigin={{
|
||||||
transformOrigin={{ vertical: 'bottom', horizontal: 'left' }}
|
vertical: isTop ? 'bottom' : 'top',
|
||||||
|
horizontal: isTop ? 'right' : 'left',
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: isTop ? 'top' : 'bottom',
|
||||||
|
horizontal: isTop ? 'right' : 'left',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{pwaUpdateAvailable && (
|
{pwaUpdateAvailable && (
|
||||||
<MenuItem onClick={this.handleOpenPwaUpdate} sx={{ bgcolor: 'action.hover' }}>
|
<MenuItem onClick={this.handleOpenPwaUpdate} sx={{ bgcolor: 'action.hover' }}>
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export default class ChatFab extends PureComponent {
|
|||||||
sx={(theme) => ({
|
sx={(theme) => ({
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
bottom: { xs: 20, sm: 28 },
|
bottom: { xs: 20, sm: 28 },
|
||||||
left: { xs: 20, sm: 164 },
|
left: { xs: 20, lg: 164 },
|
||||||
zIndex: theme.zIndex.speedDial || 1050,
|
zIndex: theme.zIndex.speedDial || 1050,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -220,15 +220,13 @@ class ManifestForm extends PureComponent {
|
|||||||
prevState.date !== this.state.date ||
|
prevState.date !== this.state.date ||
|
||||||
prevState.partyId !== this.state.partyId ||
|
prevState.partyId !== this.state.partyId ||
|
||||||
prevState.externalNumber !== this.state.externalNumber ||
|
prevState.externalNumber !== this.state.externalNumber ||
|
||||||
prevState.lines !== this.state.lines ||
|
prevState.lines !== this.state.lines
|
||||||
prevState.attachments !== this.state.attachments
|
|
||||||
) {
|
) {
|
||||||
this.editAutomat.actions.update({
|
this.editAutomat.actions.update({
|
||||||
date: this.state.date,
|
date: this.state.date,
|
||||||
partyId: this.state.partyId,
|
partyId: this.state.partyId,
|
||||||
externalNumber: this.state.externalNumber,
|
externalNumber: this.state.externalNumber,
|
||||||
lines: this.state.lines,
|
lines: this.state.lines,
|
||||||
attachments: this.state.attachments,
|
|
||||||
});
|
});
|
||||||
const { isDirty, dirtyFields, dirtyLineKeys, dirtyLineFields, dirtySummary } = this.editAutomat.state;
|
const { isDirty, dirtyFields, dirtyLineKeys, dirtyLineFields, dirtySummary } = this.editAutomat.state;
|
||||||
if (
|
if (
|
||||||
@@ -809,18 +807,13 @@ class ManifestForm extends PureComponent {
|
|||||||
this.setState({ pdfDialogOpen: false, pdfUploading: false });
|
this.setState({ pdfDialogOpen: false, pdfUploading: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleCreatePdf() {
|
async handleCreatePdf(e) {
|
||||||
|
e?.preventDefault?.();
|
||||||
|
e?.stopPropagation?.();
|
||||||
const { docId } = this.props;
|
const { docId } = this.props;
|
||||||
if (this.state.pdfCreating || this.state.saving) return;
|
if (this.state.pdfCreating || this.state.saving) return;
|
||||||
if (docId == null) return;
|
if (docId == null) return;
|
||||||
|
|
||||||
if (this.state.isDirty) {
|
|
||||||
await this.handleSave();
|
|
||||||
if (this.state.isDirty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ pdfCreating: true });
|
this.setState({ pdfCreating: true });
|
||||||
try {
|
try {
|
||||||
const res = await quoteApi.createPdf(docId);
|
const res = await quoteApi.createPdf(docId);
|
||||||
@@ -834,20 +827,11 @@ class ManifestForm extends PureComponent {
|
|||||||
);
|
);
|
||||||
this.setState({ attachments });
|
this.setState({ attachments });
|
||||||
if (this.editAutomat) {
|
if (this.editAutomat) {
|
||||||
this.editAutomat.actions.updateDraft({ attachments });
|
this.editAutomat.actions.setAttachments?.(attachments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enqueueSnackbar('Angebot-PDF erfolgreich erstellt.', { variant: 'success' });
|
enqueueSnackbar('Angebot-PDF erfolgreich erstellt.', { variant: 'success' });
|
||||||
|
|
||||||
const fileUrl =
|
|
||||||
res.fileUrl ||
|
|
||||||
(res.attachment?.fileId
|
|
||||||
? `/api/quote/${docId}/file/${res.attachment.fileId}`
|
|
||||||
: null);
|
|
||||||
if (fileUrl) {
|
|
||||||
window.open(fileUrl, '_blank');
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!this._cancelled) {
|
if (!this._cancelled) {
|
||||||
notifyError(err);
|
notifyError(err);
|
||||||
@@ -861,23 +845,23 @@ class ManifestForm extends PureComponent {
|
|||||||
|
|
||||||
async handleAttachmentDelete(attachment) {
|
async handleAttachmentDelete(attachment) {
|
||||||
if (!attachment) return;
|
if (!attachment) return;
|
||||||
const targetId = attachment.id ?? attachment.fileId;
|
const fileId = attachment.fileId ?? attachment.id;
|
||||||
const { docId } = this.props;
|
const { docId } = this.props;
|
||||||
|
|
||||||
const nextAttachments = (this.state.attachments || []).filter(
|
const nextAttachments = (this.state.attachments || []).filter(
|
||||||
(a) => (a.id ?? a.fileId) !== targetId && a !== attachment,
|
(a) => (a.fileId ?? a.id) !== fileId && a !== attachment,
|
||||||
);
|
);
|
||||||
this.setState({ attachments: nextAttachments });
|
this.setState({ attachments: nextAttachments });
|
||||||
|
|
||||||
if (this.editAutomat) {
|
if (this.editAutomat) {
|
||||||
this.editAutomat.actions.updateDraft({ attachments: nextAttachments });
|
this.editAutomat.actions.setAttachments?.(nextAttachments);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (docId != null && targetId != null && attachment.isPersisted) {
|
if (docId != null && fileId != null && attachment.isPersisted) {
|
||||||
try {
|
try {
|
||||||
const api = apiFor(this.cfg);
|
const api = apiFor(this.cfg);
|
||||||
if (typeof api.deleteFile === 'function') {
|
if (typeof api.deleteFile === 'function') {
|
||||||
await api.deleteFile(docId, targetId);
|
await api.deleteFile(docId, fileId);
|
||||||
enqueueSnackbar('Anhang gelöscht.', { variant: 'success' });
|
enqueueSnackbar('Anhang gelöscht.', { variant: 'success' });
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -525,6 +525,7 @@ class ManifestHeader extends PureComponent {
|
|||||||
)}
|
)}
|
||||||
{kind === 'quote' && onPdfCreate && docId != null && Boolean(number) && (
|
{kind === 'quote' && onPdfCreate && docId != null && Boolean(number) && (
|
||||||
<Button
|
<Button
|
||||||
|
type="button"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
startIcon={pdfCreating ? <CircularProgress size={16} color="inherit" /> : <PictureAsPdfIcon />}
|
startIcon={pdfCreating ? <CircularProgress size={16} color="inherit" /> : <PictureAsPdfIcon />}
|
||||||
disabled={saving || pdfCreating}
|
disabled={saving || pdfCreating}
|
||||||
|
|||||||
Reference in New Issue
Block a user