From debd24601233bc8fd6b2b7fa9ec1583d4eb0f8ea Mon Sep 17 00:00:00 2001 From: seb Date: Wed, 5 Aug 2026 08:48:12 +0200 Subject: [PATCH] u --- src/api/{storageManager.jsx => ApiClient.js} | 232 +----------------- src/api/StorageManager.js | 208 ++++++++++++++++ src/api/storageManagerContext.js | 27 ++ src/components/AuthBootstrap.jsx | 2 +- src/components/CompanySettingsDialog.jsx | 2 +- src/components/CompanySetupDialog.jsx | 2 +- src/components/LoginPage.jsx | 2 +- src/components/UserMenu.jsx | 2 +- src/components/article/ArticlePhoto.jsx | 2 +- src/components/article/ArticlePhotoTile.jsx | 2 +- .../article/ArticlePhotosDialog.jsx | 2 +- src/components/article/ArticleTileTab.jsx | 2 +- .../article/ArticleUnitEditorDialog.jsx | 2 +- src/components/article/ArticleView.jsx | 2 +- .../article/boxes/ArticleViewBrand.jsx | 2 +- .../article/boxes/ArticleViewEANs.jsx | 2 +- .../article/boxes/ArticleViewName.jsx | 2 +- .../article/boxes/ArticleViewPrice.jsx | 2 +- src/main.jsx | 2 +- src/pages/artikel/index.jsx | 2 +- src/pages/artikel/sku.jsx | 2 +- 21 files changed, 259 insertions(+), 244 deletions(-) rename src/api/{storageManager.jsx => ApiClient.js} (55%) create mode 100644 src/api/StorageManager.js create mode 100644 src/api/storageManagerContext.js 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';