Added tests with storybook and like API call with service interrupt test
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Box, Flex, Text } from '@chakra-ui/react';
|
||||
import { Box, Flex, Spinner, Text } from '@chakra-ui/react';
|
||||
import Plot from 'react-plotly.js';
|
||||
import VdapApi from '../../hooks/useVdapApi.js'; // Adjust path as needed
|
||||
|
||||
export default function VaaActivity7Day() {
|
||||
// ONE LINE to handle all fetching, loading, and error states!
|
||||
const { data: apiData, isLoading, error } = VdapApi('/api/v2/comm_coor_vaa');
|
||||
|
||||
export default function VaaActivityChart({ data = [] }) {
|
||||
// Transform flat database rows into Plotly's required "Traces"
|
||||
const plotTraces = useMemo(() => {
|
||||
if (!data || data.length === 0) return [];
|
||||
if (!apiData || apiData.length === 0) return [];
|
||||
|
||||
const groupedData = data.reduce((acc, curr) => {
|
||||
const groupedData = apiData.reduce((acc, curr) => {
|
||||
const name = curr.volc_name || 'Unknown';
|
||||
if (!acc[name]) acc[name] = { x: [], y: [], text: [] };
|
||||
|
||||
@@ -27,21 +30,31 @@ export default function VaaActivityChart({ data = [] }) {
|
||||
hoverinfo: 'text',
|
||||
marker: { size: 8, line: { width: 1, color: 'white' } }
|
||||
}));
|
||||
}, [data]);
|
||||
}, [apiData]);
|
||||
|
||||
if (plotTraces.length === 0) {
|
||||
return (
|
||||
<Flex height="100%" width="100%" align="center" justify="center" bg="gray.800" borderRadius="md">
|
||||
<Text color="gray.400">No flight level data available.</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
if (isLoading) return (
|
||||
<Flex w="100%" h="100%" bg="gray.800" borderRadius="md" align="center" justify="center">
|
||||
<Spinner size="xl" color="blue.400" thickness="4px" />
|
||||
</Flex>
|
||||
);
|
||||
|
||||
if (error) return (
|
||||
<Flex w="100%" h="100%" bg="gray.800" borderRadius="md" align="center" justify="center" p={4}>
|
||||
<Text color="red.400">{error}</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
if (plotTraces.length === 0) return (
|
||||
<Flex height="100%" width="100%" align="center" justify="center" bg="gray.800" borderRadius="md">
|
||||
<Text color="gray.400">No flight level data available.</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
return (
|
||||
<Box height="100%" width="100%" bg="gray.800" borderRadius="md" overflow="hidden">
|
||||
<Plot
|
||||
data={plotTraces}
|
||||
useResizeHandler={true} // Crucial for reacting to grid drags
|
||||
useResizeHandler={true}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
layout={{
|
||||
autosize: true,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import { http, HttpResponse } from 'msw'; // Import MSW
|
||||
import VaaActivity7Day from './VaaActivity7Day.jsx';
|
||||
|
||||
export default {
|
||||
@@ -25,10 +26,47 @@ const mockData = [
|
||||
{ volc_name: "Popocatepetl", obs_va_epoch: Date.now() - 86400000 * 1, obs_fl: 200 }
|
||||
];
|
||||
|
||||
// Scenario LIVE: call our API for real
|
||||
export const LivePopulated = {};
|
||||
|
||||
// Scenario 1: Successful API Call
|
||||
export const Populated = {
|
||||
args: { data: mockData },
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
// Intercept the exact URL your component is trying to fetch
|
||||
http.get('*/api/v2/dvar_vaa', () => {
|
||||
// Return a 200 OK with the mock JSON
|
||||
return HttpResponse.json(mockData);
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const EmptyState = {
|
||||
args: { data: [] },
|
||||
// Scenario 2: The 500 Server Crash
|
||||
export const ServerCrash = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
http.get('*/api/v2/dvar_vaa', () => {
|
||||
// Return a 500 Error
|
||||
return new HttpResponse(null, { status: 500 });
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Scenario 3: Empty State (API works, but no data returned)
|
||||
export const EmptyData = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
http.get('*/api/v2/dvar_vaa', () => {
|
||||
return HttpResponse.json([]);
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export default function useWidgetApi(endpoint) {
|
||||
const [data, setData] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const baseUrl = import.meta.env.VITE_API_BASE_URL || 'http://web-api:8000';
|
||||
// Strip leading slashes to prevent double slashes in the URL
|
||||
const cleanEndpoint = endpoint.startsWith('/') ? endpoint.slice(1) : endpoint;
|
||||
const url = `${baseUrl}/${cleanEndpoint}`;
|
||||
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API Error: ${response.status}`);
|
||||
}
|
||||
|
||||
const json = await response.json();
|
||||
const responseData = Array.isArray(json) ? json : json.data;
|
||||
setData(responseData || []);
|
||||
|
||||
} catch (err) {
|
||||
console.error(`Failed to fetch from ${endpoint}:`, err);
|
||||
setError("Failed to load widget data. Is the Django API running?");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (endpoint) {
|
||||
fetchData();
|
||||
}
|
||||
}, [endpoint]); // Re-fetch if the endpoint changes
|
||||
|
||||
return { data, isLoading, error };
|
||||
}
|
||||
Reference in New Issue
Block a user