diff --git a/apps/fishing-map/features/search/search.slice.ts b/apps/fishing-map/features/search/search.slice.ts index 79081f070c..8b1626056d 100644 --- a/apps/fishing-map/features/search/search.slice.ts +++ b/apps/fishing-map/features/search/search.slice.ts @@ -15,6 +15,7 @@ import { IdentityVessel, EndpointId, VesselIdentitySourceEnum, + RegistryExtraFields, } from '@globalfishingwatch/api-types' import { AsyncError, AsyncReducerStatus } from 'utils/async-slice' import { selectDatasetById } from 'features/datasets/datasets.slice' @@ -26,7 +27,8 @@ import { ADVANCED_SEARCH_FIELDS } from 'features/search/advanced/advanced-search export type VesselLastIdentity = Omit & { dataset: Dataset | string -} & VesselDataIdentity +} & VesselDataIdentity & + RegistryExtraFields interface SearchState { selectedVessels: string[] diff --git a/apps/fishing-map/features/vessel/VesselHeader.module.css b/apps/fishing-map/features/vessel/VesselHeader.module.css index f5d47a3454..b0770acd32 100644 --- a/apps/fishing-map/features/vessel/VesselHeader.module.css +++ b/apps/fishing-map/features/vessel/VesselHeader.module.css @@ -4,31 +4,40 @@ min-height: 5.2rem; } -.sticky { - z-index: 2; - margin-top: 51px; - background-color: var(--color-white); - border-top: var(--border); +.summaryWrapper { + display: flex; + gap: var(--space-S); } .titleContainer { display: flex; - align-items: center; - justify-content: flex-end; flex-wrap: wrap; + justify-content: flex-end; gap: var(--space-S); + width: 100%; +} + +.sticky { + z-index: 2; + margin-top: 51px; + background-color: var(--color-white); + border-top: var(--border); } .title { font: var(--font-L); - min-width: max-content; - flex: 1; + flex-grow: 1; } .secondary { color: var(--color-secondary-blue); } +.vesselImage { + width: 20%; + min-width: 200px; +} + .vesselIcon { margin-right: var(--space-XS); } @@ -36,6 +45,7 @@ .actionsContainer { display: flex; justify-content: flex-end; + align-self: end; gap: var(--space-S); } diff --git a/apps/fishing-map/features/vessel/VesselHeader.tsx b/apps/fishing-map/features/vessel/VesselHeader.tsx index 56671aeb04..4f0445f9c3 100644 --- a/apps/fishing-map/features/vessel/VesselHeader.tsx +++ b/apps/fishing-map/features/vessel/VesselHeader.tsx @@ -1,5 +1,4 @@ import { useSelector } from 'react-redux' -import cx from 'classnames' import { useTranslation } from 'react-i18next' import Sticky from 'react-sticky-el' import { useCallback, useEffect } from 'react' @@ -11,7 +10,11 @@ import { formatInfoField, getVesselOtherNamesLabel } from 'utils/info' import VesselGroupAddButton, { VesselGroupAddActionButton, } from 'features/vessel-groups/VesselGroupAddButton' -import { getOtherVesselNames, getVesselProperty } from 'features/vessel/vessel.utils' +import { + getCurrentIdentityVessel, + getOtherVesselNames, + getVesselProperty, +} from 'features/vessel/vessel.utils' import { COLOR_PRIMARY_BLUE } from 'features/app/app.config' import { useLocationConnect } from 'routes/routes.hook' import { @@ -49,7 +52,10 @@ const VesselHeader = () => { const vesselPrintMode = useSelector(selectVesselPrintMode) const vesselProfileDataview = useSelector(selectVesselProfileDataview) const { boundsReady, setVesselBounds } = useVesselProfileBounds() - + const vesselIdentity = getCurrentIdentityVessel(vessel, { + identityId, + identitySource, + }) const vesselPrintCallback = useCallback(() => { window.print() }, []) @@ -97,6 +103,8 @@ const VesselHeader = () => { const shipname = getVesselProperty(vessel, 'shipname', { identityId, identitySource }) const nShipname = getVesselProperty(vessel, 'nShipname', { identityId, identitySource }) + // TODO remove false when we have a vessel image + const vesselImage = false && vesselIdentity?.images?.[0].url const otherNamesLabel = getVesselOtherNamesLabel(getOtherVesselNames(vessel, nShipname)) const onVesselFitBoundsClick = () => { @@ -117,76 +125,84 @@ const VesselHeader = () => { return ( -
-

