import { Box, Typography } from '@mui/material' import { useWidgetSelector } from '../stores/use-widget-selector' import type { WidgetNoDataProps } from './types' import { styles } from './style' /** * NoData wrapper component that displays empty state UI when widget has no data * * Integrates with widget store to check loading/fetching state and source data availability. * Uses `sourceData` (pre-pipeline data) instead of `data` (post-pipeline) to distinguish * "API returned nothing" from "pipeline tools filtered everything out". * * @example Basic usage * ```tsx * * * * ``` * * @example With SkeletonLoader * ```tsx * * * * * * ``` * * @example With custom messages * ```tsx * * * * ``` */ export function WidgetNoData({ id, children, title = 'No data available', description = 'There are no results for the combination of filters applied to your data. Try tweaking your filters, or zoom and pan the map to adjust filters', isEmpty = defaultIsEmpty, }: WidgetNoDataProps) { // Single consolidated subscription instead of 3 separate ones. // Reads sourceData (pre-pipeline) to check emptiness, not data (post-pipeline). const { isLoading, isFetching, sourceData } = useWidgetSelector(id, (w) => ({ isLoading: w?.isLoading, isFetching: w?.isFetching, sourceData: w?.sourceData, })) // If loading or fetching, show children // SkeletonLoader handles loading state, this allows proper composition if (isLoading || isFetching) { return children } // Check if data is empty if (isEmpty(sourceData)) { return ( {title} {description} ) } // Data exists, render children return children } /** * Default function to determine if data is empty * Handles various data structures commonly used in widgets */ function defaultIsEmpty(data: unknown): boolean { // Null or undefined if (data == null) { return true } // Arrays (most common case) if (Array.isArray(data)) { // Empty array if (data.length === 0) { return true } // Array of arrays (CategoryWidget pattern: [[],[]]) // Check if all inner arrays are empty if (data.every((item) => Array.isArray(item) && item.length === 0)) { return true } return false } // Objects if (typeof data === 'object') { return Object.keys(data).length === 0 } // Primitives (numbers, strings, booleans) are considered valid data return false }