@spteck/fluentui-react-charts 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +255 -0
  2. package/dist/fluentui-react-charts.cjs.development.js +2478 -2198
  3. package/dist/fluentui-react-charts.cjs.development.js.map +1 -1
  4. package/dist/fluentui-react-charts.cjs.production.min.js +1 -1
  5. package/dist/fluentui-react-charts.cjs.production.min.js.map +1 -1
  6. package/dist/fluentui-react-charts.esm.js +2479 -2200
  7. package/dist/fluentui-react-charts.esm.js.map +1 -1
  8. package/dist/hooks/index.d.ts +1 -1
  9. package/dist/hooks/useChartFactory.d.ts +6 -0
  10. package/dist/hooks/{useGraphUtils.d.ts → useChartUtils.d.ts} +2 -5
  11. package/dist/hooks/useIndexedDBCache.d.ts +33 -0
  12. package/dist/index.d.ts +1 -0
  13. package/package.json +2 -1
  14. package/src/charts/BarChart/BarChart.tsx +2 -2
  15. package/src/charts/ComboChart/ComboChart.tsx +2 -2
  16. package/src/charts/Doughnut/DoughnutChart.tsx +2 -2
  17. package/src/charts/PieChart/PieChart.tsx +3 -3
  18. package/src/charts/areaChart/AreaChart.tsx +2 -2
  19. package/src/charts/barHorizontalChart/BarHotizontalChart.tsx +2 -2
  20. package/src/charts/bubbleChart/BubbleChart.tsx +2 -2
  21. package/src/charts/floatBarChart/FloatBarChart.tsx +2 -2
  22. package/src/charts/lineChart/LineChart.tsx +2 -2
  23. package/src/charts/polarChart/PolarChart.tsx +2 -2
  24. package/src/charts/radarChart/RadarChart.tsx +2 -2
  25. package/src/charts/scatterChart/ScatterChart.tsx +2 -2
  26. package/src/charts/stackedLineChart/StackedLineChart.tsx +2 -2
  27. package/src/charts/steamChart/SteamChart.tsx +2 -2
  28. package/src/components/dashboard/DashBoard.tsx +117 -23
  29. package/src/components/dashboard/ExampleDashboardUsage.tsx +1 -1
  30. package/src/components/dashboard/IDashboardProps.tsx +0 -2
  31. package/src/hooks/index.ts +1 -1
  32. package/src/hooks/useChartFactory.tsx +136 -0
  33. package/src/hooks/{useGraphUtils.tsx → useChartUtils.tsx} +3 -130
  34. package/src/hooks/useIndexedDBCache.ts +122 -0
  35. package/src/hooks/useResponsiveLegend.ts +2 -2
  36. package/src/index.tsx +1 -0
  37. package/src/models/ICardChartContainer.tsx +0 -2
@@ -1 +1 @@
1
- export * from './useGraphUtils';
1
+ export * from './useChartUtils';
@@ -0,0 +1,6 @@
1
+ import { Theme } from "@fluentui/react-components";
2
+ import { IChart } from "../models";
3
+ import React from 'react';
4
+ export declare const useChartFactory: () => {
5
+ getChartComponent: (chart: IChart, theme: Theme) => React.JSX.Element;
6
+ };
@@ -1,7 +1,5 @@
1
1
  import { ChartType, TooltipOptions } from 'chart.js';
2
2
  import { Theme } from '@fluentui/react-components';
3
- import { IChart } from '../models/IChart';
4
- import React from 'react';
5
3
  /**
6
4
  * Lightens a given hex color by a percentage amount (0 to 1).
7
5
  */
@@ -21,12 +19,11 @@ export declare const createAxisLabelFormatter: ({ maxLength, suffix, prefix, }:
21
19
  }) => (this: any, value: string | number) => string;
22
20
  declare function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): T;
23
21
  /**
24
- * useGraphUtils — shared theming and chart helpers.
22
+ * useChartUtils — shared theming and chart helpers.
25
23
  */
