diff --git a/web/src/app/theme.ts b/web/src/app/theme.ts index 13f9dd5c3..3e252ceec 100644 --- a/web/src/app/theme.ts +++ b/web/src/app/theme.ts @@ -91,3 +91,6 @@ export const PLANNING_AREA = { height: 45 } export const UNSELECTED_STATION_COLOR = 'rgba(0,0,0,0.54)' +export const DARK_GREY = '#A7A7A7' +export const LIGHT_GREY = '#DADADA' +export const MEDIUM_GREY = '#B5B5B5' diff --git a/web/src/features/moreCast2/components/DataGridColumns.tsx b/web/src/features/moreCast2/components/DataGridColumns.tsx index ee06b8807..f33b02e95 100644 --- a/web/src/features/moreCast2/components/DataGridColumns.tsx +++ b/web/src/features/moreCast2/components/DataGridColumns.tsx @@ -1,3 +1,4 @@ +import React from 'react' import { GridColumnVisibilityModel, GridColDef, GridColumnGroupingModel } from '@mui/x-data-grid' import { WeatherDeterminate, WeatherDeterminateChoices } from 'api/moreCast2API' import { @@ -6,9 +7,12 @@ import { MORECAST2_INDEX_FIELDS, MORECAST2_STATION_DATE_FIELDS } from 'features/moreCast2/components/MoreCast2Column' +import GroupHeader from 'features/moreCast2/components/GroupHeader' +import { handleShowHideChangeType } from 'features/moreCast2/components/TabbedDataGrid' export interface ColumnVis { columnName: string + displayName?: string visible: boolean } @@ -27,7 +31,27 @@ export class DataGridColumns { return model } - public static updateGridColumnVisibliityModel( + public static initGridColumnVisibilityModelNew() { + // First check local storage for existing column visibility + const groupedColumnVisibility = localStorage.getItem('groupedColumnVisibility') + if (groupedColumnVisibility) { + console.log(groupedColumnVisibility) + } + + const model: GridColumnVisibilityModel = {} + const weatherParameterColumns = this.getWeatherParameterColumns() + weatherParameterColumns.forEach(columnName => { + // temperature columns are visible by default + if (columnName.startsWith('temp')) { + model[columnName] = true + } else { + model[columnName] = false + } + }) + return model + } + + public static updateGridColumnVisibilityModel( parameters: ColumnVis[], columnVisibilityModel: GridColumnVisibilityModel ) { @@ -44,6 +68,18 @@ export class DataGridColumns { return newModel } + public static updateGridColumnVisibilityFromShowHideColumnsModel( + parameters: ColumnVis[], + columnVisibilityModel: GridColumnVisibilityModel + ) { + const newModel: GridColumnVisibilityModel = {} + Object.assign(newModel, columnVisibilityModel) + for (const param of parameters) { + newModel[param.columnName] = param.visible + } + return newModel + } + public static getTabColumns(): GridColDef[] { let tabColumns: GridColDef[] = [] MORECAST2_FIELDS.forEach(field => { @@ -64,6 +100,65 @@ export class DataGridColumns { const fields = DataGridColumns.getTabColumns().map(column => column.field) return fields.filter(field => field !== 'stationName' && field !== 'forDate') } + + public static getWeatherModelColumns() { + const columns = DataGridColumns.getTabColumns() + return columns.filter( + column => column.field !== 'stationName' && column.field !== 'forDate' && !column.field.endsWith('Forecast') + ) + } +} + +const renderGroupHeader = ( + id: string, + weatherParam: string, + columns: ColumnVis[], + handleShowHideChange: handleShowHideChangeType +) => { + return ( + + ) +} + +export const getColumnGroupingModel = ( + showHideColumnsModel: Record, + handleShowHideChange: handleShowHideChangeType +) => { + const model = [ + { + groupId: 'ID', + children: [{ field: 'stationName' }, { field: 'forDate' }] + }, + { + groupId: 'Temp', + children: columnGroupingModelChildGenerator('temp'), + renderHeaderGroup: () => renderGroupHeader('Temp', 'temp', showHideColumnsModel['temp'], handleShowHideChange) + }, + { + groupId: 'RH', + children: columnGroupingModelChildGenerator('rh'), + renderHeaderGroup: () => renderGroupHeader('RH', 'rh', showHideColumnsModel['rh'], handleShowHideChange) + }, + { + groupId: 'Precip', + children: columnGroupingModelChildGenerator('precip'), + renderHeaderGroup: () => + renderGroupHeader('Precip', 'precip', showHideColumnsModel['precip'], handleShowHideChange) + }, + { + groupId: 'Wind Dir', + children: columnGroupingModelChildGenerator('windDirection'), + renderHeaderGroup: () => + renderGroupHeader('Wind Dir', 'windDirection', showHideColumnsModel['windDirection'], handleShowHideChange) + }, + { + groupId: 'Wind Speed', + children: columnGroupingModelChildGenerator('windSpeed'), + renderHeaderGroup: () => + renderGroupHeader('Wind Speed', 'windSpeed', showHideColumnsModel['windSpeed'], handleShowHideChange) + } + ] + return model } export const columnGroupingModel: GridColumnGroupingModel = [ diff --git a/web/src/features/moreCast2/components/GridComponentRenderer.tsx b/web/src/features/moreCast2/components/GridComponentRenderer.tsx index 0251e04bf..e734de4b3 100644 --- a/web/src/features/moreCast2/components/GridComponentRenderer.tsx +++ b/web/src/features/moreCast2/components/GridComponentRenderer.tsx @@ -14,7 +14,7 @@ const NOT_AVAILABLE = 'N/A' export class GridComponentRenderer { public renderForecastHeaderWith = (params: GridColumnHeaderParams) => { - return + return } public renderHeaderWith = (params: GridColumnHeaderParams) => { if (params.field.endsWith('_BIAS')) { @@ -22,13 +22,13 @@ export class GridComponentRenderer { const index = headerName.indexOf('_BIAS') const prefix = headerName.slice(0, index) return ( -
+
{prefix} bias
) } - return <>{params.colDef.headerName} + return
{params.colDef.headerName}
} public renderCellWith = (params: Pick) => ( diff --git a/web/src/features/moreCast2/components/GroupHeader.tsx b/web/src/features/moreCast2/components/GroupHeader.tsx new file mode 100644 index 000000000..028d9ea7e --- /dev/null +++ b/web/src/features/moreCast2/components/GroupHeader.tsx @@ -0,0 +1,90 @@ +import { Checkbox, FormControlLabel, FormGroup, IconButton, Popover, Stack, Typography, styled } from '@mui/material' +import { ExpandMore } from '@mui/icons-material' +import React, { ChangeEvent, MouseEvent, useState } from 'react' +import { LIGHT_GREY, MEDIUM_GREY, DARK_GREY } from 'app/theme' +import { ColumnVis } from 'features/moreCast2/components/DataGridColumns' + +interface GroupHeaderProps { + id: string + columns: ColumnVis[] + weatherParam: string + handleShowHideChange: (weatherParam: string, columnName: string, value: boolean) => void +} + +const PopoverHeader = styled(Typography)(({ theme }) => ({ + backgroundColor: DARK_GREY, + fontSize: '14px', + fontWeight: 'bold', + padding: theme.spacing(1) +})) + +const PopoverFormControlLabel = styled(FormControlLabel)(({ theme }) => ({ + height: theme.spacing(4), + marginRight: 0, + paddingLeft: theme.spacing(1), + [':hover']: { + backgroundColor: LIGHT_GREY + } +})) + +const ShowHideCheckbox = styled(Checkbox)({ + ['&.Mui-checked']: { + color: MEDIUM_GREY + } +}) + +const GroupHeader = ({ id, columns, weatherParam, handleShowHideChange }: GroupHeaderProps) => { + const [anchorEl, setAnchorEl] = useState(null) + const open = Boolean(anchorEl) + const handleClick = (event: MouseEvent) => { + setAnchorEl(event.currentTarget) + } + + const handleClose = () => { + setAnchorEl(null) + } + + const handleOnChange = (event: ChangeEvent) => { + handleShowHideChange(weatherParam, event.target.name, event.target.checked) + } + + return ( + <> + {id} + + + + + + Choose Models to Display + + {columns.map(column => { + return ( + + } + key={column.columnName} + label={{column.displayName}} + /> + ) + })} + + + + + ) +} + +export default React.memo(GroupHeader) diff --git a/web/src/features/moreCast2/components/SelectableButton.tsx b/web/src/features/moreCast2/components/SelectableButton.tsx index 85dc95a66..74ea6fda9 100644 --- a/web/src/features/moreCast2/components/SelectableButton.tsx +++ b/web/src/features/moreCast2/components/SelectableButton.tsx @@ -5,13 +5,19 @@ import { theme } from 'app/theme' interface SelectableButtonProps { children?: React.ReactNode + dataTestId?: string onClick: () => void selected: boolean } -const SelectableButton = ({ children, onClick, selected }: SelectableButtonProps) => { +const SelectableButton = ({ children, dataTestId, onClick, selected }: SelectableButtonProps) => { return ( - ) diff --git a/web/src/features/moreCast2/components/TabbedDataGrid.tsx b/web/src/features/moreCast2/components/TabbedDataGrid.tsx index fe530429d..7fc0cdbb6 100644 --- a/web/src/features/moreCast2/components/TabbedDataGrid.tsx +++ b/web/src/features/moreCast2/components/TabbedDataGrid.tsx @@ -1,8 +1,14 @@ import { AlertColor, List, Stack } from '@mui/material' import { styled } from '@mui/material/styles' -import { GridCellParams, GridColDef, GridColumnVisibilityModel, GridEventListener } from '@mui/x-data-grid' +import { + GridCellParams, + GridColDef, + GridColumnGroupingModel, + GridColumnVisibilityModel, + GridEventListener +} from '@mui/x-data-grid' import { ModelChoice, ModelType, submitMoreCastForecastRecords } from 'api/moreCast2API' -import { DataGridColumns, columnGroupingModel } from 'features/moreCast2/components/DataGridColumns' +import { getColumnGroupingModel, ColumnVis, DataGridColumns } from 'features/moreCast2/components/DataGridColumns' import ForecastDataGrid from 'features/moreCast2/components/ForecastDataGrid' import ForecastSummaryDataGrid from 'features/moreCast2/components/ForecastSummaryDataGrid' import SelectableButton from 'features/moreCast2/components/SelectableButton' @@ -16,7 +22,7 @@ import React, { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { MoreCast2ForecastRow, MoreCast2Row, PredictionItem } from 'features/moreCast2/interfaces' import { selectSelectedStations } from 'features/moreCast2/slices/selectedStationsSlice' -import { groupBy, isEqual, isUndefined } from 'lodash' +import { cloneDeep, groupBy, isEqual, isNull, isUndefined } from 'lodash' import SaveForecastButton from 'features/moreCast2/components/SaveForecastButton' import { ROLES } from 'features/auth/roles' import { selectAuthentication, selectWf1Authentication } from 'app/rootReducer' @@ -44,13 +50,16 @@ const FORECAST_ERROR_MESSAGE = 'The forecast was not saved; an unexpected error const FORECAST_SAVED_MESSAGE = 'Forecast was successfully saved and sent to Wildfire One.' const FORECAST_WARN_MESSAGE = 'Forecast not submitted. A forecast can only contain N/A values for the Wind Direction.' +const SHOW_HIDE_COLUMNS_LOCAL_STORAGE_KEY = 'showHideColumnsModel' + interface TabbedDataGridProps { morecast2Rows: MoreCast2Row[] - fetchWeatherIndeterminates: () => void fromTo: DateRange setFromTo: React.Dispatch> } +export type handleShowHideChangeType = (weatherParam: string, columnName: string, value: boolean) => void + const TabbedDataGrid = ({ morecast2Rows, fromTo, setFromTo }: TabbedDataGridProps) => { const dispatch: AppDispatch = useDispatch() const selectedStations = useSelector(selectSelectedStations) @@ -65,7 +74,7 @@ const TabbedDataGrid = ({ morecast2Rows, fromTo, setFromTo }: TabbedDataGridProp const [visibleRows, setVisibleRows] = useState([]) const [columnVisibilityModel, setColumnVisibilityModel] = useState( - DataGridColumns.initGridColumnVisibilityModel() + DataGridColumns.initGridColumnVisibilityModelNew() ) const [tempVisible, setTempVisible] = useState(true) @@ -79,7 +88,10 @@ const TabbedDataGrid = ({ morecast2Rows, fromTo, setFromTo }: TabbedDataGridProp const [snackbarOpen, setSnackbarOpen] = useState(false) const [snackbarSeverity, setSnackbarSeverity] = useState('success') - const [contextMenu, setContextMenu] = React.useState<{ + const [showHideColumnsModel, setShowHideColumnsModel] = useState>({}) + const [columnGroupingModel, setColumnGroupingModel] = useState([]) + + const [contextMenu, setContextMenu] = useState<{ mouseX: number mouseY: number } | null>(null) @@ -100,6 +112,128 @@ const TabbedDataGrid = ({ morecast2Rows, fromTo, setFromTo }: TabbedDataGridProp setContextMenu(null) } + const groupByWeatherParam = (ungroupedState: ColumnVis[]) => { + const grouper = (item: ColumnVis) => { + const field = item.columnName + if (field.startsWith('temp')) { + return 'temp' + } + if (field.startsWith('rh')) { + return 'rh' + } + if (field.startsWith('precip')) { + return 'precip' + } + if (field.startsWith('windDirection')) { + return 'windDirection' + } + if (field.startsWith('windSpeed')) { + return 'windSpeed' + } + } + const groupedState = groupBy(ungroupedState, grouper) + return groupedState + } + + const getColumnDisplayName = (name: string) => { + if (name.endsWith('_BIAS')) { + const index = name.indexOf('_BIAS') + return `${name.slice(0, index)} bias` + } + return name + } + + // Given an array of weather parameters (aka tabs) return a GridColumnVisibilityModel object that + // contains all weather model columns that are visible for each weather parameter. + const getVisibleColumns = (weatherParams: string[]) => { + const visibleColumns: GridColumnVisibilityModel = {} + for (const param of weatherParams) { + if (param in showHideColumnsModel) { + for (const column of showHideColumnsModel[param]) { + visibleColumns[column.columnName] = column.visible + } + } + } + return visibleColumns + } + + const getVisibleColumnsByWeatherParam = (weatherParam: string, visible: boolean) => { + const updatedColumnVisibilityModel = DataGridColumns.updateGridColumnVisibilityModel( + [{ columnName: weatherParam, visible: visible }], + columnVisibilityModel + ) + if (visible) { + const showHideColumns = showHideColumnsModel[weatherParam] || [] + for (const column of showHideColumns) { + updatedColumnVisibilityModel[column.columnName] = column.visible + } + } + return updatedColumnVisibilityModel + } + + // Save the current set of weather model columns for each weather parameter (aka tab) as selected + // by the user. + const saveShowHideColumnsModelToLocalStorage = (model: Record) => { + const modelAsString = JSON.stringify(model) + window.localStorage.setItem(SHOW_HIDE_COLUMNS_LOCAL_STORAGE_KEY, modelAsString) + } + + // Gets the previously stored set of weather model columns for each weather paramter (aka tab). + const getShowHideColumnsModelFromLocalStorage = () => { + const modelAsString = window.localStorage.getItem(SHOW_HIDE_COLUMNS_LOCAL_STORAGE_KEY) + return isNull(modelAsString) ? null : JSON.parse(modelAsString) + } + + // Get the showHideColumnsModel from local storage if it exists, else provide default values. + const initShowHideColumnsModel = (): Record => { + // First check localStorage for an existing model + const model = getShowHideColumnsModelFromLocalStorage() + if (model) { + return model + } + const weatherModelColumns = DataGridColumns.getWeatherModelColumns() + // Provide default with all columns + const showHideColumnsUngroupedState = weatherModelColumns.map((column: GridColDef): ColumnVis => { + return { + columnName: column.field, + displayName: getColumnDisplayName(column.headerName || ''), + visible: true + } + }) + return groupByWeatherParam(showHideColumnsUngroupedState) + } + + // Return an array of strings representing which weather parameters (aka tabs) are currently visible. + const getVisibleTabs = () => { + const visibleTabs = [] + tempVisible && visibleTabs.push('temp') + rhVisible && visibleTabs.push('rh') + precipVisible && visibleTabs.push('precip') + windDirectionVisible && visibleTabs.push('windDirection') + windSpeedVisible && visibleTabs.push('windSpeed') + return visibleTabs + } + + useEffect(() => { + const initialShowHideColumnsModel = initShowHideColumnsModel() + setShowHideColumnsModel(initialShowHideColumnsModel) + }, []) // eslint-disable-line react-hooks/exhaustive-deps + + useEffect(() => { + const colGroupingModel = getColumnGroupingModel(showHideColumnsModel, handleShowHideChange) + setColumnGroupingModel(colGroupingModel) + }, [showHideColumnsModel]) // eslint-disable-line react-hooks/exhaustive-deps + + useEffect(() => { + const visibleTabs = getVisibleTabs() + const visibleColumns = getVisibleColumns(visibleTabs) + const newColumnVisibilityModel = { + ...columnVisibilityModel, + ...visibleColumns + } + setColumnVisibilityModel(newColumnVisibilityModel) + }, [showHideColumnsModel]) // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => { const labelledRows = mapForecastChoiceLabels(morecast2Rows, deepClone(userEditedRows)) setAllRows(labelledRows) @@ -120,49 +254,33 @@ const TabbedDataGrid = ({ morecast2Rows, fromTo, setFromTo }: TabbedDataGridProp useEffect(() => { tempVisible && setForecastSummaryVisible(false) - setColumnVisibilityModel( - DataGridColumns.updateGridColumnVisibliityModel( - [{ columnName: 'temp', visible: tempVisible }], - columnVisibilityModel - ) - ) + const updatedColumnVisibilityModel = getVisibleColumnsByWeatherParam('temp', tempVisible) + setColumnVisibilityModel(updatedColumnVisibilityModel) }, [tempVisible]) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { rhVisible && setForecastSummaryVisible(false) - setColumnVisibilityModel( - DataGridColumns.updateGridColumnVisibliityModel([{ columnName: 'rh', visible: rhVisible }], columnVisibilityModel) - ) + const updatedColumnVisibilityModel = getVisibleColumnsByWeatherParam('rh', rhVisible) + setColumnVisibilityModel(updatedColumnVisibilityModel) }, [rhVisible]) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { precipVisible && setForecastSummaryVisible(false) - setColumnVisibilityModel( - DataGridColumns.updateGridColumnVisibliityModel( - [{ columnName: 'precip', visible: precipVisible }], - columnVisibilityModel - ) - ) + const updatedColumnVisibilityModel = getVisibleColumnsByWeatherParam('precip', precipVisible) + setColumnVisibilityModel(updatedColumnVisibilityModel) }, [precipVisible]) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { windDirectionVisible && setForecastSummaryVisible(false) - setColumnVisibilityModel( - DataGridColumns.updateGridColumnVisibliityModel( - [{ columnName: 'windDirection', visible: windDirectionVisible }], - columnVisibilityModel - ) - ) + const updatedColumnVisibilityModel = getVisibleColumnsByWeatherParam('windDirection', windDirectionVisible) + setColumnVisibilityModel(updatedColumnVisibilityModel) }, [windDirectionVisible]) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { + setForecastSummaryVisible(false) windSpeedVisible && setForecastSummaryVisible(false) - setColumnVisibilityModel( - DataGridColumns.updateGridColumnVisibliityModel( - [{ columnName: 'windSpeed', visible: windSpeedVisible }], - columnVisibilityModel - ) - ) + const updatedColumnVisibilityModel = getVisibleColumnsByWeatherParam('windSpeed', windSpeedVisible) + setColumnVisibilityModel(updatedColumnVisibilityModel) }, [windSpeedVisible]) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { @@ -174,7 +292,7 @@ const TabbedDataGrid = ({ morecast2Rows, fromTo, setFromTo }: TabbedDataGridProp setWindDirectionVisible(false) setWindSpeedVisible(false) setColumnVisibilityModel( - DataGridColumns.updateGridColumnVisibliityModel( + DataGridColumns.updateGridColumnVisibilityModel( [ { columnName: 'temp', visible: false }, { columnName: 'rh', visible: false }, @@ -319,6 +437,14 @@ const TabbedDataGrid = ({ morecast2Rows, fromTo, setFromTo }: TabbedDataGridProp return visibleRows.filter(isForecastRowPredicate).length > 0 } + const handleShowHideChange: handleShowHideChangeType = (weatherParam: string, columnName: string, value: boolean) => { + const newModel = cloneDeep(showHideColumnsModel) + const changedColumn = newModel[weatherParam].filter(column => column.columnName === columnName)[0] + changedColumn.visible = value + saveShowHideColumnsModelToLocalStorage(newModel) + setShowHideColumnsModel(newModel) + } + return ( @@ -333,25 +459,39 @@ const TabbedDataGrid = ({ morecast2Rows, fromTo, setFromTo }: TabbedDataGridProp onClick={handleSaveClick} /> - setTempVisible(!tempVisible)} selected={tempVisible}> + setTempVisible(!tempVisible)} + selected={tempVisible} + > Temp - setRhVisible(!rhVisible)} selected={rhVisible}> + setRhVisible(!rhVisible)} selected={rhVisible}> RH setWindDirectionVisible(!windDirectionVisible)} selected={windDirectionVisible} > Wind Direction - setWindSpeedVisible(!windSpeedVisible)} selected={windSpeedVisible}> + setWindSpeedVisible(!windSpeedVisible)} + selected={windSpeedVisible} + > Wind Speed - setPrecipVisible(!precipVisible)} selected={precipVisible}> + setPrecipVisible(!precipVisible)} + selected={precipVisible} + > Precip setForecastSummaryVisible(!forecastSummaryVisible)} selected={forecastSummaryVisible} > diff --git a/web/src/features/moreCast2/components/tabbedDataGrid.test.tsx b/web/src/features/moreCast2/components/tabbedDataGrid.test.tsx new file mode 100644 index 000000000..c41f44ff2 --- /dev/null +++ b/web/src/features/moreCast2/components/tabbedDataGrid.test.tsx @@ -0,0 +1,171 @@ +import React from 'react' +import { fireEvent, render, screen, waitFor } from '@testing-library/react' +import { Provider } from 'react-redux' +import TabbedDataGrid from 'features/moreCast2/components/TabbedDataGrid' +import { DateRange } from 'components/dateRangePicker/types' +import { MoreCast2Row } from 'features/moreCast2/interfaces' +import store from 'app/store' +import { createTheme } from '@mui/material/styles' + +const EMPTY_MORECAST_2_ROWS: MoreCast2Row[] = [] +const FROM_TO: DateRange = {} +const SET_FROM_TO: React.Dispatch> = jest.fn() +const TABS = [ + 'temp-tab-button', + 'rh-tab-button', + 'wind-direction-tab-button', + 'wind-speed-tab-button', + 'precip-tab-button', + 'summary-tab-button' +] +// Leaving this here for future tests +// const TEMPERATURE_WEATHER_MODELS_HEADERS = [ +// 'tempHRDPS-column-header', +// 'tempHRDPS_BIAS-column-header', +// 'tempRDPS-column-header', +// 'tempRDPS_BIAS-column-header', +// 'tempGDPS-column-header', +// 'tempGDPS_BIAS-column-header', +// 'tempNAM-column-header', +// 'tempNAM_BIAS-column-header', +// 'tempGFS-column-header', +// 'tempGFS_BIAS-column-header' +// ] +const theme = createTheme() + +const hexToRgb = (hex: string): string => { + if (hex.startsWith('#')) { + hex = hex.slice(1) + } + const value = parseInt(hex, 16) + const red = (value >> 16) & 0xff + const green = (value >> 8) & 0xff + const blue = value & 0xff + return `rgb(${red}, ${green}, ${blue})` +} + +const convertRgbaToRgb = (rgba: string): string => { + if (rgba.startsWith(rgba)) { + const temp = rgba.slice(5) + const split = temp.split(',').map(item => item.trim()) + return `rgb(${split[0]}, ${split[1]}, ${split[2]})` + } + return '' +} + +describe('TabbedDataGrid', () => { + test('Only temp tab is selected on load', () => { + render( + + + + ) + const tab = screen.getByTestId('temp-tab-button') + expect(tab).toBeVisible() + const style = getComputedStyle(tab) + // A dark background color indicates the tab is selected + expect(style.backgroundColor).toBe(hexToRgb(theme.palette.primary.dark)) + + for (const tab of TABS) { + const tabElement = screen.getByTestId(tab) + expect(tabElement).toBeVisible() + const style = getComputedStyle(tabElement) + if (tab === TABS[0]) { + expect(style.backgroundColor).toBe(hexToRgb(theme.palette.primary.dark)) + } else { + const bgColor = convertRgbaToRgb(style.backgroundColor) + expect(bgColor).toBe(hexToRgb(theme.palette.primary.main)) + } + } + }) + + test('Forecast column visibility', async () => { + render( + + + + ) + // Temp forecast column is visible on load + await waitFor(() => expect(screen.getByTestId('tempForecast-column-header')).toBeDefined()) + const tempTabElement = screen.getByTestId(TABS[0]) + // Toggle off Temp tab which should hide temp forecast column + fireEvent.click(tempTabElement) + await waitFor(() => expect(screen.queryByTestId('tempForecast-column-header')).not.toBeInTheDocument()) + // Toggle on Temp tab and ensure temp forecast column is visible again + fireEvent.click(tempTabElement) + await waitFor(() => expect(screen.getByTestId('tempForecast-column-header')).toBeDefined()) + }) +}) + +// Leaving this here for future tests +// const moreCast2Row: MoreCast2Row = { +// id: 'testId', +// stationCode: 123, +// stationName: 'foo', +// forDate: DateTime.now(), +// latitude: 49, +// longitude: -121, +// ffmcCalcActual: 1, +// dmcCalcActual: 1, +// dcCalcActual: 1, +// isiCalcActual: 1, +// buiCalcActual: 1, +// fwiCalcActual: 1, +// dgrCalcActual: 1, +// grassCuringActual: 1, +// precipActual: 0, +// rhActual: 95, +// tempActual: 3, +// windDirectionActual: 121, +// windSpeedActual: 6.5, +// precipGDPS: 0, +// rhGDPS: 0, +// tempGDPS: 0, +// windDirectionGDPS: 0, +// windSpeedGDPS: 0, +// precipGDPS_BIAS: 0, +// rhGDPS_BIAS: 0, +// tempGDPS_BIAS: 0, +// windDirectionGDPS_BIAS: 0, +// windSpeedGDPS_BIAS: 0, +// precipGFS: 0, +// rhGFS: 0, +// tempGFS: 0, +// windDirectionGFS: 0, +// windSpeedGFS: 0, +// precipGFS_BIAS: 0, +// rhGFS_BIAS: 0, +// tempGFS_BIAS: 0, +// windDirectionGFS_BIAS: 0, +// windSpeedGFS_BIAS: 0, +// precipHRDPS: 0, +// rhHRDPS: 0, +// tempHRDPS: 0, +// windDirectionHRDPS: 0, +// windSpeedHRDPS: 0, +// precipHRDPS_BIAS: 0, +// rhHRDPS_BIAS: 0, +// tempHRDPS_BIAS: 0, +// windDirectionHRDPS_BIAS: 0, +// windSpeedHRDPS_BIAS: 0, +// precipNAM: 0, +// rhNAM: 0, +// tempNAM: 0, +// windDirectionNAM: 0, +// windSpeedNAM: 0, +// precipNAM_BIAS: 0, +// rhNAM_BIAS: 0, +// tempNAM_BIAS: 0, +// windDirectionNAM_BIAS: 0, +// windSpeedNAM_BIAS: 0, +// precipRDPS: 0, +// rhRDPS: 0, +// tempRDPS: 0, +// windDirectionRDPS: 0, +// windSpeedRDPS: 0, +// precipRDPS_BIAS: 0, +// rhRDPS_BIAS: 0, +// tempRDPS_BIAS: 0, +// windDirectionRDPS_BIAS: 0, +// windSpeedRDPS_BIAS: 0 +// } diff --git a/web/src/features/moreCast2/pages/MoreCast2Page.tsx b/web/src/features/moreCast2/pages/MoreCast2Page.tsx index efcb91f82..087366b5c 100644 --- a/web/src/features/moreCast2/pages/MoreCast2Page.tsx +++ b/web/src/features/moreCast2/pages/MoreCast2Page.tsx @@ -120,12 +120,7 @@ const MoreCast2Page = () => { /> - +