Skip to content

Commit

Permalink
Merge pull request #168 from RENCI/#91-date-picker-reset
Browse files Browse the repository at this point in the history
#91 Date picker error handling
  • Loading branch information
lstillwe authored Aug 16, 2024
2 parents f06fb46 + 28bcd8a commit 2fd73b1
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 33 deletions.
8 changes: 8 additions & 0 deletions src/components/trays/model-selection/catalogItems.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ export default function CatalogItems(data) {
</div>
);
}
else if(data.data['catalog'] === undefined || data.data['catalog'] === null) {
return (
<div>
Error: { 'No catalog data retrieved.' }
</div>
);
}

// return all the data cards
else {
// save the name of the element for tropical storms and advisory numbers
Expand Down
149 changes: 116 additions & 33 deletions src/components/trays/model-selection/synopticTab.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment, useState, useEffect } from 'react';
import React, { Fragment, useState, useEffect, useMemo } from 'react';
import { Button, Divider, Select, Stack } from '@mui/joy';
import { DatePicker } from '@mui/x-date-pickers';
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
Expand All @@ -8,6 +8,7 @@ import axios from 'axios';
import DropDownOptions from "@model-selection/DropDownOptions";
import CatalogItems from "@model-selection/catalogItems";
import { getNamespacedEnvParam, getBrandingHandler } from "@utils/map-utils";
import dayjs from 'dayjs';