26
- export declare function useGraphUtils(theme?: Theme): {
24
+ export declare function useChartUtils(theme?: Theme): {
27
25
  lightenColor: (hex: string, amount: number) => string;
28
26
  getFluentPalette: (_theme: Theme) => string[];
29
- getChartComponent: (chart: IChart, theme: Theme) => React.JSX.Element;
30
27
  createFluentTooltip: typeof createFluentTooltip;
31
28
  createAxisLabelFormatter: ({ maxLength, suffix, prefix, }: {
32
29
  maxLength?: number | undefined;
@@ -0,0 +1,33 @@
1
+ export interface CacheData<T> {
2
+ data: T;
3
+ timestamp: number;
4
+ }
5
+ interface UseIndexedDBCacheReturn<T> {
6
+ getData: (key: string) => Promise<T | undefined>;
7
+ setData: (key: string, data: T) => Promise<void>;
8
+ deleteData: (key: string) => Promise<void>;
9
+ clearAllCache: () => Promise<void>;
10
+ }
11
+ /**
12
+ * Custom hook to manage IndexedDB cache with a specified maximum age.
13
+ *
14
+ * @template T - The type of data to be cached.
15
+ * @param {number} [maxAge=DEFAULT_MAX_AGE] - The maximum age (in milliseconds) for cached data before it is considered expired.
16
+ * @returns {UseIndexedDBCacheReturn<T>} An object containing methods to interact with the cache.
17
+ *
18
+ * @example
19
+ * const { getData, setData, deleteData, clearAllCache } = useIndexedDBCache<MyDataType>(3600000);
20
+ *
21
+ * @function
22
+ * @name useIndexedDBCache
23
+ * @memberof hooks
24
+ * @inner
25
+ *
26
+ * @typedef {Object} UseIndexedDBCacheReturn<T>
27
+ * @property {function(string): Promise<T | undefined>} getData - Retrieves cached data by key.
28
+ * @property {function(string, T): Promise<void>} setData - Caches data with a specified key.
29
+ * @property {function(string): Promise<void>} deleteData - Deletes cached data by key.
30
+ * @property {function(): Promise<void>} clearAllCache - Clears all cached data.
31
+ */
32
+ export declare const useIndexedDBCache: <T>(maxAge?: number) => UseIndexedDBCacheReturn<T>;
33
+ export default useIndexedDBCache;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './components';
2
2
  export * from './hooks';
3
+ export { useChartUtils as useGraphUtils } from './hooks/useChartUtils';
3
4
  export * from './models';
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.4",
2
+ "version": "1.0.6",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -54,6 +54,7 @@
54
54
  "@fluentui/react-components": "^9.66.2",
55
55
  "@iconify/react": "^6.0.0",
56
56
  "@juggle/resize-observer": "^3.4.0",
57
+ "@spteck/m365-hooks": "^1.2.0",
57
58
  "chart.js": "^4.5.0",
58
59
  "chartjs-plugin-datalabels": "^2.2.0",
59
60
  "react": "^18.3.1",
@@ -9,7 +9,7 @@ import {
9
9
  Tooltip,
10
10
  } from 'chart.js';
11
11
  import React, { useMemo, useState } from 'react';
12
- import { createAxisLabelFormatter, useGraphUtils } from '../../hooks/useGraphUtils';
12
+ import { createAxisLabelFormatter, useChartUtils } from '../../hooks/useChartUtils';
13
13
 
14
14
  import { Bar } from 'react-chartjs-2';
15
15
  import ChartDataLabels from 'chartjs-plugin-datalabels';
@@ -50,7 +50,7 @@ export default function BarChart<T extends object>({
50
50
  data.length > 1 ? data.map(s => s.label) : [data[0]?.label]
51
51
  );
52
52
 
53
- const { lightenColor, getFluentPalette, createFluentTooltip } = useGraphUtils(
53
+ const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
54
54
  theme
55
55
  );
56
56
  const styles = useGraphGlobalStyles();
@@ -16,8 +16,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
16
16
  import { Chart } from 'react-chartjs-2';
17
17
  import ChartDataLabels from 'chartjs-plugin-datalabels';
18
18
  import RenderLegend from '../../components/RenderLegend/RenderLegend';
19
+ import { useChartUtils } from '../../hooks/useChartUtils';
19
20
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
20
- import { useGraphUtils } from '../../hooks/useGraphUtils';
21
21
 
22
22
  ChartJS.register(ChartDataLabels);
23
23
  ChartJS.register(
@@ -58,7 +58,7 @@ export default function ComboChart<T extends object>({
58
58
  );
59
59
 
60
60
  const styles = useGraphGlobalStyles();
61
- const { lightenColor, getFluentPalette, createFluentTooltip } = useGraphUtils(theme);
61
+ const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(theme);
62
62
 
63
63
  const seriesColors = useMemo(() => {
64
64
  return data.reduce((acc, series, idx) => {
@@ -12,8 +12,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
12
12
  import ChartDataLabels from 'chartjs-plugin-datalabels';
13
13
  import { Doughnut } from 'react-chartjs-2';
14
14
  import RenderValueLegend from '../../components/renderValueLegend/RenderValueLegend';
15
+ import { useChartUtils } from '../../hooks/useChartUtils';
15
16
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
16
- import { useGraphUtils } from '../../hooks/useGraphUtils';
17
17
 
18
18
  ChartJS.register(ChartDataLabels);
19
19
  ChartJS.register(ArcElement, Tooltip, Legend, Title);
@@ -39,7 +39,7 @@ export default function DoughnutChart<T extends object>({
39
39
  theme = webLightTheme,
40
40
  }: DoughnutChartProps<T>) {
41
41
  const styles = useGraphGlobalStyles();
42
- const { lightenColor, getFluentPalette, createFluentTooltip } = useGraphUtils(
42
+ const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
43
43
  theme
44
44
  );
45
45
  const [hiddenLabels, setHiddenLabels] = useState<string[]>([]);
@@ -12,9 +12,9 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
12
12
  import ChartDataLabels from 'chartjs-plugin-datalabels';
13
13
  import { Pie } from 'react-chartjs-2';
14
14
  import RenderValueLegend from '../../components/renderValueLegend/RenderValueLegend';
15
- import { createFluentTooltip } from '../../hooks/useGraphUtils';
15
+ import { createFluentTooltip } from '../../hooks/useChartUtils';
16
+ import { useChartUtils } from '../../hooks/useChartUtils';
16
17
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
17
- import { useGraphUtils } from '../../hooks/useGraphUtils';
18
18
 
19
19
  ChartJS.register(ChartDataLabels);
20
20
  ChartJS.register(ArcElement, Tooltip, Legend, Title);
@@ -39,7 +39,7 @@ export default function PieChart<T extends object>({
39
39
  showDataLabels = false,
40
40
  theme = webLightTheme,
41
41
  }: PieChartProps<T>) {
42
- const { getFluentPalette, lightenColor } = useGraphUtils(theme);
42
+ const { getFluentPalette, lightenColor } = useChartUtils(theme);
43
43
  const [hiddenLabels, setHiddenLabels] = useState<string[]>([]);
44
44
  const styles = useGraphGlobalStyles();
45
45
  const toggleLabel = (label: string): void => {
@@ -16,8 +16,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
16
16
  import ChartDataLabels from 'chartjs-plugin-datalabels';
17
17
  import { Line } from 'react-chartjs-2';
18
18
  import RenderLegend from '../../components/RenderLegend/RenderLegend';
19
+ import { useChartUtils } from '../../hooks/useChartUtils';
19
20
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
20
- import { useGraphUtils } from '../../hooks/useGraphUtils';
21
21
 
22
22
  ChartJS.register(
23
23
  CategoryScale,
@@ -55,7 +55,7 @@ export default function AreaChart<T extends object>({
55
55
  );
56
56
 
57
57
  const styles = useGraphGlobalStyles();
58
- const { lightenColor, getFluentPalette, createFluentTooltip } = useGraphUtils(
58
+ const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
59
59
  theme
60
60
  );
61
61
 
@@ -14,8 +14,8 @@ import { Bar } from 'react-chartjs-2';
14
14
  import ChartDataLabels from 'chartjs-plugin-datalabels';
15
15
  import RenderLegend from '../../components/RenderLegend/RenderLegend';
16
16
  import { Theme } from '@fluentui/react-theme';
17
+ import { useChartUtils } from '../../hooks/useChartUtils';
17
18
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
18
- import { useGraphUtils } from '../../hooks/useGraphUtils';
19
19
 
20
20
  ChartJS.register(
21
21
  CategoryScale,
@@ -55,7 +55,7 @@ export default function BarHorizontalChart<T extends object>({
55
55
  );
56
56
  const styles = useGraphGlobalStyles();
57
57
 
58
- const { lightenColor, getFluentPalette , createFluentTooltip} = useGraphUtils(theme);
58
+ const { lightenColor, getFluentPalette , createFluentTooltip} = useChartUtils(theme);
59
59
 
60
60
  const seriesColors = useMemo(() => {
61
61
  return data.reduce((acc, series, idx) => {
@@ -15,8 +15,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
15
15
  import { Bubble } from 'react-chartjs-2';
16
16
  import ChartDataLabels from 'chartjs-plugin-datalabels';
17
17
  import RenderLegend from '../../components/RenderLegend/RenderLegend';
18
+ import { useChartUtils } from '../../hooks/useChartUtils';
18
19
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
19
- import { useGraphUtils } from '../../hooks/useGraphUtils';
20
20
 
21
21
  ChartJS.register(
22
22
  CategoryScale,
@@ -51,7 +51,7 @@ export default function BubbleChart<T extends object>({
51
51
  data.length > 1 ? data.map(s => s.label) : [data[0]?.label]
52
52
  );
53
53
 
54
- const { lightenColor, getFluentPalette, createFluentTooltip } = useGraphUtils(
54
+ const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
55
55
  theme
56
56
  );
57
57
 
@@ -14,8 +14,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
14
14
  import { Bar } from 'react-chartjs-2';
15
15
  import ChartDataLabels from 'chartjs-plugin-datalabels';
16
16
  import RenderLegend from '../../components/RenderLegend/RenderLegend';
17
+ import { useChartUtils } from '../../hooks/useChartUtils';
17
18
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
18
- import { useGraphUtils } from '../../hooks/useGraphUtils';
19
19
 
20
20
  ChartJS.register(ChartDataLabels);
21
21
  ChartJS.register(
@@ -49,7 +49,7 @@ export default function FloatingBarChart<T extends object>({
49
49
  );
50
50
 
51
51
  const styles = useGraphGlobalStyles();
52
- const { lightenColor, getFluentPalette, createFluentTooltip } = useGraphUtils(
52
+ const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(
53
53
  theme
54
54
  );
55
55
 
@@ -15,8 +15,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
15
15
  import ChartDataLabels from 'chartjs-plugin-datalabels';
16
16
  import { Line } from 'react-chartjs-2';
17
17
  import RenderLegend from '../../components/RenderLegend/RenderLegend';
18
+ import { useChartUtils } from '../../hooks/useChartUtils';
18
19
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
19
- import { useGraphUtils } from '../../hooks/useGraphUtils';
20
20
 
21
21
  ChartJS.register(ChartDataLabels);
22
22
  ChartJS.register(
@@ -51,7 +51,7 @@ export default function LineChart<T extends object>({
51
51
  );
52
52
 
53
53
  const styles = useGraphGlobalStyles();
54
- const { lightenColor, getFluentPalette , createFluentTooltip} = useGraphUtils(theme);
54
+ const { lightenColor, getFluentPalette , createFluentTooltip} = useChartUtils(theme);
55
55
 
56
56
  const seriesColors = useMemo(() => {
57
57
  return data.reduce((acc, series, idx) => {
@@ -9,7 +9,7 @@ import {
9
9
  } from 'chart.js';
10
10
  import React, { useMemo, useState } from 'react';
11
11
  import { Theme, webLightTheme } from '@fluentui/react-components';
12
- import { createFluentTooltip, useGraphUtils } from '../../hooks/useGraphUtils';
12
+ import { createFluentTooltip, useChartUtils } from '../../hooks/useChartUtils';
13
13
 
14
14
  import ChartDataLabels from 'chartjs-plugin-datalabels';
15
15
  import { PolarArea } from 'react-chartjs-2';
@@ -45,7 +45,7 @@ export default function PolarChart<T extends object>({
45
45
  showDataLabels = true,
46
46
  theme = webLightTheme,
47
47
  }: PolarChartProps<T>) {
48
- const { getFluentPalette, lightenColor } = useGraphUtils(theme);
48
+ const { getFluentPalette, lightenColor } = useChartUtils(theme);
49
49
  const [hiddenLabels, setHiddenLabels] = useState<string[]>([]);
50
50
  const styles = useGraphGlobalStyles();
51
51
  const toggleLabel = (label: string) => {
@@ -11,7 +11,7 @@ import {
11
11
  } from 'chart.js';
12
12
  import React, { useMemo, useState } from 'react';
13
13
  import { Theme, webLightTheme } from '@fluentui/react-components';
14
- import { createFluentTooltip, useGraphUtils } from '../../hooks/useGraphUtils';
14
+ import { createFluentTooltip, useChartUtils } from '../../hooks/useChartUtils';
15
15
 
16
16
  import ChartDataLabels from 'chartjs-plugin-datalabels';
17
17
  import { Radar } from 'react-chartjs-2';
@@ -51,7 +51,7 @@ export default function RadarChart<T extends object>({
51
51
  );
52
52
 
53
53
  const styles = useGraphGlobalStyles();
54
- const { lightenColor, getFluentPalette } = useGraphUtils(theme);
54
+ const { lightenColor, getFluentPalette } = useChartUtils(theme);
55
55
 
56
56
  const seriesColors = useMemo(() => {
57
57
  return data.reduce((acc, series, idx) => {
@@ -12,8 +12,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
12
12
  import ChartDataLabels from 'chartjs-plugin-datalabels';
13
13
  import RenderLegend from '../../components/RenderLegend/RenderLegend';
14
14
  import { Scatter } from 'react-chartjs-2';
15
+ import { useChartUtils } from '../../hooks/useChartUtils';
15
16
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
16
- import { useGraphUtils } from '../../hooks/useGraphUtils';
17
17
 
18
18
  ChartJS.register(ChartDataLabels);
19
19
  ChartJS.register(LinearScale, PointElement, Tooltip, Legend);
@@ -39,7 +39,7 @@ export default function ScatterChart<T extends object>({
39
39
  data.map(s => s.label)
40
40
  );
41
41
  const styles = useGraphGlobalStyles();
42
- const { getFluentPalette, lightenColor, createFluentTooltip } = useGraphUtils(
42
+ const { getFluentPalette, lightenColor, createFluentTooltip } = useChartUtils(
43
43
  theme
44
44
  );
45
45
 
@@ -15,8 +15,8 @@ import { Theme, webLightTheme } from '@fluentui/react-components';
15
15
  import ChartDataLabels from 'chartjs-plugin-datalabels';
16
16
  import { Line } from 'react-chartjs-2';
17
17
  import RenderLegend from '../../components/RenderLegend/RenderLegend';
18
+ import { useChartUtils } from '../../hooks/useChartUtils';
18
19
  import { useGraphGlobalStyles } from '../../graphGlobalStyles/useGraphGlobalStyles';
19
- import { useGraphUtils } from '../../hooks/useGraphUtils';
20
20
 
21
21
  ChartJS.register(ChartDataLabels);
22
22
  ChartJS.register(
@@ -51,7 +51,7 @@ export default function StackedLineChart<T extends object>({
51
51
  );
52
52
 
53
53
  const styles = useGraphGlobalStyles();
54
- const { lightenColor, getFluentPalette, createFluentTooltip } = useGraphUtils(theme);
54
+ const { lightenColor, getFluentPalette, createFluentTooltip } = useChartUtils(theme);
55
55
 
56
56
  const seriesColors = useMemo(() => {
57
57
  return data.reduce((acc, series, idx) => {
@@ -12,7 +12,7 @@ import {
12
12
  } from 'chart.js';
13
13
  import React, { useMemo, useState } from 'react';
14
14
  import { Theme, ToggleButton, webLightTheme } from '@fluentui/react-components';
15
- import { createFluentTooltip, useGraphUtils } from '../../hooks/useGraphUtils';
15
+ import { createFluentTooltip, useChartUtils } from '../../hooks/useChartUtils';
16
16
 
17
17
  import ChartDataLabels from 'chartjs-plugin-datalabels';
18
18
  import { Line } from 'react-chartjs-2';
@@ -55,7 +55,7 @@ export default function SteamChart<T extends object>({
55
55
  const [showPercent, setShowPercent] = useState(false);
56
56
  const styles = useGraphGlobalStyles();
57
57
 
58
- const { lightenColor, getFluentPalette } = useGraphUtils(theme);
58
+ const { lightenColor, getFluentPalette } = useChartUtils(theme);
59
59
 
60
60
  const seriesColors = useMemo(() => {
61
61
  return data.reduce((acc, series, idx) => {
@@ -1,5 +1,3 @@
1
- 'use client';
2
-
3
1
  import { Card, CardHeader, Text, Theme } from '@fluentui/react-components';
4
2
  import React, {
5
3
  useCallback,
@@ -13,11 +11,15 @@ import { ICardChartContainer } from '../../models/ICardChartContainer';
13
11
  import { IDashboardProps } from './IDashboardProps';
14
12
  import { NoDashboards } from './NoDashboards';
15
13
  import { SelectZoom } from './selectZoom/SelectZoom';
14
+ import { useChartFactory } from '../../hooks/useChartFactory';
16
15
  import { useDashboardStyles } from './useDashboardStyles';
17
- import { useGraphUtils } from '../../hooks';
16
+ import { useIndexedDBCache } from '@spteck/m365-hooks';
18
17
 
19
18
  const MINIMUM_DASHBOARD_WIDTH = 600;
20
19
  const MAX_ROWS = 4;
20
+ const DASHBOARD_LAYOUT_CACHE_KEY = 'dashboard-layout-settings';
21
+ const DASHBOARD_ORDER_CACHE_KEY = 'dashboard-card-order';
22
+ const CACHE_EXPIRATION_DAYS = 30;
21
23
 
22
24
  export const Dashboard: React.FC<IDashboardProps> = ({
23
25
  cardCharts,
@@ -27,8 +29,22 @@ export const Dashboard: React.FC<IDashboardProps> = ({
27
29
  maxSpanRows = MAX_ROWS,
28
30
  }) => {
29
31
  const styles = useDashboardStyles();
32
+ const { getChartComponent } = useChartFactory();
33
+
34
+ // Cache with 30-day expiration for dashboard layout settings
35
+ const { getData, setData } = useIndexedDBCache<Record<string, { spanCols: number; spanRows: number }>>(
36
+ CACHE_EXPIRATION_DAYS * 24 * 60 * 60 * 1000
37
+ );
38
+
39
+ // Cache for card order
40
+ const {
41
+ getData: getOrderData,
42
+ setData: setOrderData
43
+ } = useIndexedDBCache<string[]>(
44
+ CACHE_EXPIRATION_DAYS * 24 * 60 * 60 * 1000
45
+ );
30
46
 
31
- const { getChartComponent } = useGraphUtils(theme as Theme);
47
+
32
48
 
33
49
  const [CardChartContainer, setCardChartContainer] = useState<
34
50
  ICardChartContainer[]
@@ -42,21 +58,97 @@ export const Dashboard: React.FC<IDashboardProps> = ({
42
58
  const containerRef = useRef<HTMLDivElement>(null);
43
59
 
44
60
  React.useEffect(() => {
45
- setCardChartContainer(cardCharts);
46
- setSizes(() => {
47
- const initialSizes: Record<
48
- string,
49
- { spanCols: number; spanRows: number }
50
- > = {};
51
- cardCharts.forEach(c => {
52
- initialSizes[c.id] = {
53
- spanCols: c.defaultSpan?.spanCols ?? 1,
54
- spanRows: c.defaultSpan?.spanRows ?? 1,
55
- };
56
- });
57
- return initialSizes;
58
- });
59
- }, [cardCharts]);
61
+ // Load cached card order and sizes
62
+ const initializeData = async () => {
63
+ try {
64
+ const [cachedSizes, cachedOrder] = await Promise.all([
65
+ getData(DASHBOARD_LAYOUT_CACHE_KEY),
66
+ getOrderData(DASHBOARD_ORDER_CACHE_KEY)
67
+ ]);
68
+
69
+ // Restore card order if available, otherwise use original order
70
+ let orderedCards = cardCharts;
71
+ if (cachedOrder && cachedOrder.length > 0) {
72
+ // Reorder cards based on cached order, but handle cases where cards might have been added/removed
73
+ const cardMap = new Map(cardCharts.map(card => [card.id, card]));
74
+ const validCachedOrder = cachedOrder.filter(id => cardMap.has(id));
75
+ const missingCards = cardCharts.filter(card => !cachedOrder.includes(card.id));
76
+
77
+ orderedCards = [
78
+ ...validCachedOrder.map(id => cardMap.get(id)!),
79
+ ...missingCards
80
+ ];
81
+ }
82
+
83
+ setCardChartContainer(orderedCards);
84
+
85
+ const initialSizes: Record<
86
+ string,
87
+ { spanCols: number; spanRows: number }
88
+ > = {};
89
+
90
+ cardCharts.forEach(c => {
91
+ const cachedSize = cachedSizes?.[c.id];
92
+ initialSizes[c.id] = {
93
+ spanCols: cachedSize?.spanCols ?? c.defaultSpan?.spanCols ?? 1,
94
+ spanRows: cachedSize?.spanRows ?? c.defaultSpan?.spanRows ?? 1,
95
+ };
96
+ });
97
+
98
+ setSizes(initialSizes);
99
+ } catch (error) {
100
+ // Fallback to default values if cache fails
101
+ console.warn('Failed to load dashboard data from cache:', error);
102
+ setCardChartContainer(cardCharts);
103
+ const fallbackSizes: Record<
104
+ string,
105
+ { spanCols: number; spanRows: number }
106
+ > = {};
107
+ cardCharts.forEach(c => {
108
+ fallbackSizes[c.id] = {
109
+ spanCols: c.defaultSpan?.spanCols ?? 1,
110
+ spanRows: c.defaultSpan?.spanRows ?? 1,
111
+ };
112
+ });
113
+ setSizes(fallbackSizes);
114
+ }
115
+ };
116
+
117
+ initializeData();
118
+ }, [cardCharts, getData, getOrderData]);
119
+
120
+ // Save sizes to cache whenever they change
121
+ useEffect(() => {
122
+ const saveSizesToCache = async () => {
123
+ try {
124
+ await setData(DASHBOARD_LAYOUT_CACHE_KEY, sizes);
125
+ } catch (error) {
126
+ console.warn('Failed to save dashboard layout to cache:', error);
127
+ }
128
+ };
129
+
130
+ // Only save if sizes is not empty (avoid saving initial empty state)
131
+ if (Object.keys(sizes).length > 0) {
132
+ saveSizesToCache();
133
+ }
134
+ }, [sizes, setData]);
135
+
136
+ // Save card order to cache whenever it changes
137
+ useEffect(() => {
138
+ const saveOrderToCache = async () => {
139
+ try {
140
+ const cardOrder = CardChartContainer.map(card => card.id);
141
+ await setOrderData(DASHBOARD_ORDER_CACHE_KEY, cardOrder);
142
+ } catch (error) {
143
+ console.warn('Failed to save dashboard order to cache:', error);
144
+ }
145
+ };
146
+
147
+ // Only save if CardChartContainer is not empty
148
+ if (CardChartContainer.length > 0) {
149
+ saveOrderToCache();
150
+ }
151
+ }, [CardChartContainer, setOrderData]);
60
152
 
61
153
  useEffect(() => {
62
154
  if (containerWidth <= MINIMUM_DASHBOARD_WIDTH) {
@@ -110,12 +202,14 @@ export const Dashboard: React.FC<IDashboardProps> = ({
110
202
 
111
203
  const handleZoomSelect = useCallback(
112
204
  (id: string, span: { spanCols: number; spanRows: number }) => {
205
+ const newSizes = {
206
+ spanCols: Math.min(Math.max(span.spanCols, 1), maxZoom),
207
+ spanRows: Math.min(Math.max(span.spanRows, 1), maxSpanRows),
208
+ };
209
+
113
210
  setSizes(prev => ({
114
211
  ...prev,
115
- [id]: {
116
- spanCols: Math.min(Math.max(span.spanCols, 1), maxZoom),
117
- spanRows: Math.min(Math.max(span.spanRows, 1), maxSpanRows),
118
- },
212
+ [id]: newSizes,
119
213
  }));
120
214
  },
121
215
  [maxZoom, maxSpanRows]
@@ -105,7 +105,7 @@ const ExampleDashboardUsage: React.FC<{ theme: Theme }> = ({ theme }) => {
105
105
  cardCharts={cardChartContainers}
106
106
  theme={theme ?? webLightTheme}
107
107
  containerWidth={window.innerWidth}
108
- containerHeight={window.innerHeight - 100} // Adjust height for header
108
+ containerHeight={(window.innerHeight - 100).toString()} // Adjust height for header
109
109
  />
110
110
  </Stack>
111
111
  );
@@ -1,5 +1,3 @@
1
- 'use client';
2
-
3
1
  import { ICardChartContainer } from '../../models/ICardChartContainer';
4
2
  import { Theme } from '@fluentui/react-components';
5
3
 
@@ -1 +1 @@
1
- export * from './useGraphUtils';
1
+ export * from './useChartUtils';