diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 89c44e603..8ab80e5d8 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,3 +1,9 @@ +## May 30, 2024 + +- **Feature** Remove EAO process widget [šŸŽŸļø DESENG-626](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-626) + - Removed EAO process widget + - Added migration file to remove EAO process widget attached to any existing engagement + ## May 29, 2024 - **Bugfix** Null in the public URL [šŸŽŸļø DESENG-625](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-625) diff --git a/met-api/migrations/versions/f0f7eadf3a40_remove_phases_widget_type.py b/met-api/migrations/versions/f0f7eadf3a40_remove_phases_widget_type.py new file mode 100644 index 000000000..cbcaf010c --- /dev/null +++ b/met-api/migrations/versions/f0f7eadf3a40_remove_phases_widget_type.py @@ -0,0 +1,37 @@ +"""remove_phases_widget_type + +Revision ID: f0f7eadf3a40 +Revises: ae232e299180 +Create Date: 2024-05-30 10:26:56.318088 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f0f7eadf3a40' +down_revision = 'ae232e299180' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + conn = op.get_bind() + conn.execute('DELETE FROM widget WHERE widget_type_id=3') + conn.execute('DELETE FROM widget_type WHERE id=3') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + widget_type_table = sa.table('widget_type', + sa.Column('id', sa.Integer), + sa.Column('name', sa.String), + sa.Column('description', sa.String)) + + op.bulk_insert(widget_type_table, [ + {'id': 3, 'name': 'Phases', 'description': 'Displays information about the engagement phase'} + ]) + # ### end Alembic commands ### diff --git a/met-api/src/met_api/constants/widget.py b/met-api/src/met_api/constants/widget.py index 3da7c94d0..6507d73c2 100644 --- a/met-api/src/met_api/constants/widget.py +++ b/met-api/src/met_api/constants/widget.py @@ -20,7 +20,6 @@ class WidgetType(IntEnum): WHO_IS_LISTENING = 1 DOCUMENTS = 2 - PHASES = 3 SUBSCRIBE = 4 EVENTS = 5 Map = 6 diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesForm.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesForm.tsx deleted file mode 100644 index ab87ea8a9..000000000 --- a/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesForm.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import React, { useContext, useEffect, useState } from 'react'; -import { Autocomplete, Checkbox, Divider, FormControl, FormControlLabel, Grid, TextField } from '@mui/material'; -import { MetLabel, PrimaryButtonOld, SecondaryButtonOld } from 'components/common'; -import { EngagementPhases } from 'models/engagementPhases'; -import { useAppDispatch } from 'hooks'; -import { openNotification } from 'services/notificationService/notificationSlice'; -import { WidgetDrawerContext } from '../WidgetDrawerContext'; -import { WidgetType } from 'models/widget'; -import { useCreateWidgetItemsMutation } from 'apiManager/apiSlices/widgets'; -import { WidgetTitle } from '../WidgetTitle'; - -interface ISelectOptions { - id: EngagementPhases; - label: string; -} -const PhasesForm = () => { - const { handleWidgetDrawerOpen, widgets, loadWidgets } = useContext(WidgetDrawerContext); - - const dispatch = useAppDispatch(); - const [selectedOption, setSelectedOption] = useState(null); - const [isStandalone, setIsStandalone] = useState(false); - const [savingWidgetItems, setSavingWidgetItems] = useState(false); - const widget = widgets.filter((widget) => widget.widget_type_id === WidgetType.Phases)[0] || null; - - const [createWidgetItems] = useCreateWidgetItemsMutation(); - - useEffect(() => { - if (widget && widget.items.length > 0) { - setSelectedOption(options.find((o) => o.id === widget.items[0].widget_data_id) || null); - setIsStandalone(widget.items[0].widget_data_id === EngagementPhases.Standalone); - } - }, [widget]); - - const options = [ - { - id: EngagementPhases.EarlyEngagement, - label: 'Early Engagement', - }, - { - id: EngagementPhases.ReadinessDecision, - label: 'Readiness Decision', - }, - { - id: EngagementPhases.ProcessPlanning, - label: 'Process Planning', - }, - { - id: EngagementPhases.ApplicationDevelopmentReview, - label: 'Application Development & Review', - }, - { - id: EngagementPhases.EffectsAssessmentRecommendation, - label: 'Effects Assessment & Recommendation', - }, - { - id: EngagementPhases.Decision, - label: 'Decision', - }, - { - id: EngagementPhases.PostCertificate, - label: 'Post-certificate', - }, - ]; - - const saveWidgetItem = async () => { - const widgetsToUpdate = { - widget_id: widget.id, - widget_data_id: selectedOption?.id || EngagementPhases.Standalone, - }; - try { - setSavingWidgetItems(true); - await createWidgetItems({ widget_id: widget.id, widget_items_data: [widgetsToUpdate] }).unwrap(); - await loadWidgets(); - dispatch(openNotification({ severity: 'success', text: 'Widget successfully added' })); - handleWidgetDrawerOpen(false); - setSavingWidgetItems(false); - } catch (error) { - dispatch( - openNotification({ severity: 'error', text: 'Error occurred while attempting to add the widgets' }), - ); - setSavingWidgetItems(false); - } - }; - - return ( - - - - - - - - Engagement Phase - ( - - )} - isOptionEqualToValue={(option: ISelectOptions, value: ISelectOptions) => option.id == value.id} - getOptionLabel={(option: ISelectOptions) => option.label} - onChange={(_e: React.SyntheticEvent, option: ISelectOptions | null) => { - setSelectedOption(option); - setIsStandalone(false); - }} - /> - - - - { - setSelectedOption(null); - setIsStandalone(checked); - }} - /> - } - label="This engagement is a stand-alone engagement" - /> - - - - - - saveWidgetItem()} - >{`Save & Close`} - - - handleWidgetDrawerOpen(false)}>{`Cancel`} - - - - ); -}; - -export default PhasesForm; diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesOptionCard.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesOptionCard.tsx deleted file mode 100644 index dcc15efc1..000000000 --- a/met-web/src/components/engagement/form/EngagementWidgets/Phases/PhasesOptionCard.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import React, { useContext, useState } from 'react'; -import { MetPaper, MetLabel, MetDescription } from 'components/common'; -import { Grid, CircularProgress } from '@mui/material'; -import { WidgetDrawerContext } from '../WidgetDrawerContext'; -import { WidgetTabValues } from '../type'; -import { ActionContext } from '../../ActionContext'; -import { openNotification } from 'services/notificationService/notificationSlice'; -import { useAppDispatch } from 'hooks'; -import { WidgetType } from 'models/widget'; -import { useCreateWidgetMutation } from 'apiManager/apiSlices/widgets'; -import { Else, If, Then } from 'react-if'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faLeaf } from '@fortawesome/pro-regular-svg-icons/faLeaf'; -import { optionCardStyle } from '../constants'; - -const Title = 'Environmental Assessment Process'; -const PhasesOptionCard = () => { - const { savedEngagement } = useContext(ActionContext); - const { widgets, loadWidgets, handleWidgetDrawerTabValueChange } = useContext(WidgetDrawerContext); - const dispatch = useAppDispatch(); - const [createWidget] = useCreateWidgetMutation(); - const [isCreatingWidget, setIsCreatingWidget] = useState(false); - - const handleCreateWidget = async () => { - const alreadyExists = widgets.some((widget) => widget.widget_type_id === WidgetType.Phases); - if (alreadyExists) { - handleWidgetDrawerTabValueChange(WidgetTabValues.PHASES_FORM); - return; - } - - try { - setIsCreatingWidget(true); - await createWidget({ - widget_type_id: WidgetType.Phases, - engagement_id: savedEngagement.id, - title: Title, - }); - await loadWidgets(); - dispatch( - openNotification({ - severity: 'success', - text: 'Widget successfully added.', - }), - ); - setIsCreatingWidget(false); - handleWidgetDrawerTabValueChange(WidgetTabValues.PHASES_FORM); - } catch (error) { - setIsCreatingWidget(false); - dispatch(openNotification({ severity: 'error', text: 'Error occurred while adding phases widget' })); - } - }; - - return ( - handleCreateWidget()} - > - - - - - - - - - - - - - - {Title} - - - - Add the environmental assessment process info to this engagement - - - - - - - - ); -}; - -export default PhasesOptionCard; diff --git a/met-web/src/components/engagement/form/EngagementWidgets/Phases/index.tsx b/met-web/src/components/engagement/form/EngagementWidgets/Phases/index.tsx deleted file mode 100644 index 33800b62a..000000000 --- a/met-web/src/components/engagement/form/EngagementWidgets/Phases/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import PhasesForm from './PhasesForm'; - -export const Phases = () => { - return ; -}; - -export default Phases; diff --git a/met-web/src/components/engagement/form/EngagementWidgets/WidgetCardSwitch.tsx b/met-web/src/components/engagement/form/EngagementWidgets/WidgetCardSwitch.tsx index 261d3d405..4a4472a44 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/WidgetCardSwitch.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/WidgetCardSwitch.tsx @@ -15,20 +15,6 @@ export const WidgetCardSwitch = ({ widget, removeWidget }: WidgetCardSwitchProps return ( <> - - { - removeWidget(widget.id); - }} - onEdit={() => { - handleWidgetDrawerTabValueChange(WidgetTabValues.PHASES_FORM); - handleWidgetDrawerOpen(true); - }} - /> - { - - - diff --git a/met-web/src/components/engagement/form/EngagementWidgets/WidgetOptionCards.tsx b/met-web/src/components/engagement/form/EngagementWidgets/WidgetOptionCards.tsx index 4eaf7d86e..c4af95153 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/WidgetOptionCards.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/WidgetOptionCards.tsx @@ -3,7 +3,6 @@ import { Divider, Grid } from '@mui/material'; import WhoIsListeningOptionCard from './WhoIsListening/WhoIsListeningOptionCard'; import { MetHeader3 } from 'components/common'; import DocumentOptionCard from './Documents/DocumentOptionCard'; -import PhasesOptionCard from './Phases/PhasesOptionCard'; import SubscribeOptionCard from './Subscribe/SubscribeOptionCard'; import EventsOptionCard from './Events/EventsOptionCard'; import MapOptionCard from './Map/MapOptionCard'; @@ -24,9 +23,6 @@ const WidgetOptionCards = () => { - - - diff --git a/met-web/src/components/engagement/form/EngagementWidgets/WidgetsBlock.tsx b/met-web/src/components/engagement/form/EngagementWidgets/WidgetsBlock.tsx index 53cac22df..6b5491f33 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/WidgetsBlock.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/WidgetsBlock.tsx @@ -1,12 +1,12 @@ import React, { useContext, useEffect, useState, useRef } from 'react'; -import { Divider, Grid, Skeleton } from '@mui/material'; +import { Grid, Skeleton } from '@mui/material'; import { MetHeader2Old, MetPaper, MetTooltip, SecondaryButtonOld } from 'components/common'; import { WidgetCardSwitch } from './WidgetCardSwitch'; -import { If, Then, Else, When } from 'react-if'; +import { If, Then, Else } from 'react-if'; import { WidgetDrawerContext } from './WidgetDrawerContext'; import { ActionContext } from '../ActionContext'; import { useAppDispatch } from 'hooks'; -import { Widget, WidgetType } from 'models/widget'; +import { Widget } from 'models/widget'; import { openNotificationModal } from 'services/notificationModalService/notificationModalSlice'; import { DragDropContext, DropResult } from '@hello-pangea/dnd'; import { debounce } from 'lodash'; @@ -20,14 +20,9 @@ const WidgetsBlock = () => { const dispatch = useAppDispatch(); const [sortableWidgets, setSortableWidgets] = useState([]); - const [fixedWidgets, setFixedWidgets] = useState([]); useEffect(() => { - const fixedWidgetTypes = [WidgetType.Phases]; - const widgetsFixedList = widgets.filter((w) => fixedWidgetTypes.includes(w.widget_type_id)); - const widgetsSortedList = widgets.filter((w) => !fixedWidgetTypes.includes(w.widget_type_id)); - setFixedWidgets(widgetsFixedList); - setSortableWidgets(widgetsSortedList); + setSortableWidgets(widgets); }, [widgets]); const handleAddWidgetClick = () => { @@ -35,8 +30,8 @@ const WidgetsBlock = () => { }; const debounceUpdateWidgetsSorting = useRef( - debounce((wigetsToSort: Widget[]) => { - updateWidgetsSorting(wigetsToSort); + debounce((widgetsToSort: Widget[]) => { + updateWidgetsSorting(widgetsToSort); }, 800), ).current; @@ -49,9 +44,7 @@ const WidgetsBlock = () => { setSortableWidgets(items); - const widgets = fixedWidgets.concat(items); - - debounceUpdateWidgetsSorting(widgets); + debounceUpdateWidgetsSorting(items); }; const removeWidget = (widgetId: number) => { @@ -105,22 +98,6 @@ const WidgetsBlock = () => { - {fixedWidgets.map((widget: Widget) => { - return ( - - - - ); - })} - 0 && sortableWidgets.length > 0}> - - - - @@ -130,19 +107,17 @@ const WidgetsBlock = () => { alignItems={'flex-start'} justifyContent="flex-start" > - {sortableWidgets.map((widget: Widget, index) => { - return ( - - - - - - ); - })} + {sortableWidgets.map((widget: Widget, index) => ( + + + + + + ))} diff --git a/met-web/src/components/engagement/form/EngagementWidgets/type.tsx b/met-web/src/components/engagement/form/EngagementWidgets/type.tsx index d54ca5632..c4320efde 100644 --- a/met-web/src/components/engagement/form/EngagementWidgets/type.tsx +++ b/met-web/src/components/engagement/form/EngagementWidgets/type.tsx @@ -4,7 +4,6 @@ export const WidgetTabValues = { WHO_IS_LISTENING_FORM: 'WHO_IS_LISTENING_FORM', DOCUMENT_FORM: 'DOCUMENT_FORM', SUBSCRIBE_FORM: 'SUBSCRIBE_FORM', - PHASES_FORM: 'PHASES_FORM', EVENTS_FORM: 'EVENTS_FORM', MAP_FORM: 'MAP_FORM', VIDEO_FORM: 'VIDEO_FORM', diff --git a/met-web/src/components/engagement/view/EngagementView.tsx b/met-web/src/components/engagement/view/EngagementView.tsx index d51a09a01..26d48e7e7 100644 --- a/met-web/src/components/engagement/view/EngagementView.tsx +++ b/met-web/src/components/engagement/view/EngagementView.tsx @@ -12,8 +12,6 @@ import { RouteState } from './types'; import WidgetBlock from './widgets/WidgetBlock'; import { Else, If, Then } from 'react-if'; import { getAvailableTranslationLanguages } from 'services/engagementService'; -import { PhasesWidget } from './widgets/PhasesWidget'; -import { PhasesWidgetMobile } from './widgets/PhasesWidget/PhasesWidgetMobile/PhasesWidgetMobile'; import { EngagementBanner } from './EngagementBanner'; export const EngagementView = () => { @@ -25,7 +23,6 @@ export const EngagementView = () => { const { savedEngagement } = useContext(ActionContext); const { setEngagementViewMounted, setAvailableEngagementTranslations } = useContext(LanguageContext); const surveyId = savedEngagement.surveys[0]?.id || ''; - const isSmallScreen = useMediaQuery((theme: Theme) => theme.breakpoints.down('sm')); const navigate = useNavigate(); //Clear state on window refresh window.history.replaceState({}, document.title); @@ -93,16 +90,6 @@ export const EngagementView = () => { rowSpacing={2} columnSpacing={1} > - - - - - - - - - - { - const { widgets } = useContext(ActionContext); - const phasesWidget = widgets.find((widget) => widget.widget_type_id === WidgetType.Phases); - const currentPhase = phasesWidget?.items[0]?.widget_data_id || EngagementPhases.Standalone; - const isCurrent = phaseId >= currentPhase; - - return ( - - - - {title} - - {learnMoreText} - - - } - iconBox={popOverText ? {popOverText} : false} - isCurrentPhase={phaseId === currentPhase} - currentPhase={currentPhase} - /> - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/ForumIcon.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/ForumIcon.tsx deleted file mode 100644 index 38b3e3cc6..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/ForumIcon.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { SvgIcon } from '@mui/material'; - -export const ForumIcon = ({ ...props }: { [prop: string]: unknown }) => { - return ( - - - - - - - - - - - - - - - - - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/IconBox.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/IconBox.tsx deleted file mode 100644 index f88e233f4..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/IconBox.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React, { ReactNode, useRef, useState } from 'react'; -import { Box, ClickAwayListener, IconButton, Paper } from '@mui/material'; -import { Arrow, PopperArrow } from 'components/common/MetPopper'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faXmark } from '@fortawesome/pro-regular-svg-icons/faXmark'; -import { ForumIcon } from './ForumIcon'; - -export const IconBox = ({ children }: { children: ReactNode }) => { - const iconRef = useRef(null); - const [open, setOpen] = useState(false); - const [arrowRef, setArrowRef] = React.useState(null); - - return ( - <> - setOpen(!open)} - > - - - - setOpen(false)}> - - - - setOpen(!open)} - sx={{ position: 'relative', top: '0%', left: '92%', color: '#458686' }} - > - - - - {children} - - - - - - - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/InfoArrow.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/InfoArrow.tsx deleted file mode 100644 index e5abd7f68..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/InfoArrow.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { MetSmallTextOld } from 'components/common'; -import { Stack, Box } from '@mui/material'; -import { INFO_ARROW } from 'models/engagementPhases'; - -export const InfoArrow = () => { - return ( - - - - Engagement and consensus-seeking with participating First Nations occur at each stage of the - process, supported by dispute resolution at certain stages if required. - - - - - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/LearnMoreBox.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/LearnMoreBox.tsx deleted file mode 100644 index ef9caabf3..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/LearnMoreBox.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React, { ReactNode } from 'react'; -import { Box } from '@mui/system'; - -export const LearnMoreBox = ({ children, ...rest }: { children: ReactNode; [prop: string]: unknown }) => { - return ( - - {children} - - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/PhaseBox.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/PhaseBox.tsx deleted file mode 100644 index 2203550e8..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/PhaseBox.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import React, { ReactNode, useContext, useRef, useState } from 'react'; -import { Box, Grid, Link, Popover, Stack, SxProps, Theme, useTheme } from '@mui/material'; -import { MetHeader4, MetIconText, MetPaper, MetSmallTextOld } from 'components/common'; -import { PhaseContext } from '.'; -import { Else, If, Then, When } from 'react-if'; -import { IconBox } from './IconBox'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faLocationDot } from '@fortawesome/pro-solid-svg-icons/faLocationDot'; -import { CURRENT_PHASE, EngagementPhases } from 'models/engagementPhases'; - -interface PhaseBoxProps { - title: string; - backgroundColor?: string; - learnMoreBox?: ReactNode; - iconBox?: ReactNode; - children?: ReactNode; - border?: string; - sx?: SxProps; - isCurrentPhase: boolean; - currentPhase: number; -} -export const PhaseBox = ({ - title, - backgroundColor = 'var(--bcds-surface-background-white)', - learnMoreBox, - iconBox, - currentPhase, - border = 'none', - sx = {}, - isCurrentPhase = false, -}: PhaseBoxProps) => { - const [readMoreOpen, setReadMoreOpen] = useState(false); - const { anchorEl, setAnchorEl } = useContext(PhaseContext); - const theme = useTheme(); - - const PhaseBoxRef = useRef(null); - - const handleReadMoreClick = () => { - setAnchorEl(PhaseBoxRef.current); - setReadMoreOpen(true); - }; - return ( - - - - - - - - - Current Phase - - - - - - - - - - - - - - - - - {title} - - - - - - Learn More - - - - - - - - - - - {iconBox} - - - - - setReadMoreOpen(false)} - anchorOrigin={{ - vertical: 'bottom', - horizontal: 'left', - }} - elevation={0} - PaperProps={{ - sx: { - borderRadius: 0, - }, - }} - > - {learnMoreBox} - - - - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/EngagementPhaseMobile.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/EngagementPhaseMobile.tsx deleted file mode 100644 index cf9ab692c..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/EngagementPhaseMobile.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { useContext } from 'react'; -import { Grid } from '@mui/material'; -import { MetHeader4, MetParagraphOld } from 'components/common'; -import { EngagementPhases, PAST_PHASE, ProcessStageProps } from 'models/engagementPhases'; -import { PhaseBoxMobile } from './PhaseBoxMobile'; -import { LearnMoreBox } from '../LearnMoreBox'; -import { ActionContext } from 'components/engagement/view/ActionContext'; -import { Widget, WidgetType } from 'models/widget'; - -export const EngagementPhaseMobile = ({ - backgroundColor, - title, - learnMoreText, - popOverText, - accordionBackground, - phaseId, -}: ProcessStageProps) => { - const { widgets } = useContext(ActionContext); - const phasesWidget = widgets.find((widget: Widget) => widget.widget_type_id === WidgetType.Phases); - const currentPhase = phasesWidget?.items[0]?.widget_data_id || EngagementPhases.Standalone; - const isCurrent = phaseId >= currentPhase; - - return ( - - - - {title} - - {learnMoreText} - - - } - accordionBackground={isCurrent ? accordionBackground : PAST_PHASE.learnMoreBackgroundColor} - iconBox={popOverText ? {popOverText} : false} - isCurrentPhase={phaseId === currentPhase} - currentPhase={currentPhase} - /> - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/PhaseBoxMobile.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/PhaseBoxMobile.tsx deleted file mode 100644 index 70cde14de..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/PhaseBoxMobile.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import React, { ReactNode, useRef } from 'react'; -import { Box, Grid, Stack } from '@mui/material'; -import { MetHeader4, MetPaper } from 'components/common'; -import { IconBox } from '../IconBox'; -import Accordion from '@mui/material/Accordion'; -import AccordionSummary from '@mui/material/AccordionSummary'; -import AccordionDetails from '@mui/material/AccordionDetails'; -import Typography from '@mui/material/Typography'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faLocationDot } from '@fortawesome/pro-solid-svg-icons/faLocationDot'; -import { faChevronDown } from '@fortawesome/pro-solid-svg-icons/faChevronDown'; -import { If, Then, When } from 'react-if'; -import { EngagementPhases } from 'models/engagementPhases'; - -interface PhaseBoxProps { - title: string; - backgroundColor?: string; - learnMoreBox?: ReactNode; - iconBox?: ReactNode; - children?: ReactNode; - readMoreBackground?: string; - accordionBackground?: string; - isCurrentPhase: boolean; - currentPhase: number; -} -export const PhaseBoxMobile = ({ - title, - backgroundColor = 'var(--bcds-surface-background-white)', - learnMoreBox, - iconBox, - accordionBackground, - isCurrentPhase = false, - currentPhase, -}: PhaseBoxProps) => { - const PhaseBoxRef = useRef(null); - - return ( - <> - - - - - - - - - {title} - - - - - - - - - - - - - - - - - {iconBox} - - - - - - - } - aria-controls="panel1a-content" - id="panel1a-header" - > - Learn More - - {learnMoreBox} - - - - - - - - - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/PhasesWidgetMobile.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/PhasesWidgetMobile.tsx deleted file mode 100644 index 66871c2b7..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/PhasesWidgetMobile/PhasesWidgetMobile.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import React, { useContext } from 'react'; -import { Grid, Skeleton, Typography } from '@mui/material'; -import { MetBodyOld, MetHeader3, MetPaper } from 'components/common'; -import { WidgetType } from 'models/widget'; -import { styled } from '@mui/material/styles'; -import { ActionContext } from '../../../ActionContext'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faChevronRight } from '@fortawesome/pro-regular-svg-icons/faChevronRight'; -import { EngagementPhaseMobile } from './EngagementPhaseMobile'; -import MuiAccordion, { AccordionProps } from '@mui/material/Accordion'; -import MuiAccordionSummary, { AccordionSummaryProps } from '@mui/material/AccordionSummary'; -import MuiAccordionDetails from '@mui/material/AccordionDetails'; -import { ENGAGEMENT_PHASES, ProcessStageProps } from 'models/engagementPhases'; - -const Accordion = styled((props: AccordionProps) => )( - ({ theme }) => ({ - border: `1px solid ${theme.palette.divider}`, - '&:not(:last-child)': { - borderBottom: 0, - }, - '&:before': { - display: 'none', - }, - }), -); - -const AccordionSummary = styled((props: AccordionSummaryProps) => ( - } - {...props} - /> -))(({ theme }) => ({ - backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, .05)' : 'rgba(0, 0, 0, .03)', - flexDirection: 'row-reverse', - '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': { - transform: 'rotate(90deg)', - }, - '& .MuiAccordionSummary-content': { - marginLeft: theme.spacing(1), - }, -})); - -const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ - padding: theme.spacing(2), - borderTop: '1px solid rgba(0, 0, 0, .125)', -})); - -export const PhasesWidgetMobile = () => { - const phases = Object.values(ENGAGEMENT_PHASES); - const { widgets, isWidgetsLoading } = useContext(ActionContext); - - const phasesWidget = widgets.find((widget) => widget.widget_type_id === WidgetType.Phases); - - const [expanded, setExpanded] = React.useState(false); - - const handleChange = (state: boolean) => (event: React.SyntheticEvent, newExpanded: boolean) => { - setExpanded(newExpanded); - }; - - if (isWidgetsLoading) { - return ; - } - - if (!phasesWidget) { - return null; - } - - return ( - - - - {phasesWidget.title} - - - - Click on the sections below to expand them and learn more about each EA process phase. You can - also learn more about each engagement period by clicking the engagement icon. - - - - - - The EA Process - - - {phases.map((phase: ProcessStageProps) => ( - - ))} - - - - - - ); -}; diff --git a/met-web/src/components/engagement/view/widgets/PhasesWidget/index.tsx b/met-web/src/components/engagement/view/widgets/PhasesWidget/index.tsx deleted file mode 100644 index cef3d6763..000000000 --- a/met-web/src/components/engagement/view/widgets/PhasesWidget/index.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, { useContext, useState } from 'react'; -import { Grid, Skeleton, Stack } from '@mui/material'; -import { MetBodyOld, MetHeader3, MetLabel, MetPaper } from 'components/common'; -import { WidgetType } from 'models/widget'; -import { ActionContext } from '../../ActionContext'; -import { EngagementPhase } from './EngagementPhase'; -import { EngagementPhases, ENGAGEMENT_PHASES } from 'models/engagementPhases'; -import { ForumIcon } from './ForumIcon'; -import { InfoArrow } from './InfoArrow'; -import { When } from 'react-if'; - -interface PhaseContextProps { - anchorEl: HTMLButtonElement | null; - setAnchorEl: React.Dispatch>; -} - -export const PhaseContext = React.createContext({ - anchorEl: null, - setAnchorEl: () => { - throw new Error('Not implemented'); - }, -}); -export const PhasesWidget = () => { - const { widgets, isWidgetsLoading } = useContext(ActionContext); - const [anchorEl, setAnchorEl] = useState(null); - const phases = Object.values(ENGAGEMENT_PHASES); - const phasesWidget = widgets.find((widget) => widget.widget_type_id === WidgetType.Phases); - const currentPhaseId = phasesWidget?.items[0]?.widget_data_id || EngagementPhases.Standalone; - - if (isWidgetsLoading) { - return ; - } - - if (!phasesWidget) { - return null; - } - - return ( - - - - - {phasesWidget.title} - - - - - - Current Phase: {phases.find((phase) => phase.phaseId === currentPhaseId)?.title || ''} - - - - - - Click ā€˜learn moreā€™ on the sections below for more details about each phase in the - Environmental Assessment process. Click the speech bubble icon - {} to learn more about each - unique public commenting period. - - - - - {phases.map((phase) => ( - - ))} - - - - - - - - - ); -}; diff --git a/met-web/src/models/engagementPhases.tsx b/met-web/src/models/engagementPhases.tsx deleted file mode 100644 index 3ffc90998..000000000 --- a/met-web/src/models/engagementPhases.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import React, { ReactNode } from 'react'; -import { Grid } from '@mui/material'; -import { MetParagraphOld } from 'components/common'; - -export enum EngagementPhases { - Standalone = 0, - EarlyEngagement = 1, - ReadinessDecision = 2, - ProcessPlanning = 3, - ApplicationDevelopmentReview = 4, - EffectsAssessmentRecommendation = 5, - Decision = 6, - PostCertificate = 7, -} - -export interface ProcessStageProps { - phaseId: number; - backgroundColor: string; - learnMoreBackgroundColor: string; - title: string; - learnMoreText: ReactNode; - popOverText?: string; - accordionBackground?: string; -} - -export const INFO_ARROW = { - backgroundColor: '#54858D', -}; - -export const PAST_PHASE = { - backgroundColor: '#7B8283', - borderColor: '#565656', - learnMoreBackgroundColor: '#f2f2f2', -}; - -export const CURRENT_PHASE = { - iconColor: '#D8292F', -}; - -export const ENGAGEMENT_PHASES = { - EarlyEngagement: { - phaseId: EngagementPhases.EarlyEngagement, - title: 'Early Engagement', - backgroundColor: '#54858D', - accordionBackground: '#EFFBFD', - learnMoreBackgroundColor: '#EFFBFD', - learnMoreText: ( - - - Engage with Indigenous nations, stakeholders, technical experts and the public to identify potential - key issues early in the process, and ways they could be addressed. - - - ), - popOverText: - 'Tell us about your interests, issues and concerns about the initial proposal for the project. How would the project as proposed personally affect you, your family, or your community? Tell us how you want to provide feedback and be involved in the rest of the assessment process.', - }, - ReadinessDecision: { - phaseId: EngagementPhases.ReadinessDecision, - title: 'Readiness Decision', - backgroundColor: '#DA6D65', - learnMoreBackgroundColor: '#F2DEDE', - accordionBackground: '#F2DEDE', - learnMoreText: ( - - - Review detailed project description, and input from early engagement and technical advisors, to - determine whether to proceed to environmental assessment. Consensus with Indigenous nations sought. - - - ), - }, - ProcessPlanning: { - phaseId: EngagementPhases.ProcessPlanning, - title: 'Process Planning', - backgroundColor: '#043673', - accordionBackground: '#ECF3FC', - learnMoreBackgroundColor: '#ECF3FC', - learnMoreText: ( - - - Engage with Indigenous nations, stakeholders, technical experts to establish how the environmental - assessment will be conducted, including scope, procedures and methods, and how provincial and - Indigenous processes and decision-making will align. Consensus with Indigenous nations sought. - - - ), - popOverText: - 'Tell us what you think of the draft process order and assessment plan. Have we captured everything that should be assessed and the information required? Are the timelines and assessment methods appropriate? What do you think of how we plan to collect feedback from the public?', - }, - AppDevReview: { - phaseId: EngagementPhases.ApplicationDevelopmentReview, - title: 'Application Development & Review', - backgroundColor: '#4D95D0', - accordionBackground: '#DDF0FE', - learnMoreBackgroundColor: '#DDF0FE', - learnMoreText: ( - <> - - - Proponent consults and does technical studies, then develops the initial application. EAO then - seeks feedback on it from Indigenous nations, stakeholders, technical experts and the public. - - - - - Proponent revises application, and submits to EAO for review. Consensus with Indigenous nations - sought. - - - - - Decision point: accept revised application or require further revisions. - - - - ), - popOverText: - 'Tell us what you think about the proponentā€™s application. Are there effects that havenā€™t been fully considered? Now that you have the proponentā€™s full assessment, is there anything new or is still raising concerns for you ? Do you think something has been assessed inaccurately?', - }, - Recommendation: { - phaseId: EngagementPhases.EffectsAssessmentRecommendation, - title: 'Effects Assessment & Recommendation', - backgroundColor: '#E7A913', - accordionBackground: '#FFEFCB', - learnMoreBackgroundColor: '#FFEFCB', - learnMoreText: ( - <> - - - Assess potential effects of the project. Develop assessment report and draft conditions to - address potential adverse effects, in consultation with technical experts and Indigenous - nations. Seek and incorporate feedback from Indigenous nations, stakeholders, technical experts - and the public. Consensus with Indigenous nations sought. - - - - - Decision point: recommend to ministers whether or not to issue an Environmental Assessment - Certificate. - - - - ), - popOverText: - ' Tell us what you think about the package of draft decision materials that will be provided to Ministers, who will decide whether or not to issue an environmental assessment certificate. Is anything missing? Has something been assessed incorrectly? What should the ministers consider that isnā€™t already included?', - }, - Decision: { - phaseId: EngagementPhases.Decision, - title: 'Decision', - backgroundColor: '#6A54A3', - accordionBackground: '#F3EFFF', - learnMoreBackgroundColor: '#F3EFFF', - learnMoreText: ( - - - Decision point: Ministers determine whether or not project will receive an Environmental Assessment - Certificate, and if so, what conditions will be required to address potential adverse effects. - - - ), - }, - PostCertificate: { - phaseId: EngagementPhases.PostCertificate, - title: 'Post-Certificate', - backgroundColor: '#A6BB2E', - accordionBackground: '#F4F7E2', - learnMoreBackgroundColor: '#F4F7E2', - learnMoreText: ( - <> - - - Monitor project to make sure requirements are being followed. Projects not in compliance are - subject to enforcement measures, including fines. - - - - - Proponents may also seek amendments to the Certificate as permitting and construction proceeds - and operations get underway. - - - - ), - }, -}; diff --git a/met-web/src/models/widget.tsx b/met-web/src/models/widget.tsx index 1db936478..07043b0e3 100644 --- a/met-web/src/models/widget.tsx +++ b/met-web/src/models/widget.tsx @@ -16,7 +16,6 @@ export interface Widget { export enum WidgetType { WhoIsListening = 1, Document = 2, - Phases = 3, Subscribe = 4, Events = 5, Map = 6, diff --git a/met-web/tests/unit/components/engagement/engagement.test.tsx b/met-web/tests/unit/components/engagement/engagement.test.tsx index fe0d60e5f..053c37537 100644 --- a/met-web/tests/unit/components/engagement/engagement.test.tsx +++ b/met-web/tests/unit/components/engagement/engagement.test.tsx @@ -47,14 +47,6 @@ const whoIsListeningWidget: Widget = { items: [widgetItem], }; -const engagementPhasesWidget: Widget = { - id: 2, - title: 'Engagement Phases', - widget_type_id: WidgetType.Phases, - engagement_id: 1, - items: [], -}; - const mockLocationData = { state: { open: true }, pathname: '', search: '', hash: '', key: '' }; jest.mock('hooks', () => ({ @@ -181,26 +173,4 @@ describe('Engagement View page tests', () => { expect(mockWidgetsRtkUnwrap).toHaveBeenCalledOnce(); expect(mockContactRtkUnwrap).toHaveBeenCalledOnce(); }); - - test('Phases widget appears', async () => { - getEngagementMock.mockReturnValueOnce( - Promise.resolve({ - ...draftEngagement, - surveys: surveys, - }), - ); - mockWidgetsRtkUnwrap.mockReturnValueOnce(Promise.resolve([engagementPhasesWidget])); - const { container } = render(); - - await waitFor(() => { - expect(container.querySelector('span.MuiSkeleton-root')).toBeNull(); - expect(mockWidgetsRtkUnwrap).toHaveReturned(); - }); - - expect(mockWidgetsRtkUnwrap).toHaveBeenCalledOnce(); - expect(getEngagementMock).toHaveBeenCalledOnce(); - - const eaProcessAccordion = screen.getByTestId('eaProcessAccordion'); - expect(eaProcessAccordion).toBeVisible(); - }); }); diff --git a/met-web/tests/unit/components/engagement/form/edit/EngagementForm.Edit.Two.test.tsx b/met-web/tests/unit/components/engagement/form/edit/EngagementForm.Edit.Two.test.tsx index 72049ad38..4deafaca8 100644 --- a/met-web/tests/unit/components/engagement/form/edit/EngagementForm.Edit.Two.test.tsx +++ b/met-web/tests/unit/components/engagement/form/edit/EngagementForm.Edit.Two.test.tsx @@ -183,7 +183,7 @@ describe('Engagement form page tests', () => { await waitFor(() => { expect(screen.getByText('Select Widget')).toBeVisible(); expect(screen.getByTestId(`widget-drawer-option/${WidgetType.WhoIsListening}`)); - expect(screen.getByTestId(`widget-drawer-option/${WidgetType.Phases}`)); + expect(screen.getByTestId(`widget-drawer-option/${WidgetType.Document}`)); }); }); diff --git a/met-web/tests/unit/components/widgets/PhasesWidget.test.tsx b/met-web/tests/unit/components/widgets/PhasesWidget.test.tsx deleted file mode 100644 index a2c23f1a0..000000000 --- a/met-web/tests/unit/components/widgets/PhasesWidget.test.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import React from 'react'; -import { render, waitFor, screen, fireEvent } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import EngagementForm from '../../../../src/components/engagement/form'; -import { setupEnv } from '../setEnvVars'; -import * as reactRedux from 'react-redux'; -import * as reactRouter from 'react-router'; -import * as engagementService from 'services/engagementService'; -import * as widgetService from 'services/widgetService'; -import * as engagementMetadataService from 'services/engagementMetadataService'; -import * as membershipService from 'services/membershipService'; -import * as engagementSettingService from 'services/engagementSettingService'; -import { createDefaultSurvey, Survey } from 'models/survey'; -import { Widget, WidgetItem, WidgetType } from 'models/widget'; -import { draftEngagement, engagementMetadata } from '../factory'; -import { USER_ROLES } from 'services/userService/constants'; -import { EngagementSettings, createDefaultEngagementSettings } from 'models/engagement'; - -const survey: Survey = { - ...createDefaultSurvey(), - id: 1, - name: 'Survey 1', - engagement_id: 1, -}; - -jest.mock('axios'); - -const surveys = [survey]; - -const phaseWidgetItem: WidgetItem = { - id: 2, - widget_id: 2, - widget_data_id: 0, - sort_index: 1, -}; - -const phasesWidget: Widget = { - id: 2, - title: 'Environmental Assessment Process', - widget_type_id: WidgetType.Phases, - engagement_id: 1, - items: [], -}; - -const mockEngagementSettings: EngagementSettings = { - ...createDefaultEngagementSettings(), -}; - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useLocation: jest.fn(() => ({ search: '' })), - useParams: jest.fn(() => { - return { projectId: '' }; - }), - useNavigate: () => jest.fn(), -})); - -jest.mock('react-redux', () => ({ - ...jest.requireActual('react-redux'), - useSelector: jest.fn(() => { - return { - roles: [USER_ROLES.VIEW_PRIVATE_ENGAGEMENTS, USER_ROLES.EDIT_ENGAGEMENT, USER_ROLES.CREATE_ENGAGEMENT], - assignedEngagements: [draftEngagement.id], - }; - }), -})); - -jest.mock('@reduxjs/toolkit/query/react', () => ({ - ...jest.requireActual('@reduxjs/toolkit/query/react'), - fetchBaseQuery: jest.fn(), -})); - -jest.mock('components/map', () => () => { - return
; -}); - -const mockCreateWidget = jest.fn(() => Promise.resolve(phasesWidget)); -const mockCreateWidgetItems = jest.fn(() => Promise.resolve([phaseWidgetItem])); -const mockCreateWidgetItemsTrigger = jest.fn(() => { - return { - unwrap: mockCreateWidgetItems, - }; -}); -jest.mock('apiManager/apiSlices/widgets', () => ({ - ...jest.requireActual('apiManager/apiSlices/widgets'), - useCreateWidgetMutation: () => [mockCreateWidget], - useCreateWidgetItemsMutation: () => [mockCreateWidgetItemsTrigger], - useUpdateWidgetMutation: () => [jest.fn(() => Promise.resolve(phasesWidget))], - useDeleteWidgetMutation: () => [jest.fn(() => Promise.resolve())], - useSortWidgetsMutation: () => [jest.fn(() => Promise.resolve())], -})); - -describe('Phases widget tests', () => { - jest.spyOn(reactRedux, 'useDispatch').mockImplementation(() => jest.fn()); - const useParamsMock = jest.spyOn(reactRouter, 'useParams'); - const getEngagementMock = jest - .spyOn(engagementService, 'getEngagement') - .mockReturnValue(Promise.resolve(draftEngagement)); - const getWidgetsMock = jest.spyOn(widgetService, 'getWidgets').mockReturnValue(Promise.resolve([phasesWidget])); - jest.spyOn(engagementMetadataService, 'getEngagementMetadata').mockReturnValue( - Promise.resolve([engagementMetadata]), - ); - jest.spyOn(membershipService, 'getTeamMembers').mockReturnValue(Promise.resolve([])); - jest.spyOn(engagementSettingService, 'getEngagementSettings').mockReturnValue( - Promise.resolve(mockEngagementSettings), - ); - - beforeEach(() => { - setupEnv(); - }); - - test.only('Phases widget is created when option is clicked', async () => { - useParamsMock.mockReturnValue({ engagementId: '1' }); - getEngagementMock.mockReturnValueOnce( - Promise.resolve({ - ...draftEngagement, - surveys: surveys, - }), - ); - getWidgetsMock.mockReturnValueOnce(Promise.resolve([])); - mockCreateWidget.mockReturnValue(Promise.resolve(phasesWidget)); - mockCreateWidgetItems.mockReturnValue(Promise.resolve([phaseWidgetItem])); - render(); - - await waitFor(() => { - expect(screen.getByText('Add Widget')).toBeInTheDocument(); - }); - - const addWidgetButton = screen.getByText('Add Widget'); - fireEvent.click(addWidgetButton); - - await waitFor(() => { - expect(screen.getByText('Select Widget')).toBeVisible(); - }); - - getWidgetsMock.mockReturnValueOnce(Promise.resolve([phasesWidget])); - - const phasesOption = screen.getByTestId(`widget-drawer-option/${WidgetType.Phases}`); - fireEvent.click(phasesOption); - - await waitFor(() => { - expect(screen.getByTestId('engagementPhaseSelect')).toBeVisible(); - }); - - expect(mockCreateWidget).toHaveBeenNthCalledWith(1, { - widget_type_id: WidgetType.Phases, - engagement_id: draftEngagement.id, - title: phasesWidget.title, - }); - expect(getWidgetsMock).toHaveBeenCalledTimes(2); - - const saveWidgetButton = screen.getByTestId('savePhasesWidgetButton'); - expect(saveWidgetButton).toBeDisabled(); - - const standalonePhaseCheckbox = screen.getByTestId('standalonePhaseCheckbox'); - fireEvent.click(standalonePhaseCheckbox); - - expect(saveWidgetButton).toBeEnabled(); - - fireEvent.click(saveWidgetButton); - - await waitFor(() => { - expect(saveWidgetButton).not.toBeVisible(); - }); - - expect(mockCreateWidgetItemsTrigger).toHaveBeenNthCalledWith(1, { - widget_id: phasesWidget.id, - widget_items_data: [ - { - widget_id: phasesWidget.id, - widget_data_id: 0, - }, - ], - }); - }); -});