From ebc01a8ca238d5a3437b44d81f75aa8a5e8d0574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Andr=C3=A9=20Lelis?= Date: Thu, 20 Feb 2020 18:25:26 -0300 Subject: [PATCH] feat: #1342 - Window level tab (#1429) * WindowLevel preset code changes * Remove localStorage code as its already being saved and some small refactor on reducer/action * Creating unit tests for preferences reducer * Fix cypress after class naming change * Make hidden false as default for tab components * Remove addUserPreferences * Small refactor to use commandsManager from getCommandsModule instead of getting it from App.js --- extensions/cornerstone/src/commandsModule.js | 17 ++ platform/core/src/redux/actions.js | 3 +- .../core/src/redux/constants/ActionTypes.js | 5 + .../core/src/redux/reducers/preferences.js | 23 ++- .../src/redux/reducers/preferences.test.js | 31 +++ .../components/tabComponents/TabComponents.js | 8 +- .../common/OHIFUserPreferences.spec.js | 6 +- platform/viewer/public/config/default.js | 46 +++++ platform/viewer/public/config/demo.js | 46 +++++ platform/viewer/public/config/netlify.js | 46 +++++ .../GenericViewerCommands/commandsModule.js | 194 ++++++++++++------ .../GenericViewerCommands/index.js | 4 +- .../UserPreferences/HotkeysPreferences.js | 6 +- .../UserPreferences/HotkeysPreferences.styl | 29 +-- .../UserPreferences/UserPreferences.js | 5 +- .../UserPreferences/UserPreferences.styl | 26 +++ .../UserPreferences/WindowLevelPreferences.js | 106 +++++++++- .../WindowLevelPreferences.styl | 28 +++ 18 files changed, 510 insertions(+), 119 deletions(-) create mode 100644 platform/core/src/redux/reducers/preferences.test.js create mode 100644 platform/viewer/src/components/UserPreferences/UserPreferences.styl create mode 100644 platform/viewer/src/components/UserPreferences/WindowLevelPreferences.styl diff --git a/extensions/cornerstone/src/commandsModule.js b/extensions/cornerstone/src/commandsModule.js index 318abe9ab..35947091e 100644 --- a/extensions/cornerstone/src/commandsModule.js +++ b/extensions/cornerstone/src/commandsModule.js @@ -242,6 +242,18 @@ const commandsModule = ({ servicesManager }) => { setCornerstoneLayout: () => { setCornerstoneLayout(); }, + setWindowLevel: ({ viewports, window, level }) => { + const enabledElement = getEnabledElement(viewports.activeViewportIndex); + + if (enabledElement) { + let viewport = cornerstone.getViewport(enabledElement); + viewport.voi = { + windowWidth: Number(window), + windowCenter: Number(level), + }; + cornerstone.setViewport(enabledElement, viewport); + } + }, }; const definitions = { @@ -347,6 +359,11 @@ const commandsModule = ({ servicesManager }) => { options: {}, context: 'VIEWER', }, + setWindowLevel: { + commandFn: actions.setWindowLevel, + storeContexts: ['viewports'], + options: {}, + }, }; return { diff --git a/platform/core/src/redux/actions.js b/platform/core/src/redux/actions.js index 4ac0c14b7..259e91ca1 100644 --- a/platform/core/src/redux/actions.js +++ b/platform/core/src/redux/actions.js @@ -10,6 +10,7 @@ import { SET_VIEWPORT_ACTIVE, SET_VIEWPORT_LAYOUT, SET_VIEWPORT_LAYOUT_AND_DATA, + SET_USER_PREFERENCES, } from './constants/ActionTypes.js'; /** @@ -89,7 +90,7 @@ export const clearStudyLoadingProgress = progressId => ({ }); export const setUserPreferences = state => ({ - type: 'SET_USER_PREFERENCES', + type: SET_USER_PREFERENCES, state, }); diff --git a/platform/core/src/redux/constants/ActionTypes.js b/platform/core/src/redux/constants/ActionTypes.js index 4a9cdccf4..e5167beb9 100644 --- a/platform/core/src/redux/constants/ActionTypes.js +++ b/platform/core/src/redux/constants/ActionTypes.js @@ -20,3 +20,8 @@ export const SET_SERVERS = 'SET_SERVERS'; * EXTENSIONS */ export const SET_EXTENSION_DATA = 'SET_EXTENSION_DATA'; + +/** + * PREFERENCES + * */ +export const SET_USER_PREFERENCES = 'SET_USER_PREFERENCES'; diff --git a/platform/core/src/redux/reducers/preferences.js b/platform/core/src/redux/reducers/preferences.js index 0af7754ab..2ec01c917 100644 --- a/platform/core/src/redux/reducers/preferences.js +++ b/platform/core/src/redux/reducers/preferences.js @@ -1,25 +1,30 @@ -import cloneDeep from 'lodash.clonedeep'; - const defaultState = { windowLevelData: { - // order, description, window (int), level (int) - // 0: { description: 'Soft tissue', window: '', level: '' }, + 1: { description: 'Soft tissue', window: '550', level: '40' }, + 2: { description: 'Lung', window: '150', level: '-600' }, + 3: { description: 'Liver', window: '150', level: '90' }, + 4: { description: 'Bone', window: '2500', level: '480' }, + 5: { description: 'Brain', window: '80', level: '40' }, + 6: { description: 'Trest', window: '1', level: '1' }, + 7: { description: '', window: '', level: '' }, + 8: { description: '', window: '', level: '' }, + 9: { description: '', window: '', level: '' }, + 10: { description: '', window: '', level: '' }, }, generalPreferences: { // language: 'en-US' }, }; -const preferences = (state, action) => { +const preferences = (state = defaultState, action) => { switch (action.type) { case 'SET_USER_PREFERENCES': { - const newState = action.state || cloneDeep(defaultState); - - return Object.assign({}, state, newState); + return Object.assign({}, state, action.state); } default: - return cloneDeep(state) || cloneDeep(defaultState); + return state; } }; +export { defaultState }; export default preferences; diff --git a/platform/core/src/redux/reducers/preferences.test.js b/platform/core/src/redux/reducers/preferences.test.js new file mode 100644 index 000000000..fc81eaaac --- /dev/null +++ b/platform/core/src/redux/reducers/preferences.test.js @@ -0,0 +1,31 @@ +import { Reducer } from 'redux-testkit'; + +import reducer, { defaultState } from './preferences'; +import { SET_USER_PREFERENCES } from './../constants/ActionTypes.js'; + +describe('preferences reducer', () => { + it('should return the initial state', () => { + expect(reducer(undefined, {})).toEqual(defaultState); + }); + + it('should set user preferences state and properly merge with current state', () => { + const initialState = defaultState; + + const action = { + type: SET_USER_PREFERENCES, + state: { generalPreferences: { language: 'es' } }, + }; + + const expectedState = { + windowLevelData: defaultState.windowLevelData, + generalPreferences: { + language: 'es', + }, + }; + + Reducer(reducer) + .withState(initialState) + .expect(action) + .toReturnState(expectedState); + }); +}); diff --git a/platform/ui/src/components/tabComponents/TabComponents.js b/platform/ui/src/components/tabComponents/TabComponents.js index c706bf499..5f312e0d1 100644 --- a/platform/ui/src/components/tabComponents/TabComponents.js +++ b/platform/ui/src/components/tabComponents/TabComponents.js @@ -46,7 +46,7 @@ function TabComponents({ tabs, customProps = {} }) {
{tabs.map((tab, index) => { - const { Component, customProps: tabCustomProps, hidden } = tab; + const { + Component, + customProps: tabCustomProps, + hidden = false, + } = tab; return ( !hidden && (
{ cy.get('.HotkeysPreferences').within(() => { cy.contains('Rotate Right') // label we're looking for .parent() - .find('.errorMessage') + .find('.preferencesInputErrorMessage') .as('errorMsg') .should('have.text', '"Invert" is already using the "i" shortcut.'); }); @@ -440,7 +440,7 @@ describe('OHIF User Preferences', () => { cy.get('.HotkeysPreferences').within(() => { cy.contains('Rotate Right') // label we're looking for .parent() - .find('.errorMessage') + .find('.preferencesInputErrorMessage') .as('errorMsg') .should('have.text', '"ctrl+z" shortcut combination is not allowed'); }); @@ -461,7 +461,7 @@ describe('OHIF User Preferences', () => { cy.get('.HotkeysPreferences').within(() => { cy.contains('Zoom Out') // label we're looking for .parent() - .find('.errorMessage') + .find('.preferencesInputErrorMessage') .as('errorMsg') .should( 'have.text', diff --git a/platform/viewer/public/config/default.js b/platform/viewer/public/config/default.js index 063ff45bf..b65812b5a 100644 --- a/platform/viewer/public/config/default.js +++ b/platform/viewer/public/config/default.js @@ -69,6 +69,52 @@ window.config = { }, // ~ Cornerstone Tools { commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] }, + // ~ Window level presets + { + commandName: 'windowLevelPreset1', + label: 'W/L Preset 1', + keys: ['1'], + }, + { + commandName: 'windowLevelPreset2', + label: 'W/L Preset 2', + keys: ['2'], + }, + { + commandName: 'windowLevelPreset3', + label: 'W/L Preset 3', + keys: ['3'], + }, + { + commandName: 'windowLevelPreset4', + label: 'W/L Preset 4', + keys: ['4'], + }, + { + commandName: 'windowLevelPreset5', + label: 'W/L Preset 5', + keys: ['5'], + }, + { + commandName: 'windowLevelPreset6', + label: 'W/L Preset 6', + keys: ['6'], + }, + { + commandName: 'windowLevelPreset7', + label: 'W/L Preset 7', + keys: ['7'], + }, + { + commandName: 'windowLevelPreset8', + label: 'W/L Preset 8', + keys: ['8'], + }, + { + commandName: 'windowLevelPreset9', + label: 'W/L Preset 9', + keys: ['9'], + }, ], cornerstoneExtensionConfig: {}, }; diff --git a/platform/viewer/public/config/demo.js b/platform/viewer/public/config/demo.js index 1fd296898..bf7640f55 100644 --- a/platform/viewer/public/config/demo.js +++ b/platform/viewer/public/config/demo.js @@ -58,6 +58,52 @@ window.config = { keys: ['pageup'], }, { commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] }, + // ~ Window level presets + { + commandName: 'windowLevelPreset1', + label: 'W/L Preset 1', + keys: ['1'], + }, + { + commandName: 'windowLevelPreset2', + label: 'W/L Preset 2', + keys: ['2'], + }, + { + commandName: 'windowLevelPreset3', + label: 'W/L Preset 3', + keys: ['3'], + }, + { + commandName: 'windowLevelPreset4', + label: 'W/L Preset 4', + keys: ['4'], + }, + { + commandName: 'windowLevelPreset5', + label: 'W/L Preset 5', + keys: ['5'], + }, + { + commandName: 'windowLevelPreset6', + label: 'W/L Preset 6', + keys: ['6'], + }, + { + commandName: 'windowLevelPreset7', + label: 'W/L Preset 7', + keys: ['7'], + }, + { + commandName: 'windowLevelPreset8', + label: 'W/L Preset 8', + keys: ['8'], + }, + { + commandName: 'windowLevelPreset9', + label: 'W/L Preset 9', + keys: ['9'], + }, ], i18n: { LOCIZE_PROJECTID: 'a8da3f9a-e467-4dd6-af33-474d582a0294', diff --git a/platform/viewer/public/config/netlify.js b/platform/viewer/public/config/netlify.js index d041010c5..81bdd0188 100644 --- a/platform/viewer/public/config/netlify.js +++ b/platform/viewer/public/config/netlify.js @@ -64,6 +64,52 @@ window.config = { }, // ~ Cornerstone Tools { commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] }, + // ~ Window level presets + { + commandName: 'windowLevelPreset1', + label: 'W/L Preset 1', + keys: ['1'], + }, + { + commandName: 'windowLevelPreset2', + label: 'W/L Preset 2', + keys: ['2'], + }, + { + commandName: 'windowLevelPreset3', + label: 'W/L Preset 3', + keys: ['3'], + }, + { + commandName: 'windowLevelPreset4', + label: 'W/L Preset 4', + keys: ['4'], + }, + { + commandName: 'windowLevelPreset5', + label: 'W/L Preset 5', + keys: ['5'], + }, + { + commandName: 'windowLevelPreset6', + label: 'W/L Preset 6', + keys: ['6'], + }, + { + commandName: 'windowLevelPreset7', + label: 'W/L Preset 7', + keys: ['7'], + }, + { + commandName: 'windowLevelPreset8', + label: 'W/L Preset 8', + keys: ['8'], + }, + { + commandName: 'windowLevelPreset9', + label: 'W/L Preset 9', + keys: ['9'], + }, ], i18n: { LOCIZE_PROJECTID: 'a8da3f9a-e467-4dd6-af33-474d582a0294', diff --git a/platform/viewer/src/appExtensions/GenericViewerCommands/commandsModule.js b/platform/viewer/src/appExtensions/GenericViewerCommands/commandsModule.js index 7c9bd790c..fbc0da7e4 100644 --- a/platform/viewer/src/appExtensions/GenericViewerCommands/commandsModule.js +++ b/platform/viewer/src/appExtensions/GenericViewerCommands/commandsModule.js @@ -1,74 +1,140 @@ -import { redux, utils } from '@ohif/core'; +import { redux } from '@ohif/core'; import store from './../../store'; -const { setViewportActive, setActiveViewportSpecificData } = redux.actions; -const actions = { - updateActiveViewport: ({ viewports, direction }) => { - const { viewportSpecificData, activeViewportIndex } = viewports; - const maxIndex = Object.keys(viewportSpecificData).length - 1; +const commandsModule = ({ commandsManager }) => { + const { setViewportActive, setActiveViewportSpecificData } = redux.actions; - let newIndex = activeViewportIndex + direction; - newIndex = newIndex > maxIndex ? 0 : newIndex; - newIndex = newIndex < 0 ? maxIndex : newIndex; + const actions = { + updateActiveViewport: ({ viewports, direction }) => { + const { viewportSpecificData, activeViewportIndex } = viewports; + const maxIndex = Object.keys(viewportSpecificData).length - 1; - store.dispatch(setViewportActive(newIndex)); - }, - updateViewportDisplaySet: ({ viewports, direction }) => { - const viewportSpecificData = { ...viewports.viewportSpecificData }; - const activeViewport = viewportSpecificData[viewports.activeViewportIndex]; - const studyMetadata = utils.studyMetadataManager.get( - activeViewport.studyInstanceUid - ); + let newIndex = activeViewportIndex + direction; + newIndex = newIndex > maxIndex ? 0 : newIndex; + newIndex = newIndex < 0 ? maxIndex : newIndex; - if (!studyMetadata) { - return; - } + store.dispatch(setViewportActive(newIndex)); + }, + setWindowLevelPreset: ({ viewports, preset }) => { + const state = store.getState(); + const { preferences = {} } = state; + const { window, level } = + preferences.windowLevelData && preferences.windowLevelData[preset]; - const allDisplaySets = studyMetadata.getDisplaySets(); - const currentDisplaySetIndex = allDisplaySets.findIndex( - displaySet => - displaySet.displaySetInstanceUid === - activeViewport.displaySetInstanceUid - ); - if (currentDisplaySetIndex < 0) { - return; - } + if (window && level) { + commandsManager.runCommand('setWindowLevel', { + viewports, + window, + level, + }); + } + }, + updateViewportDisplaySet: ({ viewports, direction }) => { + const viewportSpecificData = { ...viewports.viewportSpecificData }; + const activeViewport = + viewportSpecificData[viewports.activeViewportIndex]; + const studyMetadata = utils.studyMetadataManager.get( + activeViewport.studyInstanceUid + ); - const newDisplaySetIndex = currentDisplaySetIndex + direction; - const newDisplaySetData = allDisplaySets[newDisplaySetIndex]; - if (!newDisplaySetData) { - return; - } + if (!studyMetadata) { + return; + } - store.dispatch(setActiveViewportSpecificData(newDisplaySetData)); - }, + const allDisplaySets = studyMetadata.getDisplaySets(); + const currentDisplaySetIndex = allDisplaySets.findIndex( + displaySet => + displaySet.displaySetInstanceUid === + activeViewport.displaySetInstanceUid + ); + if (currentDisplaySetIndex < 0) { + return; + } + + const newDisplaySetIndex = currentDisplaySetIndex + direction; + const newDisplaySetData = allDisplaySets[newDisplaySetIndex]; + if (!newDisplaySetData) { + return; + } + + store.dispatch(setActiveViewportSpecificData(newDisplaySetData)); + }, + }; + + const definitions = { + // Next/Previous active viewport + incrementActiveViewport: { + commandFn: actions.updateActiveViewport, + storeContexts: ['viewports'], + options: { direction: 1 }, + }, + decrementActiveViewport: { + commandFn: actions.updateActiveViewport, + storeContexts: ['viewports'], + options: { direction: -1 }, + }, + // Window level Presets + windowLevelPreset1: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 1 }, + }, + windowLevelPreset2: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 2 }, + }, + windowLevelPreset3: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 3 }, + }, + windowLevelPreset4: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 4 }, + }, + windowLevelPreset5: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 5 }, + }, + windowLevelPreset6: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 6 }, + }, + windowLevelPreset7: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 7 }, + }, + windowLevelPreset8: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 8 }, + }, + windowLevelPreset9: { + commandFn: actions.setWindowLevelPreset, + storeContexts: ['viewports'], + options: { preset: 9 }, + }, + nextViewportDisplaySet: { + commandFn: actions.updateViewportDisplaySet, + storeContexts: ['viewports'], + options: { direction: 1 }, + }, + previousViewportDisplaySet: { + commandFn: actions.updateViewportDisplaySet, + storeContexts: ['viewports'], + options: { direction: -1 }, + }, + }; + + return { + definitions, + defaultContext: 'VIEWER', + }; }; -const definitions = { - // Next/Previous active viewport - incrementActiveViewport: { - commandFn: actions.updateActiveViewport, - storeContexts: ['viewports'], - options: { direction: 1 }, - }, - decrementActiveViewport: { - commandFn: actions.updateActiveViewport, - storeContexts: ['viewports'], - options: { direction: -1 }, - }, - nextViewportDisplaySet: { - commandFn: actions.updateViewportDisplaySet, - storeContexts: ['viewports'], - options: { direction: 1 }, - }, - previousViewportDisplaySet: { - commandFn: actions.updateViewportDisplaySet, - storeContexts: ['viewports'], - options: { direction: -1 }, - }, -}; - -export default { - definitions, - defaultContext: 'VIEWER', -}; +export default commandsModule; diff --git a/platform/viewer/src/appExtensions/GenericViewerCommands/index.js b/platform/viewer/src/appExtensions/GenericViewerCommands/index.js index 042fa32b1..866055a79 100644 --- a/platform/viewer/src/appExtensions/GenericViewerCommands/index.js +++ b/platform/viewer/src/appExtensions/GenericViewerCommands/index.js @@ -2,7 +2,7 @@ import commandsModule from './commandsModule.js'; export default { id: 'generic-viewer-commands', - getCommandsModule() { - return commandsModule; + getCommandsModule({ commandsManager }) { + return commandsModule({ commandsManager }); }, }; diff --git a/platform/viewer/src/components/UserPreferences/HotkeysPreferences.js b/platform/viewer/src/components/UserPreferences/HotkeysPreferences.js index 1800ee89c..fc8151075 100644 --- a/platform/viewer/src/components/UserPreferences/HotkeysPreferences.js +++ b/platform/viewer/src/components/UserPreferences/HotkeysPreferences.js @@ -168,9 +168,11 @@ function HotkeysPreferences({ onClose }) { keys={keys} modifier_keys={MODIFIER_KEYS} handleChange={handleChange} - classNames={'hotkeyInput'} + classNames={'preferencesInput'} > - {errorMessage} + + {errorMessage} +
); diff --git a/platform/viewer/src/components/UserPreferences/HotkeysPreferences.styl b/platform/viewer/src/components/UserPreferences/HotkeysPreferences.styl index e55870a28..75acde085 100644 --- a/platform/viewer/src/components/UserPreferences/HotkeysPreferences.styl +++ b/platform/viewer/src/components/UserPreferences/HotkeysPreferences.styl @@ -2,11 +2,6 @@ display: flex padding: 20px - .errorMessage - color: var(--state-error-text) - font-size: 10px - text-transform: uppercase - .hotkeyTable display: flex flex-direction: row @@ -40,28 +35,6 @@ flex-basis: 0 flex-grow: 1.5 - .hotkeyInput - font-weight: 400 - cursor: pointer - transition: background-color .3s ease,border-color .3s ease - background-color: var(--ui-gray) - color: var(--text-primary-color) - border-color: var(--ui-border-coolor) - border: 0 - border-radius: 2px - font-size: 14px - height: 30px - width: 100% - line-height: 16px - padding: 8px 9px 6px - text-align: center - - .hotkeyInput:focus - border-color: var(--active-color) - background-color: var(--ui-gray-dark) - box-shadow: 0 0 0 2px var(--active-color) !important - outline: 0 - .hotkeyLabel padding: 5px 15px 5px 0 text-align: right @@ -69,5 +42,5 @@ flex-grow: 1.5 .stateError - .hotkeyInput + .preferencesInput background-color: var(--state-error) diff --git a/platform/viewer/src/components/UserPreferences/UserPreferences.js b/platform/viewer/src/components/UserPreferences/UserPreferences.js index dda64ba5d..a5f245945 100644 --- a/platform/viewer/src/components/UserPreferences/UserPreferences.js +++ b/platform/viewer/src/components/UserPreferences/UserPreferences.js @@ -8,24 +8,23 @@ import { HotkeysPreferences } from './HotkeysPreferences'; import { WindowLevelPreferences } from './WindowLevelPreferences'; import { GeneralPreferences } from './GeneralPreferences'; +import './UserPreferences.styl'; + const tabs = [ { name: 'Hotkeys', Component: HotkeysPreferences, customProps: {}, - hidden: false, }, { name: 'General', Component: GeneralPreferences, customProps: {}, - hidden: false, }, { name: 'Window Level', Component: WindowLevelPreferences, customProps: {}, - hidden: true, }, ]; diff --git a/platform/viewer/src/components/UserPreferences/UserPreferences.styl b/platform/viewer/src/components/UserPreferences/UserPreferences.styl new file mode 100644 index 000000000..8b5eef5ff --- /dev/null +++ b/platform/viewer/src/components/UserPreferences/UserPreferences.styl @@ -0,0 +1,26 @@ +.preferencesInputErrorMessage + color: var(--state-error-text) + font-size: 10px + text-transform: uppercase + +.preferencesInput + font-weight: 400 + cursor: pointer + transition: background-color .3s ease,border-color .3s ease + background-color: var(--ui-gray) + color: var(--text-primary-color) + border-color: var(--ui-border-coolor) + border: 0 + border-radius: 2px + font-size: 14px + height: 30px + width: 100% + line-height: 16px + padding: 8px 9px 6px + text-align: center + +.preferencesInput:focus + border-color: var(--active-color) + background-color: var(--ui-gray-dark) + box-shadow: 0 0 0 2px var(--active-color) !important + outline: 0 diff --git a/platform/viewer/src/components/UserPreferences/WindowLevelPreferences.js b/platform/viewer/src/components/UserPreferences/WindowLevelPreferences.js index e3e0cc547..744c2bc9f 100644 --- a/platform/viewer/src/components/UserPreferences/WindowLevelPreferences.js +++ b/platform/viewer/src/components/UserPreferences/WindowLevelPreferences.js @@ -1,19 +1,115 @@ -import React from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; +import { useSelector, useDispatch } from 'react-redux'; +import { redux } from '@ohif/core'; -import { TabFooter } from '@ohif/ui'; +import { TabFooter, useSnackbarContext } from '@ohif/ui'; import { useTranslation } from 'react-i18next'; +const { actions } = redux; + +import './WindowLevelPreferences.styl'; + function WindowLevelPreferences({ onClose }) { + const dispatch = useDispatch(); + + const windowLevelData = useSelector(state => { + const { preferences = {} } = state; + const { windowLevelData } = preferences; + + return windowLevelData; + }); + + const [state, setState] = useState({ + values: { ...windowLevelData }, + }); + const { t } = useTranslation('UserPreferencesModal'); const onResetPreferences = () => {}; - const onSave = () => {}; const hasErrors = false; + const onSave = () => { + dispatch(actions.setUserPreferences({ windowLevelData: state.values })); + + onClose(); + + snackbar.show({ + message: t('SaveMessage'), + type: 'success', + }); + }; + + const snackbar = useSnackbarContext(); + + const handleInputChange = event => { + const $target = event.target; + const { key, inputname } = $target.dataset; + const inputValue = $target.value; + + if (!state.values[key] || !state.values[key][inputname]) { + return; + } + + setState(prevState => ({ + ...prevState, + values: { + ...prevState.values, + [key]: { + ...prevState.values[key], + [inputname]: inputValue, + }, + }, + })); + }; return ( -
Component content: {name}
-
TDB!
+
+
+
+
Preset
+
Description
+
Window
+
Level
+
+ {Object.keys(state.values).map((key, index) => { + return ( +
+
{key}
+
+ +
+
+ +
+
+ +
+
+ ); + })} +
+