diff --git a/src/actions/user.js b/src/actions/settings.js similarity index 61% rename from src/actions/user.js rename to src/actions/settings.js index 297f517bc..40cc7a8d2 100644 --- a/src/actions/user.js +++ b/src/actions/settings.js @@ -1,5 +1,10 @@ import * as types from '../constants/actionTypes'; +export const setSystemSettings = settings => ({ + type: types.SYSTEM_SETTINGS_SET, + payload: settings, +}); + // Set user settings export const setUserSettings = settings => ({ type: types.USER_SETTINGS_SET, diff --git a/src/app.js b/src/app.js index 265c075ec..b892843d6 100644 --- a/src/app.js +++ b/src/app.js @@ -10,12 +10,11 @@ import Root from './components/Root'; import { configI18n } from './util/i18n'; import { loadOrgUnitTree } from './actions/orgUnits'; import { loadExternalLayers } from './actions/externalLayers'; -import { setUserSettings } from './actions/user'; +import { setSystemSettings, setUserSettings } from './actions/settings'; import { resizeScreen } from './actions/ui'; import { loadFavorite } from './actions/favorites'; import { getAnalyticalObject } from './actions/analyticalObject'; -import { setBingMapsApiKey } from './actions/basemap'; -import { getUrlParameter } from './util/requests'; +import { getUrlParameter, getSystemSettings } from './util/requests'; log.setLevel( process.env.NODE_ENV === 'production' ? log.levels.INFO : log.levels.TRACE @@ -65,13 +64,9 @@ getManifest('manifest.webapp') return userSettings; }) .then(configI18n) + .then(getSystemSettings) + .then(systemSettings => store.dispatch(setSystemSettings(systemSettings))) .then(init) - .then(d2 => - d2.system.settings.get('keyBingMapsApiKey').then(key => { - store.dispatch(setBingMapsApiKey(key)); - return d2; - }) - ) .then( d2 => { const mapId = getUrlParameter('id'); diff --git a/src/components/edit/BoundaryDialog.js b/src/components/edit/BoundaryDialog.js index 2a073ef2b..1eea6fee4 100644 --- a/src/components/edit/BoundaryDialog.js +++ b/src/components/edit/BoundaryDialog.js @@ -12,7 +12,7 @@ import OrgUnitLevelSelect from '../orgunits/OrgUnitLevelSelect'; import UserOrgUnitsSelect from '../orgunits/UserOrgUnitsSelect'; import Checkbox from '../core/Checkbox'; import FontStyle from '../core/FontStyle'; -import { layerDialogStyles } from './LayerDialogStyles'; +import layerDialogStyles from './LayerDialogStyles'; import { setOrgUnitLevels, @@ -56,10 +56,6 @@ const styles = { marginLeft: 12, width: 127, }, - error: { - marginTop: 10, - color: 'red', - }, }; class BoundaryDialog extends Component { diff --git a/src/components/edit/EarthEngineDialog.js b/src/components/edit/EarthEngineDialog.js index 112242ef3..c9d242a4d 100644 --- a/src/components/edit/EarthEngineDialog.js +++ b/src/components/edit/EarthEngineDialog.js @@ -12,7 +12,7 @@ import LegendItem from '../layers/legend/LegendItem'; import { setParams, setFilter, setPeriodName } from '../../actions/layerEdit'; import { getColorScale, getColorPalette } from '../../util/colors'; import { createLegend } from '../../loaders/earthEngineLoader'; -import { layerDialogStyles } from './LayerDialogStyles'; +import layerDialogStyles from './LayerDialogStyles'; import legendStyle from '../layers/legend/legendStyle'; const getDatasets = () => ({ diff --git a/src/components/edit/EventDialog.js b/src/components/edit/EventDialog.js index 439ad7dbb..629983aad 100644 --- a/src/components/edit/EventDialog.js +++ b/src/components/edit/EventDialog.js @@ -8,7 +8,7 @@ import TextField from '../core/TextField'; import ProgramSelect from '../program/ProgramSelect'; import ProgramStageSelect from '../program/ProgramStageSelect'; import RelativePeriodSelect from '../periods/RelativePeriodSelect'; -import DatePicker from '../core/DatePicker'; +import StartEndDates from '../periods/StartEndDates'; import Checkbox from '../core/Checkbox'; import FilterGroup from '../filter/FilterGroup'; import ImageSelect from '../core/ImageSelect'; @@ -19,13 +19,11 @@ import OrgUnitTree from '../orgunits/OrgUnitTree'; import UserOrgUnitsSelect from '../orgunits/UserOrgUnitsSelect'; import SelectedOrgUnits from '../orgunits/SelectedOrgUnits'; import { - DEFAULT_START_DATE, - DEFAULT_END_DATE, EVENT_COLOR, EVENT_RADIUS, EVENT_BUFFER, } from '../../constants/layers'; -import { layerDialogStyles } from './LayerDialogStyles'; +import layerDialogStyles from './LayerDialogStyles'; import { setProgram, @@ -38,8 +36,6 @@ import { setUserOrgUnits, toggleOrgUnit, setPeriod, - setStartDate, - setEndDate, setAreaRadius, } from '../../actions/layerEdit'; @@ -68,16 +64,13 @@ const styles = { paddingTop: 8, lineHeight: '22px', }, - error: { - marginTop: 10, - color: 'red', - }, }; export class EventDialog extends Component { static propTypes = { areaRadius: PropTypes.number, columns: PropTypes.array, + defaultPeriod: PropTypes.string, endDate: PropTypes.string, eventClustering: PropTypes.bool, eventCoordinateField: PropTypes.string, @@ -103,8 +96,6 @@ export class EventDialog extends Component { setUserOrgUnits: PropTypes.func.isRequired, toggleOrgUnit: PropTypes.func.isRequired, setPeriod: PropTypes.func.isRequired, - setStartDate: PropTypes.func.isRequired, - setEndDate: PropTypes.func.isRequired, setAreaRadius: PropTypes.func.isRequired, validateLayer: PropTypes.bool.isRequired, }; @@ -121,11 +112,9 @@ export class EventDialog extends Component { const { rows, filters, - startDate, - endDate, - setStartDate, - setEndDate, + defaultPeriod, setOrgUnitRoot, + setPeriod, } = this.props; const orgUnits = getOrgUnitNodesFromRows(rows); @@ -136,10 +125,11 @@ export class EventDialog extends Component { setOrgUnitRoot(); } - if (!period && !startDate && !endDate) { - // Set default period (last year) - setStartDate(DEFAULT_START_DATE); - setEndDate(DEFAULT_END_DATE); + // Set default period from system settings + if (!period && defaultPeriod) { + setPeriod({ + id: defaultPeriod, + }); } } @@ -185,8 +175,6 @@ export class EventDialog extends Component { setUserOrgUnits, toggleOrgUnit, setPeriod, - setStartDate, - setEndDate, setAreaRadius, } = this.props; @@ -254,27 +242,13 @@ export class EventDialog extends Component { onChange={setPeriod} style={styles.select} /> - {period.id === 'START_END_DATES' && [ - , - , - ]} - {periodError ? ( -
- {periodError} -
- ) : null} + {period && period.id === 'START_END_DATES' && ( + + )} )} {tab === 'orgunits' && ( @@ -491,8 +465,6 @@ export default connect( setUserOrgUnits, toggleOrgUnit, setPeriod, - setStartDate, - setEndDate, setAreaRadius, }, null, diff --git a/src/components/edit/FacilityDialog.js b/src/components/edit/FacilityDialog.js index aea059978..dbce7b8b5 100644 --- a/src/components/edit/FacilityDialog.js +++ b/src/components/edit/FacilityDialog.js @@ -13,7 +13,7 @@ import OrgUnitTree from '../orgunits/OrgUnitTree'; import OrgUnitGroupSelect from '../orgunits/OrgUnitGroupSelect'; import OrgUnitLevelSelect from '../orgunits/OrgUnitLevelSelect'; import UserOrgUnitsSelect from '../orgunits/UserOrgUnitsSelect'; -import { layerDialogStyles } from './LayerDialogStyles'; +import layerDialogStyles from './LayerDialogStyles'; import { setOrganisationUnitGroupSet, @@ -61,10 +61,6 @@ const styles = { marginTop: 10, fontSize: 14, }, - error: { - marginTop: 10, - color: 'red', - }, }; class FacilityDialog extends Component { diff --git a/src/components/edit/LayerDialogStyles.js b/src/components/edit/LayerDialogStyles.js index 8bbb4a92e..ce1d0c66c 100644 --- a/src/components/edit/LayerDialogStyles.js +++ b/src/components/edit/LayerDialogStyles.js @@ -1,4 +1,4 @@ -export const layerDialogStyles = { +const layerDialogStyles = { select: { width: 'auto', maxWidth: 300, @@ -33,4 +33,10 @@ export const layerDialogStyles = { flex: 1, margin: 8, }, + error: { + marginTop: 10, + color: 'red', + }, }; + +export default layerDialogStyles; diff --git a/src/components/edit/LayerEdit.js b/src/components/edit/LayerEdit.js index 0a7ad6189..78c994b29 100644 --- a/src/components/edit/LayerEdit.js +++ b/src/components/edit/LayerEdit.js @@ -50,6 +50,7 @@ const styles = { class LayerEdit extends Component { static propTypes = { layer: PropTypes.object, + defaultPeriod: PropTypes.string, loadLayer: PropTypes.func.isRequired, cancelLayer: PropTypes.func.isRequired, setLayerLoading: PropTypes.func.isRequired, @@ -88,7 +89,7 @@ class LayerEdit extends Component { }; render() { - const { layer, cancelLayer, classes } = this.props; + const { layer, defaultPeriod, cancelLayer, classes } = this.props; if (!layer) { return null; @@ -114,6 +115,7 @@ class LayerEdit extends Component { @@ -152,8 +154,9 @@ class LayerEdit extends Component { } export default connect( - state => ({ - layer: state.layerEdit, + ({ layerEdit, settings }) => ({ + layer: layerEdit, + defaultPeriod: settings.system.keyAnalysisRelativePeriod, }), { loadLayer, cancelLayer, setLayerLoading } )(withStyles(styles)(LayerEdit)); diff --git a/src/components/edit/TrackedEntityDialog.js b/src/components/edit/TrackedEntityDialog.js index 6042bad88..66305a669 100644 --- a/src/components/edit/TrackedEntityDialog.js +++ b/src/components/edit/TrackedEntityDialog.js @@ -7,10 +7,10 @@ import Tabs from '../core/Tabs'; import Tab from '../core/Tab'; import TextField from '../core/TextField'; import SelectField from '../core/SelectField'; -import DatePicker from '../core/DatePicker'; import Checkbox from '../core/Checkbox'; import TrackedEntityTypeSelect from '../trackedEntity/TrackedEntityTypeSelect'; import ProgramSelect from '../program/ProgramSelect'; +import StartEndDates from '../periods/StartEndDates'; import OrgUnitTree from '../orgunits/OrgUnitTree'; import SelectedOrgUnits from '../orgunits/SelectedOrgUnits'; import ColorPicker from '../core/ColorPicker'; @@ -24,7 +24,7 @@ import { TEI_RELATIONSHIP_LINE_COLOR, TEI_RELATED_RADIUS, } from '../../constants/layers'; -import { layerDialogStyles } from './LayerDialogStyles'; +import layerDialogStyles from './LayerDialogStyles'; import { setTrackedEntityType, @@ -63,10 +63,6 @@ const styles = { indent: { marginLeft: 24, }, - error: { - marginTop: 12, - color: 'red', - }, }; export class TrackedEntityDialog extends Component { @@ -194,8 +190,6 @@ export class TrackedEntityDialog extends Component { setProgramStatus, setFollowUpStatus, setTrackedEntityRelationshipType, - setStartDate, - setEndDate, toggleOrgUnit, setOrgUnitMode, setEventPointColor, @@ -366,23 +360,11 @@ export class TrackedEntityDialog extends Component {
{periodHelp}:
- - - {periodError ? ( -
{periodError}
- ) : null} )} diff --git a/src/components/edit/thematic/ThematicDialog.js b/src/components/edit/thematic/ThematicDialog.js index 47552c487..3f56e102b 100644 --- a/src/components/edit/thematic/ThematicDialog.js +++ b/src/components/edit/thematic/ThematicDialog.js @@ -27,14 +27,12 @@ import RenderingStrategy from '../../periods/RenderingStrategy'; import ProgramSelect from '../../program/ProgramSelect'; import ProgramIndicatorSelect from '../../program/ProgramIndicatorSelect'; import RelativePeriodSelect from '../../periods/RelativePeriodSelect'; -import DatePicker from '../../core/DatePicker'; +import StartEndDates from '../../periods/StartEndDates'; import UserOrgUnitsSelect from '../../orgunits/UserOrgUnitsSelect'; import DimensionFilter from '../../dimensions/DimensionFilter'; -import { layerDialogStyles } from '../LayerDialogStyles'; +import layerDialogStyles from '../LayerDialogStyles'; import { dimConf } from '../../../constants/dimension'; import { - DEFAULT_START_DATE, - DEFAULT_END_DATE, DEFAULT_ORG_UNIT_LEVEL, DEFAULT_RADIUS_LOW, DEFAULT_RADIUS_HIGH, @@ -59,8 +57,6 @@ import { setPeriod, setPeriodType, setRenderingStrategy, - setStartDate, - setEndDate, setProgram, setRadiusLow, setRadiusHigh, @@ -99,10 +95,6 @@ const styles = { font: { float: 'left', }, - error: { - marginTop: 10, - color: 'red', - }, }; export class ThematicDialog extends Component { @@ -121,6 +113,7 @@ export class ThematicDialog extends Component { dataElementGroup: PropTypes.object, program: PropTypes.object, operand: PropTypes.string, + defaultPeriod: PropTypes.string, startDate: PropTypes.string, endDate: PropTypes.string, periodType: PropTypes.string, @@ -141,8 +134,6 @@ export class ThematicDialog extends Component { setLegendSet: PropTypes.func.isRequired, setOperand: PropTypes.func.isRequired, setPeriod: PropTypes.func.isRequired, - setStartDate: PropTypes.func.isRequired, - setEndDate: PropTypes.func.isRequired, setOrgUnitLevels: PropTypes.func.isRequired, setOrgUnitGroups: PropTypes.func.isRequired, toggleOrgUnit: PropTypes.func.isRequired, @@ -165,16 +156,16 @@ export class ThematicDialog extends Component { const { valueType, columns, + rows, + filters, setValueType, - startDate, - endDate, - setStartDate, - setEndDate, + defaultPeriod, + setPeriod, setOrgUnitLevels, - rows, } = this.props; const dataItem = getDataItemFromColumns(columns); + const period = getPeriodFromFilters(filters); // Set value type if favorite is loaded if (!valueType) { @@ -191,10 +182,11 @@ export class ThematicDialog extends Component { } } - // Set default period (last year) - if (!startDate && !endDate) { - setStartDate(DEFAULT_START_DATE); - setEndDate(DEFAULT_END_DATE); + // Set default period from system settings + if (!period && defaultPeriod) { + setPeriod({ + id: defaultPeriod, + }); } // Set default org unit level @@ -282,8 +274,6 @@ export class ThematicDialog extends Component { setOrgUnitLevels, setOrgUnitGroups, setPeriod, - setStartDate, - setEndDate, setPeriodType, setRenderingStrategy, setProgram, @@ -499,27 +489,13 @@ export class ThematicDialog extends Component { errorText={periodError} /> )} - {periodType === 'StartEndDates' && [ - , - , - periodError ? ( -
- {periodError} -
- ) : null, - ]} + {periodType === 'StartEndDates' && ( + + )} {periodType === 'relativePeriods' && ( ({ +export default connect(({ map, download, settings }) => ({ name: map.name, interpretationDate: map.interpretationDate, showName: download.showDialog ? download.showName : true, - uiLocale: userSettings.keyUiLocale, + uiLocale: settings.user.keyUiLocale, }))(withStyles(styles)(MapName)); diff --git a/src/components/periods/PeriodSelect.js b/src/components/periods/PeriodSelect.js index 65cd9db26..f31e05459 100644 --- a/src/components/periods/PeriodSelect.js +++ b/src/components/periods/PeriodSelect.js @@ -157,6 +157,6 @@ class PeriodSelect extends Component { }; } -export default connect(state => ({ - locale: state.userSettings.keyUiLocale, +export default connect(({ settings }) => ({ + locale: settings.user.keyUiLocale, }))(withStyles(styles)(PeriodSelect)); diff --git a/src/components/periods/StartEndDates.js b/src/components/periods/StartEndDates.js new file mode 100644 index 000000000..94423e26e --- /dev/null +++ b/src/components/periods/StartEndDates.js @@ -0,0 +1,51 @@ +import React, { Fragment, useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import i18n from '@dhis2/d2-i18n'; +import DatePicker from '../core/DatePicker'; +import { setStartDate, setEndDate } from '../../actions/layerEdit'; +import { DEFAULT_START_DATE, DEFAULT_END_DATE } from '../../constants/layers'; +import styles from '../edit/LayerDialogStyles'; + +const StartEndDates = props => { + const { startDate, endDate, setStartDate, setEndDate, errorText } = props; + + useEffect(() => { + if (!startDate && !endDate) { + setStartDate(DEFAULT_START_DATE); + setEndDate(DEFAULT_END_DATE); + } + }, [startDate, endDate, setStartDate, setEndDate]); + + return startDate && endDate ? ( + + + + {errorText && ( +
+ {errorText} +
+ )} +
+ ) : null; +}; + +StartEndDates.propTypes = { + startDate: PropTypes.string, + endDate: PropTypes.string, + errorText: PropTypes.string, + setStartDate: PropTypes.func.isRequired, + setEndDate: PropTypes.func.isRequired, +}; + +export default connect(null, { setStartDate, setEndDate })(StartEndDates); diff --git a/src/constants/actionTypes.js b/src/constants/actionTypes.js index 156b5fdac..c16bdc0ad 100644 --- a/src/constants/actionTypes.js +++ b/src/constants/actionTypes.js @@ -288,9 +288,6 @@ export const EARTH_ENGINE_COLLECTION_LOAD_ERROR = 'EARTH_ENGINE_COLLECTION_LOAD_ERROR'; export const EARTH_ENGINE_COLLECTION_SET = 'EARTH_ENGINE_COLLECTION_SET'; -/* USER */ -export const USER_SETTINGS_SET = 'USER_SETTINGS_SET'; - /* MESSAGE (SNACKBAR) */ export const MESSAGE_SET = 'MESSAGE_SET'; export const MESSAGE_CLEAR = 'MESSAGE_CLEAR'; @@ -324,3 +321,7 @@ export const ANALYTICAL_OBJECT_GET = 'ANALYTICAL_OBJECT_GET'; export const ANALYTICAL_OBJECT_SET = 'ANALYTICAL_OBJECT_SET'; export const ANALYTICAL_OBJECT_CLEAR = 'ANALYTICAL_OBJECT_CLEAR'; export const ANALYTICAL_OBJECT_FAILURE = 'ANALYTICAL_OBJECT_FAILURE'; + +/* SETTINGS */ +export const SYSTEM_SETTINGS_SET = 'SYSTEM_SETTINGS_SET'; +export const USER_SETTINGS_SET = 'USER_SETTINGS_SET'; diff --git a/src/constants/settings.js b/src/constants/settings.js new file mode 100644 index 000000000..b23e715eb --- /dev/null +++ b/src/constants/settings.js @@ -0,0 +1,4 @@ +export const SYSTEM_SETTINGS = [ + 'keyAnalysisRelativePeriod', + 'keyBingMapsApiKey', +]; diff --git a/src/reducers/basemaps.js b/src/reducers/basemaps.js index 5d7a21975..101a2e5c6 100644 --- a/src/reducers/basemaps.js +++ b/src/reducers/basemaps.js @@ -3,6 +3,8 @@ import { defaultBasemaps } from '../constants/basemaps'; import * as types from '../constants/actionTypes'; const basemaps = (state = defaultBasemaps(), action) => { + let bingMapsKey; + switch (action.type) { case types.BASEMAP_ADD: return [...state, action.payload]; @@ -10,9 +12,11 @@ const basemaps = (state = defaultBasemaps(), action) => { case types.BASEMAP_REMOVE: return state.filter(basemap => basemap.id !== action.id); - case types.BASEMAP_BING_KEY_SET: + case types.SYSTEM_SETTINGS_SET: + bingMapsKey = action.payload && action.payload.keyBingMapsApiKey; + // Remove Bing basemaps is no key is provided - if (!action.key) { + if (!bingMapsKey) { return state.filter(layer => layer.config.type !== 'bingLayer'); } @@ -26,7 +30,7 @@ const basemaps = (state = defaultBasemaps(), action) => { ...layer, config: { ...layer.config, - apiKey: action.key, + apiKey: bingMapsKey, }, }; }); diff --git a/src/reducers/index.js b/src/reducers/index.js index 619f2a0a4..bc5382c84 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -34,7 +34,7 @@ import programStageDataElements from './programStageDataElements'; import programTrackedEntityAttributes from './programTrackedEntityAttributes'; import relocate from './relocate'; import ui from './ui'; -import userSettings from './userSettings'; +import settings from './settings'; import trackedEntityTypes from './trackedEntityTypes'; import dataDownload from './dataDownload'; @@ -74,7 +74,7 @@ export default combineReducers({ programTrackedEntityAttributes, relocate, ui, - userSettings, + settings, trackedEntityTypes, dataDownload, }); diff --git a/src/reducers/settings.js b/src/reducers/settings.js new file mode 100644 index 000000000..f326a5784 --- /dev/null +++ b/src/reducers/settings.js @@ -0,0 +1,29 @@ +import * as types from '../constants/actionTypes'; + +const defaultState = { + system: { + keyAnalysisRelativePeriod: 'LAST_12_MONTHS', + }, + user: {}, +}; + +const userSettings = (state = defaultState, action) => { + switch (action.type) { + case types.SYSTEM_SETTINGS_SET: + return { + ...state, + system: action.payload, + }; + + case types.USER_SETTINGS_SET: + return { + ...state, + user: action.payload, + }; + + default: + return state; + } +}; + +export default userSettings; diff --git a/src/reducers/userSettings.js b/src/reducers/userSettings.js deleted file mode 100644 index 801012462..000000000 --- a/src/reducers/userSettings.js +++ /dev/null @@ -1,13 +0,0 @@ -import * as types from '../constants/actionTypes'; - -const userSettings = (state = null, action) => { - switch (action.type) { - case types.USER_SETTINGS_SET: - return action.payload; - - default: - return state; - } -}; - -export default userSettings; diff --git a/src/util/requests.js b/src/util/requests.js index 8877bf967..9a6557727 100644 --- a/src/util/requests.js +++ b/src/util/requests.js @@ -1,6 +1,8 @@ import { getInstance as getD2 } from 'd2'; import { mapFields } from './helpers'; import { isString, isObject, sortBy } from 'lodash/fp'; +import { apiFetch } from './api'; +import { SYSTEM_SETTINGS } from '../constants/settings'; // API requests @@ -31,6 +33,10 @@ export const getBingMapsApiKey = async () => { return d2.system.settings.get('keyBingMapsApiKey'); }; +// Returns system settings for keys (d2 returns one or all) +export const getSystemSettings = () => + apiFetch(`/systemSettings/?key=${SYSTEM_SETTINGS.join(',')}`); + // Different ways of specifying a basemap - TODO: simplify! const getBasemap = config => { const externalBasemap = config.mapViews.find(