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
}