diff --git a/src/components/WellShow/AlternateIds.tsx b/src/components/WellShow/AlternateIds.tsx index 850c19aa..134f7784 100644 --- a/src/components/WellShow/AlternateIds.tsx +++ b/src/components/WellShow/AlternateIds.tsx @@ -1,11 +1,11 @@ import { useMemo } from 'react' -import { Box, Paper, Stack, Typography } from '@mui/material' +import { Box, Paper, Typography } from '@mui/material' import type { UseDataGridReturnType } from '@refinedev/mui' import { MoreVertOutlined } from '@mui/icons-material' import { DataGrid, GridColDef } from '@mui/x-data-grid' import { settings } from '@/settings' -export const AlternateIdsAccordion = ({ +export const AlternateIdsCard = ({ dataGridProps, }: { dataGridProps: UseDataGridReturnType['dataGridProps'] @@ -25,7 +25,9 @@ export const AlternateIdsAccordion = ({ return ( - + Alternate IDs diff --git a/src/components/WellShow/Attachments.tsx b/src/components/WellShow/Attachments.tsx index c55cb9b1..bb4414af 100644 --- a/src/components/WellShow/Attachments.tsx +++ b/src/components/WellShow/Attachments.tsx @@ -23,7 +23,7 @@ import type { IAsset } from '@/interfaces/ocotillo' type ImageViewMode = 'grid' | 'slideshow' -export const AttachmentsAccordion = ({ +export const AttachmentsCard = ({ assets, isLoading, }: { diff --git a/src/components/WellShow/ConstructionInfo.tsx b/src/components/WellShow/ConstructionInfo.tsx index 7b44415a..3802a507 100644 --- a/src/components/WellShow/ConstructionInfo.tsx +++ b/src/components/WellShow/ConstructionInfo.tsx @@ -1,8 +1,26 @@ -import { Box, Paper, Stack, Typography } from '@mui/material' +import { useEffect, useMemo, useState } from 'react' +import { + Paper, + Box, + Stack, + Typography, + ToggleButtonGroup, + ToggleButton, +} from '@mui/material' import { IWell } from '@/interfaces/ocotillo' import { formatAppDate } from '@/utils' +import { INCHES_IN_A_FOOT } from '@/constants' +import { SupportedUnits } from '@/config' +import { convertFeetToInches, convertInchesToFeet, formatNumber } from '@/utils' + +export const ConstructionInfoCard = ({ well }: { well?: IWell }) => { + const elevation = well?.current_location?.properties?.elevation + const normalizedElevation = + elevation != null && elevation !== 0 ? elevation : null + const elevationUnit = well?.current_location?.properties?.elevation_unit + const elevationMethod = well?.current_location?.properties?.elevation_method + const verticalDatum = well?.current_location?.properties?.vertical_datum -export const ConstructionInfoAccordion = ({ well }: { well?: IWell }) => { return ( @@ -12,6 +30,37 @@ export const ConstructionInfoAccordion = ({ well }: { well?: IWell }) => { + + + + + + + + { label="Driller Name" value={well?.well_driller_name || 'N/A'} /> + + 0 + ? well.historic_depth_to_water.join(', ') + : 'No original depth to water available' + } + /> { ) } -const InlineRow = ({ label, value }: { label: string; value: string }) => ( - - {label}:{' '} - - {value} +const InlineRow = ({ label, value }: { label: string; value: string }) => { + const isLong = value.length > 30 + + return ( + + {label}:{' '} + + {value} + - -) + ) +} + +const getDefaultDisplayUnit = ( + value: number | null | undefined, + normalizedUnit: SupportedUnits | null +): SupportedUnits => { + const hasNumericValue = typeof value === 'number' && !Number.isNaN(value) + + if (normalizedUnit === 'in' && hasNumericValue) { + return value >= INCHES_IN_A_FOOT ? 'ft' : 'in' + } + + return 'ft' +} + +const InlineRowWithUnitConversion = ({ + label, + value, + unit, +}: { + label: string + value: number | null | undefined + unit: SupportedUnits | string | null | undefined +}) => { + const normalizedUnit: SupportedUnits | null = + unit === 'in' || unit === 'ft' ? unit : null + + const hasNumericValue = typeof value === 'number' && !Number.isNaN(value) + + const [displayUnit, setDisplayUnit] = useState(() => + getDefaultDisplayUnit(value, normalizedUnit) + ) + + useEffect(() => { + setDisplayUnit(getDefaultDisplayUnit(value, normalizedUnit)) + }, [value, normalizedUnit]) + + const displayValue = useMemo(() => { + if (!hasNumericValue) return null + + if (normalizedUnit === 'in') { + return displayUnit === 'ft' + ? convertInchesToFeet(value, { precision: 2 }) + : value + } + + if (normalizedUnit === 'ft') { + return displayUnit === 'in' + ? convertFeetToInches(value, { precision: 2 }) + : value + } + + return value + }, [displayUnit, normalizedUnit, value, hasNumericValue]) + + const handleUnitChange = ( + _event: React.MouseEvent, + nextUnit: SupportedUnits | null + ) => { + if (nextUnit) { + setDisplayUnit(nextUnit) + } + } + + if (!hasNumericValue) { + return + } + + const shouldShowToggle = normalizedUnit === 'in' || normalizedUnit === 'ft' + + return ( + + + {label}:{' '} + + {formatNumber(displayValue, { precision: 2 })} + {shouldShowToggle + ? ` ${displayUnit}` + : normalizedUnit + ? ` ${normalizedUnit}` + : ''} + + + + {shouldShowToggle && ( + ({ + '& .MuiToggleButton-root': { + color: 'text.secondary', + border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.3)' : theme.palette.divider}`, + }, + '& .MuiToggleButton-root + .MuiToggleButton-root': { + borderLeft: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.3)' : theme.palette.divider}`, + marginLeft: 0, + }, + '& .MuiToggleButton-root.Mui-selected': { + bgcolor: 'primary.main', + color: 'primary.contrastText', + border: `1px solid ${theme.palette.primary.main} !important`, + '&:hover': { bgcolor: 'primary.dark' }, + }, + })} + > + + in + + + ft + + + )} + + ) +} diff --git a/src/components/WellShow/Equipment.tsx b/src/components/WellShow/Equipment.tsx index 268b7a3f..10b69732 100644 --- a/src/components/WellShow/Equipment.tsx +++ b/src/components/WellShow/Equipment.tsx @@ -8,7 +8,6 @@ import { GridToolbarContainer, GridToolbarDensitySelector, } from '@mui/x-data-grid' -import { settings } from '@/settings' import { ISensor } from '@/interfaces/ocotillo' import { useSensorDeploymentRows } from '@/hooks' import { SensorDeploymentRow } from '@/utils' @@ -20,7 +19,7 @@ const EquipmentToolbar = () => ( ) -export const EquipmentAccordion = ({ +export const EquipmentCard = ({ sensors, deployments, isDetailsPending, @@ -65,7 +64,10 @@ export const EquipmentAccordion = ({ const rowSelectionModel = useMemo( () => selectedEquipmentId != null - ? { type: 'include' as const, ids: new Set([selectedEquipmentId]) } + ? { + type: 'include' as const, + ids: new Set([selectedEquipmentId]), + } : { type: 'include' as const, ids: new Set() }, [selectedEquipmentId] ) diff --git a/src/components/WellShow/GeologyInformation.tsx b/src/components/WellShow/GeologyInformation.tsx index 4e930370..4a628c5d 100644 --- a/src/components/WellShow/GeologyInformation.tsx +++ b/src/components/WellShow/GeologyInformation.tsx @@ -1,7 +1,7 @@ import { Paper, Box, Stack, Typography } from '@mui/material' import { IWell } from '@/interfaces/ocotillo' -export const GeologyInformationAccordion = ({ well }: { well?: IWell }) => { +export const GeologyInformationCard = ({ well }: { well?: IWell }) => { return ( @@ -28,7 +28,9 @@ export const GeologyInformationAccordion = ({ well }: { well?: IWell }) => { label="Aquifer Types" value={ well?.aquifers && well.aquifers.length > 0 - ? [...new Set(well.aquifers.flatMap((a) => a.aquifer_types))].join(', ') + ? [ + ...new Set(well.aquifers.flatMap((a) => a.aquifer_types)), + ].join(', ') : 'N/A' } /> diff --git a/src/components/WellShow/WellPhysicalProperties.tsx b/src/components/WellShow/WellPhysicalProperties.tsx deleted file mode 100644 index fa7d1e62..00000000 --- a/src/components/WellShow/WellPhysicalProperties.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { - Paper, - Box, - Stack, - Typography, - ToggleButtonGroup, - ToggleButton, -} from '@mui/material' -import { IWell } from '@/interfaces/ocotillo' -import { useEffect, useMemo, useState } from 'react' -import { INCHES_IN_A_FOOT } from '@/constants' -import { SupportedUnits } from '@/config' -import { convertFeetToInches, convertInchesToFeet, formatNumber } from '@/utils' - -export const WellPhysicalPropertiesAccordion = ({ well }: { well?: IWell }) => { - const elevation = well?.current_location?.properties?.elevation - const normalizedElevation = - elevation != null && elevation !== 0 ? elevation : null - const elevationUnit = well?.current_location?.properties?.elevation_unit - const elevationMethod = well?.current_location?.properties?.elevation_method - const verticalDatum = well?.current_location?.properties?.vertical_datum - - return ( - - - - Physical Properties - - - - - - - - - - - - - - - - ) -} - -const InlineRow = ({ label, value }: { label: string; value: string }) => ( - - {label}:{' '} - - {value} - - -) - -const InlineRowWithUnitConversion = ({ - label, - value, - unit, -}: { - label: string - value: number | null | undefined - unit: SupportedUnits | string | null | undefined -}) => { - const normalizedUnit: SupportedUnits | null = - unit === 'in' || unit === 'ft' ? unit : null - - const hasNumericValue = typeof value === 'number' && !Number.isNaN(value) - - const [displayUnit, setDisplayUnit] = useState(() => - getDefaultDisplayUnit(value, normalizedUnit) - ) - - useEffect(() => { - setDisplayUnit(getDefaultDisplayUnit(value, normalizedUnit)) - }, [value, normalizedUnit]) - - const displayValue = useMemo(() => { - if (!hasNumericValue) return null - - if (normalizedUnit === 'in') { - return displayUnit === 'ft' - ? convertInchesToFeet(value, { precision: 2 }) - : value - } - - if (normalizedUnit === 'ft') { - return displayUnit === 'in' - ? convertFeetToInches(value, { precision: 2 }) - : value - } - - return value - }, [displayUnit, normalizedUnit, value, hasNumericValue]) - - const handleUnitChange = ( - _event: React.MouseEvent, - nextUnit: SupportedUnits | null - ) => { - if (nextUnit) { - setDisplayUnit(nextUnit) - } - } - - if (!hasNumericValue) { - return - } - - const shouldShowToggle = normalizedUnit === 'in' || normalizedUnit === 'ft' - - return ( - - - {label}:{' '} - - {formatNumber(displayValue, { precision: 2 })} - {shouldShowToggle - ? ` ${displayUnit}` - : normalizedUnit - ? ` ${normalizedUnit}` - : ''} - - - - {shouldShowToggle && ( - ({ - '& .MuiToggleButton-root': { - color: 'text.secondary', - border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.3)' : theme.palette.divider}`, - }, - '& .MuiToggleButton-root + .MuiToggleButton-root': { - borderLeft: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.3)' : theme.palette.divider}`, - marginLeft: 0, - }, - '& .MuiToggleButton-root.Mui-selected': { - bgcolor: 'primary.main', - color: 'primary.contrastText', - border: `1px solid ${theme.palette.primary.main} !important`, - '&:hover': { bgcolor: 'primary.dark' }, - }, - })} - > - - in - - - ft - - - )} - - ) -} - -const getDefaultDisplayUnit = ( - value: number | null | undefined, - normalizedUnit: SupportedUnits | null -): SupportedUnits => { - const hasNumericValue = typeof value === 'number' && !Number.isNaN(value) - - if (normalizedUnit === 'in' && hasNumericValue) { - return value >= INCHES_IN_A_FOOT ? 'ft' : 'in' - } - - return 'ft' -} diff --git a/src/components/WellShow/WellScreens.tsx b/src/components/WellShow/WellScreens.tsx index aa2bdec3..88fc267d 100644 --- a/src/components/WellShow/WellScreens.tsx +++ b/src/components/WellShow/WellScreens.tsx @@ -1,11 +1,11 @@ import { useMemo } from 'react' -import { Box, Paper, Stack, Typography } from '@mui/material' +import { Box, Paper, Typography } from '@mui/material' import { MoreVertOutlined } from '@mui/icons-material' import { DataGrid, GridColDef } from '@mui/x-data-grid' import { settings } from '@/settings' import type { IWellScreen } from '@/interfaces/ocotillo' -export const WellScreensAccordion = ({ +export const WellScreensCard = ({ rows, isLoading, }: { diff --git a/src/components/WellShow/index.ts b/src/components/WellShow/index.ts index b96fd8a1..7abc3074 100644 --- a/src/components/WellShow/index.ts +++ b/src/components/WellShow/index.ts @@ -2,7 +2,6 @@ export * from './ConstructionInfo' export * from './MonitoringInfo' export * from './GeologyInformation' export * from './OwnerPermissions' -export * from './WellPhysicalProperties' export * from './Attachments' export * from './AlternateIds' export * from './Contacts' diff --git a/src/interfaces/ocotillo/IWell.ts b/src/interfaces/ocotillo/IWell.ts index 471095a9..40252533 100644 --- a/src/interfaces/ocotillo/IWell.ts +++ b/src/interfaces/ocotillo/IWell.ts @@ -63,4 +63,6 @@ export interface IWell extends IThing { contacts?: Partial[] | null site_name?: string | null + + historic_depth_to_water?: string[] | null } diff --git a/src/pages/ocotillo/thing/well-show.tsx b/src/pages/ocotillo/thing/well-show.tsx index 50be1c27..ead0032d 100644 --- a/src/pages/ocotillo/thing/well-show.tsx +++ b/src/pages/ocotillo/thing/well-show.tsx @@ -26,17 +26,16 @@ import { HydrographCard, RecentWaterLevelObservationsCard, ContactsCard, - AttachmentsAccordion, - AlternateIdsAccordion, + AttachmentsCard, + AlternateIdsCard, USGSInfoCard, OSEPODInfoCard, WellPDFPreviewButton, - WellScreensAccordion, - EquipmentAccordion, + WellScreensCard, + EquipmentCard, NotesAccordion, - ConstructionInfoAccordion, - GeologyInformationAccordion, - WellPhysicalPropertiesAccordion, + ConstructionInfoCard, + GeologyInformationCard, WellPDFDownloadButton, WellShowTitle, OwnerPermissionsCard, @@ -52,8 +51,7 @@ const EMPTY_WELL_SCREENS: IWellScreen[] = [] const EMPTY_FIELD_EVENTS: IFieldEvent[] = [] const EMPTY_PARTICIPANTS: IFieldEventParticipant[] = [] const EMPTY_MANUAL_HYDRO_ROWS: IObservation[] = [] -const EMPTY_TRANSDUCER_HYDRO_ROWS: TransducerObservationWithBlockResponse[] = - [] +const EMPTY_TRANSDUCER_HYDRO_ROWS: TransducerObservationWithBlockResponse[] = [] export const WellShow = () => { const dataProvider = useDataProvider() @@ -373,17 +371,17 @@ export const WellShow = () => { isLoading={isDetailsLoading} /> - - - - + @@ -407,9 +405,8 @@ export const WellShow = () => { isLoading={isDetailsLoading} /> - - - + + diff --git a/src/test/pages/well-show.test.tsx b/src/test/pages/well-show.test.tsx index 01294cb6..bb41c2c2 100644 --- a/src/test/pages/well-show.test.tsx +++ b/src/test/pages/well-show.test.tsx @@ -48,17 +48,16 @@ vi.mock('@/components', () => { HydrographCard: () => , RecentWaterLevelObservationsCard: () => , ContactsCard: () => , - AttachmentsAccordion: () => , - AlternateIdsAccordion: () => , + AttachmentsCard: () => , + AlternateIdsCard: () => , USGSInfoCard: () => , OSEPODInfoCard: () => , WellPDFPreviewButton: () => , - WellScreensAccordion: () => , - EquipmentAccordion: () => , + WellScreensCard: () => , + EquipmentCard: () => , NotesAccordion: () => , - ConstructionInfoAccordion: () => , - GeologyInformationAccordion: () => , - WellPhysicalPropertiesAccordion: () => , + ConstructionInfoCard: () => , + GeologyInformationCard: () => , WellPDFDownloadButton: () => , WellShowTitle: () => , OwnerPermissionsCard: () => ,