Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/components/WellShow/AlternateIds.tsx
Original file line number Diff line number Diff line change
@@ -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']
Expand All @@ -25,7 +25,9 @@ export const AlternateIdsAccordion = ({

return (
<Paper elevation={2} sx={{ borderRadius: 2, overflow: 'hidden' }}>
<Box sx={{ px: 2, py: 1.5, display: 'flex', alignItems: 'center', gap: 1 }}>
<Box
sx={{ px: 2, py: 1.5, display: 'flex', alignItems: 'center', gap: 1 }}
>
<MoreVertOutlined color="primary" />
<Typography variant="body1" fontWeight="bold">
Alternate IDs
Expand Down
2 changes: 1 addition & 1 deletion src/components/WellShow/Attachments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type { IAsset } from '@/interfaces/ocotillo'

type ImageViewMode = 'grid' | 'slideshow'

export const AttachmentsAccordion = ({
export const AttachmentsCard = ({
assets,
isLoading,
}: {
Expand Down
217 changes: 208 additions & 9 deletions src/components/WellShow/ConstructionInfo.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Paper elevation={2} sx={{ borderRadius: 2, overflow: 'hidden' }}>
<Box sx={{ px: 2, py: 1.5 }}>
Expand All @@ -12,6 +30,37 @@ export const ConstructionInfoAccordion = ({ well }: { well?: IWell }) => {
</Box>
<Box sx={{ p: 2 }}>
<Stack spacing={1}>
<InlineRowWithUnitConversion
label="Casing Diameter"
value={well?.well_casing_diameter ?? null}
unit={well?.well_casing_diameter_unit ?? null}
/>
<InlineRow
label="Casing Depth"
value={`${well?.well_casing_depth?.toFixed(2) || 'N/A'}${well?.well_casing_depth ? ` ${well.well_casing_depth_unit}` : ''}`}
/>
<InlineRow
label="Casing Materials"
value={well?.well_casing_materials?.join(', ') || 'N/A'}
/>
<InlineRow label="Pump Type" value={well?.well_pump_type || 'N/A'} />
<InlineRow
label="Pump Depth"
value={`${well?.well_pump_depth?.toFixed(2) || 'N/A'}${well?.well_pump_depth ? ` ${well.well_pump_depth_unit}` : ''}`}
/>
<InlineRow
label="Elevation"
value={
normalizedElevation != null
? `${normalizedElevation.toFixed(2)}${elevationUnit ? ` ${elevationUnit}` : ''}`
: 'N/A'
}
/>
<InlineRow
label="Elevation Method"
value={elevationMethod || 'N/A'}
/>
<InlineRow label="Vertical Datum" value={verticalDatum || 'N/A'} />
<InlineRow
label="Datalogger Suitability"
value={well?.is_suitable_for_datalogger?.toString() || 'N/A'}
Expand All @@ -20,6 +69,18 @@ export const ConstructionInfoAccordion = ({ well }: { well?: IWell }) => {
label="Driller Name"
value={well?.well_driller_name || 'N/A'}
/>
<InlineRow
label="Depth Source"
value={well?.well_depth_source || 'N/A'}
/>
<InlineRow
label="Historic Depth to Water"
value={
(well?.historic_depth_to_water?.length ?? 0) > 0
? well.historic_depth_to_water.join(', ')
: 'No original depth to water available'
}
/>
<Box>
<InlineRow
label="Completion Date"
Expand Down Expand Up @@ -56,11 +117,149 @@ export const ConstructionInfoAccordion = ({ well }: { well?: IWell }) => {
)
}

const InlineRow = ({ label, value }: { label: string; value: string }) => (
<Typography variant="body2">
{label}:{' '}
<Typography variant="body2" color="text.secondary" component="span">
{value}
const InlineRow = ({ label, value }: { label: string; value: string }) => {
const isLong = value.length > 30

return (
<Typography variant="body2">
{label}:{' '}
<Typography
variant="body2"
color="text.secondary"
component="span"
sx={{
display: isLong ? 'block' : 'inline',
ml: isLong ? 0 : 0.5,
}}
>
{value}
</Typography>
</Typography>
</Typography>
)
)
}

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<SupportedUnits>(() =>
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<HTMLElement>,
nextUnit: SupportedUnits | null
) => {
if (nextUnit) {
setDisplayUnit(nextUnit)
}
}

if (!hasNumericValue) {
return <InlineRow label={label} value="N/A" />
}

const shouldShowToggle = normalizedUnit === 'in' || normalizedUnit === 'ft'

return (
<Stack direction="row" spacing={1} alignItems="center" flexWrap="wrap">
<Typography variant="body2">
{label}:{' '}
<Typography variant="body2" color="text.secondary" component="span">
{formatNumber(displayValue, { precision: 2 })}
{shouldShowToggle
? ` ${displayUnit}`
: normalizedUnit
? ` ${normalizedUnit}`
: ''}
</Typography>
</Typography>

{shouldShowToggle && (
<ToggleButtonGroup
size="small"
exclusive
value={displayUnit}
onChange={handleUnitChange}
aria-label={`${label} unit toggle`}
sx={(theme) => ({
'& .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' },
},
})}
>
<ToggleButton
value="in"
aria-label="inches"
sx={{ py: 0, fontSize: '0.7rem' }}
>
in
</ToggleButton>
<ToggleButton
value="ft"
aria-label="feet"
sx={{ py: 0, fontSize: '0.7rem' }}
>
ft
</ToggleButton>
</ToggleButtonGroup>
)}
</Stack>
)
}
8 changes: 5 additions & 3 deletions src/components/WellShow/Equipment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -20,7 +19,7 @@ const EquipmentToolbar = () => (
</GridToolbarContainer>
)

export const EquipmentAccordion = ({
export const EquipmentCard = ({
sensors,
deployments,
isDetailsPending,
Expand Down Expand Up @@ -65,7 +64,10 @@ export const EquipmentAccordion = ({
const rowSelectionModel = useMemo(
() =>
selectedEquipmentId != null
? { type: 'include' as const, ids: new Set<GridRowId>([selectedEquipmentId]) }
? {
type: 'include' as const,
ids: new Set<GridRowId>([selectedEquipmentId]),
}
: { type: 'include' as const, ids: new Set<GridRowId>() },
[selectedEquipmentId]
)
Expand Down
6 changes: 4 additions & 2 deletions src/components/WellShow/GeologyInformation.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Paper elevation={2} sx={{ borderRadius: 2, overflow: 'hidden' }}>
<Box sx={{ px: 2, py: 1.5 }}>
Expand All @@ -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'
}
/>
Expand Down
Loading
Loading