diff --git a/src/api/storageManager.jsx b/src/api/ApiClient.js
similarity index 55%
rename from src/api/storageManager.jsx
rename to src/api/ApiClient.js
index 7344499..eb67460 100644
--- a/src/api/storageManager.jsx
+++ b/src/api/ApiClient.js
@@ -1,8 +1,3 @@
-import { createContext, useContext, useRef } from 'react';
-import { requireArray, requireDefined, requireObject } from '../utils/apiShape';
-
-export const StorageManagerContext = createContext(null);
-
function enc(value) {
return encodeURIComponent(String(value));
}
@@ -23,38 +18,10 @@ function buildPath(path, query) {
}
/**
- * Stale-while-revalidate cache: readers keep the current promise; update()
- * swaps only after a successful reload. Failed updates leave the cache intact.
+ * Thin HTTP client for the dashback API (cookie auth, JSON / blob / empty).
*/
-function createCache(label, load) {
- let promise = load().catch((err) => {
- console.error(`[storageMgr] ${label} failed`, err);
- throw err;
- });
-
- async function update() {
- try {
- const data = await load();
- promise = Promise.resolve(data);
- return data;
- } catch (err) {
- console.error(`[storageMgr] update ${label} failed`, err);
- throw err;
- }
- }
-
- return {
- update,
- get promise() {
- return promise;
- },
- };
-}
-
-class StorageManager {
+export class ApiClient {
#baseUrl;
- /** @type {EventSource | null} */
- #events = null;
constructor(baseUrl = window.location.origin) {
this.#baseUrl = baseUrl;
@@ -201,171 +168,11 @@ class StorageManager {
/** Absolute URL for
(same-origin / cookie auth). */
url: (fullHash) => buildUrl(this.#baseUrl, `/api/thumb/${enc(fullHash)}`),
};
-
- this.#initCaches();
}
- #initCaches() {
- const authMeCache = createCache('GET /auth/me', () => this.#loadAuthMe());
- const articleIndexCache = createCache('GET /articleIndex', () => this.#loadArticleIndex());
- const brandCache = createCache('GET /brand', () => this.#loadBrands());
- const unitCache = createCache('GET /unit', () => this.#loadUnits());
- const companyCache = createCache('GET /company', () => this.#loadCompanies());
- const categoryTreeCache = createCache('GET /category/tree', () => this.#loadCategoryTree());
- const posterminalCache = createCache('GET /posterminal', () => this.#loadPosterminals());
-
- Object.defineProperties(this, {
- authMePromise: { get: () => authMeCache.promise },
- updateAuthMe: { value: authMeCache.update },
-
- articleIndexPromise: { get: () => articleIndexCache.promise },
- updateArticleIndex: { value: articleIndexCache.update },
-
- brandPromise: { get: () => brandCache.promise },
- updateBrand: { value: brandCache.update },
-
- unitPromise: { get: () => unitCache.promise },
- updateUnit: { value: unitCache.update },
-
- companyPromise: { get: () => companyCache.promise },
- updateCompany: { value: companyCache.update },
-
- categoryTreePromise: { get: () => categoryTreeCache.promise },
- updateCategoryTree: { value: categoryTreeCache.update },
-
- posterminalPromise: { get: () => posterminalCache.promise },
- updatePosterminal: { value: posterminalCache.update },
-
- /** Close and reopen GET /api/events (required after selected-company change). */
- reconnectEvents: { value: () => this.#reconnectEvents() },
- });
- }
-
- /**
- * GET /api/events — SSE signals for the selected company.
- * Stream is bound at connect time; reconnect after company switch.
- */
- #reconnectEvents() {
- this.#disconnectEvents();
- const url = buildUrl(this.#baseUrl, '/api/events');
- const es = new EventSource(url, { withCredentials: true });
- es.addEventListener('category', () => {
- void this.updateCategoryTree().catch((err) => {
- console.error('[storageMgr] category event refresh failed', err);
- });
- });
- es.addEventListener('articles', () => {
- void this.updateArticleIndex().catch((err) => {
- console.error('[storageMgr] articles event refresh failed', err);
- });
- });
- es.onerror = () => {
- console.error('[storageMgr] events stream error');
- };
- this.#events = es;
- }
-
- #disconnectEvents() {
- if (!this.#events) return;
- this.#events.close();
- this.#events = null;
- }
-
- #syncEvents(user) {
- if (user?.selectedCompanyId != null) {
- this.#reconnectEvents();
- } else {
- this.#disconnectEvents();
- }
- }
-
- async #loadAuthMe() {
- try {
- const data = await this.auth.me();
- requireObject(data, 'GET /api/auth/me');
- const session = {
- user: data.user,
- googleClientId: data.googleClientId,
- };
- this.#syncEvents(session.user);
- return session;
- } catch (err) {
- if (err.status === 401 || err.status === 403) {
- this.#syncEvents(null);
- return {
- user: null,
- googleClientId: err.data?.googleClientId,
- forbidden: err.status === 403,
- message: err.message,
- };
- }
- throw err;
- }
- }
-
- async #loadArticleIndex() {
- const data = await this.article.index();
- requireObject(data, 'GET /api/articleIndex');
- const articles = requireArray(data.articles, 'articleIndex.articles');
- // Map backend rows to the recordset shape used by the result list.
- // `categories` is a comma-joined string (formatCategoryList splits on ',').
- return articles.map((a) => ({
- id: a.id,
- sku: a.sku,
- name: a.name,
- eans: a.eans ?? [],
- categories: Array.isArray(a.categoryIds) ? a.categoryIds.join(',') : null,
- }));
- }
-
- async #loadBrands() {
- const data = await this.brand.list();
- requireObject(data, 'GET /api/brand');
- return requireArray(data.brands, 'brands');
- }
-
- async #loadUnits() {
- const data = await this.unit.list();
- requireObject(data, 'GET /api/unit');
- return requireArray(data.units, 'units');
- }
-
- async #loadCompanies() {
- const data = await this.company.list();
- requireObject(data, 'GET /api/company');
- return requireArray(data.companies, 'companies');
- }
-
- async #loadCategoryTree() {
- const data = await this.category.tree();
- requireObject(data, 'GET /api/category/tree');
- requireArray(data.tree, 'category/tree.tree');
- requireArray(data.articles, 'category/tree.articles');
- requireDefined(data.languageId, 'category/tree.languageId');
- return data;
- }
-
- async #loadPosterminals() {
- const data = await this.posterminal.list();
- requireObject(data, 'GET /api/posterminal');
- return requireArray(data.posterminals, 'posterminals');
- }
-
- async doSearch({ target, filter, offset, maxCount, onUpdate }) {
- const articles = await this.articleIndexPromise;
- const query = target.trim().toLowerCase();
- const matches = articles.filter(
- (p) =>
- p.name.toLowerCase().includes(query) ||
- p.sku.toLowerCase().includes(query) ||
- (p.eans ?? []).some((ean) => String(ean).includes(query)),
- );
- onUpdate({
- categoryFacets: {},
- totalCount: matches.length,
- recordset: matches,
- error: null,
- });
+ /** Absolute URL for a same-origin API path (e.g. SSE). */
+ urlFor(path) {
+ return buildUrl(this.#baseUrl, path);
}
async #json(method, path, { body, query, contentType, raw } = {}) {
@@ -441,31 +248,4 @@ class StorageManager {
}
}
-/**
- * Provider — mount once near the top of the tree.
- */
-export function StorageManagerProvider({ children }) {
- const mgrRef = useRef(null);
- if (!mgrRef.current) {
- mgrRef.current = new StorageManager();
- }
-
- return (
-
- {children}
-
- );
-}
-
-/**
- * Hook for function components that need the store manager.
- */
-export function useStorageManager() {
- const ctx = useContext(StorageManagerContext);
- if (!ctx) {
- throw new Error('useStorageManager must be used within a ');
- }
- return ctx;
-}
-
-export default StorageManagerContext;
+export default ApiClient;
diff --git a/src/api/StorageManager.js b/src/api/StorageManager.js
new file mode 100644
index 0000000..cb64d69
--- /dev/null
+++ b/src/api/StorageManager.js
@@ -0,0 +1,208 @@
+import { requireArray, requireDefined, requireObject } from '../utils/apiShape';
+import { ApiClient } from './ApiClient';
+
+/**
+ * Stale-while-revalidate cache: readers keep the current promise; update()
+ * swaps only after a successful reload. Failed updates leave the cache intact.
+ */
+function createCache(label, load) {
+ let promise = load().catch((err) => {
+ console.error(`[storageMgr] ${label} failed`, err);
+ throw err;
+ });
+
+ async function update() {
+ try {
+ const data = await load();
+ promise = Promise.resolve(data);
+ return data;
+ } catch (err) {
+ console.error(`[storageMgr] update ${label} failed`, err);
+ throw err;
+ }
+ }
+
+ return {
+ update,
+ get promise() {
+ return promise;
+ },
+ };
+}
+
+/**
+ * ApiClient plus stale-while-revalidate caches and GET /api/events invalidation.
+ */
+export class StorageManager extends ApiClient {
+ /** @type {EventSource | null} */
+ #events = null;
+
+ constructor(baseUrl = window.location.origin) {
+ super(baseUrl);
+ this.#initCaches();
+ }
+
+ #initCaches() {
+ const authMeCache = createCache('GET /auth/me', () => this.#loadAuthMe());
+ const articleIndexCache = createCache('GET /articleIndex', () => this.#loadArticleIndex());
+ const brandCache = createCache('GET /brand', () => this.#loadBrands());
+ const unitCache = createCache('GET /unit', () => this.#loadUnits());
+ const companyCache = createCache('GET /company', () => this.#loadCompanies());
+ const categoryTreeCache = createCache('GET /category/tree', () => this.#loadCategoryTree());
+ const posterminalCache = createCache('GET /posterminal', () => this.#loadPosterminals());
+
+ Object.defineProperties(this, {
+ authMePromise: { get: () => authMeCache.promise },
+ updateAuthMe: { value: authMeCache.update },
+
+ articleIndexPromise: { get: () => articleIndexCache.promise },
+ updateArticleIndex: { value: articleIndexCache.update },
+
+ brandPromise: { get: () => brandCache.promise },
+ updateBrand: { value: brandCache.update },
+
+ unitPromise: { get: () => unitCache.promise },
+ updateUnit: { value: unitCache.update },
+
+ companyPromise: { get: () => companyCache.promise },
+ updateCompany: { value: companyCache.update },
+
+ categoryTreePromise: { get: () => categoryTreeCache.promise },
+ updateCategoryTree: { value: categoryTreeCache.update },
+
+ posterminalPromise: { get: () => posterminalCache.promise },
+ updatePosterminal: { value: posterminalCache.update },
+
+ /** Close and reopen GET /api/events (required after selected-company change). */
+ reconnectEvents: { value: () => this.#reconnectEvents() },
+ });
+ }
+
+ /**
+ * GET /api/events — SSE signals for the selected company.
+ * Stream is bound at connect time; reconnect after company switch.
+ */
+ #reconnectEvents() {
+ this.#disconnectEvents();
+ const es = new EventSource(this.urlFor('/api/events'), { withCredentials: true });
+ es.addEventListener('category', () => {
+ void this.updateCategoryTree().catch((err) => {
+ console.error('[storageMgr] category event refresh failed', err);
+ });
+ });
+ es.addEventListener('articles', () => {
+ void this.updateArticleIndex().catch((err) => {
+ console.error('[storageMgr] articles event refresh failed', err);
+ });
+ });
+ es.onerror = () => {
+ console.error('[storageMgr] events stream error');
+ };
+ this.#events = es;
+ }
+
+ #disconnectEvents() {
+ if (!this.#events) return;
+ this.#events.close();
+ this.#events = null;
+ }
+
+ #syncEvents(user) {
+ if (user?.selectedCompanyId != null) {
+ this.#reconnectEvents();
+ } else {
+ this.#disconnectEvents();
+ }
+ }
+
+ async #loadAuthMe() {
+ try {
+ const data = await this.auth.me();
+ requireObject(data, 'GET /api/auth/me');
+ const session = {
+ user: data.user,
+ googleClientId: data.googleClientId,
+ };
+ this.#syncEvents(session.user);
+ return session;
+ } catch (err) {
+ if (err.status === 401 || err.status === 403) {
+ this.#syncEvents(null);
+ return {
+ user: null,
+ googleClientId: err.data?.googleClientId,
+ forbidden: err.status === 403,
+ message: err.message,
+ };
+ }
+ throw err;
+ }
+ }
+
+ async #loadArticleIndex() {
+ const data = await this.article.index();
+ requireObject(data, 'GET /api/articleIndex');
+ const articles = requireArray(data.articles, 'articleIndex.articles');
+ // Map backend rows to the recordset shape used by the result list.
+ // `categories` is a comma-joined string (formatCategoryList splits on ',').
+ return articles.map((a) => ({
+ id: a.id,
+ sku: a.sku,
+ name: a.name,
+ eans: a.eans ?? [],
+ categories: Array.isArray(a.categoryIds) ? a.categoryIds.join(',') : null,
+ }));
+ }
+
+ async #loadBrands() {
+ const data = await this.brand.list();
+ requireObject(data, 'GET /api/brand');
+ return requireArray(data.brands, 'brands');
+ }
+
+ async #loadUnits() {
+ const data = await this.unit.list();
+ requireObject(data, 'GET /api/unit');
+ return requireArray(data.units, 'units');
+ }
+
+ async #loadCompanies() {
+ const data = await this.company.list();
+ requireObject(data, 'GET /api/company');
+ return requireArray(data.companies, 'companies');
+ }
+
+ async #loadCategoryTree() {
+ const data = await this.category.tree();
+ requireObject(data, 'GET /api/category/tree');
+ requireArray(data.tree, 'category/tree.tree');
+ requireArray(data.articles, 'category/tree.articles');
+ requireDefined(data.languageId, 'category/tree.languageId');
+ return data;
+ }
+
+ async #loadPosterminals() {
+ const data = await this.posterminal.list();
+ requireObject(data, 'GET /api/posterminal');
+ return requireArray(data.posterminals, 'posterminals');
+ }
+
+ async doSearch({ target, filter, offset, maxCount, onUpdate }) {
+ const articles = await this.articleIndexPromise;
+ const query = target.trim().toLowerCase();
+ const matches = articles.filter(
+ (p) =>
+ p.name.toLowerCase().includes(query) ||
+ p.sku.toLowerCase().includes(query) ||
+ (p.eans ?? []).some((ean) => String(ean).includes(query)),
+ );
+ onUpdate({
+ categoryFacets: {},
+ totalCount: matches.length,
+ recordset: matches,
+ error: null,
+ });
+ }
+}
+
+export default StorageManager;
diff --git a/src/api/storageManagerContext.js b/src/api/storageManagerContext.js
new file mode 100644
index 0000000..7467554
--- /dev/null
+++ b/src/api/storageManagerContext.js
@@ -0,0 +1,27 @@
+import { createContext, createElement, useContext, useRef } from 'react';
+import { StorageManager } from './StorageManager';
+
+export const StorageManagerContext = createContext(null);
+
+/**
+ * Provider — mount once near the top of the tree.
+ */
+export function StorageManagerProvider({ children }) {
+ const mgrRef = useRef(null);
+ if (!mgrRef.current) {
+ mgrRef.current = new StorageManager();
+ }
+
+ return createElement(StorageManagerContext.Provider, { value: mgrRef.current }, children);
+}
+
+/**
+ * Hook for function components that need the store manager.
+ */
+export function useStorageManager() {
+ const ctx = useContext(StorageManagerContext);
+ if (!ctx) {
+ throw new Error('useStorageManager must be used within a ');
+ }
+ return ctx;
+}
diff --git a/src/components/AuthBootstrap.jsx b/src/components/AuthBootstrap.jsx
index 0e8cefa..f97de7a 100644
--- a/src/components/AuthBootstrap.jsx
+++ b/src/components/AuthBootstrap.jsx
@@ -2,7 +2,7 @@ import { Component } from 'react';
import { connect } from 'react-redux';
import { enqueueSnackbar } from 'notistack';
import { notifyError } from '../utils/notify';
-import { StorageManagerContext } from '../api/storageManager';
+import { StorageManagerContext } from '../api/storageManagerContext';
import { bootstrapSession as bootstrapSessionThunk } from '../store/authSlice';
let sessionBootstrapped = false;
diff --git a/src/components/CompanySettingsDialog.jsx b/src/components/CompanySettingsDialog.jsx
index f8944f0..7640969 100644
--- a/src/components/CompanySettingsDialog.jsx
+++ b/src/components/CompanySettingsDialog.jsx
@@ -25,7 +25,7 @@ import PointOfSaleIcon from '@mui/icons-material/PointOfSale';
import { enqueueSnackbar } from 'notistack';
import BackendError from './BackendError';
import SingleLineTextEdit from './SingleLineTextEdit';
-import { StorageManagerContext } from '../api/storageManager';
+import { StorageManagerContext } from '../api/storageManagerContext';
import { requireDefined, requireObject } from '../utils/apiShape';
import { ISO639_OPTIONS, parseTaxRate } from '../utils/companyForm';
import { backendErrorFrom, isBackendFailure } from '../utils/backendError';
diff --git a/src/components/CompanySetupDialog.jsx b/src/components/CompanySetupDialog.jsx
index b7afad7..2534a11 100644
--- a/src/components/CompanySetupDialog.jsx
+++ b/src/components/CompanySetupDialog.jsx
@@ -22,7 +22,7 @@ import Typography from '@mui/material/Typography';
import BusinessIcon from '@mui/icons-material/Business';
import BackendError from './BackendError';
import { company } from '../api';
-import { StorageManagerContext } from '../api/storageManager';
+import { StorageManagerContext } from '../api/storageManagerContext';
import {
createCompany as createCompanyThunk,
logout as logoutThunk,
diff --git a/src/components/LoginPage.jsx b/src/components/LoginPage.jsx
index 0af8552..03833a8 100644
--- a/src/components/LoginPage.jsx
+++ b/src/components/LoginPage.jsx
@@ -6,7 +6,7 @@ import GoogleIcon from '@mui/icons-material/Google';
import { enqueueSnackbar } from 'notistack';
import { notifyErrorMessage } from '../utils/notify';
import { loginWithGoogle, selectAuthStatus, selectGoogleClientId } from '../store/authSlice';
-import { StorageManagerContext } from '../api/storageManager';
+import { StorageManagerContext } from '../api/storageManagerContext';
import {
abortGoogleSignIn,
FEDCM_BLOCKED_MESSAGE,
diff --git a/src/components/UserMenu.jsx b/src/components/UserMenu.jsx
index 5119465..7afac24 100644
--- a/src/components/UserMenu.jsx
+++ b/src/components/UserMenu.jsx
@@ -9,7 +9,7 @@ import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import LogoutIcon from '@mui/icons-material/Logout';
import BusinessIcon from '@mui/icons-material/Business';
-import { StorageManagerContext } from '../api/storageManager';
+import { StorageManagerContext } from '../api/storageManagerContext';
import { logout } from '../store/authSlice';
import CompanySettingsDialog from './CompanySettingsDialog';
import { notifyError } from '../utils/notify';
diff --git a/src/components/article/ArticlePhoto.jsx b/src/components/article/ArticlePhoto.jsx
index c3225db..3f9be99 100644
--- a/src/components/article/ArticlePhoto.jsx
+++ b/src/components/article/ArticlePhoto.jsx
@@ -1,6 +1,6 @@
import { Component } from 'react';
import Box from '@mui/material/Box';
-import { StorageManagerContext } from '../../api/storageManager';
+import { StorageManagerContext } from '../../api/storageManagerContext';
import ThumbHashImage from './ThumbHashImage';
class ArticlePhoto extends Component {
diff --git a/src/components/article/ArticlePhotoTile.jsx b/src/components/article/ArticlePhotoTile.jsx
index a79028f..6677341 100644
--- a/src/components/article/ArticlePhotoTile.jsx
+++ b/src/components/article/ArticlePhotoTile.jsx
@@ -1,7 +1,7 @@
import { Component, createRef } from 'react';
import ContentPasteIcon from '@mui/icons-material/ContentPaste';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
-import { StorageManagerContext } from '../../api/storageManager';
+import { StorageManagerContext } from '../../api/storageManagerContext';
import { PanelTile } from '../panels';
import { requireObject } from '../../utils/apiShape';
import { notifyError } from '../../utils/notify';
diff --git a/src/components/article/ArticlePhotosDialog.jsx b/src/components/article/ArticlePhotosDialog.jsx
index a64e351..01ab251 100644
--- a/src/components/article/ArticlePhotosDialog.jsx
+++ b/src/components/article/ArticlePhotosDialog.jsx
@@ -11,7 +11,7 @@ import ContentPasteIcon from '@mui/icons-material/ContentPaste';
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
-import { StorageManagerContext } from '../../api/storageManager';
+import { StorageManagerContext } from '../../api/storageManagerContext';
import { requireArray, requireObject } from '../../utils/apiShape';
import {
articleWithPhotoOrder,
diff --git a/src/components/article/ArticleTileTab.jsx b/src/components/article/ArticleTileTab.jsx
index ac8ef63..cce1124 100644
--- a/src/components/article/ArticleTileTab.jsx
+++ b/src/components/article/ArticleTileTab.jsx
@@ -14,7 +14,7 @@ import LocalShippingIcon from '@mui/icons-material/LocalShipping';
import ManageSearchIcon from '@mui/icons-material/ManageSearch';
import PushPinIcon from '@mui/icons-material/PushPin';
import SettingsIcon from '@mui/icons-material/Settings';
-import { StorageManagerContext } from '../../api/storageManager';
+import { StorageManagerContext } from '../../api/storageManagerContext';
import {
ARTICLE_TAB,
DEFAULT_ARTICLE_TAB,
diff --git a/src/components/article/ArticleUnitEditorDialog.jsx b/src/components/article/ArticleUnitEditorDialog.jsx
index 523ce43..5ebd889 100644
--- a/src/components/article/ArticleUnitEditorDialog.jsx
+++ b/src/components/article/ArticleUnitEditorDialog.jsx
@@ -15,7 +15,7 @@ import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
-import { StorageManagerContext } from '../../api/storageManager';
+import { StorageManagerContext } from '../../api/storageManagerContext';
import { requireObject } from '../../utils/apiShape';
import { notifyError } from '../../utils/notify';
import { parsePriceInput } from '../../utils/price';
diff --git a/src/components/article/ArticleView.jsx b/src/components/article/ArticleView.jsx
index f75a57a..f62e33c 100644
--- a/src/components/article/ArticleView.jsx
+++ b/src/components/article/ArticleView.jsx
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { PanelTileGrid } from '../panels';
import { requireDefined } from '../../utils/apiShape';
-import { useStorageManager } from '../../api/storageManager';
+import { useStorageManager } from '../../api/storageManagerContext';
import { parseCategoryTreeResponse } from '../../store/categorySlice';
import { PANEL_TILE_KEYS } from '../../theme';
import { notifyError } from '../../utils/notify';
diff --git a/src/components/article/boxes/ArticleViewBrand.jsx b/src/components/article/boxes/ArticleViewBrand.jsx
index 372383d..a30b2e4 100644
--- a/src/components/article/boxes/ArticleViewBrand.jsx
+++ b/src/components/article/boxes/ArticleViewBrand.jsx
@@ -4,7 +4,7 @@ import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
import { EditablePanelTile } from '../../panels';
-import { useStorageManager } from '../../../api/storageManager';
+import { useStorageManager } from '../../../api/storageManagerContext';
import { requireDefined, requireObject } from '../../../utils/apiShape';
import { notifyError } from '../../../utils/notify';
import { PANEL_TILE_KEYS } from '../../../theme';
diff --git a/src/components/article/boxes/ArticleViewEANs.jsx b/src/components/article/boxes/ArticleViewEANs.jsx
index 95e5a55..80fc51b 100644
--- a/src/components/article/boxes/ArticleViewEANs.jsx
+++ b/src/components/article/boxes/ArticleViewEANs.jsx
@@ -3,7 +3,7 @@ import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
import { EditablePanelTile } from '../../panels';
-import { useStorageManager } from '../../../api/storageManager';
+import { useStorageManager } from '../../../api/storageManagerContext';
import { requireObject } from '../../../utils/apiShape';
import { articleEans } from '../../../utils/articleDetail';
import { PANEL_TILE_KEYS } from '../../../theme';
diff --git a/src/components/article/boxes/ArticleViewName.jsx b/src/components/article/boxes/ArticleViewName.jsx
index 2790855..3daf204 100644
--- a/src/components/article/boxes/ArticleViewName.jsx
+++ b/src/components/article/boxes/ArticleViewName.jsx
@@ -1,7 +1,7 @@
import { useState } from 'react';
import { EditablePanelTile } from '../../panels';
import SingleLineTextEdit from '../../SingleLineTextEdit';
-import { useStorageManager } from '../../../api/storageManager';
+import { useStorageManager } from '../../../api/storageManagerContext';
import { requireObject } from '../../../utils/apiShape';
import { PANEL_TILE_KEYS } from '../../../theme';
import { getCategoryBreadcrumbs } from '../../../store/categorySlice';
diff --git a/src/components/article/boxes/ArticleViewPrice.jsx b/src/components/article/boxes/ArticleViewPrice.jsx
index aabc9c7..206575f 100644
--- a/src/components/article/boxes/ArticleViewPrice.jsx
+++ b/src/components/article/boxes/ArticleViewPrice.jsx
@@ -6,7 +6,7 @@ import Typography from '@mui/material/Typography';
import { EditablePanelTile } from '../../panels';
import ArticlePriceTiersDialog from '../ArticlePriceTiersDialog';
import ArticleUnitEditorDialog from '../ArticleUnitEditorDialog';
-import { useStorageManager } from '../../../api/storageManager';
+import { useStorageManager } from '../../../api/storageManagerContext';
import { requireDefined, requireObject } from '../../../utils/apiShape';
import {
buildPosPricesPutBody,
diff --git a/src/main.jsx b/src/main.jsx
index e80a548..82c5f23 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -4,7 +4,7 @@ import { ThemeProvider } from '@mui/material/styles';
import { Provider } from 'react-redux';
import { SnackbarProvider } from 'notistack';
import AuthBootstrap from './components/AuthBootstrap';
-import { StorageManagerProvider } from './api/storageManager';
+import { StorageManagerProvider } from './api/storageManagerContext';
import App from './App';
import { store } from './store';
import { getActiveTheme } from './theme';
diff --git a/src/pages/artikel/index.jsx b/src/pages/artikel/index.jsx
index a914fae..32d7a4c 100644
--- a/src/pages/artikel/index.jsx
+++ b/src/pages/artikel/index.jsx
@@ -9,7 +9,7 @@ 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/storageManager';
+import { StorageManagerContext } from '../../api/storageManagerContext';
import BackendError from '../../components/BackendError';
import { formatPrice } from '../../utils/price';
import {
diff --git a/src/pages/artikel/sku.jsx b/src/pages/artikel/sku.jsx
index 0caa7ae..04a2f06 100644
--- a/src/pages/artikel/sku.jsx
+++ b/src/pages/artikel/sku.jsx
@@ -3,7 +3,7 @@ import { useNavigate, useParams } from 'react-router-dom';
import Alert from '@mui/material/Alert';
import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
-import { useStorageManager } from '../../api/storageManager';
+import { useStorageManager } from '../../api/storageManagerContext';
import { ArticleView } from '../../components/article';
import BackendError from '../../components/BackendError';
import { requireObject } from '../../utils/apiShape';