diff --git a/packages/openchs-android/package.json b/packages/openchs-android/package.json index f330626d1..4da9c4475 100644 --- a/packages/openchs-android/package.json +++ b/packages/openchs-android/package.json @@ -58,7 +58,7 @@ "lodash": "4.17.21", "moment": "2.29.4", "native-base": "3.4.9", - "openchs-models": "1.31.78", + "openchs-models": "1.31.79", "prop-types": "15.8.1", "react": "18.2.0", "react-native": "0.72.3", diff --git a/packages/openchs-android/src/action/customDashboard/CustomDashboardActions.js b/packages/openchs-android/src/action/customDashboard/CustomDashboardActions.js index 19db98e21..eb4810406 100644 --- a/packages/openchs-android/src/action/customDashboard/CustomDashboardActions.js +++ b/packages/openchs-android/src/action/customDashboard/CustomDashboardActions.js @@ -7,8 +7,8 @@ import ReportCardService from "../../service/customDashboard/ReportCardService"; import General from "../../utility/General"; import DashboardFilterService from "../../service/reports/DashboardFilterService"; import CustomDashboardCacheService from '../../service/CustomDashboardCacheService'; -import CryptoUtils from '../../utility/CryptoUtils'; import MessageService from '../../service/MessageService'; +import dashboardCacheService from "../../service/DashboardCacheService"; function loadCurrentDashboardInfo(context, newState) { const dashboardFilterService = context.get(DashboardFilterService); @@ -30,7 +30,6 @@ class CustomDashboardActions { cardToCountResultMap: {}, countUpdateTime: null, hasFilters: false, - ruleInput: null, activeDashboardUUID: null, customDashboardFilters: [] }; @@ -42,6 +41,9 @@ class CustomDashboardActions { const dashboards = dashboardService.getDashboards(action.customDashboardType); newState.dashboards = dashboards; newState.activeDashboardUUID = _.get(_.head(dashboards), 'uuid'); + + // context.get(CustomDashboardCacheService).clearAllCache(); + return loadCurrentDashboardInfo(context, newState); } @@ -61,16 +63,19 @@ class CustomDashboardActions { const itemKey = action.reportCardUUID; const rcUUID = context.get(ReportCardService).getPlainUUIDFromCompositeReportCardUUID(action.reportCardUUID); const reportCard = context.get(EntityService).findByUUID(rcUUID, ReportCard.schema.name); + const {selectedFilterValues} = context.get(CustomDashboardCacheService).getDashboardCache(state.activeDashboardUUID); + const ruleInputArray = context.get(DashboardFilterService).toRuleInputObjects(state.activeDashboardUUID, selectedFilterValues); + reportCard.itemKey = itemKey; if (reportCard.isStandardTaskType()) { - action.goToTaskLists(reportCard.standardReportCardType.getTaskTypeType(), state.ruleInput.ruleInputArray); + action.goToTaskLists(reportCard.standardReportCardType.getTaskTypeType(), ruleInputArray); } else { - const {result, status} = context.get(ReportCardService).getReportCardResult(reportCard, state.ruleInput.ruleInputArray); + const {result, status} = context.get(ReportCardService).getReportCardResult(reportCard, ruleInputArray); const standardReportCardType = reportCard.standardReportCardType; const viewName = CustomDashboardActions._getViewName(standardReportCardType); if (!_.isNil(result)) { setTimeout(() => action.onCustomRecordCardResults(result, status, viewName, - standardReportCardType && standardReportCardType.getApprovalStatusForType(), state.ruleInput.ruleInputArray, reportCard), 0); + standardReportCardType && standardReportCardType.getApprovalStatusForType(), ruleInputArray, reportCard), 0); } } return newState; @@ -94,14 +99,17 @@ class CustomDashboardActions { } static refreshCount(state, action, context) { + const {dashboardCache, selectedFilterValues} = context.get(CustomDashboardCacheService).getDashboardCache(state.activeDashboardUUID); + const I18n = context.get(MessageService).getI18n(); const reportCardSectionMappings = state.reportCardSectionMappings; const newState = {...state}; - newState.ruleInput = action.filterApplied ? action.ruleInput : newState.ruleInput; + newState.countUpdateTime = new Date(); //Update this to ensure reportCard count change is reflected + const ruleInputArray = context.get(DashboardFilterService).toRuleInputObjects(state.activeDashboardUUID, selectedFilterValues); reportCardSectionMappings.forEach(rcm => { const start = new Date(); - const countQueryResponse = context.get(ReportCardService).getReportCardCount(rcm.card, newState.ruleInput.ruleInputArray); + const countQueryResponse = context.get(ReportCardService).getReportCardCount(rcm.card, ruleInputArray); if (rcm.card.nested) { if (countQueryResponse && countQueryResponse.length === rcm.card.countOfCards) { _.forEach(countQueryResponse, (reportCard, index) => { diff --git a/packages/openchs-android/src/action/mydashboard/FiltersActionsV2.js b/packages/openchs-android/src/action/mydashboard/FiltersActionsV2.js index 435db66ab..40f0a50b7 100644 --- a/packages/openchs-android/src/action/mydashboard/FiltersActionsV2.js +++ b/packages/openchs-android/src/action/mydashboard/FiltersActionsV2.js @@ -4,6 +4,7 @@ import {ArrayUtil, Concept, CustomFilter, ModelGeneral} from 'openchs-models'; import CustomDashboardCacheService from '../../service/CustomDashboardCacheService'; import General from "../../utility/General"; +import {JSONStringify} from "../../utility/JsonStringify"; class FiltersActionsV2 { static getInitialState() { @@ -89,27 +90,31 @@ class FiltersActionsV2 { const {filterConfigs, selectedValues} = state; const {navigateToDashboardView, setFiltersDataOnDashboardView} = action; const newState = {...state, filterApplied: true, filterErrors: {}}; - const filledFilterValues = _.filter(Object.entries(selectedValues), ([, filterValue]) => !ModelGeneral.isDeepEmpty(filterValue)); - //Check if there are errors in filter values specified - filledFilterValues.forEach(([filterUUID, filterValue]) => { - const [success, message] = filterConfigs[filterUUID].validate && filterConfigs[filterUUID].validate(filterValue) || [false, `validate for filterConfig ${filterUUID} not found`]; - if (!success) - newState.filterErrors[filterUUID] = message; + const filledFilterValues = {}; + Object.keys(selectedValues).forEach((filterUUID) => { + const filterValue = selectedValues[filterUUID]; + if (!ModelGeneral.isDeepEmpty(filterValue)) { + filledFilterValues[filterUUID] = filterValue; + + const [success, message] = filterConfigs[filterUUID].validate && filterConfigs[filterUUID].validate(filterValue) || [false, `validate for filterConfig ${filterUUID} not found`]; + if (!success) + newState.filterErrors[filterUUID] = message; + } }); + //Check if there are errors in filter values specified if (Object.keys(newState.filterErrors).length > 0) { newState.filterApplied = false; newState.loading = false; return newState; } - const dashboardFilterService = context.get(DashboardFilterService); - const ruleInputArray = filledFilterValues - .map(([filterUUID, filterValue]) => dashboardFilterService.toRuleInputObject(filterConfigs[filterUUID], filterValue)); - const customDashboardCacheService = context.get(CustomDashboardCacheService); - customDashboardCacheService.setSelectedFilterValues(newState.dashboardUUID, selectedValues, true); + customDashboardCacheService.setSelectedFilterValues(newState.dashboardUUID, filledFilterValues, true); //Invoke callbacks. Used only in test. // setFiltersDataOnDashboardView(serializableFilterData); + const dashboardFilterService = context.get(DashboardFilterService); + const ruleInputArray = dashboardFilterService.toRuleInputObjects(newState.dashboardUUID, filledFilterValues); + General.logDebugTemp("FiltersActionsV2", `ruleInputArray: ${JSONStringify(ruleInputArray)}`); navigateToDashboardView(ruleInputArray); return newState; } diff --git a/packages/openchs-android/src/service/BaseService.js b/packages/openchs-android/src/service/BaseService.js index 076bdc397..89c2911cf 100644 --- a/packages/openchs-android/src/service/BaseService.js +++ b/packages/openchs-android/src/service/BaseService.js @@ -80,6 +80,10 @@ class BaseService { return this.getReturnValue(entities); } + findByFiltered(filter, value, schema = this.getSchema()) { + return this.getReturnValue(this.findAll(schema).filtered(`${filter} = '${value}'`)); + } + getReturnValue(entities) { if (entities.length === 0) return undefined; if (entities.length === 1) return entities[0]; diff --git a/packages/openchs-android/src/service/CustomDashboardCacheService.js b/packages/openchs-android/src/service/CustomDashboardCacheService.js index e4c69bb96..4e7da4e8f 100644 --- a/packages/openchs-android/src/service/CustomDashboardCacheService.js +++ b/packages/openchs-android/src/service/CustomDashboardCacheService.js @@ -3,8 +3,9 @@ import Service from "../framework/bean/Service"; import {CustomDashboardCache} from "avni-models"; import _ from "lodash"; import EntityService from "./EntityService"; -import {AddressLevel, Concept, CustomFilter, EncounterType, Gender, Individual, Program, SubjectType} from "openchs-models"; +import {AddressLevel, Concept, CustomFilter, Dashboard, EncounterType, Gender, Individual, Program, SubjectType} from "openchs-models"; import DashboardFilterService from "./reports/DashboardFilterService"; +import General from "../utility/General"; const dataTypeDetails = new Map(); dataTypeDetails.set(Concept.dataType.Coded, {type: Concept, isArray: true}); @@ -13,11 +14,12 @@ dataTypeDetails.set(CustomFilter.type.Address, {type: AddressLevel, isArray: tru dataTypeDetails.set(CustomFilter.type.GroupSubject, {type: Individual, isArray: false}); function getDashboardCache(service, dashboardUUID) { - let cache = service.findByKey("dashboard.uuid", dashboardUUID, CustomDashboardCache.schema.name); + let cache = service.findByFiltered("dashboard.uuid", dashboardUUID, CustomDashboardCache.schema.name); if (_.isNil(cache)) { - cache = service.save(CustomDashboardCache.newInstance(), CustomDashboardCache.schema.name); + const dashboard = service.findByUUID(dashboardUUID, Dashboard.schema.name); + cache = service.save(CustomDashboardCache.newInstance(dashboard), CustomDashboardCache.schema.name); } - return cache; + return cache.clone(); } @Service('customDashboardCacheService') @@ -30,12 +32,18 @@ class CustomDashboardCacheService extends BaseService { return CustomDashboardCache.schema.name; } + clearAllCache() { + this.db.write(() => { + this.db.delete(this.db.objects(CustomDashboardCache.schema.name)); + }); + } + getDashboardCache(dashboardUUID) { + const entityService = this.getService(EntityService); const dashboardCache = getDashboardCache(this, dashboardUUID); try { const selectedSerialisedValues = dashboardCache.getSelectedValues(); const dashboardFilterService = this.getService(DashboardFilterService); - const entityService = this.getService(EntityService); const selectedFilterValues = {}; Object.keys(selectedSerialisedValues).forEach((filterUuid) => { @@ -60,8 +68,9 @@ class CustomDashboardCacheService extends BaseService { }); return {selectedFilterValues, dashboardCache}; } catch (e) { + General.logError("CustomDashboardCacheService", e); dashboardCache.reset(); - this.save(dashboardCache, CustomDashboardCache.schema.name); + this.saveOrUpdate(dashboardCache, CustomDashboardCache.schema.name); return {selectedFilterValues: {}, dashboardCache}; } } @@ -69,13 +78,13 @@ class CustomDashboardCacheService extends BaseService { reset(dashboardUUID) { const cache = getDashboardCache(this, dashboardUUID); cache.reset(); - this.save(cache); + this.saveOrUpdate(cache); } setSelectedFilterValues(dashboardUUID, selectedFilterValues, filterApplied) { - const cachedData = this.findByUUID(dashboardUUID); - cachedData.filterApplied = filterApplied; - cachedData.updatedAt = new Date(); + const dashboardCache = getDashboardCache(this, dashboardUUID); + dashboardCache.filterApplied = filterApplied; + dashboardCache.updatedAt = new Date(); const dashboardFilterService = this.getService(DashboardFilterService); const serialisedSelectedValues = {}; @@ -102,8 +111,8 @@ class CustomDashboardCacheService extends BaseService { } }); - cachedData.selectedValuesJSON = JSON.stringify(serialisedSelectedValues); - this.save(cachedData); + dashboardCache.selectedValuesJSON = JSON.stringify(serialisedSelectedValues); + this.saveOrUpdate(dashboardCache); } resetCache(dashboardUUID) { diff --git a/packages/openchs-android/src/service/customDashboard/CustomDashboardService.js b/packages/openchs-android/src/service/customDashboard/CustomDashboardService.js index d8d8697cf..492a2570a 100644 --- a/packages/openchs-android/src/service/customDashboard/CustomDashboardService.js +++ b/packages/openchs-android/src/service/customDashboard/CustomDashboardService.js @@ -31,7 +31,6 @@ class CustomDashboardService extends BaseService { } getDashboards(customDashboardType) { - General.logDebugTemp("CustomDashboardService", customDashboardType); switch (customDashboardType) { case CustomDashboardType.Primary: return [this.getOnePrimaryDashboard()]; diff --git a/packages/openchs-android/src/service/reports/DashboardFilterService.js b/packages/openchs-android/src/service/reports/DashboardFilterService.js index 710e9389c..02d656bd2 100644 --- a/packages/openchs-android/src/service/reports/DashboardFilterService.js +++ b/packages/openchs-android/src/service/reports/DashboardFilterService.js @@ -59,6 +59,13 @@ class DashboardFilterService extends BaseService { return filterConfig; } + toRuleInputObjects(dashboardUUID, selectedFilterValues) { + const filterConfigs = this.getFilterConfigsForDashboard(dashboardUUID); + const thisService = this; + return Object.entries(selectedFilterValues) + .map(([filterUUID, filterValue]) => thisService.toRuleInputObject(filterConfigs[filterUUID], filterValue)); + } + toRuleInputObject(filterConfig, filterValue) { const ruleInput = new DashboardReportFilter(); ruleInput.type = filterConfig.type; diff --git a/packages/openchs-android/test/action/dashboard/FiltersActionsV2Test.js b/packages/openchs-android/test/action/dashboard/FiltersActionsV2Test.js deleted file mode 100644 index 2435c4e38..000000000 --- a/packages/openchs-android/test/action/dashboard/FiltersActionsV2Test.js +++ /dev/null @@ -1,24 +0,0 @@ -import {FiltersActionsV2} from "../../../src/action/mydashboard/FiltersActionsV2"; -import TestContext from "../views/testframework/TestContext"; -import {CustomFilter} from 'openchs-models'; -import TestDashboardFilterConfigFactory from "../../model/TestDashboardFilterConfigFactory"; -import TestDashboardFilterFactory from "../../model/TestDashboardFilterFactory"; -import {assert} from 'chai'; -import _ from 'lodash'; - -it('should update and apply date range filter', function () { - let state = FiltersActionsV2.getInitialState(); - const dashboardFilterConfig = TestDashboardFilterConfigFactory.create({type: CustomFilter.type.RegistrationDate, widget: CustomFilter.widget.Range}); - const dashboardFilter = TestDashboardFilterFactory.create({filterConfig: dashboardFilterConfig, uuid: "df1"}); - const capturedData = {}; - const testContext = new TestContext({filters: {"d": [dashboardFilter]}}, capturedData); - const today = new Date(); - - state = FiltersActionsV2.onLoad(state, {dashboardUUID: "d"}, testContext); - state = FiltersActionsV2.onFilterUpdate(state, {filter: dashboardFilter, value: {minValue: today}}); - state = FiltersActionsV2.onFilterUpdate(state, {filter: dashboardFilter, value: {maxValue: today}}); - FiltersActionsV2.appliedFilter(state, {navigateToDashboardView: _.noop, setFiltersDataOnDashboardView: _.noop}, testContext); - - assert.equal(_.isNil(capturedData.ruleInputFileConfig), false); - assert.equal(_.isNil(capturedData.ruleInputFilterValue), false); -});