COmponente
import { setSubcenter } from 'redux-store/reducers/cadSession/actions'; import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useQuery } from 'react-query'; import { useDispatch, useSelector } from 'react-redux'; import { Avatar, Button, Col, Collapse, Form, Layout, Row, Select, Space, Spin, Switch, Tag, Tooltip, Typography } from 'antd'; import { LeftOutlined, MenuOutlined, RightOutlined, SoundFilled, SoundOutlined } from '@ant-design/icons'; import { PROFILE_SUBMODULES } from 'config/profile-permissions'; import { REACT_QUERY_KEYS } from 'config/react-query-keys'; import emergenciesCatalogues from 'api/emergenciesCatalogues'; import { advanceFilterOption } from 'utils'; import { AUTHORITIES, DISPATCH_TYPE_VIEW, EMERGENCIES_STATUS } from 'utils/constants'; import { useSdcApi } from 'hooks'; import { useAccess } from 'hooks/useAccess'; import DelayedSearcher from 'components/DelayedSearcher'; import EmptyContentSelect from 'components/EmptyContentSelect'; import { GridIcon, ListIcon, MapIcon, TriangleWarningIcon } from 'components/icons'; import { DEFAULT_FILTER_PARAMS } from '../constants'; import './index.scss'; const { Header } = Layout; const { Text } = Typography; const assignedStatusOptionsValue = { ASSIGNED: 'assigned', UNASSIGNED: 'unassigned' }; const NoCossableTag = (props) => { const { label } = props; return ( <Tag {...props} closable={false}> {label} </Tag> ); }; /** * * @param {{ * onChangeParams: (params:import('types').GetEmergenciesByFiltersParams) => void, * onChangeTypeView: (value:number) => void, * typeView: number, * loadingEmergencies:boolean, * muteEmergencySoundAlert:boolean, * showMuteEmergencySoundAlertButton:boolean, * onClickMuteEmergencySoundAlert: () => void, * onClickHideSidebarButton: () => void, * emergencyFilterParams: import('types').GetEmergenciesByFiltersParams * showAssignationStatusFilter?: boolean, * showEmergencyStatusButtonsFilter?: boolean, * showMunicipalityFilter?: boolean, * showDispatchedByMeFilter?: boolean, * showDispatchingStatusFilter?: boolean, * showOpenEmergenciesFilter?: boolean, * showCreateIncidentByMeFilter?: boolean * showHideSidebarButton?: boolean * showSidebar?: boolean * }} param0 * @returns */ const EmergenciesHeader = ({ onChangeTypeView, onClickMuteEmergencySoundAlert, onChangeParams, onClickHideSidebarButton, muteEmergencySoundAlert, showMuteEmergencySoundAlertButton = true, typeView, loadingEmergencies, emergencyFilterParams, showAssignationStatusFilter, showEmergencyStatusButtonsFilter, showMunicipalityFilter, showDispatchedByMeFilter, showDispatchingStatusFilter, showOpenEmergenciesFilter, showCreateIncidentByMeFilter, showHideSidebarButton, showSidebar }) => { const { microservices: { admin: { priority: { getAll: getAllPriorities } }, stateSuperviser: { admin: { getSubcenter } }, dispatch: { incidentRelevant: { getIncidentRelevantCount } } } } = useSdcApi(); const dispatch = useDispatch(); const { t } = useTranslation('translations'); const [form] = Form.useForm(); const { timeOpenEmergencies, stateIdDefault } = useSelector((state) => state.systemParamas); const [searchText, setSearchText] = useState(null); const [activeCollapsiblePanel, setActiveCollapsiblePanel] = useState(); const [checkAssignedUnit, setCheckAssignedUnit] = useState(false); const { userId, assignedCorporation: profileCorporations, subcenter } = useSelector((state) => state.CadSession); const { validateAuthority, hasAccess } = useAccess(); const showFilterByTime = useMemo(() => hasAccess(PROFILE_SUBMODULES.SDCW_SHOW_FILTER_BY_TIME), [hasAccess]); const corporationOptions = useMemo( () => profileCorporations?.map((pc) => ({ label: pc?.name, value: pc?.id })), [profileCorporations] ); /** * filteredOperativeGroups devuelve un listado de grupos operativos que estén relacionados a alguna de las corporaciones que recibe por props */ const filteredOperativeGroups = useCallback( (corporationIds = []) => profileCorporations?.reduce((result, corporation) => { if (corporationIds.includes(corporation.id)) { result.push(...corporation.operativeGroups.map(({ name, id }) => ({ label: name, value: id }))); } return result; }, []) ?? [], [profileCorporations] ); const operativeGroupOptions = useMemo(() => { return filteredOperativeGroups(emergencyFilterParams?.corporationIds); }, [filteredOperativeGroups, emergencyFilterParams?.corporationIds]); /* QUERIES */ const { data: priorityOptions, isLoading: isLoadingPriorities } = useQuery( [getAllPriorities.queryKeyFunction()], () => getAllPriorities.endpoint(), { select: (data) => data?.data?.result?.map((p) => ({ label: p?.name, value: p?.id })) } ); const { data: subcenters, isLoading: isLoadingSubcenters } = useQuery( [getSubcenter.queryKeyFunction()], () => getSubcenter.endpoint(), { enabled: validateAuthority(AUTHORITIES.STATE_SUPERVISOR), select: getSubcenter.selectQueryFunction, onSuccess: (data) => { if (!subcenter?.dwKey && data?.length > 0) { selectSubcenterFromDwKey(data?.[0]?.subCenter, data); } } } ); const { data: dataMunicipalities = [], isLoading: isLoadingMunicipalitys } = useQuery( [REACT_QUERY_KEYS.admin.municipality.getByStateId(`id-municipality-${stateIdDefault}`)], () => emergenciesCatalogues.municipalitiesByState(stateIdDefault) /** CAMBIAR A dispatchDefaultStateId */, { select: (data) => data?.data?.result } ); const { data: incidentRelevantCount } = useQuery( [getIncidentRelevantCount.queryKeyFunction(userId), userId], () => getIncidentRelevantCount.endpoint({ 'user-id': userId }), { select: (data) => { const { count } = getIncidentRelevantCount.selectQueryFunction(data) || { count: 0 }; return count; } } ); const subcenterOptions = useMemo( () => subcenters?.map((p) => ({ label: p?.ambiente, value: p?.subCenter })), [subcenters] ); const munipalityOptions = useMemo( () => dataMunicipalities?.map((item) => ({ label: item?.name, value: item?.id })), [dataMunicipalities] ); /* EFFECTS */ const triangleWarningIconColor = useMemo(() => { if (emergencyFilterParams?.filterByRelevantIncident) return 'var(--primary-color-main)'; else if (incidentRelevantCount > 0) return 'var(--error-color)'; return '#C6C6C6'; }, [emergencyFilterParams?.filterByRelevantIncident, incidentRelevantCount]); /* EFFECTS */ // Set initial state useEffect(() => { const initialParams = DEFAULT_FILTER_PARAMS; if (showOpenEmergenciesFilter && timeOpenEmergencies) initialParams.maxHours = timeOpenEmergencies; if (showDispatchingStatusFilter) initialParams.statusEmergency = EMERGENCIES_STATUS.DISPATCHING; if (!showDispatchedByMeFilter) delete initialParams.assignedUnit; onChangeParams(initialParams); }, [showOpenEmergenciesFilter, dispatch, timeOpenEmergencies, showDispatchingStatusFilter]); const changeViewTypeHandler = (v) => { onChangeTypeView && onChangeTypeView(v); }; function changeSearchHandler(event) { // setSearchText(!e.target.value ? undefined : e.target.value); setSearchText(event?.target?.value); } const clickAdvanceFilterButtonHandler = () => { setActiveCollapsiblePanel((v) => (v ? null : '1')); }; function delayedSearchHandler() { if (searchText !== null) { onChangeParams({ page: 0, query: searchText?.trim() }); } } function selectSubcenterFromDwKey(dwKey, subcenters) { const subcenterSelected = subcenters?.find((sc) => sc?.subCenter === dwKey); if (subcenterSelected) { const { subCenter: dwKey, ambiente: name, ...rest } = subcenterSelected; const newSubcenter = { ...rest, id: undefined, dwKey, name }; dispatch(setSubcenter(newSubcenter)); } } function onChangeSubcenter(value) { selectSubcenterFromDwKey(value, subcenters); } const changeFormFilterValuesHandler = () => { const values = form?.getFieldsValue(); const createdBy = showCreateIncidentByMeFilter && values?.createdBy ? userId : values.createdByMe ? userId : undefined; const statusEmergency = showEmergencyStatusButtonsFilter && values?.incompleteEmergency ? 'OPEN' : undefined; if (values?.corporationOperativeIds) /** Esta linea de código actualiza los grupos operativos seleccionado cuando se quita una corporación */ values.corporationOperativeIds = values?.corporationOperativeIds?.reduce((result, ogId) => { if (filteredOperativeGroups(values?.corporationIds).some(({ value }) => ogId === value)) result.push(ogId); return result; }, []); form?.setFieldValue('corporationOperativeIds', values.corporationOperativeIds); const updatedParams = { ...values, page: 0, createdBy, statusEmergency, status: 'OPEN' }; // Esta validación aplica sólo si `!allowAdvanceFilter` ya que el input de `incompleteEmergency` sólo se muestra en dicha condición if (!showEmergencyStatusButtonsFilter) { updatedParams.statusEmergency = values?.incompleteEmergency ? 'OPEN' : undefined; } delete values.createdByMe; delete values.incompleteEmergency; onChangeParams(updatedParams); }; const assignedStatusOptions = useMemo( () => [ { label: t('despacho.assigned_folio'), value: assignedStatusOptionsValue?.ASSIGNED }, { label: t('despacho.unassigned_folio'), value: assignedStatusOptionsValue?.UNASSIGNED } ], [t] ); function changeStatusEmergency(corporationStatus, statusEmergency) { onChangeParams({ status: corporationStatus, statusEmergency }); } const onSelectRelevantView = () => { if (loadingEmergencies) return; onChangeParams({ filterByRelevantIncident: !emergencyFilterParams.filterByRelevantIncident, page: 0 }); }; const clickDispatchedTabButtonHandler = () => changeStatusEmergency(EMERGENCIES_STATUS.OPEN, undefined); const clickOpenedTabButtonHandler = () => changeStatusEmergency(undefined, EMERGENCIES_STATUS.OPEN); const clickClosedTabButtonHandler = () => changeStatusEmergency(undefined, EMERGENCIES_STATUS.CLOSED); const statusButtonsType = useMemo( () => ({ dispatched: !emergencyFilterParams.statusEmergency ? 'primary' : 'text', opened: emergencyFilterParams.statusEmergency === EMERGENCIES_STATUS.OPEN ? 'primary' : 'text', closed: emergencyFilterParams.statusEmergency === EMERGENCIES_STATUS.CLOSED ? 'primary' : 'text' }), [emergencyFilterParams.statusEmergency] ); const onHandlerFilterDispatch = (e) => { setCheckAssignedUnit(e); }; return ( <Header className="dashboard-dispatcher-emergencies-header "> <Row justify="space-between" align="middle" wrap={false} className="options-view-wrapper" gutter={10}> <Col span={3}> <Row justify="start"> <Space className="title-header-wrapper"> <Typography.Text>{t('map_operador.Incident')}</Typography.Text> {loadingEmergencies && <Spin size="small" />} </Space> </Row> </Col> <Col flex="auto"> {showEmergencyStatusButtonsFilter && ( <Space size="middle"> <Button type={statusButtonsType?.dispatched} onClick={clickDispatchedTabButtonHandler}> {t('despacho.dispatched')} </Button> <Button type={statusButtonsType?.opened} onClick={clickOpenedTabButtonHandler}> {t('despacho.opened')} </Button> <Button type={statusButtonsType?.closed} onClick={clickClosedTabButtonHandler}> {t('despacho.closed')} </Button> </Space> )} </Col> <Col flex="250px"> {validateAuthority(AUTHORITIES.STATE_SUPERVISOR) && ( <Form.Item label={t('despacho.subcenter')} className="select-item" labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} > <Select allowClear={false} className="cadlite-ant-select" value={subcenter?.dwKey} loading={isLoadingSubcenters} options={subcenterOptions} filterOption={advanceFilterOption} onChange={onChangeSubcenter} /> </Form.Item> )} </Col> <Col flex="auto"> <Row justify="end" align="middle" wrap={false} gutter={8}> <Col className="relevant-emergencies-filter" style={{ cursor: 'pointer', paddingRight: '12px', borderRight: '1px solid #3E5378', marginRight: '12px' }} > <Tooltip title={t('Incidentes Relevantes')}> <TriangleWarningIcon className="relevant-incident" color={triangleWarningIconColor} width={21} height={21} onClick={onSelectRelevantView} /> </Tooltip> </Col> {showMuteEmergencySoundAlertButton && ( <Col className="button-wrapper"> <Button type="text" icon={ <Tooltip title={t('despacho.emergency_sound_alert')}> {muteEmergencySoundAlert ? ( <SoundFilled style={{ color: '#3867FC', fontSize: '19px' }} /> ) : ( <SoundOutlined style={{ color: '#C6C6C6', fontSize: '19px' }} /> )} </Tooltip> } onClick={onClickMuteEmergencySoundAlert} /> </Col> )} <Col className="button-wrapper"> <Button type="text" icon={<GridIcon status={typeView === DISPATCH_TYPE_VIEW.GRID ? 'true' : undefined} />} onClick={() => changeViewTypeHandler(DISPATCH_TYPE_VIEW.GRID)} /> </Col> <Col className="button-wrapper"> <Button type="text" icon={<ListIcon status={typeView === DISPATCH_TYPE_VIEW.LIST ? 'true' : undefined} />} onClick={() => changeViewTypeHandler(DISPATCH_TYPE_VIEW.LIST)} /> </Col> <Col className="button-wrapper"> <Button type="text" icon={<MapIcon status={typeView === DISPATCH_TYPE_VIEW.MAP ? 'true' : undefined} />} onClick={() => changeViewTypeHandler(DISPATCH_TYPE_VIEW.MAP)} /> </Col> <Col style={{ display: 'flex' }}> <DelayedSearcher allowClear value={searchText} onChange={changeSearchHandler} delayedTime={1250} onDelayedChange={delayedSearchHandler} placeholder={t('searchAdvaced.input')} informationText={t('despacho.info_text')} /> </Col> <Col> <Tooltip title={t('despacho.advanced_filter')} placement="bottom"> <Button className="filter-button" type="primary" shape="default" icon={<MenuOutlined />} onClick={clickAdvanceFilterButtonHandler} /> </Tooltip> </Col> {showHideSidebarButton && ( <Col> <Avatar className="icon-button" style={{ background: 'var(--primary-color-main)' }} size={20} icon={showSidebar ? <RightOutlined /> : <LeftOutlined />} onClick={onClickHideSidebarButton} /> </Col> )} </Row> </Col> </Row> <Collapse bordered={false} collapsible="disabled" className="collapse-filter-panel" activeKey={activeCollapsiblePanel} items={[ { key: '1', children: ( <Row align="middle" className="advanced-filter-row-wrapper" gutter={12} wrap={false}> <Col flex="100px"> <Text strong>{t('despacho.filter_by')}:</Text> </Col> <Col flex="auto"> <Form layout="inline" form={form} onFieldsChange={changeFormFilterValuesHandler}> <Form.Item name="priorityIds" label={t('despacho.Prioridad')} labelCol={{ span: 24 }} className="select-item" wrapperCol={{ className: 'advanced-filter-col-wrapper', span: 24 }} > <Select className="cadlite-ant-select" value={emergencyFilterParams?.priorityIds} mode="multiple" loading={isLoadingPriorities} options={priorityOptions} tagRender={NoCossableTag} filterOption={advanceFilterOption} notFoundContent={<EmptyContentSelect fullText={t('despacho.not_found_priority')} />} /> </Form.Item> <Form.Item name="corporationIds" label={t('despacho.Corporacion')} className="select-item" labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} > <Select className="cadlite-ant-select" value={emergencyFilterParams?.corporationIds} mode="multiple" options={corporationOptions} tagRender={NoCossableTag} filterOption={advanceFilterOption} notFoundContent={<EmptyContentSelect fullText={t('despacho.not_found_corporation')} />} /> </Form.Item> <Form.Item name="corporationOperativeIds" label={t('despacho.operative_groups')} className="select-item" labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} > <Select className="cadlite-ant-select" value={emergencyFilterParams?.corporationOperativeIds} mode="multiple" options={operativeGroupOptions} tagRender={NoCossableTag} filterOption={advanceFilterOption} notFoundContent={<EmptyContentSelect fullText={t('despacho.operative_group_search_msg')} />} /> </Form.Item> {showAssignationStatusFilter && ( <Form.Item name="assignedStatus" label={t('despacho.assigned_status')} className="select-item" labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} > <Select allowClear className="cadlite-ant-select" value={emergencyFilterParams?.corporationIds} options={assignedStatusOptions} filterOption={advanceFilterOption} /> </Form.Item> )} {showMunicipalityFilter && ( <Form.Item name="municipalityAlternativeIds" label={t('despacho.municipality')} className="select-item" labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} > <Select allowClear mode="multiple" className="cadlite-ant-select" loading={isLoadingMunicipalitys} options={munipalityOptions} filterOption={advanceFilterOption} /> </Form.Item> )} {showCreateIncidentByMeFilter && ( <Form.Item label={t('despacho.Creados_mi')} labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} name="createdBy" > <Switch checked={ (emergencyFilterParams?.createdBy && emergencyFilterParams?.createdBy === userId) || false } /> </Form.Item> )} {showDispatchedByMeFilter && ( <Form.Item label={t('despacho.dispatched_by_me')} labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} name="assignedUnit" > <Switch onClick={(e) => onHandlerFilterDispatch(e)} checked={checkAssignedUnit} /> </Form.Item> )} {!showEmergencyStatusButtonsFilter && ( <Form.Item label={t('despacho.incomplete_folio')} labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} name="incompleteEmergency" > <Switch checked={ (emergencyFilterParams?.statusEmergency && emergencyFilterParams?.statusEmergency === 'OPEN') || false } /> </Form.Item> )} {!showFilterByTime && ( <Form.Item label={t('despacho.filter_by_time')} labelCol={{ span: 24 }} wrapperCol={{ className: 'advanced-filter-col-wrapper' }} name="moreQueries" > <Switch checked={emergencyFilterParams?.moreQueries || false} onChange={(checked) => { const updatedParams = { ...emergencyFilterParams, moreQueries: checked ? true : undefined }; onChangeParams(updatedParams); }} /> </Form.Item> )} </Form> </Col> </Row> ) } ]} ></Collapse> </Header> ); }; export default memo(EmergenciesHeader);
Leave a Comment