- - - - {formatInfoField(shipname, 'shipname')} - {otherNamesLabel} -
- - {t('vessel.linkToVessel', 'Check the vessel profile here')} - -
-

-
- {vesselProfileDataview && ( - i.identitySource === VesselIdentitySourceEnum.SelfReported) - .map((i) => i.id)} - vesselTitle={shipname} - datasetId={vessel.track as string} - iconType="border" - /> - )} - {isWorkspaceVesselLocation && ( - +
+
+ {vesselImage && ( + // eslint-disable-next-line @next/next/no-img-element + {shipname} )} - - - trackAction('add_to_group')} - > - - +
+

+ + + + {formatInfoField(shipname, 'shipname')} + {otherNamesLabel} + +

+
+ {vesselProfileDataview && ( + i.identitySource === VesselIdentitySourceEnum.SelfReported) + .map((i) => i.id)} + vesselTitle={shipname} + datasetId={vessel.track as string} + iconType="border" + /> + )} + {isWorkspaceVesselLocation && ( + + )} + + + trackAction('add_to_group')} + > + + +
+
diff --git a/apps/fishing-map/features/vessel/identity/VesselIdentity.module.css b/apps/fishing-map/features/vessel/identity/VesselIdentity.module.css index f40a7d6beb..3e2dc38a20 100644 --- a/apps/fishing-map/features/vessel/identity/VesselIdentity.module.css +++ b/apps/fishing-map/features/vessel/identity/VesselIdentity.module.css @@ -66,3 +66,15 @@ display: flex; align-items: center; } + +.extraInfoContainer { + display: flex; + gap: var(--space-S); + margin-top: var(--space-M); + align-items: center; +} + +.registrySourceLogo { + width: 98px; + height: 26px; +} diff --git a/apps/fishing-map/features/vessel/identity/VesselIdentity.tsx b/apps/fishing-map/features/vessel/identity/VesselIdentity.tsx index 59aa7e7382..6da1e36130 100644 --- a/apps/fishing-map/features/vessel/identity/VesselIdentity.tsx +++ b/apps/fishing-map/features/vessel/identity/VesselIdentity.tsx @@ -5,13 +5,14 @@ import { saveAs } from 'file-saver' import { Fragment, useEffect, useMemo } from 'react' import { uniq } from 'es-toolkit' import { IconButton, Tab, Tabs, TabsProps, Tooltip } from '@globalfishingwatch/ui-components' -import { VesselRegistryOwner, VesselRegistryProperty } from '@globalfishingwatch/api-types' +import { VesselRegistryOwner } from '@globalfishingwatch/api-types' import { VesselIdentitySourceEnum } from '@globalfishingwatch/api-types' -import I18nDate, { formatI18nDate } from 'features/i18n/i18nDate' +import { formatI18nDate } from 'features/i18n/i18nDate' import { CUSTOM_VMS_IDENTITY_FIELD_GROUPS, IDENTITY_FIELD_GROUPS, REGISTRY_FIELD_GROUPS, + REGISTRY_SOURCES, } from 'features/vessel/vessel.config' import DataTerminology from 'features/vessel/identity/DataTerminology' import { selectVesselInfoData } from 'features/vessel/selectors/vessel.selectors' @@ -35,12 +36,12 @@ import VesselIdentityField from 'features/vessel/identity/VesselIdentityField' import { useLocationConnect } from 'routes/routes.hook' import { useTimerangeConnect } from 'features/timebar/timebar.hooks' import { selectIsVesselLocation } from 'routes/routes.selectors' -import { useRegionTranslationsById } from 'features/regions/regions.hooks' import { VesselLastIdentity } from 'features/search/search.slice' -import VesselIdentityCombinedSourceField from 'features/vessel/identity/VesselIdentityCombinedSourceField' import { TrackCategory, trackEvent } from 'features/app/analytics.hooks' import UserLoggedIconButton from 'features/user/UserLoggedIconButton' import styles from './VesselIdentity.module.css' +import VesselRegistryField from './VesselRegistryField' +import VesselTypesField from './VesselTypesField' const VesselIdentity = () => { const { t } = useTranslation() @@ -48,7 +49,6 @@ const VesselIdentity = () => { const identityId = useSelector(selectVesselIdentityId) const identitySource = useSelector(selectVesselIdentitySource) const isStandaloneVesselLocation = useSelector(selectIsVesselLocation) - const { getRegionTranslationsById } = useRegionTranslationsById() const { dispatchQueryParams } = useLocationConnect() const { setTimerange } = useTimerangeConnect() @@ -171,6 +171,9 @@ const VesselIdentity = () => { : IDENTITY_FIELD_GROUPS[identitySource] }, [identitySource, vesselIdentity?.sourceCode]) + const hasMoreInfo = vesselIdentity?.hasComplianceInfo || vesselIdentity?.iuuStatus === 'Current' + const registrySourceData = REGISTRY_SOURCES.find((s) => s.key === vesselIdentity.registrySource) + return ( @@ -242,6 +245,10 @@ const VesselIdentity = () => { label = 'gfw_' + label } const key = field.key as keyof VesselLastIdentity + let value = vesselIdentity[key] as string + if (key === 'depthM' || key === 'builtYear') { + value = vesselIdentity[key]?.value?.toString() + } return (
@@ -255,17 +262,15 @@ const VesselIdentity = () => { /> )}
- {vesselIdentity.combinedSourcesInfo && - (key === 'shiptypes' || key === 'geartypes') ? ( - ) : ( )}
@@ -274,101 +279,35 @@ const VesselIdentity = () => {
))} {identitySource === VesselIdentitySourceEnum.Registry && - REGISTRY_FIELD_GROUPS.map(({ key, label, terminologyKey }, index) => { - const allRegistryInfo = vesselIdentity[key] - if (!allRegistryInfo) return null - const timerange = { - start: vesselIdentity.transmissionDateFrom, - end: vesselIdentity.transmissionDateTo, - } - const filteredRegistryInfo = filterRegistryInfoByDateAndSSVID( - vesselIdentity[key] as VesselRegistryProperty[], - timerange, - vesselIdentity.ssvid - ) - if (!filteredRegistryInfo) return null + REGISTRY_FIELD_GROUPS.map((registryField) => { return ( -
-
- - {terminologyKey && ( - - )} -
- {allRegistryInfo?.length > 0 ? ( -
    - {allRegistryInfo.map((registry, index) => { - const registryOverlapsTimeRange = filteredRegistryInfo.includes(registry) - const fieldType = key === 'registryOwners' ? 'owner' : 'authorization' - let Component = - if (registryOverlapsTimeRange) { - if (fieldType === 'owner') { - const value = `${formatInfoField( - (registry as VesselRegistryOwner).name, - 'owner' - )} (${formatInfoField( - (registry as VesselRegistryOwner).flag, - 'flag' - )})` - Component = - } else { - const sourceTranslations = (registry.sourceCode as any[]) - .map(getRegionTranslationsById) - .join(',') - Component = ( - - - - ) - } - } - return ( -
  • - {Component}{' '} - - -{' '} - - -
  • - ) - })} -
- ) : ( - EMPTY_FIELD_PLACEHOLDER - )} -
+ ) })} + {identitySource === VesselIdentitySourceEnum.Registry && + hasMoreInfo && + registrySourceData && ( +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {registrySourceData?.key} +
+ +

{`${t(`vessel.extraInfo`, 'Request additional information at')} ${ + registrySourceData?.contact + }`}

+
+
+ )}
)} diff --git a/apps/fishing-map/features/vessel/identity/VesselIdentityCombinedSourceField.tsx b/apps/fishing-map/features/vessel/identity/VesselIdentityCombinedSourceField.tsx index 9f838bacb7..49dbefd2b5 100644 --- a/apps/fishing-map/features/vessel/identity/VesselIdentityCombinedSourceField.tsx +++ b/apps/fishing-map/features/vessel/identity/VesselIdentityCombinedSourceField.tsx @@ -18,6 +18,7 @@ const VesselIdentityCombinedSourceField = ({ ) : null } + return (
    {[...combinedSource] diff --git a/apps/fishing-map/features/vessel/identity/VesselRegistryField.tsx b/apps/fishing-map/features/vessel/identity/VesselRegistryField.tsx new file mode 100644 index 0000000000..9a841039f0 --- /dev/null +++ b/apps/fishing-map/features/vessel/identity/VesselRegistryField.tsx @@ -0,0 +1,149 @@ +import cx from 'classnames' +import { t } from 'i18next' +import { uniq } from 'es-toolkit' +import { + VesselRegistryOperator, + VesselRegistryOwner, + VesselRegistryProperty, +} from '@globalfishingwatch/api-types' +import { Tooltip } from '@globalfishingwatch/ui-components' +import { EMPTY_FIELD_PLACEHOLDER, formatInfoField } from 'utils/info' +import I18nDate from 'features/i18n/i18nDate' +import { useRegionTranslationsById } from 'features/regions/regions.hooks' +import { VesselLastIdentity } from 'features/search/search.slice' +import { filterRegistryInfoByDateAndSSVID } from '../vessel.utils' +import { VesselRenderField } from '../vessel.config' +import styles from './VesselIdentity.module.css' +import DataTerminology from './DataTerminology' +import VesselIdentityField from './VesselIdentityField' + +const RegistryOperatorField = ({ + registryField, + vesselIdentity, +}: { + registryField: VesselRenderField + vesselIdentity: VesselLastIdentity +}) => { + const { key } = registryField + const operator = vesselIdentity[key as keyof VesselLastIdentity] as VesselRegistryOperator + if (!operator?.name) return null + const formatedOperator = uniq( + operator.name + .split('|') + .map((s: string) => s.replaceAll('"', '').trim().split(';')) + .flat() + ) + return ( +
    + + {formatedOperator.map((operator, index) => ( +

    + +

    + ))} +
    + ) +} +const VesselRegistryField = ({ + registryField, + vesselIdentity, +}: { + registryField: VesselRenderField + vesselIdentity: VesselLastIdentity +}) => { + const { key, label, terminologyKey } = registryField + const { getRegionTranslationsById } = useRegionTranslationsById() + if (key === 'operator') { + return + } + const allRegistryInfo = vesselIdentity[ + key as keyof VesselLastIdentity + ] as VesselRegistryProperty[] + if (!allRegistryInfo) return null + const timerange = { + start: vesselIdentity.transmissionDateFrom, + end: vesselIdentity.transmissionDateTo, + } + const filteredRegistryInfo = filterRegistryInfoByDateAndSSVID( + vesselIdentity[key as keyof VesselLastIdentity] as VesselRegistryProperty[], + timerange, + vesselIdentity.ssvid + ) + + if (!filteredRegistryInfo) return null + + return ( +
    +
    + + {terminologyKey && ( + + )} +
    + {allRegistryInfo?.length > 0 ? ( +
      + {allRegistryInfo.map((registry, index) => { + const registryOverlapsTimeRange = filteredRegistryInfo.includes(registry) + const fieldType = key === 'registryOwners' ? 'owner' : 'authorization' + let Component = + if (registryOverlapsTimeRange) { + if (fieldType === 'owner') { + const value = `${formatInfoField( + (registry as VesselRegistryOwner).name, + 'owner' + )} (${formatInfoField((registry as VesselRegistryOwner).flag, 'flag')})` + Component = + } else { + const sourceTranslations = (registry.sourceCode as any[]) + .map(getRegionTranslationsById) + .join(',') + Component = ( + + + + ) + } + } + return ( +
    • + {Component}{' '} + + - + +
    • + ) + })} +
    + ) : ( + EMPTY_FIELD_PLACEHOLDER + )} +
    + ) +} + +export default VesselRegistryField diff --git a/apps/fishing-map/features/vessel/identity/VesselTypesField.tsx b/apps/fishing-map/features/vessel/identity/VesselTypesField.tsx new file mode 100644 index 0000000000..347ab1d126 --- /dev/null +++ b/apps/fishing-map/features/vessel/identity/VesselTypesField.tsx @@ -0,0 +1,34 @@ +import { VesselIdentitySourceEnum } from '@globalfishingwatch/api-types' +import { formatInfoField } from 'utils/info' +import { VesselLastIdentity } from 'features/search/search.slice' +import VesselIdentityCombinedSourceField from './VesselIdentityCombinedSourceField' +import VesselIdentityField from './VesselIdentityField' + +interface VesselTypesFieldProps { + vesselIdentity: VesselLastIdentity + fieldKey: 'shiptypes' | 'geartypes' + identitySource: VesselIdentitySourceEnum +} + +const VesselTypesField = ({ vesselIdentity, fieldKey, identitySource }: VesselTypesFieldProps) => { + if (vesselIdentity.combinedSourcesInfo) { + return + } + if (identitySource === VesselIdentitySourceEnum.Registry) { + if (typeof vesselIdentity?.[fieldKey] === 'string') { + return ( + + ) + } + return vesselIdentity?.[fieldKey]?.map((value: string) => ( + + )) + } + return ( + + ) +} + +export default VesselTypesField diff --git a/apps/fishing-map/features/vessel/vessel.config.ts b/apps/fishing-map/features/vessel/vessel.config.ts index f0940510c9..b781afdb53 100644 --- a/apps/fishing-map/features/vessel/vessel.config.ts +++ b/apps/fishing-map/features/vessel/vessel.config.ts @@ -9,6 +9,13 @@ export const DEFAULT_VESSEL_IDENTITY_VERSION = 'v3.0' export const DEFAULT_VESSEL_IDENTITY_ID = `${DEFAULT_VESSEL_IDENTITY_DATASET}:${DEFAULT_VESSEL_IDENTITY_VERSION}` export const INCLUDES_RELATED_SELF_REPORTED_INFO_ID = 'POTENTIAL_RELATED_SELF_REPORTED_INFO' export const CACHE_FALSE_PARAM = { id: 'cache', value: 'false' } +export const REGISTRY_SOURCES = [ + { + key: 'TMT', + logo: 'https://globalfishingwatch.org/wp-content/uploads/TMT_logo_primary_RGB@2x.png', + contact: 'jac-coord@tm-tracking.org', + }, +] export const DEFAULT_VESSEL_STATE: VesselProfileState = { vesselDatasetId: DEFAULT_VESSEL_IDENTITY_ID, @@ -28,9 +35,12 @@ export type VesselRenderField = { terminologyKey?: I18nNamespaces['dataTerminology'] } -const COMMON_FIELD_GROUPS: VesselRenderField[][] = [ - [{ key: 'shipname' }, { key: 'flag' }], - [{ key: 'ssvid', label: 'mmsi' }, { key: 'imo' }, { key: 'callsign' }], +const COMMON_FIELD_GROUPS: VesselRenderField[] = [{ key: 'shipname' }, { key: 'flag' }] + +const IDENTIFIER_FIELDS: VesselRenderField[] = [ + { key: 'ssvid', label: 'mmsi' }, + { key: 'imo' }, + { key: 'callsign' }, ] // TODO review private datasets to ensure there are no missing fields @@ -52,33 +62,51 @@ export const CUSTOM_VMS_IDENTITY_FIELD_GROUPS: CustomVMSGroup = { [SelfReportedSource.Chile]: [[{ key: 'fleet' }]], } -const SELF_REPORTED_FIELD_GROUPS: VesselRenderField[][] = [ - [ - { key: 'shiptypes', terminologyKey: 'shiptype' }, - { key: 'geartypes', terminologyKey: 'geartype' }, - ], +const VESSEL_FISICAL_FEATURES_FIELDS: VesselRenderField[] = [ + { key: 'lengthM', label: 'length' }, + { key: 'depthM', label: 'draft' }, + { key: 'tonnageGt', label: 'grossTonnage' }, +] + +const VESSEL_SHIPTYPES_FIELD: VesselRenderField = { + key: 'shiptypes', + terminologyKey: 'shiptype', + label: 'vessel type', +} + +const VESSEL_GEARTYPES_FIELD: VesselRenderField = { + key: 'geartypes', + terminologyKey: 'geartype', + label: 'gear type', +} + +const VESSEL_CLASSIFICATION_FIELDS: VesselRenderField[] = [ + VESSEL_SHIPTYPES_FIELD, + VESSEL_GEARTYPES_FIELD, ] export const IDENTITY_FIELD_GROUPS: Record = { - [VesselIdentitySourceEnum.SelfReported]: [...COMMON_FIELD_GROUPS, ...SELF_REPORTED_FIELD_GROUPS], + [VesselIdentitySourceEnum.SelfReported]: [COMMON_FIELD_GROUPS, VESSEL_CLASSIFICATION_FIELDS], [VesselIdentitySourceEnum.Registry]: [ - ...COMMON_FIELD_GROUPS, - [ - { key: 'geartypes' }, - { key: 'lengthM', label: 'length' }, - { key: 'tonnageGt', label: 'grossTonnage' }, - ], + COMMON_FIELD_GROUPS, + [VESSEL_GEARTYPES_FIELD, { key: 'builtYear', label: 'year built' }], + IDENTIFIER_FIELDS, + VESSEL_FISICAL_FEATURES_FIELDS, ], } export const REGISTRY_FIELD_GROUPS: VesselRenderField< - keyof Pick + keyof Pick >[] = [ { key: 'registryOwners', label: 'owner', terminologyKey: 'owner', }, + { + key: 'operator', + label: 'operator', + }, { key: 'registryPublicAuthorizations', label: 'authorization', diff --git a/apps/fishing-map/features/vessel/vessel.slice.ts b/apps/fishing-map/features/vessel/vessel.slice.ts index 657c104d17..ed6f678390 100644 --- a/apps/fishing-map/features/vessel/vessel.slice.ts +++ b/apps/fishing-map/features/vessel/vessel.slice.ts @@ -8,6 +8,7 @@ import { DatasetTypes, GearType, IdentityVessel, + RegistryExtraFields, Resource, ResourceStatus, SelfReportedInfo, @@ -47,6 +48,10 @@ export type VesselDataIdentity = (SelfReportedInfo | VesselRegistryInfo) & { dataset?: string geartypes?: GearType[] shiptypes?: VesselType[] + registrySource?: string + hasComplianceInfo?: boolean + iuuStatus?: string + extraFields?: RegistryExtraFields[] } // Merges and plain all the identities of a vessel export type IdentityVesselData = { @@ -57,7 +62,11 @@ export type IdentityVesselData = { } & VesselInstanceDatasets & Pick< IdentityVessel, - 'registryOwners' | 'registryPublicAuthorizations' | 'matchCriteria' | 'combinedSourcesInfo' + | 'registryOwners' + | 'registryPublicAuthorizations' + | 'matchCriteria' + | 'combinedSourcesInfo' + | 'operator' > type VesselInfoEntry = { diff --git a/apps/fishing-map/features/vessel/vessel.utils.ts b/apps/fishing-map/features/vessel/vessel.utils.ts index 578ee6c905..f877d5db74 100644 --- a/apps/fishing-map/features/vessel/vessel.utils.ts +++ b/apps/fishing-map/features/vessel/vessel.utils.ts @@ -29,6 +29,13 @@ const getVesselIdentitiesBySource = ( return [] as VesselDataIdentity[] } return (vessel?.[identitySource] || []).map((identity) => { + if (identitySource === VesselIdentitySourceEnum.Registry) { + return { + ...identity, + identitySource, + dataset: vessel.dataset, + } as VesselDataIdentity + } const geartypes = getVesselCombinedSourceProperty(vessel, { vesselId: identity.id, property: 'geartypes', @@ -84,6 +91,7 @@ export type VesselIdentityProperty = | keyof VesselRegistryInfo | 'owner' | 'id' + | 'image' export function getLatestIdentityPrioritised(vessel: VesselsParamsSupported) { const latestRegistryIdentity = getVesselIdentity(vessel, { @@ -280,6 +288,8 @@ export function getCurrentIdentityVessel( const { dataset, registryPublicAuthorizations, registryOwners } = vessel return { ...vesselData, + // TODO:VV3 review if we could have more than one extra field + ...(vesselData?.extraFields?.length && vesselData.extraFields[0]), dataset, shiptypes: getVesselProperty(vessel, 'shiptypes', { identityId, identitySource }), geartypes: getVesselProperty(vessel, 'geartypes', { identityId, identitySource }), diff --git a/apps/fishing-map/public/images/tmt-logo.png b/apps/fishing-map/public/images/tmt-logo.png new file mode 100644 index 0000000000..40d1e48b54 Binary files /dev/null and b/apps/fishing-map/public/images/tmt-logo.png differ diff --git a/libs/api-types/src/identity-vessel.ts b/libs/api-types/src/identity-vessel.ts index fced304fb4..d2e4d2615b 100644 --- a/libs/api-types/src/identity-vessel.ts +++ b/libs/api-types/src/identity-vessel.ts @@ -105,6 +105,30 @@ export type SelfReportedInfo = VesselInfo & { vesselType?: string } +export type RegistryImage = { + url: string + copyright: string +} + +export type RegistryExtraFieldValue = { + dateFrom: string + dateFromMask: string + // dateTo: ?? + // dateToMask: ?? + value: number +} + +export type RegistryExtraFields = { + builtYear: RegistryExtraFieldValue + depthM: RegistryExtraFieldValue + hasArchiveInfo: boolean + hasComplianceInfo: boolean + iuuStatus: string | null + operator: string | null + registrySource: string + images: RegistryImage[] +} + export type VesselRegistryInfo = VesselInfo & { geartypes: GearType[] | RegistryLoginMessage latestVesselInfo: true @@ -113,6 +137,7 @@ export type VesselRegistryInfo = VesselInfo & { recordId: string tonnageGt: number | RegistryLoginMessage vesselInfoReference: string + extraFields?: RegistryExtraFields[] } export type VesselRegistryProperty = { @@ -128,6 +153,10 @@ export type VesselRegistryOwner = VesselRegistryProperty & { flag: string } +export type VesselRegistryOperator = { + name: string +} + export type VesselRegistryAuthorization = VesselRegistryProperty export type VesselIdentitySearchMatch = { @@ -161,5 +190,6 @@ export interface IdentityVessel { registryPublicAuthorizations?: VesselRegistryAuthorization[] registryInfo?: VesselRegistryInfo[] registryOwners?: VesselRegistryOwner[] + operator?: VesselRegistryOperator selfReportedInfo: SelfReportedInfo[] }