From 9b568e14cd3840bc9505004543f4a82a23ccdcda Mon Sep 17 00:00:00 2001 From: Mat Busby <83598933+matbusby-fw@users.noreply.github.com> Date: Tue, 10 Oct 2023 13:12:45 -0600 Subject: [PATCH] [MDS-5353] ESUP Modal updates (#2705) * Add Explosives Permit form and Remove token after complete download New form has been created to handle the addition of explosives permits. Form will handle business rules validations, state, and UI. Ant.design and redux-form have been used to handle state management and UI. In addition, a minor bug fix was implemented in the document.py file to ensure that the cache for downloading documents get deleted after the download operation completes. This is to prevent reuse of the same token for downloading multiple documents, which could be a potential security vulnerability. Styles have also been tweaked for MinePermitTable, Modal, and new styles for ExplosivesPermits have been created. Re-ordered import statements to keep maintain consistency and readability across the code base. * "Remove unnecessary defaultProps from DocumentTable component The defaultProps object in DocumentTable.tsx was removed because it was not being used bring any value to the declared component. The methods: openModal and closeModal, defined in this object, were not applied in the component. It enhances readability by removing unused parts of code." * Remove unused dataIndex from ExplosivesPermitTable * address PR comments --- Makefile | 2 +- services/common/src/utils/featureFlag.ts | 1 + .../models/explosives_permit.py | 3 +- .../core-web/src/assets/icons/violet-edit.js | 15 + .../ExplosivesPermitFormNew.tsx | 432 ++++++++++++++++++ .../ExplosivesPermit/MagazineFormNew.tsx | 308 +++++++++++++ .../src/components/common/ActionMenu.tsx | 47 ++ .../src/components/common/DocumentTable.tsx | 38 +- .../common/wrappers/ModalWrapper.js | 26 +- .../ExplosivesPermit/ExplosivesPermit.tsx | 30 +- .../mine/ExplosivesPermit/Magazine.tsx | 80 ++++ .../MineExplosivesPermitTable.tsx | 279 ++++++----- .../modalContent/AddExplosivesPermitModal.tsx | 18 +- .../ExplosivesPermitViewModal.tsx | 292 ++++++++++++ .../src/components/modalContent/config.js | 2 + .../styles/components/ExplosivesPermits.scss | 35 ++ .../styles/components/MinePermitTable.scss | 5 + .../core-web/src/styles/components/Modal.scss | 2 + .../src/styles/elements/elements.scss | 14 +- .../core-web/src/styles/generic/layout.scss | 8 +- services/core-web/src/styles/index.scss | 1 + .../__snapshots__/ModalWrapper.spec.js.snap | 16 +- .../ExplosivesPermit.spec.js.snap | 1 + .../backend/app/docman/resources/document.py | 2 +- 24 files changed, 1456 insertions(+), 201 deletions(-) create mode 100644 services/core-web/src/assets/icons/violet-edit.js create mode 100644 services/core-web/src/components/Forms/ExplosivesPermit/ExplosivesPermitFormNew.tsx create mode 100644 services/core-web/src/components/Forms/ExplosivesPermit/MagazineFormNew.tsx create mode 100644 services/core-web/src/components/common/ActionMenu.tsx create mode 100644 services/core-web/src/components/mine/ExplosivesPermit/Magazine.tsx create mode 100644 services/core-web/src/components/modalContent/ExplosivesPermitViewModal.tsx create mode 100644 services/core-web/src/styles/components/ExplosivesPermits.scss diff --git a/Makefile b/Makefile index 470f4c6faf..688861ed81 100644 --- a/Makefile +++ b/Makefile @@ -68,7 +68,7 @@ ms: extra: @echo "+\n++ Building tertiary services ...\n+" - @docker-compose $(DC_FILE) up -d minespace docgen-api + @docker-compose $(DC_FILE) up -d docgen-api # Simply for legacy support, this command will be retired shortly fe: diff --git a/services/common/src/utils/featureFlag.ts b/services/common/src/utils/featureFlag.ts index 3613b0d255..f9c842062e 100644 --- a/services/common/src/utils/featureFlag.ts +++ b/services/common/src/utils/featureFlag.ts @@ -6,6 +6,7 @@ export enum Feature { DOCUMENTS_REPLACE_FILE = "major_project_replace_file", MAJOR_PROJECT_ALL_DOCUMENTS = "major_project_all_documents", MAJOR_PROJECT_DECISION_PACKAGE = "major_project_decision_package", + ESUP_PERMIT_AMENDMENT = "esup_permit_amendment", FLAGSMITH = "flagsmith", TSF_V2 = "tsf_v2", } diff --git a/services/core-api/app/api/mines/explosives_permit/models/explosives_permit.py b/services/core-api/app/api/mines/explosives_permit/models/explosives_permit.py index b33207bec5..b7ce70994c 100644 --- a/services/core-api/app/api/mines/explosives_permit/models/explosives_permit.py +++ b/services/core-api/app/api/mines/explosives_permit/models/explosives_permit.py @@ -122,7 +122,8 @@ def process_magazines(magazines, updated_magazines, type): if explosives_permit_magazine_id: magazine = ExplosivesPermitMagazine.find_by_explosives_permit_magazine_id( explosives_permit_magazine_id) - magazine.update_from_data(magazine_data) + if magazine: + magazine.update_from_data(magazine_data) else: magazine = ExplosivesPermitMagazine.create_from_data(type, magazine_data) magazines.append(magazine) diff --git a/services/core-web/src/assets/icons/violet-edit.js b/services/core-web/src/assets/icons/violet-edit.js new file mode 100644 index 0000000000..ae74bb757b --- /dev/null +++ b/services/core-web/src/assets/icons/violet-edit.js @@ -0,0 +1,15 @@ +import React from "react"; +import Icon from "@ant-design/icons"; + +const EditSvg = () => ( + + + +); + +const VioletEditIcon = (props) => ; + +export default VioletEditIcon; diff --git a/services/core-web/src/components/Forms/ExplosivesPermit/ExplosivesPermitFormNew.tsx b/services/core-web/src/components/Forms/ExplosivesPermit/ExplosivesPermitFormNew.tsx new file mode 100644 index 0000000000..9d4244f484 --- /dev/null +++ b/services/core-web/src/components/Forms/ExplosivesPermit/ExplosivesPermitFormNew.tsx @@ -0,0 +1,432 @@ +import React, { FC, useEffect, useState } from "react"; +import { connect } from "react-redux"; +import { bindActionCreators, compose } from "redux"; +import { change, Field, formValueSelector, getFormValues, reduxForm } from "redux-form"; +import { Form } from "@ant-design/compatible"; +import "@ant-design/compatible/assets/index.css"; +import { Alert, Button, Col, Popconfirm, Row, Table, Typography } from "antd"; +import { getUserAccessData } from "@common/selectors/authenticationSelectors"; +import { USER_ROLES } from "@mds/common"; +import { getNoticeOfWorkList } from "@common/selectors/noticeOfWorkSelectors"; +import { + dateNotInFuture, + lat, + lon, + lonNegative, + maxLength, + number, + required, +} from "@common/utils/Validate"; +import { createDropDownList, formatDate, resetForm } from "@common/utils/helpers"; +import { + getAllPartyRelationships, + getPartyRelationships, +} from "@common/selectors/partiesSelectors"; +import { getPermits } from "@common/selectors/permitSelectors"; +import { renderConfig } from "@/components/common/config"; +import * as FORM from "@/constants/forms"; +import ExplosivesPermitMap from "@/components/maps/ExplosivesPermitMap"; +import DocumentCategoryForm from "@/components/Forms/DocumentCategoryForm"; +import * as Permission from "@/constants/permissions"; +import MagazineFormNew from "@/components/Forms/ExplosivesPermit/MagazineFormNew"; +import { + generatedDocColumns, + supportingDocColumns, +} from "@/components/modalContent/ExplosivesPermitViewModal"; + +const defaultProps = { + initialValues: {}, + mines_permit_guid: null, +}; + +const validateBusinessRules = (values) => { + const errors: any = {}; + if (!values.mine_manager_mine_party_appt_id) { + errors.mine_manager_mine_party_appt_id = "The Site must have a Mine Manager on record."; + } + if (!values.permittee_mine_party_appt_id) { + errors.permittee_mine_party_appt_id = "The Permit must have a Permittee on record."; + } + return errors; +}; + +interface ExplosivesPermitFormNewProps { + handleSubmit?: any; + closeModal?: any; + initialValues: any; + mineGuid: string; + isProcessed?: boolean; + documentTypeDropdownOptions: any; + isPermitTab: boolean; + inspectors: any; + submitting?: boolean; + noticeOfWorkApplications?: any; + permits?: any; + formValues?: any; + partyRelationships?: any; + allPartyRelationships?: any; + mines_permit_guid?: string; + userRoles?: any; +} + +export const ExplosivesPermitFormNew: FC = (props) => { + const { initialValues } = props; + + const [generatedDocs, setGeneratedDocs] = useState([]); + const [supportingDocs, setSupportingDocs] = useState([]); + + const partiesData = props.isPermitTab ? props.allPartyRelationships : props.partyRelationships; + const mineManagers = partiesData.filter( + ({ mine_party_appt_type_code }) => mine_party_appt_type_code === "MMG" + ); + const permittee = partiesData.filter( + ({ mine_party_appt_type_code, related_guid }) => + mine_party_appt_type_code === "PMT" && related_guid === props.mines_permit_guid + ); + + useEffect(() => { + if (initialValues.documents) { + const generatedTypes = ["LET", "PER"]; + setGeneratedDocs( + initialValues.documents.filter((doc) => + generatedTypes.includes(doc.explosives_permit_document_type_code) + ) + ); + setSupportingDocs( + initialValues.documents.filter( + (doc) => !generatedTypes.includes(doc.explosives_permit_document_type_code) + ) + ); + } + }, [initialValues]); + + const dropdown = (array) => + array.length > 0 + ? array.map((item) => { + const endDate = formatDate(item.end_date) || "Present"; + return { + value: item.mine_party_appt_id, + label: `${item.party.name} (${formatDate(item.start_date)} - ${endDate})`, + }; + }) + : []; + const mineManagersDropdown = dropdown(mineManagers); + const permitteeDropdown = dropdown(permittee); + const permitDropdown = createDropDownList(props.permits, "permit_no", "permit_guid"); + const nowDropdown = createDropDownList( + props.noticeOfWorkApplications, + "now_number", + "now_application_guid" + ); + + const isHistoric = !props.initialValues?.explosives_permit_id && props.isPermitTab; + const isESUP = props.userRoles.includes(USER_ROLES[Permission.EDIT_EXPLOSIVES_PERMITS]); + + const disabled = props.isProcessed; // props.isProcessed && !hasEditPermission; + return ( +
+ +
  • + To add information from a previously created permit, go to the + permits page and add an existing permit +
  • +
  • To amend an explosives storage and use permit, open it and create an ammendment
  • + + } + type="info" + showIcon + /> + +
    + + Create Explosives Storage and Use Permit + + + + + Explosives Permit Details + + {props.isPermitTab && ( + <> + + + + + + + + + + + + + + + + + + + + + )} + + {props.isPermitTab && ( + + + + + + )} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Storage Details + + + + + + + + + + + + + + +
    + + + Supporting Documents + + + Permit Documents + + These documents were generated when this version of the permit was created. These + documents will be viewable by Minespace users + + + + + + {supportingDocs.length > 0 && ( +
    +
    + Uploaded Documents + + Documents uploaded here will be viewable by Minespace users + + + +
    + + + )} + + + + + + {isHistoric && ( + <> + + + + Permit Status + + + Permit Status + + + {props.initialValues?.is_closed ? "Closed" : "-"} + + + + + )} +
    + + + +
    + + + + +
    + + ); +}; + +ExplosivesPermitFormNew.defaultProps = defaultProps; + +const selector = formValueSelector(FORM.EXPLOSIVES_PERMIT); +const mapStateToProps = (state) => ({ + permits: getPermits(state), + documents: selector(state, "documents"), + mines_permit_guid: selector(state, "permit_guid"), + formValues: getFormValues(FORM.EXPLOSIVES_PERMIT)(state), + partyRelationships: getPartyRelationships(state), + allPartyRelationships: getAllPartyRelationships(state), + noticeOfWorkApplications: getNoticeOfWorkList(state), + userRoles: getUserAccessData(state), +}); + +const mapDispatchToProps = (dispatch) => + bindActionCreators( + { + change, + }, + dispatch + ); + +export default compose( + connect(mapStateToProps, mapDispatchToProps), + reduxForm({ + form: FORM.EXPLOSIVES_PERMIT, + touchOnBlur: true, + validate: validateBusinessRules, + onSubmitSuccess: resetForm(FORM.EXPLOSIVES_PERMIT), + }) +)(ExplosivesPermitFormNew as any) as FC; diff --git a/services/core-web/src/components/Forms/ExplosivesPermit/MagazineFormNew.tsx b/services/core-web/src/components/Forms/ExplosivesPermit/MagazineFormNew.tsx new file mode 100644 index 0000000000..51d812d896 --- /dev/null +++ b/services/core-web/src/components/Forms/ExplosivesPermit/MagazineFormNew.tsx @@ -0,0 +1,308 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { Field, FieldArray } from "redux-form"; +import { Form } from "@ant-design/compatible"; +import { + lat, + lon, + lonNegative, + maxLength, + number, + positiveNumber, + required, +} from "@common/utils/Validate"; + +import "@ant-design/compatible/assets/index.css"; +import { Button, Col, Collapse, Divider, Popconfirm, Row, Typography } from "antd"; +import { PlusOutlined } from "@ant-design/icons"; +import { TRASHCAN } from "@/constants/assets"; +import { renderConfig } from "@/components/common/config"; +import { COLOR } from "@/constants/styles"; + +const propTypes = { + isProcessed: PropTypes.bool.isRequired, +}; + +const defaultProps = {}; + +export const MagazineForm = (props) => { + const addField = (event, fields) => { + event.preventDefault(); + fields.push({}); + }; + + const removeField = (index, fields) => () => { + fields.remove(index); + }; + + const panelHeader = (index, fields, type) => ( +
    + + {type === "EXP" ? `Explosive Magazine ${index + 1}` : `Detonator Magazine ${index + 1}`} + + } + /> +
    event.preventDefault()}> + + + +
    +
    + ); + + const renderInputs = (field, type) => { + const unit = type === "EXP" ? "(Kg)" : "(Unit)"; + const showDetonatorType = type === "DET"; + return ( + <> + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {showDetonatorType && ( + + + + + + + + )} + + + + + + + + + + + + + + + + + + + + + + + + + ); + }; + + const renderExplosive = ({ fields }) => { + return ( +
    + +
    + {fields.map((field, index) => ( + + + {renderInputs(field, "EXP")} + + + ))} + + + + + ); + }; + + const renderDetonator = ({ fields }) => { + return ( +
    + +
    + {fields.map((field, index) => ( + + + {renderInputs(field, "DET")} + + + ))} + + + + + ); + }; + + return ( +
    + + Explosives Magazines + + + + + Detonator Magazines + + +
    + ); +}; + +MagazineForm.propTypes = propTypes; +MagazineForm.defaultProps = defaultProps; + +export default MagazineForm; diff --git a/services/core-web/src/components/common/ActionMenu.tsx b/services/core-web/src/components/common/ActionMenu.tsx new file mode 100644 index 0000000000..ad865b0c7f --- /dev/null +++ b/services/core-web/src/components/common/ActionMenu.tsx @@ -0,0 +1,47 @@ +import { Button, Dropdown, MenuProps } from "antd"; +import { CARAT, EDIT_OUTLINE_VIOLET } from "@/constants/assets"; +import React, { FC } from "react"; +import { ITableAction } from "@/components/common/CoreTableCommonColumns"; + +interface ActionMenuProps { + record: any; + actionItems: ITableAction[]; + category: string; +} +const ActionMenu: FC = ({ record, actionItems, category }) => { + const items = actionItems.map((action) => { + return { + key: action.key, + icon: action.icon, + label: ( + + ), + }; + }); + return ( + + + + ); +}; + +export default ActionMenu; diff --git a/services/core-web/src/components/common/DocumentTable.tsx b/services/core-web/src/components/common/DocumentTable.tsx index a6f72431eb..b15b1df7e0 100644 --- a/services/core-web/src/components/common/DocumentTable.tsx +++ b/services/core-web/src/components/common/DocumentTable.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, FC } from "react"; import CoreTable from "@/components/common/CoreTable"; import { documentNameColumn, @@ -34,32 +34,32 @@ import { useFeatureFlag } from "@common/providers/featureFlags/useFeatureFlag"; interface DocumentTableProps { documents: MineDocument[]; - isLoaded: boolean; - isViewOnly: boolean; - canArchiveDocuments: boolean; - showVersionHistory: boolean; - enableBulkActions: boolean; - documentParent: string; - view: string; - openModal: (arg) => void; + isLoaded?: boolean; + isViewOnly?: boolean; + canArchiveDocuments?: boolean; + showVersionHistory?: boolean; + enableBulkActions?: boolean; + documentParent?: string; + view?: "standard" | "minimal"; + openModal?: (arg) => void; openDocument: any; - closeModal: () => void; + closeModal?: () => void; removeDocument: (event, doc_guid: string, mine_guid: string) => void; - archiveMineDocuments: (mineGuid: string, mineDocumentGuids: string[]) => void; - onArchivedDocuments: (docs?: MineDocument[]) => void; - onReplaceDocument: (document: MineDocument) => void; + archiveMineDocuments?: (mineGuid: string, mineDocumentGuids: string[]) => void; + onArchivedDocuments?: (docs?: MineDocument[]) => void; + onReplaceDocument?: (document: MineDocument) => void; documentColumns: ColumnType[]; - additionalColumns: ColumnType[]; - defaultSortKeys: string[]; - excludedColumnKeys: string[]; - additionalColumnProps: { key: string; colProps: any }[]; + additionalColumns?: ColumnType[]; + defaultSortKeys?: string[]; + excludedColumnKeys?: string[]; + additionalColumnProps?: { key: string; colProps: any }[]; userRoles: string[]; - handleRowSelectionChange: (arg1: MineDocument[]) => void; + handleRowSelectionChange?: (arg1: MineDocument[]) => void; replaceAlertMessage?: string; } // eslint-disable-next-line @typescript-eslint/no-shadow -export const DocumentTable = ({ +export const DocumentTable: FC = ({ isViewOnly = false, excludedColumnKeys = [], additionalColumnProps = [], diff --git a/services/core-web/src/components/common/wrappers/ModalWrapper.js b/services/core-web/src/components/common/wrappers/ModalWrapper.js index 2e25553304..ea4f230185 100644 --- a/services/core-web/src/components/common/wrappers/ModalWrapper.js +++ b/services/core-web/src/components/common/wrappers/ModalWrapper.js @@ -2,19 +2,17 @@ import React, { useEffect, useRef } from "react"; import { bindActionCreators } from "redux"; import { connect } from "react-redux"; import PropTypes from "prop-types"; -import { Modal, Button, Popconfirm } from "antd"; +import { Button, Modal, Popconfirm } from "antd"; import { CloseOutlined } from "@ant-design/icons"; import { closeModal } from "@common/actions/modalActions"; import { + getClearOnSubmit, + getContent, getIsModalOpen, + getIsViewOnly, getProps, - getContent, - getClearOnSubmit, getWidth, - getIsViewOnly, } from "@common/selectors/modalSelectors"; -import LoadingBar from "react-redux-loading-bar"; -import * as Styles from "@/constants/styles"; import AddPartyComponentWrapper from "./AddPartyComponentWrapper"; const propTypes = { @@ -93,33 +91,23 @@ export const ModalWrapper = (props) => { destroyOnClose={true} > {isViewOnly ? ( - ) : ( closeModal(event)} > - )} - {content && ( = ({ }); }; + const handleOpenViewExplosivesPermitModal = (event, record) => { + event.preventDefault(); + const mine = mines[mineGuid]; + props.openModal({ + props: { + title: "View Explosives Storage & Use Permit", + explosivesPermit: record, + mine, + closeModal: props.closeModal, + }, + content: modalConfig.EXPLOSIVES_PERMIT_VIEW_MODAL, + isViewOnly: true, + }); + }; + const handleIssueExplosivesPermit = (values, record) => { const payload = { ...record, ...values, application_status: "APP" }; return props @@ -230,6 +245,7 @@ export const ExplosivesPermit: FC = ({ handleOpenExplosivesPermitDecisionModal={handleOpenExplosivesPermitDecisionModal} handleOpenAddExplosivesPermitModal={handleOpenAddExplosivesPermitModal} handleOpenViewMagazineModal={handleOpenViewMagazineModal} + handleOpenViewExplosivesPermitModal={handleOpenViewExplosivesPermitModal} explosivesPermitStatusOptionsHash={props.explosivesPermitStatusOptionsHash} explosivesPermitDocumentTypeOptionsHash={props.explosivesPermitDocumentTypeOptionsHash} handleOpenExplosivesPermitStatusModal={handleOpenExplosivesPermitStatusModal} diff --git a/services/core-web/src/components/mine/ExplosivesPermit/Magazine.tsx b/services/core-web/src/components/mine/ExplosivesPermit/Magazine.tsx new file mode 100644 index 0000000000..9e0a1e6d72 --- /dev/null +++ b/services/core-web/src/components/mine/ExplosivesPermit/Magazine.tsx @@ -0,0 +1,80 @@ +import React, { FC } from "react"; +import { Col, Collapse, Row, Typography } from "antd"; +import { IExplosivesPermitMagazine } from "@mds/common"; + +interface IMagazineProps { + label: string; + magazine: IExplosivesPermitMagazine; +} + +const Magazine: FC = (props) => { + const { label, magazine } = props; + return ( + + + {label} + + } + key={label} + > +
    + +
    + Type No. + {magazine.type_no} + + + Tag No. + {magazine.tag_no} + + + + + Construction + {magazine.construction} + + + Quantity (Kg) + {magazine.quantity} + + + + + Latitude + {magazine.latitude} + + + Longitude + {magazine.longitude} + + + Distance from road or work aread (m) + {magazine.distance_road} + + Distance from dwelling or flammable material storage area (m) + + {magazine.distance_dwelling} + + + Length (m) + {magazine.length} + + + Width (m) + {magazine.width} + + + Height (m) + {magazine.height} + + + + + + ); +}; + +export default Magazine; diff --git a/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx b/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx index 9b3deabd53..1c99a291f7 100644 --- a/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx +++ b/services/core-web/src/components/mine/ExplosivesPermit/MineExplosivesPermitTable.tsx @@ -1,8 +1,8 @@ import React, { FC } from "react"; -import { Badge, Tooltip, Button, Menu, Popconfirm, Dropdown } from "antd"; import { RouteComponentProps, withRouter } from "react-router-dom"; -import { WarningOutlined } from "@ant-design/icons"; -import { formatDate, dateSorter } from "@common/utils/helpers"; +import { Badge, Button, Dropdown, Popconfirm, Tooltip, Menu } from "antd"; +import { EyeOutlined, WarningOutlined } from "@ant-design/icons"; +import { dateSorter, formatDate } from "@common/utils/helpers"; import * as Strings from "@common/constants/strings"; import CoreTable from "@/components/common/CoreTable"; import { @@ -15,9 +15,12 @@ import DocumentLink from "@/components/common/DocumentLink"; import { EDIT_OUTLINE_VIOLET, EDIT, CARAT, TRASHCAN } from "@/constants/assets"; import { CoreTooltip } from "@/components/common/CoreTooltip"; -import { IExplosivesPermit } from "@mds/common"; +import { IExplosivesPermit, isFeatureEnabled, Feature } from "@mds/common"; import { ColumnType } from "antd/lib/table"; import moment from "moment-timezone"; +import { ITableAction } from "@/components/common/CoreTableCommonColumns"; +import VioletEditIcon from "@/assets/icons/violet-edit"; +import ActionMenu from "@/components/common/ActionMenu"; interface MineExplosivesPermitTableProps { data: IExplosivesPermit[]; @@ -35,6 +38,7 @@ interface MineExplosivesPermitTableProps { ) => void; handleOpenViewMagazineModal: (event, record: IExplosivesPermit, type: string) => void; handleOpenExplosivesPermitCloseModal: (event, record: IExplosivesPermit) => void; + handleOpenViewExplosivesPermitModal: (event, record: IExplosivesPermit) => void; } const transformRowData = (permits: IExplosivesPermit[]) => { @@ -56,6 +60,8 @@ const MineExplosivesPermitTable: FC { const columns: ColumnType[] = [ @@ -204,7 +210,7 @@ const MineExplosivesPermitTable: FC props.handleOpenViewMagazineModal(event, record, "EXP")} + onClick={(event) => handleOpenViewMagazineModal(event, record, "EXP")} > {text || "0"} kg @@ -223,19 +229,18 @@ const MineExplosivesPermitTable: FC props.handleOpenViewMagazineModal(event, record, "DET")} + onClick={(event) => handleOpenViewMagazineModal(event, record, "DET")} > {text || "0"} units ), sorter: false, }, - { title: "", key: "addEditButton", align: "right", - render: (record) => { + render: (text, record) => { const isApproved = record.application_status === "APP"; const isProcessed = record.application_status !== "REC"; const hasDocuments = @@ -243,97 +248,113 @@ const MineExplosivesPermitTable: FC 0; const isCoreSource = record.originating_system === "Core"; - const approvedMenu = ( - - - - - - - - - ); - const menu = ( - - {!isProcessed && ( - - - - )} - {!isProcessed && ( - - - - )} - - - - - ); + ), + }, + ] + : [ + ...(!isProcessed + ? [ + { + key: "process", + label: "Process", + clickFunction: (event) => + props.handleOpenExplosivesPermitDecisionModal(event, record), + icon: , + }, + { + key: "edit", + label: "Edit", + clickFunction: (event) => + props.handleOpenAddExplosivesPermitModal(event, isPermitTab, record), + icon: , + }, + ] + : []), + { + key: "0", + label: "Edit Documents", + clickFunction: (event) => + props.handleOpenAddExplosivesPermitModal(event, isPermitTab, record), + icon: , + }, + ]; const showActions = !isApproved || (isApproved && isPermitTab); const showDelete = (record.application_status !== "APP" && !isPermitTab) || (isApproved && isPermitTab); @@ -341,40 +362,52 @@ const MineExplosivesPermitTable: FC {isApproved && !hasDocuments && isCoreSource && ( - + {!isFeatureEnabled(Feature.ESUP_PERMIT_AMENDMENT) && ( + + )} )} {showActions && ( - - - + {isFeatureEnabled(Feature.ESUP_PERMIT_AMENDMENT) ? ( + + ) : ( + + + + )} )} {showDelete && ( diff --git a/services/core-web/src/components/modalContent/AddExplosivesPermitModal.tsx b/services/core-web/src/components/modalContent/AddExplosivesPermitModal.tsx index d1a6996ca9..f8b1507d2a 100644 --- a/services/core-web/src/components/modalContent/AddExplosivesPermitModal.tsx +++ b/services/core-web/src/components/modalContent/AddExplosivesPermitModal.tsx @@ -1,6 +1,8 @@ import React, { FC } from "react"; -import ExplosivesPermitForm from "@/components/Forms/ExplosivesPermit/ExplosivesPermitForm"; import { IOption, IGroupedDropdownList } from "@mds/common"; +import ExplosivesPermitForm from "@/components/Forms/ExplosivesPermit/ExplosivesPermitForm"; +import { Feature, isFeatureEnabled } from "@mds/common"; +import ExplosivesPermitFormNew from "@/components/Forms/ExplosivesPermit/ExplosivesPermitFormNew"; interface ExplosivesPermitModalProps { title: string; @@ -14,12 +16,14 @@ interface ExplosivesPermitModalProps { isProcessed: boolean; } -export const AddExplosivesPermitModal: FC = (props) => { - return ( -
    +export const AddExplosivesPermitModal: FC = (props) => ( +
    + {isFeatureEnabled(Feature.ESUP_PERMIT_AMENDMENT) ? ( + + ) : ( -
    - ); -}; + )} +
    +); export default AddExplosivesPermitModal; diff --git a/services/core-web/src/components/modalContent/ExplosivesPermitViewModal.tsx b/services/core-web/src/components/modalContent/ExplosivesPermitViewModal.tsx new file mode 100644 index 0000000000..9b9fc8212c --- /dev/null +++ b/services/core-web/src/components/modalContent/ExplosivesPermitViewModal.tsx @@ -0,0 +1,292 @@ +import "@ant-design/compatible/assets/index.css"; + +import { Button, Col, Row, Table, Typography } from "antd"; +import { IExplosivesPermit, IMine } from "@mds/common"; +import React, { FC, useEffect, useState } from "react"; +import { connect } from "react-redux"; +import ExplosivesPermitMap from "@/components/maps/ExplosivesPermitMap"; +import { formatDate } from "@common/utils/helpers"; +import Magazine from "@/components/mine/ExplosivesPermit/Magazine"; +import { bindActionCreators } from "redux"; +import { openDocument } from "@/components/syncfusion/DocumentViewer"; +import { downloadFileFromDocumentManager } from "@common/utils/actionlessNetworkCalls"; + +export const getGeneratedDocCategory = (doc: IExplosivesPermit) => { + switch (doc.explosives_permit_document_type_code) { + case "LET": + return "Permit Enclosed Letter"; + case "PER": + return "Explosives Storage and Use Permit"; + default: + return ""; + } +}; + +export const generatedDocColumns = [ + { + title: "Category", + dataIndex: "explosives_permit_document_type_code", + key: "explosives_permit_document_type_code", + render: (text, record) =>
    {getGeneratedDocCategory(record)}
    , + }, + { + title: "File Name", + dataIndex: "document_name", + key: "document_name", + render: (text, record) => downloadFileFromDocumentManager(record)}>{text}, + }, + { + title: "Created", + dataIndex: "upload_date", + key: "upload_date", + render: (text) =>
    {formatDate(text)}
    , + }, +]; + +export const supportingDocColumns = [ + { + title: "File Name", + dataIndex: "document_name", + key: "document_name", + render: (text, record) => downloadFileFromDocumentManager(record)}>{text}, + }, + { + title: "Created By", + dataIndex: "create_user", + key: "create_user", + render: (text) =>
    {text}
    , + }, + { + title: "Uploaded", + dataIndex: "upload_date", + key: "upload_date", + render: (text) =>
    {formatDate(text)}
    , + }, +]; + +interface ExplosivesPermitViewModalProps { + explosivesPermit: IExplosivesPermit; + mine: IMine; + title: string; + closeModal: () => void; + openDocument: (document_manager_guid: string, mine_document_guid: string) => void; +} + +export const ExplosivesPermitViewModal: FC = (props) => { + const { explosivesPermit, mine, title } = props; + + const [generatedDocs, setGeneratedDocs] = useState([]); + const [supportingDocs, setSupportingDocs] = useState([]); + + useEffect(() => { + if (explosivesPermit) { + const generatedTypes = ["LET", "PER"]; + setGeneratedDocs( + explosivesPermit.documents.filter((doc) => + generatedTypes.includes(doc.explosives_permit_document_type_code) + ) + ); + setSupportingDocs( + explosivesPermit.documents.filter( + (doc) => !generatedTypes.includes(doc.explosives_permit_document_type_code) + ) + ); + } + }, [explosivesPermit]); + + return ( +
    + + Explosive Storage and Use Permit + + +
    + + Explosives Permit Details + + + Select the location and one or more incident types for this submission. + + <> + + + Issue Date + {explosivesPermit.issue_date} + + + Expiry Date + {explosivesPermit.expiry_date} + + + + + Issuing Inspector + + {explosivesPermit.issuing_inspector_name} + + + + + + + + Explosives Permit Number + {explosivesPermit.permit_number} + + + + Mines Act Permit + example + + + Notice of Work Number + {explosivesPermit.now_number} + + + Mine Manager + + {explosivesPermit.mine_manager_mine_party_appt_id} + + + + Permittee + + {explosivesPermit.permittee_mine_party_appt_id} + + + + Application Date + {explosivesPermit.application_date} + Other Information + {explosivesPermit.description} + + Storage Details + + + + Latitude + {explosivesPermit?.latitude} + + + Longitude + {explosivesPermit?.longitude} + + + +
    + {supportingDocs.length > 0 && ( + + + Supporting Documents + + Permit Documents + + These documents were generated when this version of the permit was created. These + documents will be viewable by Minespace users + +
    + Uploaded Documents + + Documents uploaded here will be viewable by Minespace users + +
    + + )} + + + <> + + Permit Status + + + + + Permit Status + + + {explosivesPermit.is_closed && ( + + + Date Closed + + + )} + + + + + {explosivesPermit.is_closed ? "Closed" : "Open"} + + + + {explosivesPermit.is_closed ? ( + + {formatDate(explosivesPermit.closed_timestamp)} + + ) : ( + + )} + + + {explosivesPermit.is_closed && ( + + + Reason for Closure + + + {explosivesPermit.closed_reason} + + + )} + + Explosives Magazines + + {explosivesPermit?.explosive_magazines?.length > 0 && + explosivesPermit.explosive_magazines.map((magazine, index) => ( + + ))} + + Detonator Magazines + + {explosivesPermit?.detonator_magazines?.length > 0 && + explosivesPermit.detonator_magazines.map((magazine, index) => ( + + ))} + + Permit History + + + + +
    + +
    + + ); +}; + +const mapDispatchToProps = (dispatch) => + bindActionCreators( + { + openDocument, + }, + dispatch + ); + +export default connect(null, mapDispatchToProps)(ExplosivesPermitViewModal); diff --git a/services/core-web/src/components/modalContent/config.js b/services/core-web/src/components/modalContent/config.js index 0fa6dc78d9..fa2ae55570 100644 --- a/services/core-web/src/components/modalContent/config.js +++ b/services/core-web/src/components/modalContent/config.js @@ -45,6 +45,7 @@ import ExplosivesPermitApplicationDecisionModal from "./ExplosivesPermitApplicat import ViewMagazineModal from "./ViewMagazineModal"; import ExplosivesPermitStatusModal from "./ExplosivesPermitStatusModal"; import ExplosivesPermitCloseModal from "./ExplosivesPermitCloseModal"; +import ExplosivesPermitViewModal from "./ExplosivesPermitViewModal"; import MergePartyConfirmationModal from "./MergePartyConfirmationModal"; import ViewAllConditionsModal from "./ViewAllConditionsModal"; import UpdateNoWDateModal from "./UpdateNoWDateModal"; @@ -110,6 +111,7 @@ export const modalConfig = { NO_PERMIT_REQUIRED_SELECTION_MODAL: NoPermitRequiredSelectionModal, EXPLOSIVES_PERMIT_MODAL: AddExplosivesPermitModal, EXPLOSIVES_PERMIT_DECISION_MODAL: ExplosivesPermitApplicationDecisionModal, + EXPLOSIVES_PERMIT_VIEW_MODAL: ExplosivesPermitViewModal, VIEW_MAGAZINE_MODAL: ViewMagazineModal, EXPLOSIVES_PERMIT_STATUS_MODAL: ExplosivesPermitStatusModal, EXPLOSIVES_PERMIT_CLOSE_MODAL: ExplosivesPermitCloseModal, diff --git a/services/core-web/src/styles/components/ExplosivesPermits.scss b/services/core-web/src/styles/components/ExplosivesPermits.scss new file mode 100644 index 0000000000..1cb7053a29 --- /dev/null +++ b/services/core-web/src/styles/components/ExplosivesPermits.scss @@ -0,0 +1,35 @@ +.close-permit-button, +.add-magazine-button { + text-align: center; + border: $violet 2px solid; + color: $violet !important; + display: flex; + margin-right: 24px; + justify-content: center; + align-items: center; + padding: 6px 16px; +} + +.close-permit-button { + width: 90%; +} + +.add-magazine-button > span { + display: flex; +} + +.magazine-collapse, +.magazine-collapse > div { + background-color: rgb(242, 242, 242); + align-items: center !important; +} + +.esup-alert { + background-color: #F4F0F0; + border: 1px solid #6B6363; +} + +.esup-alert > span > svg { + fill: #6B6363; + background-color: #F4F0F0; +} diff --git a/services/core-web/src/styles/components/MinePermitTable.scss b/services/core-web/src/styles/components/MinePermitTable.scss index 71ec734817..6f79c4ca4e 100644 --- a/services/core-web/src/styles/components/MinePermitTable.scss +++ b/services/core-web/src/styles/components/MinePermitTable.scss @@ -29,6 +29,7 @@ } .add-permit-dropdown-button { + border: none; div { display: flex; align-items: center; @@ -36,6 +37,10 @@ } } +.add-permit-dropdown-button:hover { + border: none; +} + .add-permit-dropdown-button-icon { font-size: 18px; padding-left: 8px; diff --git a/services/core-web/src/styles/components/Modal.scss b/services/core-web/src/styles/components/Modal.scss index e46b7aa206..f482132ec6 100644 --- a/services/core-web/src/styles/components/Modal.scss +++ b/services/core-web/src/styles/components/Modal.scss @@ -4,4 +4,6 @@ color: $violet; font-size: 24px; right: 0; + z-index: 999; + border: none; } diff --git a/services/core-web/src/styles/elements/elements.scss b/services/core-web/src/styles/elements/elements.scss index 7ad19378ae..4e9c66c547 100644 --- a/services/core-web/src/styles/elements/elements.scss +++ b/services/core-web/src/styles/elements/elements.scss @@ -10,7 +10,7 @@ p { width: auto; } -h1 { +h1, h1.ant-typography { font-size: $default-h1; font-weight: $bold; color: $h1-color; @@ -20,7 +20,7 @@ h1 { } } -h2 { +h2, h2.ant-typography { font-size: $default-h2; font-weight: $bold; color: $h2-color; @@ -29,7 +29,7 @@ h2 { } } -h3 { +h3, h3.ant-typography { font-size: $default-h3; font-weight: $bold; color: $h3-color; @@ -38,7 +38,7 @@ h3 { } } -h4 { +h4, h4.ant-typography { font-size: $default-h4; font-weight: $bold; color: $h4-color; @@ -47,7 +47,7 @@ h4 { } } -h5 { +h5, h5.ant-typography { font-size: $default-h5; font-weight: $light; color: $h5-color; @@ -85,6 +85,10 @@ p, } } +.purple { + color: $violet !important; +} + .p-white { color: $pure-white; } diff --git a/services/core-web/src/styles/generic/layout.scss b/services/core-web/src/styles/generic/layout.scss index 9c45197e40..93bbfd5b05 100644 --- a/services/core-web/src/styles/generic/layout.scss +++ b/services/core-web/src/styles/generic/layout.scss @@ -42,7 +42,7 @@ html { } .horizontal-center { - align-items: center; + align-items: center !important; } .justify-center { @@ -116,7 +116,7 @@ html { height: 50%; } - &>div { + & > div { margin-right: 5px; } @@ -405,7 +405,7 @@ html { } .margin-none { - margin: 0; + margin: 0 !important; } .margin-small { @@ -676,4 +676,4 @@ img.lessOpacity { &-125 { margin-top: 125px !important; } -} \ No newline at end of file +} diff --git a/services/core-web/src/styles/index.scss b/services/core-web/src/styles/index.scss index 320ba33b78..69a8f64567 100755 --- a/services/core-web/src/styles/index.scss +++ b/services/core-web/src/styles/index.scss @@ -48,5 +48,6 @@ @import "./components/DocumentTableWithExpandedRows.scss"; @import "./components/DocumentCompressionProgressBar.scss"; @import "./components/Menu.scss"; +@import "./components/ExplosivesPermits.scss"; // UTILITIES - utilities and helper classes. This layer has the highest specificity. \ No newline at end of file diff --git a/services/core-web/src/tests/components/common/wrappers/__snapshots__/ModalWrapper.spec.js.snap b/services/core-web/src/tests/components/common/wrappers/__snapshots__/ModalWrapper.spec.js.snap index d98dc7d76f..b749749cea 100644 --- a/services/core-web/src/tests/components/common/wrappers/__snapshots__/ModalWrapper.spec.js.snap +++ b/services/core-web/src/tests/components/common/wrappers/__snapshots__/ModalWrapper.spec.js.snap @@ -14,6 +14,7 @@ exports[`ModalWrapper renders properly 1`] = ` > - ')