diff --git a/src/client/app/actions/admin.ts b/src/client/app/actions/admin.ts index f89b983e7..178150cc7 100644 --- a/src/client/app/actions/admin.ts +++ b/src/client/app/actions/admin.ts @@ -61,6 +61,34 @@ export function updateDefaultMeterReadingFrequency(defaultMeterReadingFrequency: return { type: ActionType.UpdateDefaultMeterReadingFrequency, defaultMeterReadingFrequency }; } +export function updateDefaultMeterMinimumValue(defaultMeterMinimumValue: number): t.UpdateDefaultMeterMinimumValueAction { + return { type: ActionType.UpdateDefaultMeterMinimumValue, defaultMeterMinimumValue }; +} + +export function updateDefaultMeterMaximumValue(defaultMeterMaximumValue: number): t.UpdateDefaultMeterMaximumValueAction { + return { type: ActionType.UpdateDefaultMeterMaximumValue, defaultMeterMaximumValue }; +} + +export function updateDefaultMeterMinimumDate(defaultMeterMinimumDate: string): t.UpdateDefaultMeterMinimumDateAction { + return { type: ActionType.UpdateDefaultMeterMinimumDate, defaultMeterMinimumDate }; +} + +export function updateDefaultMeterMaximumDate(defaultMeterMaximumDate: string): t.UpdateDefaultMeterMaximumDateAction { + return { type: ActionType.UpdateDefaultMeterMaximumDate, defaultMeterMaximumDate }; +} + +export function updateDefaultMeterReadingGap(defaultMeterReadingGap: number): t.UpdateDefaultMeterReadingGapAction { + return { type: ActionType.UpdateDefaultMeterReadingGap, defaultMeterReadingGap }; +} + +export function updateDefaultMeterMaximumErrors(defaultMeterMaximumErrors: number): t.UpdateDefaultMeterMaximumErrorsAction { + return { type: ActionType.UpdateDefaultMeterMaximumErrors, defaultMeterMaximumErrors }; +} + +export function updateDefaultMeterDisableChecks(defaultMeterDisableChecks: boolean): t.UpdateDefaultMeterDisableChecksAction { + return { type: ActionType.UpdateDefaultMeterDisableChecks, defaultMeterDisableChecks }; +} + function requestPreferences(): t.RequestPreferencesAction { return { type: ActionType.RequestPreferences }; } @@ -103,7 +131,40 @@ function fetchPreferences(): Thunk { } }; } +// TODO: Add warning for invalid data in admin panel src/client/app/components/admin/PreferencesComponent.tsx +/* Validates preferences + Create Preferences Validation: + Mininum Value cannot bigger than Maximum Value + Minimum Value and Maximum Value must be between valid input + Minimum Date and Maximum cannot be blank + Minimum Date cannot be after Maximum Date + Minimum Date and Maximum Value must be between valid input + Maximum No of Error must be between 0 and valid input +*/ +function validPreferences(state: State) { + const MIN_VAL = Number.MIN_SAFE_INTEGER; + const MAX_VAL = Number.MAX_SAFE_INTEGER; + const MIN_DATE_MOMENT = moment(0).utc(); + const MAX_DATE_MOMENT = moment(0).utc().add(5000, 'years'); + const MAX_ERRORS = 75; + if (state.admin.defaultMeterReadingGap >= 0 && + state.admin.defaultMeterMinimumValue >= MIN_VAL && + state.admin.defaultMeterMinimumValue <= state.admin.defaultMeterMaximumValue && + state.admin.defaultMeterMinimumValue <= MAX_VAL && + state.admin.defaultMeterMinimumDate !== '' && + state.admin.defaultMeterMaximumDate !== '' && + moment(state.admin.defaultMeterMinimumDate).isValid() && + moment(state.admin.defaultMeterMaximumDate).isValid() && + moment(state.admin.defaultMeterMinimumDate).isSameOrAfter(MIN_DATE_MOMENT) && + moment(state.admin.defaultMeterMinimumDate).isSameOrBefore(moment(state.admin.defaultMeterMaximumDate)) && + moment(state.admin.defaultMeterMaximumDate).isSameOrBefore(MAX_DATE_MOMENT) && + (state.admin.defaultMeterMaximumErrors >= 0 && state.admin.defaultMeterMaximumErrors <= MAX_ERRORS)) { + return true; + } else { + return false; + } +} /** * Submits preferences stored in the state to the API to be stored in the database */ @@ -111,6 +172,9 @@ export function submitPreferences() { return async (dispatch: Dispatch, getState: GetState) => { const state = getState(); try { + if (!validPreferences(state)) { + throw new Error('invalid input'); + } const preferences = await preferencesApi.submitPreferences({ displayTitle: state.admin.displayTitle, defaultChartToRender: state.admin.defaultChartToRender, @@ -121,7 +185,14 @@ export function submitPreferences() { defaultFileSizeLimit: state.admin.defaultFileSizeLimit, defaultAreaNormalization: state.admin.defaultAreaNormalization, defaultAreaUnit: state.admin.defaultAreaUnit, - defaultMeterReadingFrequency: state.admin.defaultMeterReadingFrequency + defaultMeterReadingFrequency: state.admin.defaultMeterReadingFrequency, + defaultMeterMinimumValue: state.admin.defaultMeterMinimumValue, + defaultMeterMaximumValue: state.admin.defaultMeterMaximumValue, + defaultMeterMinimumDate: state.admin.defaultMeterMinimumDate, + defaultMeterMaximumDate: state.admin.defaultMeterMaximumDate, + defaultMeterReadingGap: state.admin.defaultMeterReadingGap, + defaultMeterMaximumErrors: state.admin.defaultMeterMaximumErrors, + defaultMeterDisableChecks: state.admin.defaultMeterDisableChecks }); // Only return the defaultMeterReadingFrequency because the value from the DB // generally differs from what the user input so update state with DB value. diff --git a/src/client/app/components/GraphicRateMenuComponent.tsx b/src/client/app/components/GraphicRateMenuComponent.tsx index 6e1884c75..65819a79d 100644 --- a/src/client/app/components/GraphicRateMenuComponent.tsx +++ b/src/client/app/components/GraphicRateMenuComponent.tsx @@ -66,4 +66,4 @@ export default function GraphicRateMenuComponent() { } ); -} +} \ No newline at end of file diff --git a/src/client/app/components/admin/PreferencesComponent.tsx b/src/client/app/components/admin/PreferencesComponent.tsx index e926707af..b8e5683a3 100644 --- a/src/client/app/components/admin/PreferencesComponent.tsx +++ b/src/client/app/components/admin/PreferencesComponent.tsx @@ -15,7 +15,15 @@ import { UpdateDefaultFileSizeLimit, ToggleDefaultAreaNormalizationAction, UpdateDefaultAreaUnitAction, - UpdateDefaultMeterReadingFrequencyAction + UpdateDefaultMeterReadingFrequencyAction, + UpdateDefaultMeterMinimumValueAction, + UpdateDefaultMeterMaximumValueAction, + UpdateDefaultMeterMinimumDateAction, + UpdateDefaultMeterMaximumDateAction, + UpdateDefaultMeterReadingGapAction, + UpdateDefaultMeterMaximumErrorsAction, + UpdateDefaultMeterDisableChecksAction + } from '../../types/redux/admin'; import { removeUnsavedChanges, updateUnsavedChanges } from '../../actions/unsavedWarning'; import { defineMessages, FormattedMessage, injectIntl, WrappedComponentProps } from 'react-intl'; @@ -24,6 +32,8 @@ import TimeZoneSelect from '../TimeZoneSelect'; import store from '../../index'; import { fetchPreferencesIfNeeded, submitPreferences } from '../../actions/admin'; import { AreaUnitType } from '../../utils/getAreaUnitConversion'; +import translate from '../../utils/translate'; +import { TrueFalseType } from '../../types/items'; interface PreferencesProps { displayTitle: string; @@ -37,6 +47,13 @@ interface PreferencesProps { defaultFileSizeLimit: number; defaultAreaUnit: AreaUnitType; defaultMeterReadingFrequency: string; + defaultMeterMinimumValue: number; + defaultMeterMaximumValue: number; + defaultMeterMinimumDate: string; + defaultMeterMaximumDate: string; + defaultMeterReadingGap: number; + defaultMeterMaximumErrors: number; + defaultMeterDisableChecks: boolean; updateDisplayTitle(title: string): UpdateDisplayTitleAction; updateDefaultChartType(defaultChartToRender: ChartTypes): UpdateDefaultChartToRenderAction; toggleDefaultBarStacking(): ToggleDefaultBarStackingAction; @@ -48,10 +65,18 @@ interface PreferencesProps { updateDefaultFileSizeLimit(defaultFileSizeLimit: number): UpdateDefaultFileSizeLimit; updateDefaultAreaUnit(defaultAreaUnit: AreaUnitType): UpdateDefaultAreaUnitAction; updateDefaultMeterReadingFrequency(defaultMeterReadingFrequency: string): UpdateDefaultMeterReadingFrequencyAction; + updateDefaultMeterMinimumValue(defaultMeterMinimumValue : number): UpdateDefaultMeterMinimumValueAction; + updateDefaultMeterMaximumValue(defaultMeterMaximumValue: number): UpdateDefaultMeterMaximumValueAction; + updateDefaultMeterMinimumDate(defaultMeterMinimumDate: string): UpdateDefaultMeterMinimumDateAction; + updateDefaultMeterMaximumDate(defaultMeterMaximumDate: string): UpdateDefaultMeterMaximumDateAction; + updateDefaultMeterReadingGap(defaultMeterReadingGap: number): UpdateDefaultMeterReadingGapAction; + updateDefaultMeterMaximumErrors(defaultMeterMaximumErrors: number): UpdateDefaultMeterMaximumErrorsAction; + updateDefaultMeterDisableChecks(defaultMeterDisableChecks: boolean): UpdateDefaultMeterDisableChecksAction; } type PreferencesPropsWithIntl = PreferencesProps & WrappedComponentProps; +// TODO: Add warning for invalid data class PreferencesComponent extends React.Component { constructor(props: PreferencesPropsWithIntl) { super(props); @@ -66,6 +91,13 @@ class PreferencesComponent extends React.Component { this.handleDefaultAreaNormalizationChange = this.handleDefaultAreaNormalizationChange.bind(this); this.handleDefaultAreaUnitChange = this.handleDefaultAreaUnitChange.bind(this); this.handleDefaultMeterReadingFrequencyChange = this.handleDefaultMeterReadingFrequencyChange.bind(this); + this.handleDefaultMeterMinimumValueChange = this.handleDefaultMeterMinimumValueChange.bind(this); + this.handleDefaultMeterMaximumValueChange = this.handleDefaultMeterMaximumValueChange.bind(this); + this.handleDefaultMeterMinimumDateChange = this.handleDefaultMeterMinimumDateChange.bind(this); + this.handleDefaultMeterMaximumDateChange = this.handleDefaultMeterMaximumDateChange.bind(this); + this.handleDefaultMeterReadingGapChange = this.handleDefaultMeterReadingGapChange.bind(this); + this.handleDefaultMeterMaximumErrorsChange = this.handleDefaultMeterMaximumErrorsChange.bind(this); + this.handleDefaultMeterDisableChecksChange = this.handleDefaultMeterDisableChecksChange.bind(this); } public render() { @@ -294,6 +326,85 @@ class PreferencesComponent extends React.Component { onChange={this.handleDefaultMeterReadingFrequencyChange} /> +
+

+ : +

+ +
+
+

+ : +

+ +
+
+

+ : +

+ +
+
+

+ : +

+ +
+
+

+ : +

+ +
+
+

+ : +

+ +
+
+

+ : +

+ + {Object.keys(TrueFalseType).map(key => { + return () + })} + +