diff --git a/src/api/delivery.js b/src/api/delivery.js
index d57c3dc..0a9d23d 100644
--- a/src/api/delivery.js
+++ b/src/api/delivery.js
@@ -84,6 +84,19 @@ export const delivery = {
},
// #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"
* Accepts PDF, TXT or CSV document (max 50 MB)
diff --git a/src/api/order.js b/src/api/order.js
index e56d412..419aaa9 100644
--- a/src/api/order.js
+++ b/src/api/order.js
@@ -62,4 +62,17 @@ export const order = {
return http(`/api/order/${id}`, { method: 'DELETE' });
},
// #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
};
diff --git a/src/automats/manifestDraftAutomat.js b/src/automats/manifestDraftAutomat.js
index 1be1db6..c5feea7 100644
--- a/src/automats/manifestDraftAutomat.js
+++ b/src/automats/manifestDraftAutomat.js
@@ -363,7 +363,7 @@ export function getManifestDirtyDetails(current, baseline) {
const count = dirtyLineKeys.length;
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;
@@ -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() {
if (!automat.state.baseline) return;
const base = automat.state.baseline;
diff --git a/src/components/AppShell.jsx b/src/components/AppShell.jsx
index b3a5610..82e1fe4 100644
--- a/src/components/AppShell.jsx
+++ b/src/components/AppShell.jsx
@@ -66,19 +66,37 @@ class AppSidebar extends PureComponent {
({
- width: SIDEBAR_WIDTH,
+ width: { xs: '100%', lg: SIDEBAR_WIDTH },
flexShrink: 0,
display: 'flex',
- flexDirection: 'column',
+ flexDirection: { xs: 'row', lg: 'column' },
+ alignItems: { xs: 'center', lg: 'stretch' },
backgroundColor: theme.nav.backgroundColor || NAV_SURFACE,
background: theme.nav.background,
position: 'sticky',
top: 0,
+ zIndex: theme.zIndex.appBar || 1100,
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' },
})}
>
-
+
{NAV_ITEMS.map(({ path, label, help, icon: Icon }) => {
const active = path === activeNav;
@@ -110,12 +128,21 @@ class AppSidebar extends PureComponent {
}
}}
sx={(theme) => ({
- borderRadius: 0,
- px: 1.5,
- py: 1.25,
- borderLeft: '3px solid transparent',
+ borderRadius: { xs: 1, lg: 0 },
+ width: { xs: 'auto', lg: '100%' },
+ height: { xs: '100%', lg: 'auto' },
+ 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,
- '& .MuiListItemIcon-root': { color: 'inherit' },
+ whiteSpace: 'nowrap',
+ flexShrink: 0,
+ '& .MuiListItemIcon-root': {
+ color: 'inherit',
+ minWidth: { xs: 'auto', lg: 36 },
+ mr: { xs: 0.75, lg: 0 },
+ },
'&:hover': {
bgcolor: theme.nav.itemHover,
color: theme.nav.itemHoverText,
@@ -124,7 +151,8 @@ class AppSidebar extends PureComponent {
bgcolor: theme.nav.itemActive,
color: theme.nav.itemActiveText,
fontWeight: 600,
- borderLeftColor: theme.nav.itemActiveAccent,
+ borderLeftColor: { xs: 'transparent', lg: theme.nav.itemActiveAccent },
+ borderBottomColor: { xs: theme.nav.itemActiveAccent, lg: 'transparent' },
'&:hover': {
bgcolor: theme.nav.itemActive,
color: theme.nav.itemActiveText,
@@ -132,18 +160,28 @@ class AppSidebar extends PureComponent {
},
})}
>
-
+
-
+
);
})}
-
+
+
+
);
}
@@ -187,10 +225,11 @@ class AppSubNav extends PureComponent {
return (
);
@@ -201,19 +240,23 @@ class AppSubNav extends PureComponent {
component="nav"
aria-label="Unternavigation"
sx={{
- width: SUB_NAV_WIDTH,
+ width: { xs: 60, sm: 72, md: SUB_NAV_WIDTH },
flexShrink: 0,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 1.5,
position: 'sticky',
- top: 0,
+ top: { xs: 52, sm: 56, lg: 0 },
alignSelf: 'flex-start',
- height: 'var(--df-vh, 100vh)',
- py: 4,
- ml: 3,
- mr: 2,
+ height: {
+ xs: 'calc(var(--df-vh, 100vh) - 52px)',
+ sm: 'calc(var(--df-vh, 100vh) - 56px)',
+ 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 }) => {
@@ -247,7 +290,7 @@ class AppSubNav extends PureComponent {
navigate(segment ? `${activeNav}/${segment}` : activeNav);
}}
sx={(theme) => ({
- width: SUB_NAV_WIDTH,
+ width: { xs: 60, sm: 72, md: SUB_NAV_WIDTH },
py: 1,
px: 0.5,
borderRadius: 2,
@@ -271,14 +314,14 @@ class AppSubNav extends PureComponent {
})}
>
-
+
{label ? (
+
-
({
- flexGrow: 1,
+ sx={{
display: 'flex',
- flexDirection: 'column',
- py: 4,
- pr: 3,
- bgcolor: theme.nav.mainBackground,
+ flexDirection: 'row',
+ flexGrow: 1,
minWidth: 0,
- })}
+ }}
>
-
+
+ ({
+ 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,
+ })}
+ >
+
+
diff --git a/src/components/UserMenu.jsx b/src/components/UserMenu.jsx
index 87d1592..8baad42 100644
--- a/src/components/UserMenu.jsx
+++ b/src/components/UserMenu.jsx
@@ -110,9 +110,21 @@ class UserMenu extends PureComponent {
return `data:${mime};base64,${pic}`;
})();
+ const isTop = Boolean(
+ anchorEl && typeof anchorEl.getBoundingClientRect === 'function' && anchorEl.getBoundingClientRect().top < 200
+ );
+
return (
<>
-
+
{pwaUpdateAvailable && (