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`] = ` > - ')