ohif-viewer/platform/ui/src/components/userPreferencesForm/UserPreferencesForm.js
Rodrigo Antinarelli 1df21a9e07 fix: User Preferences Issues (#1207)
* fix: study list translations

* Don't render until translations are ready

* Try to wait for translations to load

* Use null to render "nothing"

* Try toggling useSuspense off up a layer

* logging

* Remove useSuspense false flags

* DO NOT OPEN A PR WITH IT.
Experimental changes only.
Try to solve issues with useTranslation hooks
 #Please enter the commit message for your changes. Lines starting

* Remove unecessary changes

* feat: 🎸 useMedia hook to not use one more prop for upd state vl

* docs: Add license scan report and status (#1161)

Signed-off-by: fossabot <badges@fossa.io>

* fix: 🐛 Fix for JS breaking on header (#1164)

* feat: 🎸 Code review and refact

Revised code based on PRs(variable alias,...). Changed hook for
useMedia. Now, it provides two hooks: one to get displayMediaSize and
other to get Entity(component, objects...) based on displayMediaSize.
Implemented a similar solution for state manager to store
mediaQueryList(s) and displaySize for app.

* feat: 🎸 Fine tunning on mediaQuery value, fixed issue about it

* fix: 🐛 Fixed issue and refactoring

Fixed js exception and also refactoring userPreferences components to
functional component

* fix: 🐛 Code review. Localstorage fix minor bugs

* fix: 🐛 Ensure hotkey lower case always

* fix: translation switcher

* chore(release): publish [skip ci]

 - @ohif/extension-vtk@0.53.6
 - @ohif/ui@0.62.1
 - @ohif/viewer@2.8.2

* Add new modal service

* Change serviceManager prop to servicesManager

* CR Update: fix casing and add required proptypes to providers

* CR Update: Improve ohifmodal proptypes

* CR Update: Fix typo in extensionmanager

* CR Update: add default props to service and check service in provider

* Refactor modal provider to better use its own state

* ci: don't build our master branch (#1177)

* ci: don't build our master branch

* Add netlify-cli as a dev dependency

* ci: trying a sheltered merge flow for promotions

* Use modal instead of modal context

* Ci/promotable builds (#1179)

* ci: don't build our master branch

* Add netlify-cli as a dev dependency

* ci: trying a sheltered merge flow for promotions

* ci: try building with QUICK_BUILD flag

* Change modal children order

* Ci/promotable builds (#1180)

* ci: don't build our master branch

* Add netlify-cli as a dev dependency

* ci: trying a sheltered merge flow for promotions

* ci: try building with QUICK_BUILD flag

* Try using ~/repo prefix in command

* Ci/promotable builds (#1181)

* ci: don't build our master branch

* Add netlify-cli as a dev dependency

* ci: trying a sheltered merge flow for promotions

* ci: try building with QUICK_BUILD flag

* Try using ~/repo prefix in command

* ci: make sure netlify command is available

* Ci/promotable builds (#1182)

* ci: don't build our master branch

* Add netlify-cli as a dev dependency

* ci: trying a sheltered merge flow for promotions

* ci: try building with QUICK_BUILD flag

* Try using ~/repo prefix in command

* ci: make sure netlify command is available

* ci: use sudo for global command

* Fix OHIFModal proptypes

* Ci/promotable builds (#1183)

* ci: don't build our master branch

* Add netlify-cli as a dev dependency

* ci: trying a sheltered merge flow for promotions

* ci: try building with QUICK_BUILD flag

* Try using ~/repo prefix in command

* ci: make sure netlify command is available

* ci: use sudo for global command

* Inline personal access token w/ env var

* Ci/promotable builds (#1184)

* ci: don't build our master branch

* Add netlify-cli as a dev dependency

* ci: trying a sheltered merge flow for promotions

* ci: try building with QUICK_BUILD flag

* Try using ~/repo prefix in command

* ci: make sure netlify command is available

* ci: use sudo for global command

* Inline personal access token w/ env var

* ci: workaround for sudo limitations

* ci: restore release workflow (#1185)

* ci: don't build our master branch

* Add netlify-cli as a dev dependency

* ci: trying a sheltered merge flow for promotions

* ci: try building with QUICK_BUILD flag

* Try using ~/repo prefix in command

* ci: make sure netlify command is available

* ci: use sudo for global command

* Inline personal access token w/ env var

* ci: workaround for sudo limitations

* ci: restore release workflow

* Pass services to each module, improve tests

* Add servicesManager test and registerServices method

* Fix key warning of snackbar elements

* Remove netlify-cli; we';ll install this on CI server

* Update staging and prod netlify site IDs

* Clean up NPM_PUBLISH step

* Clean up DOCS_PUBLISH step

* Clean up Deploy workflow

* Custom executor to override cypress config

* Spacing

* Use an existing docker hub image

* Switch to npx instead of digging into npm bin location

* Remove e2e test before prod deploy

* Add workflow images

* docs: continous integrationn

* Add default props to modal

* chore(release): publish [skip ci]

 - @ohif/extension-cornerstone@1.5.1
 - @ohif/extension-vtk@0.53.7
 - @ohif/core@1.9.1
 - @ohif/ui@0.62.2
 - @ohif/viewer@2.8.3

* chore(release): publish [skip ci]

 - @ohif/extension-vtk@0.53.8
 - @ohif/core@1.10.0
 - @ohif/ui@0.62.3
 - @ohif/viewer@2.8.4

* ci: Redirect site traffic to index.html if file is not resolved

* ci: fix typo

* fix: 🐛 Code review. Remove 'global state' for displaySize

* fix: 🐛 Code review. Ref back to useMedia and pass value down

Code review. Ref back to useMedia and pass value down (components)
instead of creating a specialized hook to tied any component on it

* fix: translation switcher

* fix

* cleanup

* add missed translation

* fix: 🐛 Code review

* fix: 🐛 Fix unit tests

* fix: 🐛 Fix unit test

* fix: 🐛 Code merge solve conflicts. Missing files changes

* Merge from master. Missing files changes

* feat: 🎸 Code review. Fix issues with DatePicker

Fixed at least the minimum issue with datePicker and update some content
on every translation changed

* fix: 🐛 Code review. Style fix on modal

* fixes in general preferences after merge

* fix

* export default i18n language

* translation fixes

* increase snackbar zindex

* initialize language

* WIP propagate props<>state fixes

* fix state propagation

* remove hotkey error when reset default

* fix datePicker

* i18n updates

* fix i18n strings

* fix reset default -- set right input value

* fix default language

* fix e2e for user preferences

* small fix datePicker props

* remove i18n from window -- debugging purposes only

* lint fixes
2019-11-28 00:48:27 -05:00

220 lines
5.5 KiB
JavaScript

import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useSnackbarContext } from '@ohif/ui';
import './UserPreferencesForm.styl';
import { useTranslation } from 'react-i18next';
// Tabs Component wrapper
import { UserPreferencesTabs } from './UserPreferencesTabs';
// Tabs
import { HotKeysPreferences } from './HotKeysPreferences';
import { WindowLevelPreferences } from './WindowLevelPreferences';
import { GeneralPreferences } from './GeneralPreferences';
/**
@typedef TabObject
@type {Object}
@property {string} name Name for given tab
@property {ReactComponent} Component React component for given tab.
@property {object} props Props State for given tab component
@property {boolean} [hidden] To hidden tab or not
*/
/**
* Create tabs obj.
* @returns {TabObject[]} Array of TabObjs.
*/
const createTabs = () => {
return [
{
name: 'Hotkeys',
Component: HotKeysPreferences,
props: {},
},
{
name: 'General',
Component: GeneralPreferences,
props: {},
},
{
name: 'Window Level',
Component: WindowLevelPreferences,
props: {},
hidden: true,
},
];
};
/**
* Main form component to render preferences tabs and buttons
* @param {object} props component props
* @param {string} props.name Tab`s name
* @param {object} props.hotkeyDefinitions Hotkeys Data
* @param {object} props.windowLevelData Window level data
* @param {function} props.onSave Callback function when saving
* @param {function} props.onClose Callback function when closing
* @param {function} props.onResetToDefaults Callback function when resetting
*/
function UserPreferencesForm({
onClose,
onSave,
onResetToDefaults,
windowLevelData,
hotkeyDefinitions,
generalPreferences,
hotkeysManager,
defaultLanguage,
hotkeyDefaults,
}) {
const [tabs, setTabs] = useState(createTabs());
const createTabsState = (
windowLevelData,
hotkeyDefinitions,
generalPreferences
) => {
return {
Hotkeys: { hotkeyDefinitions },
'Window Level': { windowLevelData },
General: { generalPreferences },
};
};
const [tabsState, setTabsState] = useState(
createTabsState(windowLevelData, hotkeyDefinitions, generalPreferences)
);
const [tabsError, setTabsError] = useState(
tabs.reduce((acc, tab) => {
acc[tab.name] = false;
return acc;
}, {})
);
const snackbar = useSnackbarContext();
const { t, ready: translationsAreReady } = useTranslation(
'UserPreferencesModal'
);
const onTabStateChanged = (tabName, newState) => {
setTabsState({ ...tabsState, [tabName]: newState });
};
const onTabErrorChanged = (tabName, hasError) => {
setTabsError({ ...tabsError, [tabName]: hasError });
};
const hasAnyError = () => {
return Object.values(tabsError).reduce((acc, value) => acc || value);
};
const onResetPreferences = () => {
const defaultHotKeyDefitions = {};
hotkeyDefaults.map(item => {
const { commandName, ...values } = item;
defaultHotKeyDefitions[commandName] = { ...values };
});
// update local state
setTabsState({
...tabsState,
Hotkeys: { hotkeyDefinitions: defaultHotKeyDefitions },
General: { generalPreferences: { language: defaultLanguage } },
});
// update tabs state
setTabs(createTabs(windowLevelData, hotkeyDefinitions, generalPreferences));
// reset errors
setTabsError(
tabs.reduce((acc, tab) => {
acc[tab.name] = false;
return acc;
}, {})
);
snackbar.show({
message: (
<div dangerouslySetInnerHTML={{ __html: t('ResetDefaultMessage') }} />
),
type: 'info',
});
};
const onSavePreferences = event => {
const toSave = Object.values(tabsState).reduce((acc, tabState) => {
return { ...acc, ...tabState };
}, {});
onSave(toSave);
snackbar.show({
message: t('SaveMessage'),
type: 'success',
});
};
// update local state if prop values changes
useEffect(() => {
setTabsState(
createTabsState(windowLevelData, hotkeyDefinitions, generalPreferences)
);
}, [windowLevelData, hotkeyDefinitions, generalPreferences]);
return translationsAreReady ? (
<div className="UserPreferencesForm">
<UserPreferencesTabs
tabs={tabs}
tabsState={tabsState}
tabsError={tabsError}
onTabStateChanged={onTabStateChanged}
onTabErrorChanged={onTabErrorChanged}
/>
<div className="footer">
<button
className="btn btn-danger pull-left"
data-cy="reset-default-btn"
onClick={onResetPreferences}
>
{t('Reset to Defaults')}
</button>
<div>
<div
onClick={onClose}
data-cy="cancel-btn"
className="btn btn-default"
>
{t('Cancel')}
</div>
<button
className="btn btn-primary"
data-cy="save-btn"
disabled={hasAnyError()}
onClick={onSavePreferences}
>
{t('Save')}
</button>
</div>
</div>
</div>
) : null;
}
UserPreferencesForm.propTypes = {
onClose: PropTypes.func,
onSave: PropTypes.func,
onResetToDefaults: PropTypes.func,
windowLevelData: PropTypes.object,
hotkeyDefinitions: PropTypes.object,
generalPreferences: PropTypes.object,
hotkeysManager: PropTypes.object,
defaultLanguage: PropTypes.string,
hotkeyDefaults: PropTypes.array,
};
export { UserPreferencesForm };