diff --git a/app/javascript/components/permissions/constants.js b/app/javascript/components/permissions/constants.js index 3c513dc014..ddde945315 100644 --- a/app/javascript/components/permissions/constants.js +++ b/app/javascript/components/permissions/constants.js @@ -111,6 +111,7 @@ export const ACTIONS = { SERVICES_SECTION_FROM_CASE: "services_section_from_case", SYNC_EXTERNAL: "sync_external", TRANSFER: "transfer", + VERIFY_MRM: "verify_mrm", VIEW_INCIDENT_FROM_CASE: "view_incident_from_case", VIEW_REGISTRY_RECORD: "view_registry_record", VIOLATIONS: "violations", diff --git a/app/javascript/components/permissions/constants.unit.test.js b/app/javascript/components/permissions/constants.unit.test.js index eca094ff73..48bc7d0a71 100644 --- a/app/javascript/components/permissions/constants.unit.test.js +++ b/app/javascript/components/permissions/constants.unit.test.js @@ -119,6 +119,7 @@ describe("Verifying config constant", () => { "WORKFLOW_REPORT", "SYNC_EXTERNAL", "TRANSFER", + "VERIFY_MRM", "VIEW_FAMILY_RECORD", "VIEW_INCIDENT_FROM_CASE", "VIEW_REGISTRY_RECORD", diff --git a/app/javascript/components/record-actions/constants.js b/app/javascript/components/record-actions/constants.js index ac1a313891..b377edeb61 100644 --- a/app/javascript/components/record-actions/constants.js +++ b/app/javascript/components/record-actions/constants.js @@ -63,5 +63,6 @@ export const RECORD_ACTION_ABILITIES = { canRequestGbvClosure: [ACTIONS.MANAGE, ACTIONS.REQUEST_APPROVAL_GBV_CLOSURE], canShowExports: SHOW_EXPORTS, canTransfer: [ACTIONS.MANAGE, ACTIONS.TRANSFER], - canMarkForOffline: [ACTIONS.MANAGE, ACTIONS.MARK_FOR_OFFLINE] + canMarkForOffline: [ACTIONS.MANAGE, ACTIONS.MARK_FOR_OFFLINE], + canVerify: [ACTIONS.MANAGE,ACTIONS.VERIFY_MRM] }; diff --git a/app/javascript/components/record-actions/constants.unit.test.js b/app/javascript/components/record-actions/constants.unit.test.js index 87f5307823..49e9b4c868 100644 --- a/app/javascript/components/record-actions/constants.unit.test.js +++ b/app/javascript/components/record-actions/constants.unit.test.js @@ -69,7 +69,8 @@ describe(" - Constants", () => { "canRequestGbvClosure", "canShowExports", "canTransfer", - "canMarkForOffline" + "canMarkForOffline", + "canVerify" ].forEach(property => { expect(recordActionAbilities).to.have.property(property); delete recordActionAbilities[property]; diff --git a/app/javascript/components/record-form/form/subforms/styles.css b/app/javascript/components/record-form/form/subforms/styles.css index adf6daae16..ffb943de07 100644 --- a/app/javascript/components/record-form/form/subforms/styles.css +++ b/app/javascript/components/record-form/form/subforms/styles.css @@ -1,5 +1,16 @@ /* Copyright (c) 2014 - 2023 UNICEF. All rights reserved. */ +.verifiedSpan{ + color: var(--c-white); + height: 25px; + font-size: var(--fs-13); + font-weight: 600; + float: right; + top: 12px; + position: absolute; + left: 79%; + width: 115px; +} .secondarySubformHeader { font-size: var(--fs-12); color: var(--c-dark-grey); @@ -196,3 +207,8 @@ padding-top: 0px; } } + +.keyboardDatePickerWrapper { + display: flex; + justify-content: space-between; +} \ No newline at end of file diff --git a/app/javascript/components/record-form/form/subforms/subform-fields/component.jsx b/app/javascript/components/record-form/form/subforms/subform-fields/component.jsx index 1f51f78fcf..20565e4a93 100644 --- a/app/javascript/components/record-form/form/subforms/subform-fields/component.jsx +++ b/app/javascript/components/record-form/form/subforms/subform-fields/component.jsx @@ -178,6 +178,7 @@ const Component = ({ renderSecondaryText={Boolean(entryFilter)} associatedViolations={associatedViolations} parentTitle={parentTitle} + mode={mode} /> {isTracesSubform && } diff --git a/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/component.jsx b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/component.jsx index bcf2d11cbb..99d2a12586 100644 --- a/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/component.jsx +++ b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/component.jsx @@ -1,19 +1,128 @@ -// Copyright (c) 2014 - 2023 UNICEF. All rights reserved. - +import { useEffect, useState } from "react"; +import { useDispatch } from "react-redux"; import PropTypes from "prop-types"; -import { ListItemText } from "@material-ui/core"; +import { ListItemText, Button } from "@material-ui/core"; +import { useParams } from "react-router-dom"; +import { KeyboardDatePicker, MuiPickersUtilsProvider } from "@material-ui/pickers"; +import DateFnsUtils from "@date-io/date-fns"; +import ActionDialog from "../../../../../../action-dialog"; import ViolationTitle from "../violation-title"; import css from "../../../styles.css"; +import { saveRecord } from "../../../../../../records"; +import { usePermissions } from "../../../../../../permissions"; +import { RECORD_ACTION_ABILITIES } from "../../../../../../record-actions/constants"; +import { useI18n } from "../../../../../../i18n"; +import { toServerDateFormat } from "../../../../../../../libs"; -import { NAME } from "./constants"; +import VerifySelect from "./select"; import { getViolationTallyLabel } from "./utils"; +import { NAME } from "./constants"; -const Component = ({ fields, values, locale, displayName, index, collapsedFieldValues }) => { +const Component = ({ fields, values, locale, displayName, index, collapsedFieldValues, mode }) => { const currentValues = values[index]; + const verifyParams = useParams(); + const i18n = useI18n(); + const DATE_FORMAT = "dd-MMM-yyyy"; + + // State variables + const dispatch = useDispatch(); + const [verifyModal, setVerifyModal] = useState(false); + const [verificationValue, setVerificationValue] = useState(currentValues?.ctfmr_verified || ""); + const [selectedDate, setSelectedDate] = useState(new Date()); + const [validationError, setValidationError] = useState(""); + const maxDate = new Date(); + + useEffect(() => { + // Changing dropdown select value when backend data updated + setVerificationValue(currentValues?.ctfmr_verified); + }, [currentValues?.ctfmr_verified]); + + const handleDropdownDate = date => { + if (selectedDate) { + setSelectedDate(date); + } else { + setValidationError("date should not be null"); + setSelectedDate(null); + } + }; + + const handleOpenVerifyModal = (idx, event) => { + // To open verify dialog confirmation popup + event.stopPropagation(); + setVerifyModal(true); + }; + + const cancelVerifyHandler = () => { + // To close verify dialog popup + setVerifyModal(false); + }; + const { canVerify } = usePermissions("incidents", RECORD_ACTION_ABILITIES); // check permission to verify violations const violationTally = getViolationTallyLabel(fields, currentValues, locale); + const handleOk = () => { + // To update the verify status to Verified + + dispatch( + saveRecord( + verifyParams.recordType, + "update", + { + data: { + [currentValues.type]: [ + { + unique_id: currentValues.unique_id, + ctfmr_verified: verificationValue, + ctfmr_verified_date: toServerDateFormat(selectedDate) + } + ] + } + }, // Save API Call + verifyParams.id, + "Updated successfully", + "", + false, + false + ) + ); + // close(); + }; + + // Define VerifySelect component + const VerifySelectComponent = ( + + ); + + const keyboardDatePickerInputStyles = { + borderColor: validationError ? "red" : undefined, + marginLeft: "5px" // Add left margin here + }; + + // Define MuiPickersUtilsProvider component + const MuiPickersUtilsProviderComponent = ( + +
+ +
+
+ ); + return ( } > + {canVerify && mode.isShow ? ( + + ) : null} + + + {VerifySelectComponent} + {verificationValue === "verified" ? MuiPickersUtilsProviderComponent : null} + ); }; @@ -37,6 +171,7 @@ Component.propTypes = { fields: PropTypes.array.isRequired, index: PropTypes.number.isRequired, locale: PropTypes.string.isRequired, + mode: PropTypes.object.isRequired, values: PropTypes.array.isRequired }; diff --git a/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/select.jsx b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/select.jsx new file mode 100644 index 0000000000..a85e195779 --- /dev/null +++ b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/select.jsx @@ -0,0 +1,63 @@ +import { Box, FormControl, MenuItem, Select } from "@material-ui/core"; +import useOptions from "../../../../../../form/use-options"; +import { LOOKUPS } from "../../../../../../../config"; +import css from "./styles.css" +import PropTypes from "prop-types"; + +const MENU_PROPS = { + getContentAnchorEl: null, + anchorOrigin: { + vertical: "bottom", + horizontal: 'left' + }, + transformOrigin: { + vertical: "top", + horizontal: 'left' + } +} + +const Component = ({ selectedValue, setSelectedValue }) => { + + const verificationStatus = useOptions({ source: LOOKUPS.verification_status }); + + const handleChange = (event) => { // Change dropdown value + setSelectedValue(event.target.value); + }; + + const onSel = true; + + return ( + + + + + + ); +} +Component.propTypes = { + selectedValue: PropTypes.string, + setSelectedValue: PropTypes.string +}; + +Component.displayName = "VerifySelect"; + +export default Component; diff --git a/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/styles.css b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/styles.css new file mode 100644 index 0000000000..87118acf65 --- /dev/null +++ b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-item/styles.css @@ -0,0 +1,22 @@ + +.verifyFormControlRoot { + padding: 4px; +} + +.verifySelectComponent { + padding: 12px !important; + border-radius: 4px; + border-bottom: none; +} + +.verifySelectComponentSelect, .verifySelectComponentSelect:focus { + border-radius: 4px; +} + +.verifySelectComponent[aria-expanded="true"], .verifySelectComponent:focus { + outline: 4px solid var(--c-light-blue-rgba); +} + +.selectWrapper { + min-width: 150px; +} \ No newline at end of file diff --git a/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-title/component.jsx b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-title/component.jsx index 9a8de51d94..4133e54144 100644 --- a/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-title/component.jsx +++ b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-title/component.jsx @@ -22,8 +22,8 @@ const Component = ({ title, values, fields }) => { ) : null; return ( -
-
+
+
{title} {renderShortUniqueId}
{renderChipStatus}
diff --git a/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-title/styles.css b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-title/styles.css index ec355fc729..cf1e1c9350 100644 --- a/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-title/styles.css +++ b/app/javascript/components/record-form/form/subforms/subform-fields/components/violation-title/styles.css @@ -4,16 +4,26 @@ color: var(--c-white); border: solid 1px var(--c-blue); background-color: var(--c-blue); + width: 120px ; + word-wrap: normal; } .container { display: inline-flex; gap: var(--sp-2); - align-items: center; + align-items: flex-start; } .title { display: flex; align-items: center; margin-top: 0.1em; -} \ No newline at end of file +} + +.titleViolation { + display: flex; + align-items: center; + margin-top: 0.1em; + width: 300px !important; + word-wrap: normal !important; +} diff --git a/app/javascript/components/record-form/form/subforms/subform-header/component.jsx b/app/javascript/components/record-form/form/subforms/subform-header/component.jsx index 650936b514..9af80d1103 100644 --- a/app/javascript/components/record-form/form/subforms/subform-header/component.jsx +++ b/app/javascript/components/record-form/form/subforms/subform-header/component.jsx @@ -27,7 +27,8 @@ const Component = ({ isViolationSubform, associatedViolations, renderSecondaryText = false, - parentTitle + parentTitle, + mode }) => { const i18n = useI18n(); const { collapsed_field_names: collapsedFieldNames, fields } = field.subform_section_id; @@ -104,6 +105,7 @@ const Component = ({ values={values} index={index} collapsedFieldValues={subformValues} + mode={mode} /> ); } @@ -140,9 +142,10 @@ Component.propTypes = { index: PropTypes.number.isRequired, isViolationSubform: PropTypes.bool, locale: PropTypes.string.isRequired, + mode: PropTypes.object.isRequired, parentTitle: PropTypes.string, renderSecondaryText: PropTypes.bool, - values: PropTypes.array.isRequired + values: PropTypes.array.isRequired }; export default Component; diff --git a/app/models/permission.rb b/app/models/permission.rb index 9aebdad551..f5198c7f08 100644 --- a/app/models/permission.rb +++ b/app/models/permission.rb @@ -16,6 +16,7 @@ class Permission < ValueObject # If the role_unique_ids property is empty on a ROLE permission, then that allows this role to manage all other ROLES attr_accessor :resource, :actions, :role_unique_ids, :agency_unique_ids, :managed_report_scope + VERIFY_MRM = 'verify_mrm' READ = 'read' WRITE = 'write' ENABLE_DISABLE_RECORD = 'enable_disable_record' @@ -195,7 +196,7 @@ class Permission < ValueObject INCIDENT => [ READ, CREATE, WRITE, ENABLE_DISABLE_RECORD, FLAG, FLAG_RESOLVE_ANY, EXPORT_LIST_VIEW, EXPORT_CSV, EXPORT_EXCEL, EXPORT_PDF, EXPORT_INCIDENT_RECORDER, EXPORT_JSON, EXPORT_CUSTOM, IMPORT, SYNC_MOBILE, CHANGE_LOG, - EXPORT_MRM_VIOLATION_XLS, REMOVE_ALERT, ASSIGN, MANAGE + EXPORT_MRM_VIOLATION_XLS, REMOVE_ALERT, VERIFY_MRM, ASSIGN, MANAGE ], TRACING_REQUEST => [ READ, CREATE, WRITE, ENABLE_DISABLE_RECORD, FLAG, FLAG_RESOLVE_ANY, EXPORT_LIST_VIEW, EXPORT_CSV, EXPORT_EXCEL, diff --git a/config/locales/en.yml b/config/locales/en.yml index fe89ebc5fa..0897ec7fe3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1504,6 +1504,7 @@ en: military_use: Military use of school(s) and/or hospital(s) denial_humanitarian_access: Denial of humanitarian access for children incidents: + change_status: Change Status disable_dialog: Clicking OK will change the status of this incident to Disabled. disable_dialog_title: Disable Incident disable_success: Successfully disabled incident @@ -1585,6 +1586,7 @@ en: survivor_code: Survivor Code show_incident: 'Incident ID %{short_id}' social_worker: Social Worker + verify_mrm: Verify MRM violation_type: Violation Type violence_type: Violence Type type_violence: Type of Violence @@ -2393,6 +2395,7 @@ en: transfer: Can be used for transfer user: Users user_group: User Groups + verify_mrm: Verify MRM view_approvals: View Approvals view_assessment: View Assessment view_photo: View Photo @@ -3308,6 +3311,9 @@ en: also cannot sync their mobile devices with the web application in general, meaning that they cannot use the mobile app to manage incidents. label: Sync with mobile device + verify_mrm: + explanation: MRM user can change the status of violations. + label: Verify MRM write: explanation: Ability to click the "Edit" button, update information about the incident, and click "Save". Also allows the user to disable or enable