From 46e6b8a327286b10a184d88fb81758098a6db528 Mon Sep 17 00:00:00 2001 From: Eliav Maimon Date: Wed, 23 Sep 2026 15:48:20 +0300 Subject: [PATCH 1/6] fix: add basemaps tab --- src/common/i18n/en.json | 2 + src/common/i18n/he.json | 2 + src/discrete-layer/models/RootStore.ts | 4 ++ src/discrete-layer/models/basemapsStore.ts | 24 ++++++++++ .../models/discreteLayersStore.ts | 2 +- .../tabs-views-switcher.component.tsx | 38 ++------------- .../views/discrete-layer-view.css | 1 + .../views/discrete-layer-view.tsx | 42 +++++++---------- src/discrete-layer/views/tab-views.ts | 47 +++++++++++++++++++ 9 files changed, 102 insertions(+), 60 deletions(-) create mode 100644 src/discrete-layer/models/basemapsStore.ts diff --git a/src/common/i18n/en.json b/src/common/i18n/en.json index 33e7af484..a024eee74 100644 --- a/src/common/i18n/en.json +++ b/src/common/i18n/en.json @@ -76,6 +76,7 @@ "action.tab-views.search-results.tooltip": "Search results tab", "action.tab-views.create-best.tooltip": "BEST draft creation/edit tab", "action.tab-views.export-layer.tooltip": "Export layer tab", + "action.tab-views.basemaps.tooltip": "Basemaps tab", "action.point.tooltip": "Search by POI", "action.box.tooltip": "Search by bounding box", @@ -207,6 +208,7 @@ "tab-views.catalog.site.slave": "Secondary", "tab-views.create-best": "BEST edit", "tab-views.export-layer": "Export Layer", + "tab-views.basemaps": "Basemaps", "tab-views.catalog.top-categories.unpublished": "Unpublished", "tab-views.catalog.top-categories.bests": "BESTs", diff --git a/src/common/i18n/he.json b/src/common/i18n/he.json index 92827a43b..33e1a752e 100644 --- a/src/common/i18n/he.json +++ b/src/common/i18n/he.json @@ -76,6 +76,7 @@ "action.tab-views.search-results.tooltip": "טאב תוצאות חיפוש", "action.tab-views.create-best.tooltip": "טאב עריכת טיוטת BEST", "action.tab-views.export-layer.tooltip": "טאב ייצוא שכבה", + "action.tab-views.basemaps.tooltip": "טאב מפות בסיס", "action.point.tooltip": "חיפוש בקטלוג בעזרת קואורדינטות נקודת ציון", "action.box.tooltip": "חיפוש בקטלוג בעזרת מלבן חוסם", @@ -207,6 +208,7 @@ "tab-views.catalog.site.slave": "משני", "tab-views.create-best": "עריכת טיוטת BEST", "tab-views.export-layer": "ייצוא שכבה", + "tab-views.basemaps": "מפות בסיס", "tab-views.catalog.top-categories.unpublished": "לא מפורסמים", "tab-views.catalog.top-categories.bests": "BESTs", diff --git a/src/discrete-layer/models/RootStore.ts b/src/discrete-layer/models/RootStore.ts index 01d42464a..c9b555cbb 100644 --- a/src/discrete-layer/models/RootStore.ts +++ b/src/discrete-layer/models/RootStore.ts @@ -14,6 +14,7 @@ import { mapMenusManagerStore } from './mapMenusManagerStore'; import { exportStore } from './exportStore'; import { servicesAvailabilityStore } from './servicesAvailabilityStore'; import { jobsStore } from './jobsStore'; +import { basemapsStore } from './basemapsStore'; type FetchAction = ( url: string, @@ -51,6 +52,9 @@ export const baseRootStore = RootStoreBase jobsStore: types.optional(jobsStore, { state: ResponseState.IDLE, }), + basemapsStore: types.optional(basemapsStore, { + state: ResponseState.IDLE, + }), }) .views((self) => ({ get fetch(): FetchAction { diff --git a/src/discrete-layer/models/basemapsStore.ts b/src/discrete-layer/models/basemapsStore.ts new file mode 100644 index 000000000..3f292aa16 --- /dev/null +++ b/src/discrete-layer/models/basemapsStore.ts @@ -0,0 +1,24 @@ +import { types, getParent } from 'mobx-state-tree'; +import { ResponseState } from '../../common/models/response-state.enum'; +import { ModelBase } from './ModelBase'; +import { IRootStore, RootStoreType } from './RootStore'; + +export const basemapsStore = ModelBase + .props({ + state: types.enumeration( + 'State', + Object.values(ResponseState) + ), + }) + .views((self) => ({ + get store(): IRootStore { + return self.__getStore() + }, + get root(): IRootStore { + return getParent(self); + }, + })) + .actions(() => { + + return {}; + }); diff --git a/src/discrete-layer/models/discreteLayersStore.ts b/src/discrete-layer/models/discreteLayersStore.ts index e51b9aca8..b30fef9e8 100644 --- a/src/discrete-layer/models/discreteLayersStore.ts +++ b/src/discrete-layer/models/discreteLayersStore.ts @@ -57,7 +57,7 @@ const INITIAL_STATE = { highlightedLayer: null, selectedLayer: null, selectedLayerOperationMode: undefined, - tabViews: [{idx: TabViews.CATALOG}, {idx: TabViews.SEARCH_RESULTS}, {idx: TabViews.EXPORT_LAYER}], + tabViews: [{idx: TabViews.CATALOG}, {idx: TabViews.SEARCH_RESULTS}, {idx: TabViews.EXPORT_LAYER}, {idx: TabViews.BASEMAPS}], entityDescriptors: [], entityTooltipFields: new Map(), previewedLayers: [], diff --git a/src/discrete-layer/views/components/tabs-views-switcher.component.tsx b/src/discrete-layer/views/components/tabs-views-switcher.component.tsx index 32f575f12..1b5ceaff8 100644 --- a/src/discrete-layer/views/components/tabs-views-switcher.component.tsx +++ b/src/discrete-layer/views/components/tabs-views-switcher.component.tsx @@ -1,12 +1,11 @@ -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { isEmpty } from 'lodash'; import { observer } from 'mobx-react-lite'; import { useIntl } from 'react-intl'; import { Box } from '@map-colonies/react-components'; import { IconButton, Tooltip, useTheme } from '@map-colonies/react-core'; -import { isRtl } from '../../../common/i18n/helpers'; import { useStore } from '../../models/RootStore'; -import { TabViews } from '../tab-views'; +import { ITabViewConfig, TabViews, useTabViewsConfig } from '../tab-views'; import './tabs-views-switcher.component.css'; @@ -15,13 +14,6 @@ interface TabViewsSwitcherComponentProps { activeTabView: TabViews; } -export interface ITabView { - idx: TabViews; - title: string; - iconClassName: string; - dependentValue?: unknown; -} - export const TabViewsSwitcher: React.FC = observer((props) => { const store = useStore(); const intl = useIntl(); @@ -30,29 +22,9 @@ export const TabViewsSwitcher: React.FC = observ const layerToExport = store.exportStore.layerToExport; - const tabViews: ITabView[] = useMemo( - () => [ - { - idx: TabViews.CATALOG, - title: 'tab-views.catalog', - iconClassName: 'mc-icon-Catalog', - }, - { - idx: TabViews.SEARCH_RESULTS, - title: 'tab-views.search-results', - iconClassName: 'mc-icon-Search-History', - }, - { - idx: TabViews.EXPORT_LAYER, - title: 'tab-views.export-layer', - iconClassName: isRtl(intl.locale) ? 'mc-icon-Export-Left' : 'mc-icon-Export', - dependentValue: store.exportStore.layerToExport, - }, - ], - [layerToExport] - ); + const tabViews: ITabViewConfig[] = useTabViewsConfig(intl.locale); - const [availableTabs, setAvailableTabs] = useState(tabViews); + const [availableTabs, setAvailableTabs] = useState(tabViews); useEffect(() => { const dependentTabs = tabViews.filter((tab) => { @@ -69,7 +41,7 @@ export const TabViewsSwitcher: React.FC = observ useEffect(() => { if (layerToExport !== undefined) { handleTabViewChange(TabViews.EXPORT_LAYER); - } else { + } else if (activeTabView === TabViews.EXPORT_LAYER) { handleTabViewChange(TabViews.CATALOG); } }, [layerToExport]); diff --git a/src/discrete-layer/views/discrete-layer-view.css b/src/discrete-layer/views/discrete-layer-view.css index e619f48c8..95495934a 100644 --- a/src/discrete-layer/views/discrete-layer-view.css +++ b/src/discrete-layer/views/discrete-layer-view.css @@ -138,6 +138,7 @@ body[dir='rtl'] .headerSystemAreaContainer { flex-direction: row; align-items: center; gap: 8px; + white-space: nowrap; } .tabTitle { diff --git a/src/discrete-layer/views/discrete-layer-view.tsx b/src/discrete-layer/views/discrete-layer-view.tsx index 0f036fc5b..b2bd59d84 100644 --- a/src/discrete-layer/views/discrete-layer-view.tsx +++ b/src/discrete-layer/views/discrete-layer-view.tsx @@ -50,6 +50,7 @@ import { MenuDimensions } from '../../common/hooks/mapMenus/useGetMenuDimensions import { LinkType } from '../../common/models/link-type.enum'; import { Mode } from '../../common/models/mode.enum'; import { ActiveLayersIcon } from '../../icons/4font/ActiveLayers'; +import { BasemapsRouter } from '../navigation/base-maps-router.component'; import { CatalogTreeComponent } from '../components/catalog-tree/catalog-tree'; import ExportDrawingHandler from '../components/export-layer/export-drawing-handler.component'; import { ExportLayerComponent } from '../components/export-layer/export-layer.component'; @@ -98,7 +99,7 @@ import { MapActionResolver } from './components/map-action-resolver.component'; import { TabViewsSwitcher } from './components/tabs-views-switcher.component'; import UserModeSwitch from './components/user-mode-switch/user-mode-switch.component'; import { EntityDelete3DDialog } from '../components/layer-details/3D/entity.3d.delete-dialog'; -import { TabViews } from './tab-views'; +import { useTabViewsConfig, TabViews } from './tab-views'; import '@material/tab-bar/dist/mdc.tab-bar.css'; import '@material/tab/dist/mdc.tab.css'; @@ -136,6 +137,8 @@ const noDrawing: IDrawingObject = { const getTimeStamp = (): string => new Date().getTime().toString(); +const TABS_WITH_SIDE_DETAILS_PANEL = [TabViews.CATALOG, TabViews.SEARCH_RESULTS]; + const DiscreteLayerView: React.FC = observer(() => { const [isFilterSearchLoading, setIsFilterSearchLoading] = useState(false); const [data, setData] = useState(); @@ -654,23 +657,7 @@ const DiscreteLayerView: React.FC = observer(() => { store.discreteLayersStore.setSelectedLayerOperationMode(undefined); }, [store.discreteLayersStore.setSelectedLayerOperationMode]); - const tabViews = [ - { - idx: TabViews.CATALOG, - title: 'tab-views.catalog', - iconClassName: 'mc-icon-Catalog', - }, - { - idx: TabViews.SEARCH_RESULTS, - title: 'tab-views.search-results', - iconClassName: 'mc-icon-Search-History', - }, - { - idx: TabViews.EXPORT_LAYER, - title: 'tab-views.export-layer', - iconClassName: isRtl(intl.locale) ? 'mc-icon-Export-Left' : 'mc-icon-Export', - }, - ]; + const tabViews = useTabViewsConfig(intl.locale); const permissions = useMemo(() => { return { @@ -1177,6 +1164,8 @@ const DiscreteLayerView: React.FC = observer(() => { [intl] ); + const showSideDetailsPanel = TABS_WITH_SIDE_DETAILS_PANEL.includes(activeTabView); + return ( <> @@ -1313,12 +1302,7 @@ const DiscreteLayerView: React.FC = observer(() => { className="sidePanelContainer" style={{ backgroundColor: theme.custom?.GC_ALTERNATIVE_SURFACE as string, - height: - activeTabView !== TabViews.EXPORT_LAYER - ? detailsPanelExpanded - ? '50%' - : '75%' - : '100%', + height: showSideDetailsPanel ? (detailsPanelExpanded ? '50%' : '75%') : '100%', display: tabsPanelExpanded ? 'block' : 'none', }} > @@ -1355,8 +1339,14 @@ const DiscreteLayerView: React.FC = observer(() => { /> )} + {activeTabView === TabViews.BASEMAPS && ( + + {getActiveTabHeader(activeTabView, site)} + + + )} - {activeTabView !== TabViews.EXPORT_LAYER && ( + {showSideDetailsPanel && ( { {...(CONFIG.MAP.SHOW_GEOCODER_TOOL ? { geocoderPanel: GEOCODER_OPTIONS } : {})} {...(drapingLayerPredicate !== undefined ? { drapingLayerPredicate } : {})} > - {activeTabView !== TabViews.EXPORT_LAYER && ( + {showSideDetailsPanel && ( { + const store = useStore(); + const layerToExport = store.exportStore.layerToExport; + const isAdmin = store.userStore.isUserAdmin(); + const user = store.userStore.user; + + return useMemo( + () => [ + { + idx: TabViews.CATALOG, + title: 'tab-views.catalog', + iconClassName: 'mc-icon-Catalog', + }, + { + idx: TabViews.SEARCH_RESULTS, + title: 'tab-views.search-results', + iconClassName: 'mc-icon-Search-History', + }, + { + idx: TabViews.EXPORT_LAYER, + title: 'tab-views.export-layer', + iconClassName: isRtl(locale) ? 'mc-icon-Export-Left' : 'mc-icon-Export', + dependentValue: layerToExport, + }, + { + idx: TabViews.BASEMAPS, + title: 'tab-views.basemaps', + iconClassName: 'mc-icon-Bests', + dependentValue: isAdmin ? user : undefined, + }, + ], + [locale, layerToExport, isAdmin, user] + ); +}; From d28073aee0d05e9876e21a8083bbc35dbef76113 Mon Sep 17 00:00:00 2001 From: Eliav Maimon Date: Wed, 23 Sep 2026 16:26:40 +0300 Subject: [PATCH 2/6] fix: disable PolygonSelectionUi --- src/discrete-layer/views/discrete-layer-view.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/discrete-layer/views/discrete-layer-view.tsx b/src/discrete-layer/views/discrete-layer-view.tsx index b2bd59d84..43c382c63 100644 --- a/src/discrete-layer/views/discrete-layer-view.tsx +++ b/src/discrete-layer/views/discrete-layer-view.tsx @@ -1197,7 +1197,9 @@ const DiscreteLayerView: React.FC = observer(() => { onPoiUpdate={onPoiSelection} poi={poi} corners={corners} - disabled={activeTabView === TabViews.EXPORT_LAYER} + disabled={ + activeTabView === TabViews.EXPORT_LAYER || activeTabView === TabViews.BASEMAPS + } /> From 06e97325307e2525146b12169dc4d82519a11c62 Mon Sep 17 00:00:00 2001 From: Eliav Maimon Date: Wed, 23 Sep 2026 17:06:57 +0300 Subject: [PATCH 3/6] fix: add basemaps management to user role --- .../models/discreteLayersStore.ts | 2 +- src/discrete-layer/models/userStore.ts | 3 ++ .../tabs-views-switcher.component.tsx | 3 +- .../views/discrete-layer-view.tsx | 8 ++-- src/discrete-layer/views/tab-views.ts | 41 +----------------- .../views/useTabViewsConfig.hook.ts | 42 +++++++++++++++++++ 6 files changed, 54 insertions(+), 45 deletions(-) create mode 100644 src/discrete-layer/views/useTabViewsConfig.hook.ts diff --git a/src/discrete-layer/models/discreteLayersStore.ts b/src/discrete-layer/models/discreteLayersStore.ts index b30fef9e8..5843f941d 100644 --- a/src/discrete-layer/models/discreteLayersStore.ts +++ b/src/discrete-layer/models/discreteLayersStore.ts @@ -57,7 +57,7 @@ const INITIAL_STATE = { highlightedLayer: null, selectedLayer: null, selectedLayerOperationMode: undefined, - tabViews: [{idx: TabViews.CATALOG}, {idx: TabViews.SEARCH_RESULTS}, {idx: TabViews.EXPORT_LAYER}, {idx: TabViews.BASEMAPS}], + tabViews: [{idx: TabViews.CATALOG}, {idx: TabViews.SEARCH_RESULTS}, {idx: TabViews.EXPORT_LAYER}, {idx: TabViews.BASEMAPS_MANAGEMENT}], entityDescriptors: [], entityTooltipFields: new Map(), previewedLayers: [], diff --git a/src/discrete-layer/models/userStore.ts b/src/discrete-layer/models/userStore.ts index ad9c79242..d346a95e1 100644 --- a/src/discrete-layer/models/userStore.ts +++ b/src/discrete-layer/models/userStore.ts @@ -19,6 +19,7 @@ export enum UserAction { SYSTEM_ACTION_FILTER = 'system_action.filter', SYSTEM_ACTION_FREETEXTSEARCH = 'system_action.freeTextSearch', SYSTEM_ACTION_SIDEBARCOLLAPSEEXPAND = 'system_action.sidebarCollapseExapnd', + SYSTEM_ACTION_BASEMAPS_MANAGEMENT = 'system_action.baseMapsManagement', ENTITY_ACTION_LAYERRASTERRECORD_CREATE = 'entity_action.LayerRasterRecord.create', ENTITY_ACTION_LAYER3DRECORD_CREATE = 'entity_action.Layer3DRecord.create', @@ -110,6 +111,7 @@ const ROLES: IRole[] = [ [UserAction.SYSTEM_ACTION_FILTER]: {enabled: false}, [UserAction.SYSTEM_ACTION_FREETEXTSEARCH]: {enabled: true}, [UserAction.SYSTEM_ACTION_SIDEBARCOLLAPSEEXPAND]: {enabled: true}, + [UserAction.SYSTEM_ACTION_BASEMAPS_MANAGEMENT]: {enabled: true}, [UserAction.ENTITY_ACTION_LAYERRASTERRECORD_CREATE]: {enabled: true}, [UserAction.ENTITY_ACTION_LAYER3DRECORD_CREATE]: {enabled: true}, [UserAction.ENTITY_ACTION_LAYERDEMRECORD_CREATE]: {enabled: false}, @@ -167,6 +169,7 @@ const ROLES: IRole[] = [ [UserAction.SYSTEM_ACTION_FILTER]: {enabled: false}, [UserAction.SYSTEM_ACTION_FREETEXTSEARCH]: {enabled: true}, [UserAction.SYSTEM_ACTION_SIDEBARCOLLAPSEEXPAND]: {enabled: true}, + [UserAction.SYSTEM_ACTION_BASEMAPS_MANAGEMENT]: {enabled: false}, [UserAction.ENTITY_ACTION_LAYERRASTERRECORD_CREATE]: {enabled: false}, [UserAction.ENTITY_ACTION_LAYER3DRECORD_CREATE]: {enabled: false}, [UserAction.ENTITY_ACTION_LAYERDEMRECORD_CREATE]: {enabled: false}, diff --git a/src/discrete-layer/views/components/tabs-views-switcher.component.tsx b/src/discrete-layer/views/components/tabs-views-switcher.component.tsx index 1b5ceaff8..86cee5b32 100644 --- a/src/discrete-layer/views/components/tabs-views-switcher.component.tsx +++ b/src/discrete-layer/views/components/tabs-views-switcher.component.tsx @@ -5,7 +5,8 @@ import { useIntl } from 'react-intl'; import { Box } from '@map-colonies/react-components'; import { IconButton, Tooltip, useTheme } from '@map-colonies/react-core'; import { useStore } from '../../models/RootStore'; -import { ITabViewConfig, TabViews, useTabViewsConfig } from '../tab-views'; +import { ITabViewConfig, TabViews } from '../tab-views'; +import { useTabViewsConfig } from '../useTabViewsConfig.hook'; import './tabs-views-switcher.component.css'; diff --git a/src/discrete-layer/views/discrete-layer-view.tsx b/src/discrete-layer/views/discrete-layer-view.tsx index 43c382c63..d98065154 100644 --- a/src/discrete-layer/views/discrete-layer-view.tsx +++ b/src/discrete-layer/views/discrete-layer-view.tsx @@ -99,7 +99,8 @@ import { MapActionResolver } from './components/map-action-resolver.component'; import { TabViewsSwitcher } from './components/tabs-views-switcher.component'; import UserModeSwitch from './components/user-mode-switch/user-mode-switch.component'; import { EntityDelete3DDialog } from '../components/layer-details/3D/entity.3d.delete-dialog'; -import { useTabViewsConfig, TabViews } from './tab-views'; +import { TabViews } from './tab-views'; +import { useTabViewsConfig } from './useTabViewsConfig.hook'; import '@material/tab-bar/dist/mdc.tab-bar.css'; import '@material/tab/dist/mdc.tab.css'; @@ -1198,7 +1199,8 @@ const DiscreteLayerView: React.FC = observer(() => { poi={poi} corners={corners} disabled={ - activeTabView === TabViews.EXPORT_LAYER || activeTabView === TabViews.BASEMAPS + activeTabView === TabViews.EXPORT_LAYER || + activeTabView === TabViews.BASEMAPS_MANAGEMENT } /> @@ -1341,7 +1343,7 @@ const DiscreteLayerView: React.FC = observer(() => { /> )} - {activeTabView === TabViews.BASEMAPS && ( + {activeTabView === TabViews.BASEMAPS_MANAGEMENT && ( {getActiveTabHeader(activeTabView, site)} diff --git a/src/discrete-layer/views/tab-views.ts b/src/discrete-layer/views/tab-views.ts index e28958395..99ce00247 100644 --- a/src/discrete-layer/views/tab-views.ts +++ b/src/discrete-layer/views/tab-views.ts @@ -1,12 +1,8 @@ -import { useMemo } from 'react'; -import { useStore } from '../models/RootStore'; -import { isRtl } from '../../common/i18n/helpers'; - export enum TabViews { CATALOG, SEARCH_RESULTS, EXPORT_LAYER, - BASEMAPS, + BASEMAPS_MANAGEMENT, } export interface ITabViewConfig { @@ -15,38 +11,3 @@ export interface ITabViewConfig { iconClassName: string; dependentValue?: unknown; } - -export const useTabViewsConfig = (locale: string): ITabViewConfig[] => { - const store = useStore(); - const layerToExport = store.exportStore.layerToExport; - const isAdmin = store.userStore.isUserAdmin(); - const user = store.userStore.user; - - return useMemo( - () => [ - { - idx: TabViews.CATALOG, - title: 'tab-views.catalog', - iconClassName: 'mc-icon-Catalog', - }, - { - idx: TabViews.SEARCH_RESULTS, - title: 'tab-views.search-results', - iconClassName: 'mc-icon-Search-History', - }, - { - idx: TabViews.EXPORT_LAYER, - title: 'tab-views.export-layer', - iconClassName: isRtl(locale) ? 'mc-icon-Export-Left' : 'mc-icon-Export', - dependentValue: layerToExport, - }, - { - idx: TabViews.BASEMAPS, - title: 'tab-views.basemaps', - iconClassName: 'mc-icon-Bests', - dependentValue: isAdmin ? user : undefined, - }, - ], - [locale, layerToExport, isAdmin, user] - ); -}; diff --git a/src/discrete-layer/views/useTabViewsConfig.hook.ts b/src/discrete-layer/views/useTabViewsConfig.hook.ts new file mode 100644 index 000000000..c95a6ad99 --- /dev/null +++ b/src/discrete-layer/views/useTabViewsConfig.hook.ts @@ -0,0 +1,42 @@ +import { useMemo } from 'react'; +import { isRtl } from '../../common/i18n/helpers'; +import { UserAction } from '../models/userStore'; +import { useStore } from '../models/RootStore'; +import { ITabViewConfig, TabViews } from './tab-views'; + +export const useTabViewsConfig = (locale: string): ITabViewConfig[] => { + const store = useStore(); + const layerToExport = store.exportStore.layerToExport; + const isBasemapsManagementAllowed = store.userStore.isActionAllowed( + UserAction.SYSTEM_ACTION_BASEMAPS_MANAGEMENT + ); + const user = store.userStore.user; + + return useMemo( + () => [ + { + idx: TabViews.CATALOG, + title: 'tab-views.catalog', + iconClassName: 'mc-icon-Catalog', + }, + { + idx: TabViews.SEARCH_RESULTS, + title: 'tab-views.search-results', + iconClassName: 'mc-icon-Search-History', + }, + { + idx: TabViews.EXPORT_LAYER, + title: 'tab-views.export-layer', + iconClassName: isRtl(locale) ? 'mc-icon-Export-Left' : 'mc-icon-Export', + dependentValue: layerToExport, + }, + { + idx: TabViews.BASEMAPS_MANAGEMENT, + title: 'tab-views.basemaps', + iconClassName: 'mc-icon-Bests', + dependentValue: isBasemapsManagementAllowed ? user : undefined, + }, + ], + [locale, layerToExport, isBasemapsManagementAllowed, user] + ); +}; From e84bd9cf711f6f7fe74a02e1540a522920e8b2fc Mon Sep 17 00:00:00 2001 From: Eliav Maimon Date: Thu, 24 Sep 2026 09:47:20 +0300 Subject: [PATCH 4/6] fix: prevent hidden tabs from flashing on mount --- .../tabs-views-switcher.component.tsx | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/discrete-layer/views/components/tabs-views-switcher.component.tsx b/src/discrete-layer/views/components/tabs-views-switcher.component.tsx index 86cee5b32..779cf8a44 100644 --- a/src/discrete-layer/views/components/tabs-views-switcher.component.tsx +++ b/src/discrete-layer/views/components/tabs-views-switcher.component.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { isEmpty } from 'lodash'; import { observer } from 'mobx-react-lite'; import { useIntl } from 'react-intl'; @@ -25,19 +25,13 @@ export const TabViewsSwitcher: React.FC = observ const tabViews: ITabViewConfig[] = useTabViewsConfig(intl.locale); - const [availableTabs, setAvailableTabs] = useState(tabViews); - - useEffect(() => { - const dependentTabs = tabViews.filter((tab) => { - if ('dependentValue' in tab) { - return !isEmpty(tab.dependentValue); - } - - return tab; - }); + const availableTabs = tabViews.filter((tab) => { + if ('dependentValue' in tab) { + return !isEmpty(tab.dependentValue); + } - setAvailableTabs(dependentTabs); - }, [tabViews]); + return true; + }); useEffect(() => { if (layerToExport !== undefined) { From 768f910ca3ec44e5eaec7c0fc9ceaabeb016a73e Mon Sep 17 00:00:00 2001 From: Eliav Maimon Date: Thu, 24 Sep 2026 10:08:02 +0300 Subject: [PATCH 5/6] fix: basemaps tabviews dependentValue --- src/discrete-layer/views/useTabViewsConfig.hook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/discrete-layer/views/useTabViewsConfig.hook.ts b/src/discrete-layer/views/useTabViewsConfig.hook.ts index c95a6ad99..a94c819e8 100644 --- a/src/discrete-layer/views/useTabViewsConfig.hook.ts +++ b/src/discrete-layer/views/useTabViewsConfig.hook.ts @@ -34,7 +34,7 @@ export const useTabViewsConfig = (locale: string): ITabViewConfig[] => { idx: TabViews.BASEMAPS_MANAGEMENT, title: 'tab-views.basemaps', iconClassName: 'mc-icon-Bests', - dependentValue: isBasemapsManagementAllowed ? user : undefined, + dependentValue: isBasemapsManagementAllowed ? { notInUse: '***notInUse***' } : undefined, }, ], [locale, layerToExport, isBasemapsManagementAllowed, user] From 594d6b8cafd44bf4db577c01f0219033c85750ee Mon Sep 17 00:00:00 2001 From: Eliav Maimon Date: Thu, 24 Sep 2026 12:45:02 +0300 Subject: [PATCH 6/6] fix: add placeholder panel --- .../navigation/react-navigation.proxy.ts | 6 +- .../navigation/base-maps-router.component.tsx | 126 ++++++++++++++---- .../tabs-views-switcher.component.tsx | 2 +- .../views/useTabViewsConfig.hook.ts | 2 +- 4 files changed, 108 insertions(+), 28 deletions(-) diff --git a/src/common/navigation/react-navigation.proxy.ts b/src/common/navigation/react-navigation.proxy.ts index 080a841e6..66d40ede5 100644 --- a/src/common/navigation/react-navigation.proxy.ts +++ b/src/common/navigation/react-navigation.proxy.ts @@ -1,3 +1,7 @@ // Single import point for @react-navigation/*. No other file should import from those packages directly. -export { NavigationIndependentTree, NavigationContainer } from '@react-navigation/native'; +export { + DefaultTheme, + NavigationIndependentTree, + NavigationContainer, +} from '@react-navigation/native'; export { createStackNavigator } from '@react-navigation/stack'; diff --git a/src/discrete-layer/navigation/base-maps-router.component.tsx b/src/discrete-layer/navigation/base-maps-router.component.tsx index 786bc36d7..3e9b5670e 100644 --- a/src/discrete-layer/navigation/base-maps-router.component.tsx +++ b/src/discrete-layer/navigation/base-maps-router.component.tsx @@ -1,42 +1,118 @@ import React from 'react'; +import { Button, useTheme } from '@map-colonies/react-core'; import { Box } from '@map-colonies/react-components'; import { + DefaultTheme, NavigationIndependentTree, NavigationContainer, createStackNavigator, } from '../../common/navigation/react-navigation.proxy'; -// TODO: replace `undefined` params once BaseMapsListScreen / EditBaseMapScreen / AddLayerScreen land. -type BaseMapsStackParamList = { - BaseMapsList: undefined; - EditBaseMap: undefined; - AddLayer: undefined; +interface BasemapsPanelProps { + navigation: { + navigate: (routeName: BasemapsRouteName) => void; + }; +} + +type PanelParams = BasemapsPanelProps & T; + +type BasemapsStackPanel = { + BaseMapsList: PanelParams; + EditBaseMap: PanelParams; + AddLayer: PanelParams; +}; + +type BasemapsRouteName = keyof BasemapsStackPanel; + +//#region TODO: Should be deleted when real implementation is exist +interface PlaceholderPanelProps extends BasemapsPanelProps { + currentScreen: BasemapsRouteName; + label: string; +} +const PlaceholderPanel: React.FC = ({ + currentScreen, + label, + navigation, +}) => { + const STACK_SCREENS: Array<{ name: BasemapsRouteName; label: string }> = [ + { name: 'BaseMapsList', label: 'Base maps list' }, + { name: 'EditBaseMap', label: 'Edit base map' }, + { name: 'AddLayer', label: 'Add layer' }, + ]; + + return ( + + {label} + + {STACK_SCREENS.filter(({ name }) => name !== currentScreen).map( + ({ name, label: targetLabel }) => ( + + ) + )} + + + ); }; +//#endregion + +const BaseMapsListScreen: React.FC = ({ navigation }) => ( + +); -const Stack = createStackNavigator(); +const EditBaseMapScreen: React.FC = ({ navigation }) => ( + +); + +const AddLayerScreen: React.FC = ({ navigation }) => ( + +); + +const Stack = createStackNavigator(); export const BasemapsRouter: React.FC = () => { + const theme = useTheme(); + const navigationTheme = { + ...DefaultTheme, + colors: { + ...DefaultTheme.colors, + background: theme.custom?.GC_TAB_ACTIVE_BACKGROUND, + }, + }; + return ( - - - PLACEHOLDER_BASEMAPS} - /> - PLACEHOLDER_EDIT_BASEMAP} - /> - PLACEHOLDER_ADD_LAYER} - /> - - + + + + + + + + + ); }; diff --git a/src/discrete-layer/views/components/tabs-views-switcher.component.tsx b/src/discrete-layer/views/components/tabs-views-switcher.component.tsx index 779cf8a44..7b9466479 100644 --- a/src/discrete-layer/views/components/tabs-views-switcher.component.tsx +++ b/src/discrete-layer/views/components/tabs-views-switcher.component.tsx @@ -27,7 +27,7 @@ export const TabViewsSwitcher: React.FC = observ const availableTabs = tabViews.filter((tab) => { if ('dependentValue' in tab) { - return !isEmpty(tab.dependentValue); + return !isEmpty(tab.dependentValue) || tab.dependentValue === true; } return true; diff --git a/src/discrete-layer/views/useTabViewsConfig.hook.ts b/src/discrete-layer/views/useTabViewsConfig.hook.ts index a94c819e8..b99381f58 100644 --- a/src/discrete-layer/views/useTabViewsConfig.hook.ts +++ b/src/discrete-layer/views/useTabViewsConfig.hook.ts @@ -34,7 +34,7 @@ export const useTabViewsConfig = (locale: string): ITabViewConfig[] => { idx: TabViews.BASEMAPS_MANAGEMENT, title: 'tab-views.basemaps', iconClassName: 'mc-icon-Bests', - dependentValue: isBasemapsManagementAllowed ? { notInUse: '***notInUse***' } : undefined, + dependentValue: isBasemapsManagementAllowed, }, ], [locale, layerToExport, isBasemapsManagementAllowed, user]