/**
* Form to filter/select synoptic runs
Expand All @@ -18,21 +19,39 @@ import { getNamespacedEnvParam, getBrandingHandler } from "@utils/map-utils";
export const SynopticTabForm = () => {

// declare all state variables for the synoptic tab dropdown data
const [synopticDate, setSynopticDate] = useState(null);
const [synopticDate, setSynopticDate] = useState(dayjs(new Date()));
const [synopticCycle, setSynopticCycle] = useState(null);
const [synopticGrid, setSynopticGrid] = useState(null);
const [synopticInstance, setSynopticInstance] = useState(null);

// init the data urls
const rootUrl = `${ getNamespacedEnvParam('REACT_APP_UI_DATA_URL') }`;
const basePulldownUrl = `get_pulldown_data?met_class=synoptic&use_v3_sp=true${ getBrandingHandler() }`;
const basePulldownUrl = `get_pulldown_data?met_class=synoptic${ getBrandingHandler() }`;
const baseDataUrl = `get_ui_data_secure?limit=14&met_class=synoptic&use_v3_sp=true${ getBrandingHandler() }`;
const [finalDataUrl, setFinalDataUrl] = useState(rootUrl + basePulldownUrl);

// storage for received data to render pulldowns
const [dropDownData, setDropDownData] = useState(null);
const [catalogData, setCatalogData] = useState(null);

// state for the date validation error
const [error, setError] = useState(null);

const setChangedSynopticDate = (newValue) => {
// if there was a valid date
if (!isNaN(newValue) && newValue !== null) {
//console.log('setChangedSynopticDate Good date: ' + newValue.$d + ', error: ' + error + ', newValue: ' + newValue);
// save the date
setSynopticDate(newValue.$d);
}
// else handle a bad date
else {
//console.log('setChangedSynopticDate Bad date: ' + newValue);
// clear the date
setSynopticDate(null);
}
};

/**
* method to initiate a model search with the filter selections on the synoptic form
*
Expand All @@ -42,6 +61,8 @@ export const SynopticTabForm = () => {
// avoid doing the usual form submit operations
event.preventDefault();

//console.log('formSynopticSubmit error: ' + error);

// build the query string from the submitted form data
let queryString =
((synopticDate) ? '&run_date=' + synopticDate.toISOString() : '') +
Expand Down Expand Up @@ -79,27 +100,45 @@ export const SynopticTabForm = () => {
};

// make the call to get the data
const {data} = await axios.get(finalDataUrl, requestOptions);
const ret_val = await axios
// make the call to get the data
.get(finalDataUrl, requestOptions)
// use the data returned
.then (( response ) => {
// return the data
return response.data;
})
.catch (( error ) => {
// make sure we do not render anything
return error.response.status;
});

// check the request type
if (finalDataUrl.indexOf('get_pulldown_data') !== -1) {
// save the dropdown data
setDropDownData(data);
}
else {
// save the catalog data
setCatalogData(data);
// if (finalDataUrl.indexOf('get_pulldown_data') !== -1)
// console.log('finalDataUrl: ' + finalDataUrl);

// if there was an error from the web service
if (ret_val !== 500) {
// check the request type to save it to the correct place
if (finalDataUrl.indexOf('get_pulldown_data') !== -1) {
// save the dropdown data
setDropDownData(ret_val);
}
else {
// save the catalog data
setCatalogData(ret_val);
}
}
else
// reset the form data
resetForm();

// return something
return true;
},

refetchOnWindowFocus: false
}, refetchOnWindowFocus: false
});

/**
* this will build the data url and will cause a DB hit
* this will build the data url and will cause a web service/DB hit
*/
useEffect(() => {
// build the new data url
Expand Down Expand Up @@ -159,53 +198,97 @@ export const SynopticTabForm = () => {
* @returns {boolean}
*/
const disableDate = (date) => {
// return false if the date is not found in the list of available dates
return !dropDownData['run_dates'].includes(date.toISOString().split("T")[0]);
if (dropDownData) {
// return false if the date is not found in the list of available dates
return !dropDownData['run_dates'].includes(date.toISOString().split("T")[0]);
}
};

/**
* handles date picker error text
*
* @type {string}
*/
const errorMessage = useMemo(() => {
//console.log('errorMessage error: ' + error);

switch (error) {
case 'maxDate': {
return 'Please select a date that is not in the future';
}

case 'minDate': {
return 'Please select a date after 01/01/2020';
}

case 'invalidDate': {
return 'This date is not yet valid';
}

case 'shouldDisableDate': {
return 'There is no data available on this date';
}

default: {
return '';
}
}

}, [error]);

/**
* return the rendered component
*/
return (
<Fragment>
<form name={"Synoptic"} onSubmit={formSynopticSubmit}>
<Stack spacing={1}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<form name={ "Synoptic" } onSubmit={ formSynopticSubmit }>
<Stack spacing={ 1 }>
<LocalizationProvider dateAdapter={ AdapterDayjs }>
<DatePicker
defaultValue={ dayjs(new Date()) }
onError={ (newError) => setError(newError) }
disableFuture
name="synoptic-date"
shouldDisableDate={disableDate}
slotProps={{textField: {size: 'small'}, field: {clearable: true}}}
shouldDisableDate={ disableDate }
minDate={ dayjs('2023-06-01') }
slotProps={{
textField: { size: 'small', helperText: errorMessage},
field: { clearable: true },
actionBar: { actions: ['clear'] },
}}

onChange={(newValue) => {
setSynopticDate(newValue.$d);
setChangedSynopticDate(newValue);
}}/>

</LocalizationProvider>

<Select name="synoptic-cycle" value={synopticCycle} placeholder="Please select a cycle" onChange={(e, newValue) => {
<Select name="synoptic-cycle" value={ synopticCycle } placeholder="Please select a cycle" onChange={ (e, newValue) => {
setSynopticCycle(newValue);
}}>
<DropDownOptions data={dropDownData} type={'cycles'}/>
<DropDownOptions data={ dropDownData } type={ 'cycles' }/>
</Select>

<Select name="synoptic-grid" value={synopticGrid} placeholder="Please select a grid" onChange={(e, newValue) => {
<Select name="synoptic-grid" value={ synopticGrid } placeholder="Please select a grid" onChange={ (e, newValue) => {
setSynopticGrid(newValue);
}}>
<DropDownOptions data={dropDownData} type={'grid_types'}/>
<DropDownOptions data={ dropDownData } type={ 'grid_types' }/>
</Select>

<Select name="synoptic-instance" value={synopticInstance} placeholder="Please select an instance" onChange={(e, newValue) => {
<Select name="synoptic-instance" value={ synopticInstance } placeholder="Please select an instance" onChange={ (e, newValue) => {
setSynopticInstance(newValue);
}}>
<DropDownOptions data={dropDownData} type={'instance_names'}/>
<DropDownOptions data={ dropDownData } type={'instance_names'}/>
</Select>

<Button type="submit">Submit</Button>
<Button type="reset" onClick={resetForm}>Reset</Button>
<Button type="submit" disabled={ !!error }>Submit</Button>
<Button type="reset" onClick={ resetForm }>Reset</Button>
</Stack>

<Divider sx={{m: 2}}/>

<Stack>
{<CatalogItems data={catalogData} isTropical={false}/>}
{ <CatalogItems data={ catalogData } isTropical={ false }/> }
</Stack>
</form>
</Fragment>
Expand Down

0 comments on commit 2fd73b1

Please sign in to comment.