Skip to content

Commit

Permalink
Fishing map/vessel profile route (#2807)
Browse files Browse the repository at this point in the history
  • Loading branch information
j8seangel authored Aug 29, 2024
2 parents 36256a5 + f619bc5 commit eb912ba
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 39 deletions.
2 changes: 2 additions & 0 deletions apps/fishing-map/features/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
WORKSPACE_REPORT,
SEARCH,
WORKSPACE_SEARCH,
VESSEL_GROUP_REPORT,
} from 'routes/routes'
import { fetchWorkspaceThunk } from 'features/workspace/workspace.slice'
import { t } from 'features/i18n/i18n'
Expand Down Expand Up @@ -161,6 +162,7 @@ function App() {
// Checking only when REPORT entrypoint or WORKSPACE_REPORT when workspace is not loaded
const locationNeedsFetch =
locationType === REPORT ||
locationType === VESSEL_GROUP_REPORT ||
(locationType === WORKSPACE_REPORT && currentWorkspaceId !== urlWorkspaceId)
const hasWorkspaceIdChanged = locationType === WORKSPACE && currentWorkspaceId !== urlWorkspaceId

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import {
selectIsAnyVesselLocation,
selectVesselId,
selectIsAnyReportLocation,
selectIsVesselGroupReportLocation,
selectReportVesselGroupId,
} from 'routes/routes.selectors'
import { getReportCategoryFromDataview } from 'features/area-report/reports.utils'
import { selectViewOnlyVessel } from 'features/vessel/vessel.config.selectors'
Expand All @@ -40,6 +42,7 @@ import {
import { isBathymetryDataview } from 'features/dataviews/dataviews.utils'
import { selectDownloadActiveTabId } from 'features/download/downloadActivity.slice'
import { HeatmapDownloadTab } from 'features/download/downloadActivity.config'
import { selectViewOnlyVesselGroup } from 'features/vessel-group-report/vessel.config.selectors'
import {
selectContextAreasDataviews,
selectActivityDataviews,
Expand All @@ -48,7 +51,7 @@ import {
selectEventsDataviews,
} from './dataviews.categories.selectors'

const VESSEL_ONLY_VISIBLE_LAYERS = [
const REPORT_ONLY_VISIBLE_LAYERS = [
DataviewType.Basemap,
DataviewType.Context,
DataviewType.UserContext,
Expand Down Expand Up @@ -97,14 +100,20 @@ export const selectDataviewInstancesResolvedVisible = createSelector(
selectIsAnyVesselLocation,
selectViewOnlyVessel,
selectVesselId,
selectIsVesselGroupReportLocation,
selectReportVesselGroupId,
selectViewOnlyVesselGroup,
],
(
dataviews = [],
isReportLocation,
reportCategory,
isVesselLocation,
viewOnlyVessel,
vesselId
vesselId,
isVesselGroupReportLocation,
reportVesselGroupId,
viewOnlyVesselGroup
) => {
if (isReportLocation) {
return dataviews.filter((dataview) => {
Expand All @@ -121,16 +130,49 @@ export const selectDataviewInstancesResolvedVisible = createSelector(
}
if (isVesselLocation && viewOnlyVessel && vesselId !== undefined) {
return dataviews.filter(({ id, config }) => {
if (VESSEL_ONLY_VISIBLE_LAYERS.includes(config?.type as DataviewType)) {
if (REPORT_ONLY_VISIBLE_LAYERS.includes(config?.type as DataviewType)) {
return config?.visible
}
return config?.type === DataviewType.Track && id.includes(vesselId)
})
}

if (isVesselGroupReportLocation && viewOnlyVesselGroup && reportVesselGroupId !== undefined) {
return getReportVesselGroupVisibleDataviews(dataviews, reportVesselGroupId)
}

return dataviews.filter((dataview) => dataview.config?.visible)
}
)

function getReportVesselGroupVisibleDataviews(
dataviews: UrlDataviewInstance[],
reportVesselGroupId: string
) {
return dataviews.filter(({ category, config }) => {
if (REPORT_ONLY_VISIBLE_LAYERS.includes(config?.type as DataviewType)) {
return config?.visible
}
return (
category === DataviewCategory.VesselGroups &&
config?.filters?.['vessel-groups'].includes(reportVesselGroupId)
)
})
}

export const selectHasOtherVesselGroupDataviews = createSelector(
[selectDataviewInstancesResolved, selectReportVesselGroupId],
(dataviews, reportVesselGroupId) => {
if (!dataviews?.length) return false
const vesselGroupReportDataviews = getReportVesselGroupVisibleDataviews(
dataviews,
reportVesselGroupId
)
const workspaceVisibleDataviews = dataviews.filter(({ config }) => config?.visible === true)
return workspaceVisibleDataviews.length > vesselGroupReportDataviews.length
}
)

export const selectBasemapLabelsDataviewInstance = createSelector(
[selectAllDataviewInstancesResolved],
(dataviews) => {
Expand Down
15 changes: 3 additions & 12 deletions apps/fishing-map/features/user/UserVesselGroups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { useAppDispatch } from 'features/app/app.hooks'
import { selectDatasetsStatus } from 'features/datasets/datasets.slice'
import { getVesselGroupLabel } from 'features/vessel-groups/vessel-groups.utils'
import { sortByCreationDate } from 'utils/dates'
import { VESSEL_GROUP_REPORT } from 'routes/routes'
import VesselGroupReportLink from 'features/vessel-group-report/VesselGroupReportLink'
import { selectUserVesselGroups } from './selectors/user.permissions.selectors'
import styles from './User.module.css'

Expand Down Expand Up @@ -78,22 +78,13 @@ function UserVesselGroups() {
sortByCreationDate<VesselGroup>(vesselGroups).map((vesselGroup) => {
return (
<li className={styles.dataset} key={vesselGroup.id}>
<Link
className={styles.workspaceLink}
to={{
type: VESSEL_GROUP_REPORT,
payload: {
vesselGroupId: vesselGroup.id,
},
query: {},
}}
>
<VesselGroupReportLink vesselGroupId={vesselGroup.id}>
<span className={styles.workspaceTitle} data-test="workspace-name">
{getVesselGroupLabel(vesselGroup)}{' '}
<span className={styles.secondary}>({vesselGroup.vessels.length})</span>
</span>
<IconButton icon="arrow-right" />
</Link>
</VesselGroupReportLink>
<IconButton
icon="edit"
loading={vesselGroup.id === editingGroupId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
text-decoration: underline;
margin: 0 0.2rem;
}

.link {
text-decoration: underline;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useSelector } from 'react-redux'
import React from 'react'
import Link from 'redux-first-router-link'
import { VESSEL_GROUP_REPORT } from 'routes/routes'
import { selectWorkspace } from 'features/workspace/workspace.selectors'
import { DEFAULT_WORKSPACE_CATEGORY, DEFAULT_WORKSPACE_ID } from 'data/workspaces'
import { selectLocationQuery } from 'routes/routes.selectors'
import styles from './VesselGroupReport.module.css'

type VesselGroupReportLinkProps = {
vesselGroupId: string
children: React.ReactNode
}

function VesselGroupReportLink({ children, vesselGroupId }: VesselGroupReportLinkProps) {
const workspace = useSelector(selectWorkspace)
const query = useSelector(selectLocationQuery)
return (
<Link
className={styles.link}
to={{
type: VESSEL_GROUP_REPORT,
payload: {
category: workspace?.category || DEFAULT_WORKSPACE_CATEGORY,
workspaceId: workspace?.id || DEFAULT_WORKSPACE_ID,
vesselGroupId: vesselGroupId,
},
query,
}}
>
{children}
</Link>
)
}

export default VesselGroupReportLink
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import cx from 'classnames'
import { Button, Icon } from '@globalfishingwatch/ui-components'
import { useSelector } from 'react-redux'
import { Button, Icon, IconButton } from '@globalfishingwatch/ui-components'
import { useSmallScreen } from '@globalfishingwatch/react-hooks'
import { useAppDispatch } from 'features/app/app.hooks'
import ReportTitlePlaceholder from 'features/area-report/placeholders/ReportTitlePlaceholder'
import { TrackCategory, trackEvent } from 'features/app/analytics.hooks'
Expand All @@ -11,8 +13,11 @@ import {
setVesselGroupsModalOpen,
} from 'features/vessel-groups/vessel-groups.slice'
import { formatInfoField } from 'utils/info'
import { useLocationConnect } from 'routes/routes.hook'
import { selectHasOtherVesselGroupDataviews } from 'features/dataviews/selectors/dataviews.selectors'
import styles from './VesselGroupReportTitle.module.css'
import { VesselGroupReport } from './vessel-group-report.slice'
import { selectViewOnlyVesselGroup } from './vessel.config.selectors'

type ReportTitleProps = {
loading?: boolean
Expand All @@ -22,6 +27,10 @@ type ReportTitleProps = {
export default function VesselGroupReportTitle({ vesselGroup, loading }: ReportTitleProps) {
const { t } = useTranslation()
const dispatch = useAppDispatch()
const { dispatchQueryParams } = useLocationConnect()
const isSmallScreen = useSmallScreen()
const viewOnlyVesselGroup = useSelector(selectViewOnlyVesselGroup)
const hasOtherLayers = useSelector(selectHasOtherVesselGroupDataviews)

const onEditClick = useCallback(() => {
if (vesselGroup?.id || !vesselGroup?.vessels?.length) {
Expand All @@ -39,6 +48,11 @@ export default function VesselGroupReportTitle({ vesselGroup, loading }: ReportT
window.print()
}

const toggleViewOnlyVesselGroup = () => {
if (isSmallScreen) dispatchQueryParams({ sidebarOpen: false })
dispatchQueryParams({ viewOnlyVesselGroup: !viewOnlyVesselGroup })
}

if (loading) {
return (
<div className={cx(styles.container, styles.placeholder)}>
Expand All @@ -62,6 +76,21 @@ export default function VesselGroupReportTitle({ vesselGroup, loading }: ReportT
</a>

<div className={styles.actions}>
{hasOtherLayers && (
<IconButton
className="print-hidden"
type="border"
icon={viewOnlyVesselGroup ? 'layers-on' : 'layers-off'}
tooltip={
viewOnlyVesselGroup
? t('vessel.showOtherLayers', 'Show other layers')
: t('vessel.hideOtherLayers', 'Hide other layers')
}
tooltipPlacement="bottom"
size="small"
onClick={toggleViewOnlyVesselGroup}
/>
)}
<Button
type="border-secondary"
size="small"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { DEFAULT_VESSEL_GROUP_REPORT_STATE } from 'features/vessel/vessel.config

type VesselGroupReportProperty<P extends VesselGroupReportStateProperty> =
Required<VesselGroupReportState>[P]
export function selectVesselProfileStateProperty<P extends VesselGroupReportStateProperty>(
function selectVesselGroupReportStateProperty<P extends VesselGroupReportStateProperty>(
property: P
) {
return createSelector(
Expand All @@ -17,15 +17,16 @@ export function selectVesselProfileStateProperty<P extends VesselGroupReportStat
)
}

export const selectVesselGroupReportSection = selectVesselProfileStateProperty(
export const selectViewOnlyVesselGroup = selectVesselGroupReportStateProperty('viewOnlyVesselGroup')
export const selectVesselGroupReportSection = selectVesselGroupReportStateProperty(
'vesselGroupReportSection'
)
export const selectVesselGroupReportVesselsSubsection = selectVesselProfileStateProperty(
export const selectVesselGroupReportVesselsSubsection = selectVesselGroupReportStateProperty(
'vesselGroupReportVesselsSubsection'
)
export const selectVesselGroupReportActivitySubsection = selectVesselProfileStateProperty(
export const selectVesselGroupReportActivitySubsection = selectVesselGroupReportStateProperty(
'vesselGroupReportActivitySubsection'
)
export const selectVesselGroupReportEventsSubsection = selectVesselProfileStateProperty(
export const selectVesselGroupReportEventsSubsection = selectVesselGroupReportStateProperty(
'vesselGroupReportEventsSubsection'
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ type VesselGroupReportVesselsProps = {}

function VesselGroupReportVessels(props: VesselGroupReportVesselsProps) {
const vesselSubSection = useSelector(selectVesselGroupReportVesselsSubsection)
console.log('🚀 ~ VesselGroupReportVessels ~ vesselSubSection:', vesselSubSection)
return (
<div>
<p>Graph here</p>
Expand Down
1 change: 1 addition & 0 deletions apps/fishing-map/features/vessel/vessel.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const DEFAULT_VESSEL_STATE: VesselProfileState = {
}

export const DEFAULT_VESSEL_GROUP_REPORT_STATE: VesselGroupReportState = {
viewOnlyVesselGroup: true,
vesselGroupReportSection: 'vessels',
vesselGroupReportVesselsSubsection: 'flag',
vesselGroupReportActivitySubsection: 'fishing-effort',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Fragment, useState } from 'react'
import cx from 'classnames'
import { useTranslation } from 'react-i18next'
import Link from 'redux-first-router-link'
import { VesselGroup } from '@globalfishingwatch/api-types'
import { IconButton, ColorBarOption, Tooltip } from '@globalfishingwatch/ui-components'
import { UrlDataviewInstance } from '@globalfishingwatch/dataviews-client'
Expand All @@ -11,7 +10,7 @@ import styles from 'features/workspace/shared/LayerPanel.module.css'
import { useDataviewInstancesConnect } from 'features/workspace/workspace.hook'
import { useLayerPanelDataviewSort } from 'features/workspace/shared/layer-panel-sort.hook'
import { formatInfoField } from 'utils/info'
import { VESSEL_GROUP_REPORT } from 'routes/routes'
import VesselGroupReportLink from 'features/vessel-group-report/VesselGroupReportLink'
import Color from '../common/Color'
import LayerSwitch from '../common/LayerSwitch'
import Remove from '../common/Remove'
Expand Down Expand Up @@ -74,16 +73,7 @@ function VesselGroupLayerPanel({
<LayerSwitch active={layerActive} className={styles.switch} dataview={dataview} />
<Title
title={
<Link
className={styles.link}
to={{
type: VESSEL_GROUP_REPORT,
payload: {
vesselGroupId: vesselGroup?.id,
},
query: {},
}}
>
<VesselGroupReportLink vesselGroupId={vesselGroup?.id!}>
<Tooltip
content={t('vesselGroupReport.clickToSee', 'Click to see the vessel group report')}
>
Expand All @@ -92,7 +82,7 @@ function VesselGroupLayerPanel({
<span className={styles.secondary}> ({vesselGroup?.vessels.length})</span>
</span>
</Tooltip>
</Link>
</VesselGroupReportLink>
}
className={styles.name}
classNameActive={styles.active}
Expand Down
6 changes: 3 additions & 3 deletions apps/fishing-map/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ export const routesMap: RoutesMap = {
[REPORT]: {
path: '/report/:reportId',
},
[VESSEL_GROUP_REPORT]: {
path: '/vessel-group-report/:vesselGroupId',
},
[VESSEL]: {
path: '/vessel/:vesselId',
},
Expand All @@ -86,6 +83,9 @@ export const routesMap: RoutesMap = {
[WORKSPACE_REPORT]: {
path: '/:category/:workspaceId/report/:datasetId?/:areaId?',
},
[VESSEL_GROUP_REPORT]: {
path: '/:category/:workspaceId/vessel-group-report/:vesselGroupId',
},
[NOT_FOUND]: {
path: '',
thunk: async (dispatch: Dispatch) => {
Expand Down
1 change: 1 addition & 0 deletions apps/fishing-map/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export type VesselGroupReportActivitySubsection = 'fishing-effort' | 'presence'
export type VesselGroupReportEventsSubsection = 'fishing' | 'encounters' | 'port' | 'loitering'

export type VesselGroupReportState = {
viewOnlyVesselGroup: boolean
vesselGroupReportSection: VesselGroupReportSection
vesselGroupReportVesselsSubsection?: VesselGroupReportVesselsSubsection
vesselGroupReportActivitySubsection?: VesselGroupReportActivitySubsection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class FourwingsHeatmapStaticLayer extends CompositeLayer<FourwingsHeatmap
if (!currentZoomData.length) {
return this.getColorDomain()
}
const values = currentZoomData.flatMap((d) => d.properties?.[HEATMAP_STATIC_PROPERTY_ID] || [])
const values = currentZoomData.flatMap((d) => d?.properties?.[HEATMAP_STATIC_PROPERTY_ID] || [])
const allValues =
values.length > MAX_RAMP_VALUES
? values.filter((d, i) => filterCells(d, i, minVisibleValue, maxVisibleValue))
Expand Down

0 comments on commit eb912ba

Please sign in to comment.