diff --git a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsight.module.css b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsight.module.css index cb646a2365..03fd61411e 100644 --- a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsight.module.css +++ b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsight.module.css @@ -85,3 +85,19 @@ top: 0.4rem; margin-left: var(--space-XS); } + +.insightContainer .collapsable { + justify-content: flex-start; +} + +.insightContainer .collapsable::before { + display: none; + content: ''; +} + +.insightContainer .collapsableLabel { + padding-left: 0; + font: var(--font-M); + color: var(--color-primary-blue); + text-transform: none; +} diff --git a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightCoverage.tsx b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightCoverage.tsx index 3034f3bd69..985df1657d 100644 --- a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightCoverage.tsx +++ b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightCoverage.tsx @@ -1,8 +1,10 @@ import { useTranslation } from 'react-i18next' import { useGetVesselGroupInsightQuery } from 'queries/vessel-insight-api' +import { useSelector } from 'react-redux' import { ParsedAPIError } from '@globalfishingwatch/api-client' import InsightError from 'features/vessel/insights/InsightErrorMessage' import DataTerminology from 'features/vessel/identity/DataTerminology' +import { selectFetchVesselGroupReportCoverageParams } from '../vessel-group-report.selectors' import styles from './VesselGroupReportInsight.module.css' import VesselGroupReportInsightCoverageGraph from './VesselGroupReportInsightCoverageGraph' @@ -11,22 +13,10 @@ const VesselGroupReportInsightCoveragePlaceholder = () => { return
} -const VesselGroupReportInsightCoverage = ({ - vesselGroupId, - start, - end, -}: { - vesselGroupId: string - start: string - end: string -}) => { +const VesselGroupReportInsightCoverage = () => { const { t } = useTranslation() - const { data, error, isLoading } = useGetVesselGroupInsightQuery({ - vesselGroupId: vesselGroupId, - insight: 'COVERAGE', - start, - end, - }) + const fetchParams = useSelector(selectFetchVesselGroupReportCoverageParams) + const { data, error, isLoading } = useGetVesselGroupInsightQuery(fetchParams) return (
diff --git a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightGapVesselEvents.tsx b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightGapVesselEvents.tsx new file mode 100644 index 0000000000..86bdf5c760 --- /dev/null +++ b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightGapVesselEvents.tsx @@ -0,0 +1,28 @@ +import { useGetVesselEventsQuery } from 'queries/vessel-events-api' +import { Spinner } from '@globalfishingwatch/ui-components' + +const VesselGroupReportInsightGapVesselEvents = ({ + vesselId, + datasetId, + start, + end, +}: { + vesselId: string + datasetId: string + start: string + end: string +}) => { + const { data, isLoading } = useGetVesselEventsQuery({ + vessels: [vesselId], + datasets: [datasetId], + 'start-date': start, + 'end-date': end, + }) + if (isLoading) { + return + } + console.log('🚀 ~ data:', data) + return TODO: show GAP events +} + +export default VesselGroupReportInsightGapVesselEvents diff --git a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightGaps.tsx b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightGaps.tsx index 75f2dbf64d..d20be24cbf 100644 --- a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightGaps.tsx +++ b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsightGaps.tsx @@ -1,32 +1,54 @@ import { useTranslation } from 'react-i18next' import { useGetVesselGroupInsightQuery } from 'queries/vessel-insight-api' import { groupBy } from 'lodash' -import { useMemo } from 'react' +import { useMemo, useState } from 'react' +import { useSelector } from 'react-redux' import { ParsedAPIError } from '@globalfishingwatch/api-client' +import { Collapsable } from '@globalfishingwatch/ui-components' import InsightError from 'features/vessel/insights/InsightErrorMessage' import DataTerminology from 'features/vessel/identity/DataTerminology' +import { getVesselId, getVesselProperty } from 'features/vessel/vessel.utils' +import { selectVesselGroupReportData } from '../vessel-group-report.slice' +import { + selectFetchVesselGroupReportGapParams, + selectVesselGroupGapInsightData, +} from '../vessel-group-report.selectors' import styles from './VesselGroupReportInsight.module.css' import VesselGroupReportInsightPlaceholder from './VesselGroupReportInsightsPlaceholders' +import VesselGroupReportInsightGapVesselEvents from './VesselGroupReportInsightGapVesselEvents' -const VesselGroupReportInsightGap = ({ - vesselGroupId, - start, - end, -}: { - vesselGroupId: string - start: string - end: string -}) => { +const VesselGroupReportInsightGap = () => { const { t } = useTranslation() - const { data, error, isLoading } = useGetVesselGroupInsightQuery({ - vesselGroupId: vesselGroupId, - insight: 'GAP', - start, - end, + const [isExpanded, setIsExpanded] = useState(false) + const [expandedVesselIds, setExpandedVesselIds] = useState([]) + console.log('🚀 ~ VesselGroupReportInsightGap ~ expandedVesselIds:', expandedVesselIds) + const vesselGroup = useSelector(selectVesselGroupReportData) + const fetchVesselGroupParams = useSelector(selectFetchVesselGroupReportGapParams) + + const { data, error, isLoading } = useGetVesselGroupInsightQuery(fetchVesselGroupParams, { + skip: !vesselGroup, }) + // const dataFromSelector = useSelector(selectVesselGroupGapInsightData) + + const vesselsWithInsigth = data?.gap?.map((vessel) => vessel.vesselId) + const vessels = vesselGroup?.vessels?.filter((vessel) => + vesselsWithInsigth?.includes(getVesselId(vessel)) + ) + + // const infoVesselDatasets = Array.from(new Set(vessels?.flatMap((vessel) => vessel.dataset))) + // const { data: events, isLoading: isEventsLoading } = useGetVesselEventsQuery( + // { + // datasets: vessels.flatMap((vessel) => vessel.dataset), + // vessels: expandedVesselIds, + // 'start-date': start, + // 'end-date': end, + // }, + // { skip: !vesselGroup } + // ) const eventsByVessel = useMemo(() => { return groupBy(data?.gap, (entry) => entry.vesselId) }, [data]) + const hasEvents = data?.gap !== undefined && data?.gap?.length > 0 const vesselsInEvents = hasEvents ? Object.keys(eventsByVessel).length : 0 const totalEvents = data?.gap?.reduce((acc, vessel) => acc + vessel.aisOff.length, 0) || 0 @@ -37,6 +59,7 @@ const VesselGroupReportInsightGap = ({ vessels: vesselsInEvents, }) : t('vessel.insights.gapsEventsEmpty', 'No AIS Off events detected') + return (
@@ -65,6 +88,8 @@ const VesselGroupReportInsightGap = ({ {vessels.map((vessel) => { const vesselId = getVesselId(vessel) const isExpandedVessel = expandedVesselIds.includes(vesselId) + // TODO: get the proper datasetId + const eventsDatasetId = 'public-global-gaps-events:v3.0' return (
  • - {eventsByVessel[vesselId].map((event) => { - return event.aisOff.join(',') - })} + {isExpandedVessel && ( + + )}
  • ) diff --git a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsights.tsx b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsights.tsx index 23be43b549..ee41b5e823 100644 --- a/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsights.tsx +++ b/apps/fishing-map/features/vessel-group-report/insights/VesselGroupReportInsights.tsx @@ -5,7 +5,6 @@ import { Icon } from '@globalfishingwatch/ui-components' import { selectTimeRange } from 'features/app/selectors/app.timebar.selectors' import { formatI18nDate } from 'features/i18n/i18nDate' import DataTerminology from 'features/vessel/identity/DataTerminology' -import { selectReportVesselGroupId } from 'routes/routes.selectors' import { MIN_INSIGHTS_YEAR } from 'features/vessel/insights/insights.config' import styles from './VesselGroupReportInsights.module.css' import VesselGroupReportInsightCoverage from './VesselGroupReportInsightCoverage' @@ -14,7 +13,6 @@ import VesselGroupReportInsightGap from './VesselGroupReportInsightGaps' const VesselGroupReportInsights = () => { const { t } = useTranslation() const { start, end } = useSelector(selectTimeRange) - const vesselGroupId = useSelector(selectReportVesselGroupId) if (DateTime.fromISO(start).year < MIN_INSIGHTS_YEAR) { return ( @@ -45,8 +43,8 @@ const VesselGroupReportInsights = () => { terminologyKey="insights" />

    - - + +
    ) } diff --git a/apps/fishing-map/features/vessel-group-report/vessel-group-report.selectors.ts b/apps/fishing-map/features/vessel-group-report/vessel-group-report.selectors.ts index 0dc2abff17..43cab278eb 100644 --- a/apps/fishing-map/features/vessel-group-report/vessel-group-report.selectors.ts +++ b/apps/fishing-map/features/vessel-group-report/vessel-group-report.selectors.ts @@ -1,6 +1,12 @@ import { createSelector } from '@reduxjs/toolkit' +import { + selectVesselGroupInsight, + selectVesselGroupInsightApiSlice, +} from 'queries/vessel-insight-api' +import { InsightType } from '@globalfishingwatch/api-types' import { selectActiveDataviewInstancesResolved } from 'features/dataviews/selectors/dataviews.instances.selectors' import { selectReportVesselGroupId } from 'routes/routes.selectors' +import { selectTimeRange } from 'features/app/selectors/app.timebar.selectors' export const selectVesselGroupReportDataview = createSelector( [selectActiveDataviewInstancesResolved, selectReportVesselGroupId], @@ -10,3 +16,35 @@ export const selectVesselGroupReportDataview = createSelector( ) } ) + +export const selectBaseVesselGroupReportParams = createSelector( + [selectTimeRange, selectReportVesselGroupId], + ({ start, end }, reportVesselGroupId) => { + return { + vesselGroupId: reportVesselGroupId, + start, + end, + } + } +) + +export const selectFetchVesselGroupReportCoverageParams = createSelector( + [selectBaseVesselGroupReportParams], + (params) => { + return { ...params, insight: 'COVERAGE' as InsightType } + } +) + +export const selectFetchVesselGroupReportGapParams = createSelector( + [selectBaseVesselGroupReportParams], + (params) => { + return { ...params, insight: 'GAP' as InsightType } + } +) + +export const selectVesselGroupGapInsightData = createSelector( + [selectVesselGroupInsightApiSlice, selectFetchVesselGroupReportGapParams], + (vesselInsightApi, params) => { + return selectVesselGroupInsight(params)({ vesselInsightApi })?.data + } +) diff --git a/apps/fishing-map/queries/vessel-insight-api.ts b/apps/fishing-map/queries/vessel-insight-api.ts index fa1d14387b..01396dd47d 100644 --- a/apps/fishing-map/queries/vessel-insight-api.ts +++ b/apps/fishing-map/queries/vessel-insight-api.ts @@ -1,5 +1,6 @@ import { createApi } from '@reduxjs/toolkit/query/react' import { getQueryParamsResolved, gfwBaseQuery } from 'queries/base' +import { RootState } from 'reducers' import { InsightResponse, InsightType, @@ -51,3 +52,8 @@ export const vesselInsightApi = createApi({ // Export hooks for usage in functional components, which are // auto-generated based on the defined endpoints export const { useGetVesselInsightMutation, useGetVesselGroupInsightQuery } = vesselInsightApi + +export const selectVesselGroupInsightApiSlice = (state: RootState) => state.vesselInsightApi + +export const selectVesselGroupInsight = (params: VesselGroupInsightParams) => + vesselInsightApi.endpoints.getVesselGroupInsight.select(params)