diff --git a/packages/openchs-android/integrationTest/EntityApprovalServiceTest.js b/packages/openchs-android/integrationTest/EntityApprovalServiceTest.js index 000897503..ba799534c 100644 --- a/packages/openchs-android/integrationTest/EntityApprovalServiceTest.js +++ b/packages/openchs-android/integrationTest/EntityApprovalServiceTest.js @@ -32,7 +32,7 @@ class EntityApprovalServiceTest extends BaseIntegrationTest { entityTypeUuid: this.metadata.subjectType.uuid, approvalStatus: this.metadata.approvedStatus })); - const subject1 = db.create(Individual, TestSubjectFactory.createWithDefaults({ + db.create(Individual, TestSubjectFactory.createWithDefaults({ uuid: subject1Id, subjectType: this.metadata.subjectType, address: this.organisationData.addressLevel, @@ -48,7 +48,7 @@ class EntityApprovalServiceTest extends BaseIntegrationTest { entityTypeUuid: this.metadata.subjectType.uuid, approvalStatus: this.metadata.approvedStatus })); - const subject2 = db.create(Individual, TestSubjectFactory.createWithDefaults({ + db.create(Individual, TestSubjectFactory.createWithDefaults({ uuid: subject2Id, subjectType: this.metadata.subjectType, address: this.organisationData.addressLevel2, @@ -58,7 +58,7 @@ class EntityApprovalServiceTest extends BaseIntegrationTest { approvalStatuses: [subject2EAS] })); - const subject3 = db.create(Individual, TestSubjectFactory.createWithDefaults({ + this.subject3 = db.create(Individual, TestSubjectFactory.createWithDefaults({ uuid: subject3Id, subjectType: this.metadata.subjectType, address: this.organisationData.addressLevel2, @@ -73,22 +73,22 @@ class EntityApprovalServiceTest extends BaseIntegrationTest { entityTypeUuid: this.metadata.program.uuid, approvalStatus: this.metadata.approvedStatus })); - const programEnrolment = db.create(ProgramEnrolment, TestProgramEnrolmentFactory.create({ + const enrolment = db.create(ProgramEnrolment, TestProgramEnrolmentFactory.create({ uuid: enrolmentId, program: this.metadata.program, - subject: subject3, + subject: this.subject3, enrolmentDateTime: moment().add(-10, "day").toDate(), latestEntityApprovalStatus: null, observations: [TestObsFactory.create({concept: this.concept, valueJSON: JSON.stringify(this.concept.getValueWrapperFor("DEFPRG"))})], approvalStatuses: [enrolmentEAS] })); + this.subject3.addEnrolment(enrolment); }); this.service = this.getService(EntityApprovalStatusService); } getSubjectEASes() { - this.logQueries(); const subjects = this.service.getAllSubjects(this.metadata.approvedStatus.status, null); assert.equal(subjects.length, 3); assert.equal(subjects[0].firstName, "ABC"); diff --git a/packages/openchs-android/integrationTest/IntegrationTestApp.js b/packages/openchs-android/integrationTest/IntegrationTestApp.js index 104bfc762..b2179522c 100644 --- a/packages/openchs-android/integrationTest/IntegrationTestApp.js +++ b/packages/openchs-android/integrationTest/IntegrationTestApp.js @@ -14,6 +14,7 @@ import UserInfoServiceTest from "./UserInfoServiceTest"; import RealmProxyTest from "./RealmProxyTest"; import ReportCardServiceIntegrationTest from "./ReportCardServiceIntegrationTest"; import EntityApprovalServiceTest from "./EntityApprovalServiceTest"; +import IndividualIntegrationTest from "./model/IndividualIntegrationTest"; const itemCommonStyle = { padding: 10, @@ -63,7 +64,7 @@ class IntegrationTestApp extends Component { super(props, context); FileSystem.init(); this.getBean = this.getBean.bind(this); - this.integrationTestRunner = new IntegrationTestRunner(EntityApprovalServiceTest, ReportCardServiceIntegrationTest, UserInfoServiceTest, DatabaseTest, PersonRegisterActionsIntegrationTest, UtilTest, RealmProxyTest); + this.integrationTestRunner = new IntegrationTestRunner(IndividualIntegrationTest, EntityApprovalServiceTest, ReportCardServiceIntegrationTest, UserInfoServiceTest, DatabaseTest, PersonRegisterActionsIntegrationTest, UtilTest, RealmProxyTest); this.state = {isInitialisationDone: false, integrationTests: this.integrationTestRunner.testSuite}; } diff --git a/packages/openchs-android/integrationTest/model/IndividualIntegrationTest.js b/packages/openchs-android/integrationTest/model/IndividualIntegrationTest.js new file mode 100644 index 000000000..ae09fcde8 --- /dev/null +++ b/packages/openchs-android/integrationTest/model/IndividualIntegrationTest.js @@ -0,0 +1,89 @@ +import BaseIntegrationTest from "../BaseIntegrationTest"; +import TestOrganisationService from "../service/TestOrganisationService"; +import {Concept, EntityApprovalStatus, Individual, ProgramEnrolment} from "openchs-models"; +import TestConceptFactory from "../../test/model/TestConceptFactory"; +import TestMetadataService from "../service/TestMetadataService"; +import General from "../../src/utility/General"; +import TestEntityApprovalStatusFactory from "../../test/model/approval/TestEntityApprovalStatusFactory"; +import TestSubjectFactory from "../../test/model/txn/TestSubjectFactory"; +import TestObsFactory from "../../test/model/TestObsFactory"; +import TestProgramEnrolmentFactory from "../../test/model/txn/TestProgramEnrolmentFactory"; +import moment from "moment"; +import {assert} from "chai"; + +class IndividualIntegrationTest extends BaseIntegrationTest { + setup(): this { + super.setup(); + this.executeInWrite((db) => { + this.organisationData = TestOrganisationService.setupOrganisation(db); + this.concept = db.create(Concept, TestConceptFactory.createWithDefaults({dataType: Concept.dataType.Text})); + this.metadata = TestMetadataService.create(db); + }); + } + + getMemberEntitiesWithLatestStatus() { + this.executeInWrite((db) => { + const subject1Id = General.randomUUID(); + const enrolmentId = General.randomUUID(); + + const subject1EAS = db.create(EntityApprovalStatus, TestEntityApprovalStatusFactory.create({ + entityType: EntityApprovalStatus.entityType.Subject, + entityUUID: subject1Id, + entityTypeUuid: this.metadata.subjectType.uuid, + approvalStatus: this.metadata.approvedStatus + })); + this.subject = db.create(Individual, TestSubjectFactory.createWithDefaults({ + uuid: subject1Id, + subjectType: this.metadata.subjectType, + address: this.organisationData.addressLevel, + firstName: "XYZ", + lastName: "bar", + observations: [TestObsFactory.create({concept: this.concept, valueJSON: JSON.stringify(this.concept.getValueWrapperFor("ABC"))})], + approvalStatuses: [subject1EAS] + })); + const enrolmentEAS = db.create(EntityApprovalStatus, TestEntityApprovalStatusFactory.create({ + entityType: EntityApprovalStatus.entityType.ProgramEnrolment, + entityUUID: enrolmentId, + entityTypeUuid: this.metadata.program.uuid, + approvalStatus: this.metadata.approvedStatus + })); + const enrolment = db.create(ProgramEnrolment, TestProgramEnrolmentFactory.create({ + uuid: enrolmentId, + program: this.metadata.program, + subject: this.subject, + enrolmentDateTime: moment().add(-10, "day").toDate(), + observations: [TestObsFactory.create({concept: this.concept, valueJSON: JSON.stringify(this.concept.getValueWrapperFor("DEFPRG"))})], + approvalStatuses: [enrolmentEAS] + })); + this.subject.addEnrolment(enrolment); + }); + assert.equal(this.subject.getMemberEntitiesWithLatestStatus(this.metadata.approvedStatus.status).length, 2); + } + + getMemberEntitiesWithLatestStatus_WithoutApprovalStatuses() { + this.executeInWrite((db) => { + const subject1Id = General.randomUUID(); + const enrolmentId = General.randomUUID(); + + this.subject = db.create(Individual, TestSubjectFactory.createWithDefaults({ + uuid: subject1Id, + subjectType: this.metadata.subjectType, + address: this.organisationData.addressLevel, + firstName: "XYZ", + lastName: "bar", + observations: [TestObsFactory.create({concept: this.concept, valueJSON: JSON.stringify(this.concept.getValueWrapperFor("ABC"))})] + })); + const enrolment = db.create(ProgramEnrolment, TestProgramEnrolmentFactory.create({ + uuid: enrolmentId, + program: this.metadata.program, + subject: this.subject, + enrolmentDateTime: moment().add(-10, "day").toDate(), + observations: [TestObsFactory.create({concept: this.concept, valueJSON: JSON.stringify(this.concept.getValueWrapperFor("DEFPRG"))})] + })); + this.subject.addEnrolment(enrolment); + }); + assert.equal(this.subject.getMemberEntitiesWithLatestStatus(this.metadata.approvedStatus.status).length, 0); + } +} + +export default IndividualIntegrationTest; diff --git a/packages/openchs-android/package.json b/packages/openchs-android/package.json index 333e0e30a..708cd2e02 100644 --- a/packages/openchs-android/package.json +++ b/packages/openchs-android/package.json @@ -57,7 +57,7 @@ "lodash": "4.17.21", "moment": "2.29.4", "native-base": "3.4.9", - "openchs-models": "1.30.92", + "openchs-models": "1.30.95", "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 0671f282c..ba826bdb6 100644 --- a/packages/openchs-android/src/action/customDashboard/CustomDashboardActions.js +++ b/packages/openchs-android/src/action/customDashboard/CustomDashboardActions.js @@ -81,7 +81,7 @@ class CustomDashboardActions { const standardReportCardType = reportCard.standardReportCardType; const viewName = CustomDashboardActions._getViewName(standardReportCardType); if (!_.isNil(result)) { - setTimeout(() => action.onApprovalItemsResults(result, result.length, status, viewName), 0); + setTimeout(() => action.onApprovalItemsResults(result, status, viewName, standardReportCardType && standardReportCardType.getApprovalStatusForType()), 0); } } return newState; diff --git a/packages/openchs-android/src/service/customDashboard/ReportCardService.js b/packages/openchs-android/src/service/customDashboard/ReportCardService.js index d58b09c34..e5e8721a2 100644 --- a/packages/openchs-android/src/service/customDashboard/ReportCardService.js +++ b/packages/openchs-android/src/service/customDashboard/ReportCardService.js @@ -1,6 +1,6 @@ import BaseService from "../BaseService"; import Service from "../../framework/bean/Service"; -import {ReportCard, StandardReportCardType, ApprovalStatus} from "avni-models"; +import {ReportCard, StandardReportCardType, ApprovalStatus} from "openchs-models"; import EntityApprovalStatusService from "../EntityApprovalStatusService"; import RuleEvaluationService from "../RuleEvaluationService"; import IndividualService from "../IndividualService"; @@ -8,20 +8,9 @@ import CommentService from "../comment/CommentService"; import _ from "lodash"; import TaskService from "../task/TaskService"; import General from "../../utility/General"; -import {JSONStringify} from "../../utility/JsonStringify"; - -function getApprovalStatusForType(type) { - const typeToStatusMap = { - [StandardReportCardType.type.PendingApproval]: ApprovalStatus.statuses.Pending, - [StandardReportCardType.type.Approved]: ApprovalStatus.statuses.Approved, - [StandardReportCardType.type.Rejected]: ApprovalStatus.statuses.Rejected, - }; - return typeToStatusMap[type]; -} @Service("reportCardService") class ReportCardService extends BaseService { - constructor(db, context) { super(db, context); } @@ -30,8 +19,8 @@ class ReportCardService extends BaseService { return ReportCard.schema.name; } - getCountForApprovalCardsType(type, reportFilters) { - const approvalStatus_status = getApprovalStatusForType(type); + getCountForApprovalCardsType(standardReportCardType, reportFilters) { + const approvalStatus_status = standardReportCardType.getApprovalStatusForType(); const {result} = this.getService(EntityApprovalStatusService).getAllEntitiesForReports(approvalStatus_status, reportFilters) return { primaryValue: _.map(result, ({data}) => data.length).reduce((total, l) => total + l, 0), @@ -40,8 +29,8 @@ class ReportCardService extends BaseService { }; } - getResultForApprovalCardsType(type, reportFilters) { - const approvalStatus_status = getApprovalStatusForType(type); + getResultForApprovalCardsType(standardReportCardType, reportFilters) { + const approvalStatus_status = standardReportCardType.getApprovalStatusForType(); return this.getService(EntityApprovalStatusService).getAllSubjects(approvalStatus_status, reportFilters); } @@ -114,7 +103,7 @@ class ReportCardService extends BaseService { case _.isNil(standardReportCardType) : return this.getService(RuleEvaluationService).getDashboardCardCount(reportCard, reportFilters); case standardReportCardType.isApprovalType() : - return this.getCountForApprovalCardsType(standardReportCardType.name, reportFilters); + return this.getCountForApprovalCardsType(standardReportCardType, reportFilters); case standardReportCardType.isDefaultType() : return this.getCountForDefaultCardsType(standardReportCardType.name, reportFilters); case standardReportCardType.isCommentType() : @@ -135,7 +124,7 @@ class ReportCardService extends BaseService { return {status: null, result}; } case standardReportCardType.isApprovalType() : - return {status: null, result: this.getResultForApprovalCardsType(standardReportCardType.name, reportFilters)}; + return {status: null, result: this.getResultForApprovalCardsType(standardReportCardType, reportFilters)}; case standardReportCardType.isDefaultType() : return this.getResultForDefaultCardsType(standardReportCardType.name, reportFilters); case standardReportCardType.isCommentType() : { diff --git a/packages/openchs-android/src/utility/CHSNavigator.js b/packages/openchs-android/src/utility/CHSNavigator.js index 1d53b8902..18b8fcd08 100644 --- a/packages/openchs-android/src/utility/CHSNavigator.js +++ b/packages/openchs-android/src/utility/CHSNavigator.js @@ -89,8 +89,8 @@ class CHSNavigator { } } - static navigateToApprovalDetailsView(source, entity, schema) { - TypedTransition.from(source).with({entity, schema}).to(ApprovalDetailsView, true); + static navigateToApprovalDetailsView(source, entity) { + TypedTransition.from(source).with({entity}).to(ApprovalDetailsView, true); } static navigateToPhoneNumberVerificationView(source, next, observation, onSuccess, onSkip) { diff --git a/packages/openchs-android/src/utility/ErrorHandler.js b/packages/openchs-android/src/utility/ErrorHandler.js index e02521c63..9f37c268b 100644 --- a/packages/openchs-android/src/utility/ErrorHandler.js +++ b/packages/openchs-android/src/utility/ErrorHandler.js @@ -32,7 +32,7 @@ export default class ErrorHandler { const frameArray = x.map((row) => Object.defineProperty(row, 'fileName', { value: `${row.fileName}:${row.lineNumber || 0}:${row.columnNumber || 0}` })); - General.logDebug('ErrorHandler', `Notifying Bugsnag ${error}`); + General.logDebug('ErrorHandler', `Notifying Bugsnag (if release stage) ${error}`); bugsnag.notify(error, (report) => report.metadata.frameArray = frameArray); errorCallback(error, JSON.stringify(frameArray)); }); diff --git a/packages/openchs-android/src/views/approval/ApprovalDetailsCard.js b/packages/openchs-android/src/views/approval/ApprovalDetailsCard.js index a443496ed..a48b08906 100644 --- a/packages/openchs-android/src/views/approval/ApprovalDetailsCard.js +++ b/packages/openchs-android/src/views/approval/ApprovalDetailsCard.js @@ -1,76 +1,60 @@ import React from "react"; import AbstractComponent from "../../framework/view/AbstractComponent"; import PropTypes from 'prop-types'; -import {SafeAreaView, StyleSheet, Text, TouchableNativeFeedback, View} from "react-native"; +import {StyleSheet, Text, TouchableNativeFeedback, View} from "react-native"; import Styles from "../primitives/Styles"; -import Colors from "../primitives/Colors"; import moment from "moment"; class ApprovalDetailsCard extends AbstractComponent { - static propTypes = { - entity: PropTypes.object.isRequired, + approvableEntity: PropTypes.object.isRequired, + onApprovalSelection: PropTypes.func.isRequired }; constructor(props, context) { super(props, context); } - renderSubjectType(subjectTypeName) { - return ( - - {this.I18n.t(subjectTypeName)} - - ); - } - background() { return TouchableNativeFeedback.SelectableBackground(); } - renderRejectionComment(entity) { - return (entity.isRejectedEntity() ? + renderRejectionComment(approvableEntity) { + return (approvableEntity.isRejectedEntity() ? {entity.latestEntityApprovalStatus.approvalStatusComment} + style={styles.commentTextStyle}>{approvableEntity.latestEntityApprovalStatus.approvalStatusComment} : null) } render() { - const entity = this.props.entity; - const individual = entity.individual; - const nameToDisplay = individual.nameString; - const entityName = entity.getName(); - const subjectTypeName = individual.subjectTypeName; - const hrs = moment().diff(entity.latestEntityApprovalStatus.statusDateTime, 'hours'); - const cardHeight = entity.isRejectedEntity() ? 125 : 90; + const {approvableEntity, onApprovalSelection} = this.props; + const hrs = moment().diff(approvableEntity.latestEntityApprovalStatus.statusDateTime, 'hours'); + const cardHeight = approvableEntity.isRejectedEntity() ? 125 : 90; return ( - + onApprovalSelection(approvableEntity)} + background={TouchableNativeFeedback.SelectableBackground()}> - - - {nameToDisplay} - {this.I18n.t('requestName', {entityName})} - - - {this.renderSubjectType(subjectTypeName)} - - - {this.renderRejectionComment(entity)} + {this.I18n.t('requestName', {entityName: approvableEntity.getEntityTypeName()})} + {this.renderRejectionComment(approvableEntity)} {this.I18n.t('addXHoursAgo', {hrs})} + + {this.I18n.t(approvableEntity.getName())} + - + ); } } const styles = StyleSheet.create({ container: { - flexDirection: 'column', + flexDirection: 'row', paddingHorizontal: Styles.ContainerHorizontalDistanceFromEdge, paddingVertical: Styles.ContainerHorizontalDistanceFromEdge, + marginBottom: -20 }, leftContainer: { flexDirection: 'column', @@ -82,12 +66,12 @@ const styles = StyleSheet.create({ alignItems: 'flex-end', flex: 1 }, - headerTextStyle: { - fontSize: Styles.normalTextSize, + entityTypeText: { + fontSize: Styles.smallerTextSize, fontStyle: 'normal', - color: 'rgba(0, 0, 0, 0.87)', - lineHeight: 24, - fontFamily: 'Inner', + color: 'white', + backgroundColor: 'darkblue', + padding: 5 }, requestTextStyle: { fontSize: Styles.smallerTextSize, @@ -109,20 +93,6 @@ const styles = StyleSheet.create({ color: 'rgba(0, 0, 0, 0.87)', fontFamily: 'Inner', }, - subjectTypeContainer: { - height: 22, - marginRight: 5, - borderRadius: 3, - paddingHorizontal: 5, - backgroundColor: Colors.SubjectTypeColor, - paddingTop: 2 - }, - subjectTypeText: { - fontSize: Styles.smallerTextSize, - fontStyle: 'normal', - color: Styles.whiteColor, - } }); - export default ApprovalDetailsCard; diff --git a/packages/openchs-android/src/views/approval/ApprovalDetailsView.js b/packages/openchs-android/src/views/approval/ApprovalDetailsView.js index 5fda04ebc..0812a8d3f 100644 --- a/packages/openchs-android/src/views/approval/ApprovalDetailsView.js +++ b/packages/openchs-android/src/views/approval/ApprovalDetailsView.js @@ -35,8 +35,7 @@ import {ScrollView} from "native-base"; @Path('/approvalDetailsView') class ApprovalDetailsView extends AbstractComponent { static propTypes = { - entity: PropTypes.object.isRequired, - schema: PropTypes.string.isRequired + entity: PropTypes.object.isRequired }; constructor(props, context) { @@ -49,7 +48,7 @@ class ApprovalDetailsView extends AbstractComponent { } UNSAFE_componentWillMount() { - this.dispatchAction(Actions.ON_LOAD,{entity: this.props.entity, schema: this.props.schema}); + this.dispatchAction(Actions.ON_LOAD,{entity: this.props.entity, schema: this.props.entity.getSchemaName()}); super.UNSAFE_componentWillMount(); } @@ -68,7 +67,7 @@ class ApprovalDetailsView extends AbstractComponent { ) } - renderEntityDate(entity, schema, I18n) { + renderEntityDate(entity, I18n) { const schemaToDatePropertyMap = { [Individual.schema.name]: {label: I18n.t('registeredOn'), dateProperty: 'registrationDate'}, [ProgramEnrolment.schema.name]: {label: `${I18n.t('enrolmentDate')}: `, dateProperty: 'enrolmentDateTime'}, @@ -76,12 +75,12 @@ class ApprovalDetailsView extends AbstractComponent { [ProgramEncounter.schema.name]: {label: `${I18n.t('encounterDate')}: `, dateProperty: 'encounterDateTime'}, [ChecklistItem.schema.name]: {label: `${I18n.t('encounterDate')}: `, dateProperty: 'completionDate'} }; - const {label, dateProperty} = schemaToDatePropertyMap[schema]; + const {label, dateProperty} = schemaToDatePropertyMap[entity.getSchemaName()]; return {`${I18n.t(label)}${General.toDisplayDate(entity[dateProperty])}`} } - renderEditButton(entity, schema) { + renderEditButton(entity) { const clonedEntity = entity.cloneForEdit(); const schemaToActionMap = { [Individual.schema.name]: () => this.getNavigateToRegisterView(clonedEntity), @@ -95,7 +94,7 @@ class ApprovalDetailsView extends AbstractComponent { name={this.I18n.t('edit')} textColor={Colors.TextOnPrimaryColor} buttonColor={Colors.DarkPrimaryColor} - onPress={schemaToActionMap[schema]} + onPress={schemaToActionMap[entity.getSchemaName()]} extraStyle={{paddingHorizontal: 50}}/> } @@ -146,10 +145,10 @@ class ApprovalDetailsView extends AbstractComponent { } // TODO: the value for conditions in this method are interchanged. As for now, it has not caused issues since we are not doing much with the form. But need to fix it to avoid confusion. - findForm(schema, entity) { + findForm(entity) { const service = this.getService(FormMappingService); const get = property => _.get(entity, property); - switch (schema) { + switch (entity.getSchemaName()) { case(Individual.schema.name) : return service.findRegistrationForm(get('subjectType')); case(ProgramEnrolment.schema.name) : @@ -179,7 +178,6 @@ class ApprovalDetailsView extends AbstractComponent { const approvalStatus = entity.latestEntityApprovalStatus.approvalStatus; const showApproveReject = approvalStatus.isPending && this.state.showApprovalButtons; const showEdit = approvalStatus.isRejected && this.state.showEditButton; - const schema = this.props.schema; const confirmActionName = this.state.showInputBox ? Actions.ON_REJECT : Actions.ON_APPROVE; const observations = _.isEmpty(entity.observations) ? this.getCancelOrExitObs(entity) : entity.observations; return ( @@ -191,13 +189,13 @@ class ApprovalDetailsView extends AbstractComponent { {this.renderDetails(entity)} - {this.renderEntityDate(entity, schema, this.I18n)} + {this.renderEntityDate(entity, this.I18n)} {showApproveReject && this.renderApproveAndRejectButtons(entity, this.I18n)} - {showEdit && this.renderEditButton(entity, schema)} + {showEdit && this.renderEditButton(entity)} @@ -206,7 +204,7 @@ class ApprovalDetailsView extends AbstractComponent { secondaryButton={this.I18n.t('cancel')} onPrimaryPress={() => this.dispatchAction(confirmActionName, { entity, - schema, + schema: entity.getSchemaName(), cb: this.goBack.bind(this) })} onSecondaryPress={() => this.dispatchAction(Actions.ON_DIALOG_CLOSE)} diff --git a/packages/openchs-android/src/views/approval/ApprovalListingView.js b/packages/openchs-android/src/views/approval/ApprovalListingView.js index 17e7c07ec..48dca5a5a 100644 --- a/packages/openchs-android/src/views/approval/ApprovalListingView.js +++ b/packages/openchs-android/src/views/approval/ApprovalListingView.js @@ -2,31 +2,30 @@ import Path from "../../framework/routing/Path"; import AbstractComponent from "../../framework/view/AbstractComponent"; import PropTypes from "prop-types"; import General from "../../utility/General"; -import {SafeAreaView, SectionList, StyleSheet, Text, TouchableNativeFeedback, View} from "react-native"; +import {FlatList, SafeAreaView, StyleSheet, Text, TouchableNativeFeedback, View} from "react-native"; import CHSContainer from "../common/CHSContainer"; import Colors from "../primitives/Colors"; import AppHeader from "../common/AppHeader"; import React from "react"; -import ApprovalDetailsCard from "./ApprovalDetailsCard"; import DropDownPicker from 'react-native-dropdown-picker'; -import {ReportCard} from 'openchs-models'; -import _ from 'lodash'; +import {getUnderlyingRealmCollection, Individual, ReportCard} from 'openchs-models'; import EntityService from "../../service/EntityService"; import ReportCardService from "../../service/customDashboard/ReportCardService"; import Icon from 'react-native-vector-icons/FontAwesome'; import FormMappingService from "../../service/FormMappingService"; -import {ScrollView} from "native-base"; +import SubjectApprovalView from "./SubjectApprovalView"; const placeHolderPicker = {label: 'All', value: {schema: null, filterQuery: null}}; @Path('/approvalListingView') class ApprovalListingView extends AbstractComponent { static propTypes = { - results: PropTypes.array.isRequired, + results: PropTypes.object.isRequired, onApprovalSelection: PropTypes.func.isRequired, headerTitle: PropTypes.string.isRequired, backFunction: PropTypes.func.isRequired, - reportCardUUID: PropTypes.string.isRequired + reportCardUUID: PropTypes.string.isRequired, + approvalStatus_status: PropTypes.string.isRequired }; constructor(props, context) { @@ -50,20 +49,6 @@ class ApprovalListingView extends AbstractComponent { } } - renderItem(item, section, onApprovalSelection) { - const entity = item; - const schema = section.title; - return ( - onApprovalSelection(this, item, schema)} - background={TouchableNativeFeedback.SelectableBackground()}> - - - - - ) - } - onFilterChange({value}) { const schemaAndQueryFilter = value; const reportCard = this.getService(EntityService).findByUUID(this.props.reportCardUUID, ReportCard.schema.name); @@ -77,20 +62,16 @@ class ApprovalListingView extends AbstractComponent { renderFilter(title) { const {allFilterItems, filterPickerOpened, selectedFilterPicker, results} = this.state; - - const total = _.map(results, ({data}) => data.length).reduce((total, l) => total + l, 0); - const maxFormLength = _.max(_.map(allFilterItems, ({label}) => label.length)); return ( - {`Showing ${total} ${title} requests`} + {`Total ${results.length} subjects`} this.openFilterPicker(value)} - containerStyle={{height: maxFormLength}} itemStyle={{justifyContent: 'flex-start'}} placeholder={'Select type'} dropDownStyle={{backgroundColor: '#fafafa'}} @@ -110,40 +91,28 @@ class ApprovalListingView extends AbstractComponent { } render() { - General.logDebug(this.viewName(), 'render'); + General.logDebug("ApprovalListingView", 'render'); const title = this.props.headerTitle; - const onApprovalSelection = this.props.onApprovalSelection; return ( {this.renderFilter(this.I18n.t(title))} - - - item.uuid} - renderItem={({item, section}) => this.renderItem(item, section, onApprovalSelection)} - initialNumToRender={50} - updateCellsBatchingPeriod={500} - maxToRenderPerBatch={20} - /> - - + item.uuid} + renderItem={(x) => + this.props.onApprovalSelection(this, entity)}/>} + initialNumToRender={50} + updateCellsBatchingPeriod={500} + maxToRenderPerBatch={20} + /> ) } - } const styles = StyleSheet.create({ - cardContainer: { - marginHorizontal: 16, - elevation: 2, - backgroundColor: Colors.cardBackgroundColor, - marginVertical: 5, - paddingBottom: 5, - borderRadius: 5, - }, filterContainer: { marginHorizontal: 16, marginVertical: 20, @@ -152,5 +121,4 @@ const styles = StyleSheet.create({ } }); - export default ApprovalListingView; diff --git a/packages/openchs-android/src/views/approval/SubjectApprovalView.js b/packages/openchs-android/src/views/approval/SubjectApprovalView.js new file mode 100644 index 000000000..3432dfdb2 --- /dev/null +++ b/packages/openchs-android/src/views/approval/SubjectApprovalView.js @@ -0,0 +1,59 @@ +import AbstractComponent from "../../framework/view/AbstractComponent"; +import {StyleSheet, Text, TouchableNativeFeedback, View} from "react-native"; +import Styles from "../primitives/Styles"; +import ApprovalDetailsCard from "./ApprovalDetailsCard"; +import React from "react"; +import Colors from "../primitives/Colors"; +import PropTypes from "prop-types"; + +class SubjectApprovalView extends AbstractComponent { + static propTypes = { + subject: PropTypes.object.isRequired, + approvalStatus_status: PropTypes.string.isRequired, + onApprovalSelection: PropTypes.func.isRequired + }; + + render() { + const {subject, approvalStatus_status} = this.props; + const nameToDisplay = subject.nameString; + + return + + + + {nameToDisplay} + + + {subject.getMemberEntitiesWithLatestStatus(approvalStatus_status).map((x) => + this.props.onApprovalSelection(x)}/>)} + + ; + } +} + +const styles = StyleSheet.create({ + cardContainer: { + marginHorizontal: 16, + elevation: 2, + backgroundColor: Colors.cardBackgroundColor, + marginVertical: 5, + borderRadius: 5, + }, + leftContainer: { + flexDirection: 'column', + alignItems: 'flex-start', + marginLeft: 10, + marginTop: 10, + flex: 1 + }, + auditTextStyle: { + fontSize: Styles.smallerTextSize, + marginTop: 6, + fontStyle: 'normal', + color: 'rgba(0, 0, 0, 0.54)', + fontFamily: 'Inner', + } +}); + +export default SubjectApprovalView; diff --git a/packages/openchs-android/src/views/customDashboard/CustomDashboardView.js b/packages/openchs-android/src/views/customDashboard/CustomDashboardView.js index 5bc618500..ad01ae1f1 100644 --- a/packages/openchs-android/src/views/customDashboard/CustomDashboardView.js +++ b/packages/openchs-android/src/views/customDashboard/CustomDashboardView.js @@ -176,16 +176,16 @@ class CustomDashboardView extends AbstractComponent { indicatorActionName: Actions.LOAD_INDICATOR }).to(TaskListView); }, - onApprovalItemsResults: (results, count, status, viewName) => TypedTransition.from(this).with({ + onApprovalItemsResults: (results, status, viewName, approvalStatus_status) => TypedTransition.from(this).with({ + approvalStatus_status: approvalStatus_status, indicatorActionName: Actions.LOAD_INDICATOR, headerTitle: status || 'subjectsList', results: results, - totalSearchResultsCount: count, reportCardUUID, listType: _.lowerCase(status), backFunction: this.onBackPress.bind(this), onIndividualSelection: (source, individual) => CHSNavigator.navigateToProgramEnrolmentDashboardView(source, individual.uuid), - onApprovalSelection: (source, entity, schema) => CHSNavigator.navigateToApprovalDetailsView(source, entity, schema), + onApprovalSelection: (source, entity) => CHSNavigator.navigateToApprovalDetailsView(source, entity), }).to(this.getViewByName(viewName), true) }), 0); } diff --git a/packages/openchs-android/test/model/txn/TestProgramEnrolmentFactory.js b/packages/openchs-android/test/model/txn/TestProgramEnrolmentFactory.js index d5be102bc..7906a9b44 100644 --- a/packages/openchs-android/test/model/txn/TestProgramEnrolmentFactory.js +++ b/packages/openchs-android/test/model/txn/TestProgramEnrolmentFactory.js @@ -23,7 +23,6 @@ class TestProgramEnrolmentFactory { programEnrolment.enrolmentDateTime = enrolmentDateTime; programEnrolment.approvalStatuses = approvalStatuses; programEnrolment.setLatestEntityApprovalStatus(latestEntityApprovalStatus); - return programEnrolment; } }