add alert-level-changes widget with working time range selector
This commit is contained in:
@@ -0,0 +1,219 @@
|
|||||||
|
import {useDashboardStore} from "@/store/useDashboardStore.jsx";
|
||||||
|
import VdapApi from "../../hooks/useVdapApi.js";
|
||||||
|
import useBuildUrl from "../../hooks/useBuildUrl.js";
|
||||||
|
import { Footprints, Plane, Sailboat, TrendingUp, TrendingDown } from 'lucide-react';
|
||||||
|
import {Box, Collapsible, Flex, Spinner, Text, Timeline, Center} from "@chakra-ui/react";
|
||||||
|
import { useMemo, useCallback } from "react";
|
||||||
|
|
||||||
|
|
||||||
|
export default function AlertChanges({ settings, widgetID}) {
|
||||||
|
// Find this specific widgets object in the state list of active & displayed widgets
|
||||||
|
const thisWidget = useDashboardStore(useCallback((state) =>
|
||||||
|
state.widgets.find((widget) => widget.id === widgetID), [widgetID]
|
||||||
|
));
|
||||||
|
|
||||||
|
// build url, default is 7 days past
|
||||||
|
const url = useBuildUrl('/api/v2/alert_changes', settings?.startDate, settings?.endDate);
|
||||||
|
|
||||||
|
// call api hook to retrieve data
|
||||||
|
const {data: apiData, isLoading, error} = VdapApi(url);
|
||||||
|
|
||||||
|
const data = useMemo(() => {
|
||||||
|
if (apiData.length === 0) return [];
|
||||||
|
|
||||||
|
// .reduce() is a built-in array method used to transform an entire array into a single value (like an object)
|
||||||
|
// here it returns a single massive object w/ volcano names as keys
|
||||||
|
const grouped = apiData.reduce((accumulator, item) => {
|
||||||
|
if (!accumulator[item.volcano]) accumulator[item.volcano] = [];
|
||||||
|
accumulator[item.volcano].push(item);
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// converts the 'grouped' object back into an array of [key, value] pairs
|
||||||
|
const group_arr = Object.entries(grouped);
|
||||||
|
|
||||||
|
// sort data newest to oldest within each volcano
|
||||||
|
const sorted = group_arr.map((item) =>
|
||||||
|
[
|
||||||
|
item[0], // volcano name
|
||||||
|
[...(item[1])].sort((a, b) =>
|
||||||
|
new Date(b.alert_start_date_local) - new Date(a.alert_start_date_local))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// volcano with most recent alert level change appears at top of list
|
||||||
|
const sorted_entries = [...sorted].sort((a, b) => new Date(b[1][0].alert_start_date_local) - new Date(a[1][0].alert_start_date_local));
|
||||||
|
|
||||||
|
if (thisWidget?.size === "small") {
|
||||||
|
return (sorted_entries.map((volcano) => {
|
||||||
|
const domain = volcano[1].reduce((acc, curr) => {
|
||||||
|
if (!acc[curr.alert_scheme_domain]) acc[curr.alert_scheme_domain] = [];
|
||||||
|
acc[curr.alert_scheme_domain].push(curr);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const domain_arr = Object.entries(domain);
|
||||||
|
return [volcano[0], domain_arr];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sorted_entries;
|
||||||
|
}, [apiData, thisWidget]);
|
||||||
|
|
||||||
|
// list of alert colors used for coloring text below
|
||||||
|
const alertColors = {
|
||||||
|
Red: "red.400",
|
||||||
|
Orange: "orange.400",
|
||||||
|
Yellow: "yellow.400",
|
||||||
|
Green: "green.400",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isLoading) return (
|
||||||
|
<Flex w="100%" h="100%" align="center" justify="center" borderRadius="lg" bg="gray.800">
|
||||||
|
<Spinner size="xl" color="blue.400" thickness="4px"/>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error) return (
|
||||||
|
<Flex w="100%" h="100%" align="center" justify="center" borderRadius="lg" bg="gray.800">
|
||||||
|
<Text color="red.400">{error}</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data.length === 0) return (
|
||||||
|
<Flex w="100%" h="100%" align="center" justify="center" borderRadius="lg" bg="gray.800">
|
||||||
|
<Text textAlign="center" color="gray.400">No flight level data available for the selected dates.</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box display="flex" flexDirection="column" gap={2} p={2} w="100%" h="100%" borderRadius="lg" bg="gray.800" overflowY="auto">
|
||||||
|
{data.map((volcano, index) => {
|
||||||
|
if (thisWidget?.size === "large") return (
|
||||||
|
<Collapsible.Root key={index} w="100%">
|
||||||
|
{/* Using context to dynamically change the border radii of the triggers */}
|
||||||
|
<Collapsible.Context>
|
||||||
|
{(collapsible) => (
|
||||||
|
<>
|
||||||
|
<Collapsible.Trigger w="100%">
|
||||||
|
<Flex direction="row"
|
||||||
|
w="100%"
|
||||||
|
justify="space-between" align="center"
|
||||||
|
p={1} pl={3} pr={3}
|
||||||
|
borderTopRadius="lg"
|
||||||
|
borderBottomRadius={collapsible.open ? "0" : "lg"}
|
||||||
|
bg="gray.600"
|
||||||
|
>
|
||||||
|
<Flex direction="column" w="100%" minW={0} textAlign="left" color="gray.100">
|
||||||
|
<Text truncate >{volcano[0]}</Text> {/* volcano name */}
|
||||||
|
<Text truncate fontSize="xs" color="gray.300/90">{volcano[1][0]?.alert_start_date_local}</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex w="100%" minW={0} justify="right">
|
||||||
|
<Text truncate pl={2} pr={2} borderRadius="lg" bg="gray.800/50" color="gray.100" fontWeight="semibold">{volcano[1][0]?.alert_level_name}</Text>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content w="100%" p={3} borderBottomRadius="lg" bg="gray.700">
|
||||||
|
<Timeline.Root size="md" variant="subtle">
|
||||||
|
{volcano[1]?.map((object, index) => (
|
||||||
|
<Timeline.Item key={index} w="100%" h="100%">
|
||||||
|
<Timeline.Connector >
|
||||||
|
{/*<Timeline.Separator borderWidth="1px" borderColor="gray.600"/>*/}
|
||||||
|
<Timeline.Indicator outline="none" bg="gray.200" color="gray.500" size="lg">
|
||||||
|
{object?.alert_scheme_domain === "terrestrial" && <Footprints size={15} />}
|
||||||
|
{object?.alert_scheme_domain === "aviation" && <Plane size={15} />}
|
||||||
|
{object?.alert_scheme_domain === "maritime" && <Sailboat size={15} />}
|
||||||
|
</Timeline.Indicator>
|
||||||
|
<Timeline.Indicator h="50%" outline="none" bg="gray.700" color="gray.100" size="lg">
|
||||||
|
{object?.change_type === "increase" ? <TrendingUp /> : <TrendingDown />}
|
||||||
|
</Timeline.Indicator>
|
||||||
|
</Timeline.Connector>
|
||||||
|
<Timeline.Content w="100%" h="100%">
|
||||||
|
{/*<Timeline.Title>{object?.volcano}</Timeline.Title>*/}
|
||||||
|
<Timeline.Description w="100%" h="100%" gap={1}>
|
||||||
|
<Flex direction="column" gap={1}>
|
||||||
|
<Text w="100%" h="100%" color="gray.200">{object?.alert_start_date_local}</Text>
|
||||||
|
<Text w="100%" h="100%"
|
||||||
|
color={alertColors[object?.alert_level_name] || "gray.200"}
|
||||||
|
fontSize="md"
|
||||||
|
fontWeight="semibold"
|
||||||
|
>
|
||||||
|
{object?.alert_level_name}
|
||||||
|
</Text>
|
||||||
|
<Flex w="100%" h="20px" direction="row" justify="left" align="center">
|
||||||
|
<Text color="gray.300">Alert Scale: </Text>
|
||||||
|
{(Array.from({ length: Number(object?.alert_scheme_highest) - Number(object?.alert_scheme_lowest) + 1}, (v, i) => Number(object?.alert_scheme_lowest) + i))
|
||||||
|
.map((num) => (
|
||||||
|
<Center
|
||||||
|
key={num}
|
||||||
|
w="20px" h="100%"
|
||||||
|
color="gray.300"
|
||||||
|
bg={num === Number(object?.alert_level_rank) ? "gray.300/20" : null} // alert level rank is a string for some reason
|
||||||
|
borderRadius={num === Number(object?.alert_level_rank) ? "xl" : null}
|
||||||
|
textAlign="center"
|
||||||
|
fontSize="sm"
|
||||||
|
fontWeight="semibold"
|
||||||
|
>
|
||||||
|
{num}
|
||||||
|
</Center>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Timeline.Description>
|
||||||
|
</Timeline.Content>
|
||||||
|
</Timeline.Item>
|
||||||
|
))}
|
||||||
|
</Timeline.Root>
|
||||||
|
</Collapsible.Content>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Collapsible.Context>
|
||||||
|
</Collapsible.Root>
|
||||||
|
)
|
||||||
|
else if (thisWidget?.size === "small") return (
|
||||||
|
volcano[1]?.map((domain, index) => (
|
||||||
|
<Flex
|
||||||
|
key={index}
|
||||||
|
direction="row"
|
||||||
|
w="100%"
|
||||||
|
gap={2}
|
||||||
|
justify="space-between" align="center"
|
||||||
|
p={1} pl={3} pr={3}
|
||||||
|
borderRadius="lg"
|
||||||
|
bg="gray.600"
|
||||||
|
>
|
||||||
|
<Flex direction="column" w="100%" minW={0} textAlign="left" color="gray.100">
|
||||||
|
<Flex direction="row" w="100%" gap={2} align="center">
|
||||||
|
<Flex color="gray.300">
|
||||||
|
{domain[0] === "aviation" && <Plane size={15}/>}
|
||||||
|
{domain[0] === "terrestrial" && <Footprints size={15}/>}
|
||||||
|
{domain[0] === "maritime" && <Sailboat size={15}/>}
|
||||||
|
</Flex>
|
||||||
|
<Text truncate>{volcano[0] || ""}</Text> {/* volcano name */}
|
||||||
|
</Flex>
|
||||||
|
<Text truncate w="100%" fontSize="xs" color="gray.300/90">{domain[1]?.[0]?.alert_start_date_local || ""}</Text>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex direction="row" w="100%" minW={0} justify="right" gap={2} color="gray.200">
|
||||||
|
<Flex w="25px" justify="right">
|
||||||
|
{domain[1]?.[0]?.change_type === "increase" ? <TrendingUp/> : <TrendingDown/>}
|
||||||
|
</Flex>
|
||||||
|
<Text
|
||||||
|
truncate
|
||||||
|
pl={2} pr={2}
|
||||||
|
borderRadius="lg"
|
||||||
|
bg="gray.800/50"
|
||||||
|
color={alertColors[domain[1]?.[0]?.alert_level_name] || "gray.100"}
|
||||||
|
fontWeight="semibold"
|
||||||
|
>
|
||||||
|
{domain[1]?.[0]?.alert_level_name}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
))
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -2,7 +2,8 @@ import { useMemo } from 'react';
|
|||||||
import { Box, Flex, Spinner, Text } from '@chakra-ui/react';
|
import { Box, Flex, Spinner, Text } from '@chakra-ui/react';
|
||||||
import { useColorMode } from "@/components/ui/color-mode.jsx";
|
import { useColorMode } from "@/components/ui/color-mode.jsx";
|
||||||
import Plot from 'react-plotly.js';
|
import Plot from 'react-plotly.js';
|
||||||
import VdapApi from '../../hooks/useVdapApi.js'; // Adjust path as needed
|
import VdapApi from '../../hooks/useVdapApi.js';
|
||||||
|
import useBuildUrl from "@/hooks/useBuildUrl.js";
|
||||||
|
|
||||||
export default function ExplosionEvents({ settings, widgetID }) {
|
export default function ExplosionEvents({ settings, widgetID }) {
|
||||||
// Plotly expects 'linear' for normal axes
|
// Plotly expects 'linear' for normal axes
|
||||||
@@ -12,22 +13,8 @@ export default function ExplosionEvents({ settings, widgetID }) {
|
|||||||
const { colorMode } = useColorMode();
|
const { colorMode } = useColorMode();
|
||||||
const isDark = colorMode === 'dark';
|
const isDark = colorMode === 'dark';
|
||||||
|
|
||||||
// Generate url with input dates are default to 7 day range
|
// Generate url with input dates, default to 7 day range
|
||||||
const url = useMemo(() =>{
|
const url = useBuildUrl('/api/v2/explosion_events', settings?.startDate, settings?.endDate);
|
||||||
if (settings?.startDate && settings?.endDate)
|
|
||||||
return '/api/v2/explosion_events?start_date=' + settings?.startDate + '&end_date=' + settings?.endDate;
|
|
||||||
else {
|
|
||||||
const base_url = '/api/v2/explosion_events';
|
|
||||||
let today = new Date();
|
|
||||||
let sevenDaysAgo = new Date(today);
|
|
||||||
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
||||||
|
|
||||||
sevenDaysAgo = sevenDaysAgo.toLocaleDateString('en-CA');
|
|
||||||
today = today.toLocaleDateString('en-CA');
|
|
||||||
|
|
||||||
return base_url + '?start_date=' + sevenDaysAgo + '&end_date=' + today;
|
|
||||||
}
|
|
||||||
}, [settings?.startDate, settings?.endDate]);
|
|
||||||
|
|
||||||
// Clean, single-line data fetching
|
// Clean, single-line data fetching
|
||||||
const { data: apiData, isLoading, error } = VdapApi(url);
|
const { data: apiData, isLoading, error } = VdapApi(url);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {Button, Flex, Spinner, Text, Box, Collapsible} from "@chakra-ui/react";
|
|||||||
import {useEffect, useMemo } from 'react';
|
import {useEffect, useMemo } from 'react';
|
||||||
import {useDashboardStore} from "@/store/useDashboardStore.jsx";
|
import {useDashboardStore} from "@/store/useDashboardStore.jsx";
|
||||||
import VdapApi from '../../hooks/useVdapApi.js';
|
import VdapApi from '../../hooks/useVdapApi.js';
|
||||||
|
import useBuildUrl from "@/hooks/useBuildUrl.js";
|
||||||
|
|
||||||
export default function IvansAlerts({ settings, widgetID }) {
|
export default function IvansAlerts({ settings, widgetID }) {
|
||||||
console.log("IvansAlerts widget ID: ", widgetID);
|
console.log("IvansAlerts widget ID: ", widgetID);
|
||||||
@@ -9,22 +10,8 @@ export default function IvansAlerts({ settings, widgetID }) {
|
|||||||
const isCopy = settings?.copyToClipboard === true; // acts as a fail-safe if no default setting is set
|
const isCopy = settings?.copyToClipboard === true; // acts as a fail-safe if no default setting is set
|
||||||
const sorts = settings?.activeSorts;
|
const sorts = settings?.activeSorts;
|
||||||
|
|
||||||
// build url once on mount
|
// build url, default is 7 days past
|
||||||
const url = useMemo(() =>{
|
const url = useBuildUrl('/api/v2/comm_coor_ivans', settings?.startDate, settings?.endDate);
|
||||||
if (settings?.startDate && settings?.endDate)
|
|
||||||
return '/api/v2/comm_coor_ivans?start_date=' + settings?.startDate + '&end_date=' + settings?.endDate;
|
|
||||||
else {
|
|
||||||
const base_url = '/api/v2/comm_coor_ivans';
|
|
||||||
let today = new Date();
|
|
||||||
let sevenDaysAgo = new Date(today);
|
|
||||||
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
||||||
|
|
||||||
sevenDaysAgo = sevenDaysAgo.toLocaleDateString('en-CA');
|
|
||||||
today = today.toLocaleDateString('en-CA');
|
|
||||||
|
|
||||||
return base_url + '?start_date=' + sevenDaysAgo + '&end_date=' + today;
|
|
||||||
}
|
|
||||||
}, [settings?.startDate, settings?.endDate]);
|
|
||||||
|
|
||||||
// VdapApi hook only calls api if the url changes and apiData remains stable since vdapApi uses state to track the data
|
// VdapApi hook only calls api if the url changes and apiData remains stable since vdapApi uses state to track the data
|
||||||
const {data: apiData, isLoading, error} = VdapApi(url);
|
const {data: apiData, isLoading, error} = VdapApi(url);
|
||||||
@@ -145,7 +132,7 @@ export default function IvansAlerts({ settings, widgetID }) {
|
|||||||
|
|
||||||
if (data.length === 0) return (
|
if (data.length === 0) return (
|
||||||
<Flex w="100%" h="100%" align="center" justify="center" borderRadius="lg" bg="gray.800">
|
<Flex w="100%" h="100%" align="center" justify="center" borderRadius="lg" bg="gray.800">
|
||||||
<Text color="gray.400">No flight level data available this week.</Text>
|
<Text textAlign="center" color="gray.400">No flight level data available for the selected dates.</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -2,24 +2,13 @@ import VdapApi from '../../hooks/useVdapApi.js';
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import Plot from 'react-plotly.js';
|
import Plot from 'react-plotly.js';
|
||||||
import {Box, Flex, Spinner, Text} from "@chakra-ui/react";
|
import {Box, Flex, Spinner, Text} from "@chakra-ui/react";
|
||||||
|
import useBuildUrl from "@/hooks/useBuildUrl.js";
|
||||||
|
|
||||||
export default function PlumeEvents({ settings, widgetID}) {
|
export default function PlumeEvents({ settings, widgetID}) {
|
||||||
const url = useMemo(() =>{
|
// Build url, defaults to 7 days past
|
||||||
if (settings?.startDate && settings?.endDate)
|
const url = useBuildUrl('/api/v2/plume_events', settings?.startDate, settings?.endDate);
|
||||||
return '/api/v2/plume_events?start_date=' + settings?.startDate + '&end_date=' + settings?.endDate;
|
|
||||||
else {
|
|
||||||
const base_url = '/api/v2/plume_events';
|
|
||||||
let today = new Date();
|
|
||||||
let sevenDaysAgo = new Date(today);
|
|
||||||
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
||||||
|
|
||||||
sevenDaysAgo = sevenDaysAgo.toLocaleDateString('en-CA');
|
|
||||||
today = today.toLocaleDateString('en-CA');
|
|
||||||
|
|
||||||
return base_url + '?start_date=' + sevenDaysAgo + '&end_date=' + today;
|
|
||||||
}
|
|
||||||
}, [settings?.startDate, settings?.endDate]);
|
|
||||||
|
|
||||||
|
// Retrieve data from api
|
||||||
const { data: apiData, isLoading, error } = VdapApi(url);
|
const { data: apiData, isLoading, error } = VdapApi(url);
|
||||||
|
|
||||||
const plotTraces = useMemo(() => {
|
const plotTraces = useMemo(() => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {Button, Flex, Spinner, Text, Box, Collapsible} from "@chakra-ui/react";
|
|||||||
import {useEffect, useMemo } from 'react';
|
import {useEffect, useMemo } from 'react';
|
||||||
import {useDashboardStore} from "@/store/useDashboardStore.jsx";
|
import {useDashboardStore} from "@/store/useDashboardStore.jsx";
|
||||||
import VdapApi from '../../hooks/useVdapApi.js';
|
import VdapApi from '../../hooks/useVdapApi.js';
|
||||||
|
import useBuildUrl from "@/hooks/useBuildUrl.js";
|
||||||
|
|
||||||
export default function RemoteSensing({ settings, widgetID }) {
|
export default function RemoteSensing({ settings, widgetID }) {
|
||||||
console.log("RS widget ID: ", widgetID);
|
console.log("RS widget ID: ", widgetID);
|
||||||
@@ -9,22 +10,8 @@ export default function RemoteSensing({ settings, widgetID }) {
|
|||||||
const isCopy = settings?.copyToClipboard === true; // acts as a fail-safe if no default setting is set
|
const isCopy = settings?.copyToClipboard === true; // acts as a fail-safe if no default setting is set
|
||||||
const sorts = settings?.activeSorts;
|
const sorts = settings?.activeSorts;
|
||||||
|
|
||||||
// build url
|
// build url, defaults to 7 days past
|
||||||
const url = useMemo(() =>{
|
const url = useBuildUrl('/api/v2/remote_sensing', settings?.startDate, settings?.endDate);
|
||||||
if (settings?.startDate && settings?.endDate)
|
|
||||||
return '/api/v2/remote_sensing?start_date=' + settings?.startDate + '&end_date=' + settings?.endDate;
|
|
||||||
else {
|
|
||||||
const base_url = '/api/v2/remote_sensing';
|
|
||||||
let today = new Date();
|
|
||||||
let sevenDaysAgo = new Date(today);
|
|
||||||
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
||||||
|
|
||||||
sevenDaysAgo = sevenDaysAgo.toLocaleDateString('en-CA');
|
|
||||||
today = today.toLocaleDateString('en-CA');
|
|
||||||
|
|
||||||
return base_url + '?start_date=' + sevenDaysAgo + '&end_date=' + today;
|
|
||||||
}
|
|
||||||
}, [settings?.startDate, settings?.endDate]);
|
|
||||||
|
|
||||||
// VdapApi hook only calls api if the url changes and apiData remains stable since vdapApi uses state to track the data
|
// VdapApi hook only calls api if the url changes and apiData remains stable since vdapApi uses state to track the data
|
||||||
const {data: apiData, isLoading, error} = VdapApi(url);
|
const {data: apiData, isLoading, error} = VdapApi(url);
|
||||||
|
|||||||
@@ -2,25 +2,13 @@ import VdapApi from '../../hooks/useVdapApi.js';
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import Plot from 'react-plotly.js';
|
import Plot from 'react-plotly.js';
|
||||||
import {Box, Flex, Spinner, Text} from "@chakra-ui/react";
|
import {Box, Flex, Spinner, Text} from "@chakra-ui/react";
|
||||||
|
import useBuildUrl from "@/hooks/useBuildUrl.js";
|
||||||
|
|
||||||
export default function SeismicEvents({ settings, widgetID}) {
|
export default function SeismicEvents({ settings, widgetID}) {
|
||||||
const url = useMemo(() =>{
|
// build url, defaults to 7 days past
|
||||||
if (settings?.startDate && settings?.endDate)
|
const url = useBuildUrl('/api/v2/seismic_events', settings?.startDate, settings?.endDate);
|
||||||
return '/api/v2/seismic_events?start_date=' + settings?.startDate + '&end_date=' + settings?.endDate;
|
|
||||||
else {
|
|
||||||
const base_url = '/api/v2/seismic_events';
|
|
||||||
let today = new Date();
|
|
||||||
let sevenDaysAgo = new Date(today);
|
|
||||||
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
||||||
|
|
||||||
sevenDaysAgo = sevenDaysAgo.toLocaleDateString('en-CA');
|
// retrieve data from api
|
||||||
today = today.toLocaleDateString('en-CA');
|
|
||||||
|
|
||||||
return base_url + '?start_date=' + sevenDaysAgo + '&end_date=' + today;
|
|
||||||
}
|
|
||||||
}, [settings?.startDate, settings?.endDate]);
|
|
||||||
|
|
||||||
console.log(url);
|
|
||||||
const { data: apiData, isLoading, error } = VdapApi(url);
|
const { data: apiData, isLoading, error } = VdapApi(url);
|
||||||
|
|
||||||
const plotTraces = useMemo(() => {
|
const plotTraces = useMemo(() => {
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import {Flex, Slider, Switch} from "@chakra-ui/react";
|
||||||
|
import {useDashboardStore} from "@/store/useDashboardStore.jsx";
|
||||||
|
|
||||||
|
export default function IvansAlertsSettings({ widgetId, currentSettings }) {
|
||||||
|
const updateSettings = useDashboardStore(state => state.updateWidgetSettings);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex flexDirection="column" justifyContent="space-between" gap={2} pb={2}>
|
||||||
|
{/* SLIDER DATE RANGE SELECTION */}
|
||||||
|
<Slider.Root
|
||||||
|
width="80%" h="100%"
|
||||||
|
min={1} max={14}
|
||||||
|
defaultValue={[7]}
|
||||||
|
step={1}
|
||||||
|
onValueChangeEnd={(e) => {
|
||||||
|
const day = new Date(Date.now() - (e.value[0])*86400000).toLocaleDateString('en-CA');
|
||||||
|
console.log("new start: ", day);
|
||||||
|
updateSettings(widgetId, {...currentSettings, startDate: day});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Slider.Label>{currentSettings?.endDate} to {currentSettings?.startDate}</Slider.Label>
|
||||||
|
<Slider.Control>
|
||||||
|
<Slider.Track>
|
||||||
|
<Slider.Range />
|
||||||
|
</Slider.Track>
|
||||||
|
<Slider.Thumbs />
|
||||||
|
<Slider.MarkerGroup p={3}>
|
||||||
|
<Slider.Marker value={1} whiteSpace="nowrap">today</Slider.Marker>
|
||||||
|
<Slider.Marker value={7} whiteSpace="nowrap">1 week ago</Slider.Marker>
|
||||||
|
<Slider.Marker value={14} whiteSpace="nowrap">2 weeks ago</Slider.Marker>
|
||||||
|
</Slider.MarkerGroup>
|
||||||
|
</Slider.Control>
|
||||||
|
</Slider.Root>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ import { lazy } from 'react';
|
|||||||
// w: 4 = one-third screen width
|
// w: 4 = one-third screen width
|
||||||
// w: 3 = one-quarter screen width
|
// w: 3 = one-quarter screen width
|
||||||
|
|
||||||
|
const getStartDate = () => (new Date(Date.now() - 604800000)).toLocaleDateString('en-CA'); // 7 days = 604800000 = 7*24*60*60*1000
|
||||||
|
const getEndDate = () => (new Date()).toLocaleDateString('en-CA'); // 'en-CA' formats the date as YYYY-MM-DD
|
||||||
|
|
||||||
export const WIDGET_REGISTRY = {
|
export const WIDGET_REGISTRY = {
|
||||||
"vaa_activity": {
|
"vaa_activity": {
|
||||||
name: "VAA 7 Day Activity",
|
name: "VAA 7 Day Activity",
|
||||||
@@ -19,7 +22,9 @@ export const WIDGET_REGISTRY = {
|
|||||||
|
|
||||||
// The baseline data every new VAA widget starts with
|
// The baseline data every new VAA widget starts with
|
||||||
defaultSettings: {
|
defaultSettings: {
|
||||||
yAxisScale: 'normal' // Options: 'normal' | 'symlog'
|
// startDate: getStartDate(),
|
||||||
|
// endDate: getEndDate(),
|
||||||
|
yAxisScale: 'normal', // Options: 'normal' | 'symlog'
|
||||||
},
|
},
|
||||||
|
|
||||||
allowedSizes: {
|
allowedSizes: {
|
||||||
@@ -44,6 +49,8 @@ export const WIDGET_REGISTRY = {
|
|||||||
component: lazy(() => import('../components/Widgets/IvansAlerts.jsx')),
|
component: lazy(() => import('../components/Widgets/IvansAlerts.jsx')),
|
||||||
settingsComponent: lazy(() => import('../components/Widgets/settings/IvansAlertsSettings.jsx')),
|
settingsComponent: lazy(() => import('../components/Widgets/settings/IvansAlertsSettings.jsx')),
|
||||||
defaultSettings: {
|
defaultSettings: {
|
||||||
|
startDate: getStartDate(),
|
||||||
|
endDate: getEndDate(),
|
||||||
copyToClipboard: false,
|
copyToClipboard: false,
|
||||||
activeSorts: {
|
activeSorts: {
|
||||||
timeSort: "desc",
|
timeSort: "desc",
|
||||||
@@ -64,6 +71,8 @@ export const WIDGET_REGISTRY = {
|
|||||||
component: lazy(() => import('../components/Widgets/RemoteSensing.jsx')),
|
component: lazy(() => import('../components/Widgets/RemoteSensing.jsx')),
|
||||||
settingsComponent: lazy(() => import('../components/Widgets/Settings/RemoteSensingSettings.jsx')),
|
settingsComponent: lazy(() => import('../components/Widgets/Settings/RemoteSensingSettings.jsx')),
|
||||||
defaultSettings: {
|
defaultSettings: {
|
||||||
|
startDate: getStartDate(),
|
||||||
|
endDate: getEndDate(),
|
||||||
copyToClipboard: false,
|
copyToClipboard: false,
|
||||||
activeSorts: {
|
activeSorts: {
|
||||||
timeSort: "desc",
|
timeSort: "desc",
|
||||||
@@ -81,9 +90,15 @@ export const WIDGET_REGISTRY = {
|
|||||||
name: "Alert Level Changes",
|
name: "Alert Level Changes",
|
||||||
category: "Daily Alerts",
|
category: "Daily Alerts",
|
||||||
description: "List of 7-day alert level changes with trend arrows.",
|
description: "List of 7-day alert level changes with trend arrows.",
|
||||||
|
component: lazy(() => import('../components/Widgets/AlertChanges.jsx')),
|
||||||
|
settingsComponent: lazy(() => import('../components/Widgets/settings/AlertChangeSettings.jsx')),
|
||||||
|
defaultSettings: {
|
||||||
|
startDate: getStartDate(),
|
||||||
|
endDate: getEndDate(),
|
||||||
|
},
|
||||||
allowedSizes: {
|
allowedSizes: {
|
||||||
small: { w: 3, h: 12 },
|
small: { w: 3, h: 6 },
|
||||||
large: { w: 9, h: 12 }
|
large: { w: 3, h: 12 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -99,6 +114,8 @@ export const WIDGET_REGISTRY = {
|
|||||||
|
|
||||||
// The baseline data every new VAA widget starts with
|
// The baseline data every new VAA widget starts with
|
||||||
defaultSettings: {
|
defaultSettings: {
|
||||||
|
startDate: getStartDate(),
|
||||||
|
endDate: getEndDate(),
|
||||||
yAxisScale: 'normal' // Options: 'normal' | 'symlog'
|
yAxisScale: 'normal' // Options: 'normal' | 'symlog'
|
||||||
},
|
},
|
||||||
allowedSizes: {
|
allowedSizes: {
|
||||||
@@ -112,7 +129,10 @@ export const WIDGET_REGISTRY = {
|
|||||||
description: "Plot of explosion heights over a weeks time.",
|
description: "Plot of explosion heights over a weeks time.",
|
||||||
component: lazy(() => import('../components/Widgets/PlumeEvents.jsx')),
|
component: lazy(() => import('../components/Widgets/PlumeEvents.jsx')),
|
||||||
settingsComponent: lazy(() => import('../components/Widgets/settings/PlumeEventsSettings.jsx')),
|
settingsComponent: lazy(() => import('../components/Widgets/settings/PlumeEventsSettings.jsx')),
|
||||||
defaultSettings: {},
|
defaultSettings: {
|
||||||
|
startDate: getStartDate(),
|
||||||
|
endDate: getEndDate(),
|
||||||
|
},
|
||||||
allowedSizes: {
|
allowedSizes: {
|
||||||
medium: { w: 6, h: 12 }
|
medium: { w: 6, h: 12 }
|
||||||
}
|
}
|
||||||
@@ -124,7 +144,10 @@ export const WIDGET_REGISTRY = {
|
|||||||
description: "Plot of number of seismic events over a weeks time.",
|
description: "Plot of number of seismic events over a weeks time.",
|
||||||
component: lazy(() => import('../components/Widgets/SeismicEvents.jsx')),
|
component: lazy(() => import('../components/Widgets/SeismicEvents.jsx')),
|
||||||
settingsComponent: lazy(() => import('../components/Widgets/settings/SeismicEventsSettings.jsx')),
|
settingsComponent: lazy(() => import('../components/Widgets/settings/SeismicEventsSettings.jsx')),
|
||||||
defaultSettings: {},
|
defaultSettings: {
|
||||||
|
startDate: getStartDate(),
|
||||||
|
endDate: getEndDate(),
|
||||||
|
},
|
||||||
allowedSizes: {
|
allowedSizes: {
|
||||||
medium: { w: 6, h: 12 }
|
medium: { w: 6, h: 12 }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
export default function useBuildUrl(base_url, start, end) {
|
||||||
|
return useMemo(() =>{
|
||||||
|
if (start && end)
|
||||||
|
return `${base_url}?start_date=${start}&end_date=${end}`;
|
||||||
|
else {
|
||||||
|
let today = new Date();
|
||||||
|
let sevenDaysAgo = new Date(today);
|
||||||
|
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
||||||
|
sevenDaysAgo = sevenDaysAgo.toLocaleDateString('en-CA');
|
||||||
|
today = today.toLocaleDateString('en-CA');
|
||||||
|
return `${base_url}?start_date=${sevenDaysAgo}&end_date=${today}`;
|
||||||
|
}
|
||||||
|
}, [base_url, start, end]);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user