UNPKG

pagamio-frontend-commons-lib

Version:

Pagamio library for Frontend reusable components like the form engine and table container

169 lines (168 loc) 8.9 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { Grid } from '@mantine/core'; import { Card } from 'flowbite-react'; import { useCallback, useEffect, useState } from 'react'; import { useApi } from '../api'; import { FilterComponent, Tab } from '../components'; import { useMediaQueries } from '../shared'; import ErrorState from './components/ErrorState'; import FilterComponentSkeleton from './components/FilterComponentSkeleton'; import { DashboardPaths, getFilterOptionsData, getGridColProps } from './utils'; import componentRegistry from './visualRegistry'; const OverviewContent = ({ visualData, renderContent, renderVisual }) => { return (_jsxs(_Fragment, { children: [renderContent(), _jsx("main", { children: visualData.map((section) => (_jsxs("div", { className: "mb-2", children: [section.sectionTitle && _jsx("h2", { className: "mb-2 text-1xl font-semibold", children: section.sectionTitle }), _jsx(Grid, { gutter: "md", align: "stretch", className: "mb-[6px]", children: section.data.map((visual) => { const numVisuals = section.data.length; const { span, offset } = getGridColProps(numVisuals, visual.id); return renderVisual(visual, visual.id, section.sectionTitle, visual?.gridColSpan ?? span, offset); }) })] }, section.id))) })] })); }; const EventsContent = ({ eventsVisualData, renderContent, renderVisual }) => { return (_jsxs(_Fragment, { children: [renderContent(), _jsx("main", { children: eventsVisualData ? eventsVisualData.map((section) => (_jsxs("div", { className: "mb-2", children: [section.sectionTitle && _jsx("h2", { className: "mb-2 text-1xl font-semibold", children: section.sectionTitle }), _jsx(Grid, { gutter: "md", align: "stretch", className: "mb-[6px]", children: section.data.map((visual) => { const numVisuals = section.data.length; const { span, offset } = getGridColProps(numVisuals, visual.id); return renderVisual(visual, visual.id, section.sectionTitle, visual?.gridColSpan ?? span, offset); }) })] }, section.id))) : null })] })); }; const renderFilterComponent = ({ isLoading, error, filters, filterOptions, selectedFilters, handleFilterChange, handleApplyFilters, resetFilters, handleRetry, isNarrow, }) => { if (isLoading) { return _jsx(FilterComponentSkeleton, {}); } if (error) { return (_jsx(Card, { className: "mb-5", children: _jsx(ErrorState, { error: error, onRetry: handleRetry }) })); } return (_jsx(FilterComponent, { filters: filters.map((filter) => ({ name: filter.name, placeholder: filter.placeholder ?? `Select ${filter.name}`, type: filter.multi ? 'multi-select' : 'select', options: filterOptions[filter.name] || filter.options, })), showClearFilters: true, selectedFilters: selectedFilters, handleFilterChange: handleFilterChange, handleApplyFilters: handleApplyFilters, resetFilters: resetFilters, isNarrow: isNarrow })); }; const DashboardWrapper = ({ data, showVisualHeader = true, showEventsTabbedLayout = false, handleFilterChange = () => { }, selectedFilters = {}, tourSelectedFilters = {}, resetFilters = () => { }, handleApplyFilters = () => { }, handleApplyTourFilters = () => { }, handleTourFilterChange = () => { }, }) => { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [tourError, setTourError] = useState(null); const [isRefreshOpttonsQuery, setIsRefreshOpttonsQuery] = useState(0); const [filterOptions, setFilterOptions] = useState({}); const [tourFilterOptions, setTourFilterOptions] = useState({}); const { isSm, isXs } = useMediaQueries(); const apiClient = useApi(); const { config, visualData, eventsVisualData } = data; const defaultTabIndex = 0; const fetchFilterData = async (key, valueKey, url, query, isTourFilter = false) => { try { setLoading(true); if (isTourFilter) { setTourError(null); } else { setError(null); } const response = await apiClient.post(url, query); if (response) { const { optionsData } = getFilterOptionsData(response, key, valueKey); if (isTourFilter) { setTourFilterOptions((prev) => ({ ...prev, [key]: optionsData })); } else { setFilterOptions((prev) => ({ ...prev, [key]: optionsData })); } } } catch (err) { const errorMessage = 'Failed to fetch metric filter data'; if (isTourFilter) { setTourError(err instanceof Error ? err : new Error(errorMessage)); } else { setError(err instanceof Error ? err : new Error(errorMessage)); } } finally { setLoading(false); } }; useEffect(() => { const fetchFilters = (filters, isTour = false) => { filters.forEach((filter) => { if (filter.query) { const queryUrl = isTour ? (filter.tourUrl ?? DashboardPaths.QUERY) : (filter.url ?? DashboardPaths.QUERY); fetchFilterData(filter.name, filter.valueKey, queryUrl, filter.query, isTour); } }); }; fetchFilters(config.filters); if (config.tourFilters) { fetchFilters(config.tourFilters, true); } }, [config.filters, isRefreshOpttonsQuery]); const handleRetry = () => { setIsRefreshOpttonsQuery((prev) => prev + 1); }; const renderTourFilter = () => { return renderFilterComponent({ isLoading: loading, error: tourError, filters: config.tourFilters || [], filterOptions: tourFilterOptions, selectedFilters: tourSelectedFilters, handleFilterChange: handleTourFilterChange, handleApplyFilters: handleApplyTourFilters, resetFilters, handleRetry, isNarrow: isSm, }); }; const renderContent = () => { return renderFilterComponent({ isLoading: loading, error, filters: config.filters, filterOptions, selectedFilters, handleFilterChange, handleApplyFilters, resetFilters, handleRetry, isNarrow: isSm, }); }; const renderVisual = useCallback((visual, index, sectionTitle, span, offset) => { const { metricData } = visual; const matchesSmall = isXs || isSm; const VisualComponent = componentRegistry[metricData.type]; if (!VisualComponent) { console.error(`Visual type "${metricData.type}" not recognized in section "${sectionTitle}" at visual index ${index}.`); return null; } const props = { data: metricData.data, options: metricData.options, title: metricData.title, label: metricData.label, colors: metricData.colors, columns: metricData.columns, format: metricData.format, stacked: metricData.stacked ?? undefined, themeColor: config.themeColor, currencyDisplaySymbol: metricData.currencyDisplaySymbol, ...metricData, }; return (_jsx(Grid.Col, { span: matchesSmall ? 12 : span, offset: offset, children: _jsx(VisualComponent, { ...props }) }, `visual-${visual.id}`)); }, [config.themeColor, isXs, isSm]); const tabs = [ { id: 1, title: 'Overview', content: _jsx(OverviewContent, { visualData: visualData, renderContent: renderContent, renderVisual: renderVisual }), }, { id: 2, title: 'Tour', content: (_jsx(EventsContent, { eventsVisualData: eventsVisualData, renderContent: renderTourFilter, renderVisual: renderVisual })), }, ]; return (_jsxs("div", { children: [showVisualHeader && (_jsxs("div", { className: "mb-4", children: [_jsx("h1", { className: "text-2xl font-bold", children: config.title }), _jsx("p", { className: "text-1xl text-gray-600", children: config.summary })] })), showEventsTabbedLayout ? (_jsx(Tab, { tabs: tabs, defaultTab: defaultTabIndex, className: "justify-end" })) : (_jsx(OverviewContent, { visualData: visualData, renderContent: renderContent, renderVisual: renderVisual }))] })); }; export default DashboardWrapper;