diff --git a/apps/web/src/api/buster_rest/metrics/requests.ts b/apps/web/src/api/buster_rest/metrics/requests.ts index c5a85da84..a7cc53405 100644 --- a/apps/web/src/api/buster_rest/metrics/requests.ts +++ b/apps/web/src/api/buster_rest/metrics/requests.ts @@ -22,8 +22,10 @@ import type { } from '@buster/server-shared/metrics'; import { serverFetch } from '@/api/createServerInstance'; import { mainApi } from '../instances'; +import { testMetricDataResponse, testMetricResponse } from './test'; -export const getMetric = async (params: GetMetricRequest) => { +export const getMetric = async (params: GetMetricRequest): Promise => { + // return testMetricResponse as unknown as GetMetricResponse; return mainApi .get(`/metrics/${params.id}`, { params @@ -37,7 +39,12 @@ export const getMetric_server = async ({ id, password }: Parameters { +export const getMetricData = async ({ + id, + version_number, + password +}: GetMetricDataRequest): Promise => { + // return testMetricDataResponse as unknown as MetricDataResponse; return mainApi .get(`/metrics/${id}/data`, { params: { password, version_number } }) .then((res) => res.data); diff --git a/apps/web/src/api/buster_rest/metrics/test.ts b/apps/web/src/api/buster_rest/metrics/test.ts new file mode 100644 index 000000000..b22902215 --- /dev/null +++ b/apps/web/src/api/buster_rest/metrics/test.ts @@ -0,0 +1,167 @@ +export const testMetricResponse = { + id: '23b15b8e-4e22-4980-83b5-0009e173f0e0', + type: 'metric', + name: 'Monthly Order Volume Decline', + version_number: 1, + description: 'Shows the declining trend in monthly order volume over the last 12 months', + file_name: 'Monthly Order Volume Decline', + time_frame: 'Last 12 months', + datasets: [], + data_source_id: '14d50bf5-6dee-42a7-bdff-a4a398156edf', + error: null, + chart_config: { + selectedChartType: 'line', + columnLabelFormats: { + order_count: { + columnType: 'number', + style: 'number', + numberSeparatorStyle: ',', + replaceMissingDataWith: 0 + }, + order_month: { + columnType: 'date', + style: 'date', + numberSeparatorStyle: null, + replaceMissingDataWith: null, + dateFormat: 'MMM YYYY' + } + }, + barAndLineAxis: { + x: ['order_month'], + y: ['order_count'] + } + }, + data_metadata: { + column_count: 2, + row_count: 13, + column_metadata: [ + { + name: 'order_month', + min_value: '2024-03-01T00:00:00.000Z', + max_value: '2025-03-01T00:00:00.000Z', + unique_values: 13, + simple_type: 'date', + type: 'timestamp' + }, + { + name: 'order_count', + min_value: 375, + max_value: 2326, + unique_values: 13, + simple_type: 'number', + type: 'int4' + } + ] + }, + status: 'notRequested', + evaluation_score: null, + evaluation_summary: '', + file: "name: Monthly Order Volume Decline\ndescription: Shows the declining trend in monthly order volume over the last 12 months\ntimeFrame: Last 12 months\nsql: \"SELECT \\n DATE_TRUNC('month', soh.orderdate) as order_month,\\n COUNT(*) as order_count\\nFROM postgres.ont_ont.sales_order_header soh\\nWHERE soh.orderdate >= (SELECT MAX(orderdate) FROM postgres.ont_ont.sales_order_header) - INTERVAL '12 months'\\nGROUP BY DATE_TRUNC('month', soh.orderdate)\\nORDER BY order_month\\n\"\nchartConfig:\n selectedChartType: line\n columnLabelFormats:\n order_count:\n columnType: number\n style: number\n numberSeparatorStyle: ','\n replaceMissingDataWith: 0\n order_month:\n columnType: date\n style: date\n numberSeparatorStyle: null\n replaceMissingDataWith: null\n dateFormat: MMM YYYY\n barAndLineAxis:\n x:\n - order_month\n y:\n - order_count\n", + created_at: '2025-07-09T22:01:16.273Z', + updated_at: '2025-07-09T22:01:16.273Z', + sent_by_id: '1fe85021-e799-471b-8837-953e9ae06e4c', + sent_by_name: '', + sent_by_avatar_url: null, + code: null, + dashboards: [], + collections: [], + versions: [ + { + version_number: 1, + updated_at: '2025-07-09T22:01:16.273Z' + } + ], + permission: 'owner', + sql: "SELECT \n DATE_TRUNC('month', soh.orderdate) as order_month,\n COUNT(*) as order_count\nFROM postgres.ont_ont.sales_order_header soh\nWHERE soh.orderdate >= (SELECT MAX(orderdate) FROM postgres.ont_ont.sales_order_header) - INTERVAL '12 months'\nGROUP BY DATE_TRUNC('month', soh.orderdate)\nORDER BY order_month\n", + individual_permissions: [ + { + email: 'blake@buster.so', + role: 'owner', + name: 'Blake Rouse' + } + ], + public_expiry_date: null, + public_enabled_by: null, + publicly_accessible: false, + public_password: null +}; + +export const testMetricDataResponse = { + metric_id: '23b15b8e-4e22-4980-83b5-0009e173f0e0', + data: [ + { + order_month: '2024-03-01T00:00:00', + order_count: 375 + }, + { + order_month: '2024-04-01T00:00:00', + order_count: 1707 + }, + { + order_month: '2024-05-01T00:00:00', + order_count: 1783 + }, + { + order_month: '2024-06-01T00:00:00', + order_count: 1815 + }, + { + order_month: '2024-07-01T00:00:00', + order_count: 1973 + }, + { + order_month: '2024-08-01T00:00:00', + order_count: 2139 + }, + { + order_month: '2024-09-01T00:00:00', + order_count: 2015 + }, + { + order_month: '2024-10-01T00:00:00', + order_count: 2130 + }, + { + order_month: '2024-11-01T00:00:00', + order_count: 2018 + }, + { + order_month: '2024-12-01T00:00:00', + order_count: 2300 + }, + { + order_month: '2025-01-01T00:00:00', + order_count: 2326 + }, + { + order_month: '2025-02-01T00:00:00', + order_count: 1982 + }, + { + order_month: '2025-03-01T00:00:00', + order_count: 871 + } + ], + data_metadata: { + column_count: 2, + row_count: 13, + column_metadata: [ + { + name: 'order_month', + min_value: '2024-03-01T00:00:00.000Z', + max_value: '2025-03-01T00:00:00.000Z', + unique_values: 13, + simple_type: 'date', + type: 'timestamp' + }, + { + name: 'order_count', + min_value: 375, + max_value: 2326, + unique_values: 13, + simple_type: 'number', + type: 'int4' + } + ] + } +}; diff --git a/apps/web/src/components/ui/charts/stories/BusterChart.LineChart.stories.tsx b/apps/web/src/components/ui/charts/stories/BusterChart.LineChart.stories.tsx index f1b6eaeef..2f176288f 100644 --- a/apps/web/src/components/ui/charts/stories/BusterChart.LineChart.stories.tsx +++ b/apps/web/src/components/ui/charts/stories/BusterChart.LineChart.stories.tsx @@ -2,6 +2,8 @@ import type { Meta, StoryObj } from '@storybook/react'; import dayjs from 'dayjs'; import { DEFAULT_COLUMN_LABEL_FORMAT, + type BarAndLineAxis, + type ChartConfigProps, type ColumnLabelFormat, type ColumnSettings, type DataMetadata, @@ -2072,21 +2074,21 @@ const test = createDefaultChartConfig({ style: 'number', numberSeparatorStyle: ',', replaceMissingDataWith: 0 - }, + } as ColumnLabelFormat, order_month: { columnType: 'date', style: 'date', numberSeparatorStyle: null, replaceMissingDataWith: null, dateFormat: 'MMM YYYY' - } - }, + } as ColumnLabelFormat + } as ChartConfigProps['columnLabelFormats'], barAndLineAxis: { x: ['order_month'], y: ['order_count'] - }, + } as BarAndLineAxis, selectedChartType: 'line' - } + } as ChartConfigProps }); const data = [ { diff --git a/apps/web/src/hooks/useLocalStorageState.tsx b/apps/web/src/hooks/useLocalStorageState.tsx index 9f7cf4584..e61f3f0ac 100644 --- a/apps/web/src/hooks/useLocalStorageState.tsx +++ b/apps/web/src/hooks/useLocalStorageState.tsx @@ -3,6 +3,7 @@ import { useState, useEffect } from 'react'; import { useMemoizedFn } from './useMemoizedFn'; import { useMount } from './useMount'; +import { isServer } from '@tanstack/react-query'; type SetState = S | ((prevState?: S) => S); @@ -38,20 +39,20 @@ export function useLocalStorageState( // Get initial value from localStorage or use default const getInitialValue = useMemoizedFn((): T | undefined => { - const letsBusterTheStorageBaby = () => { - window.localStorage.removeItem(key); + const gonnaBustTheStorage = () => { + if (!isServer) window.localStorage.removeItem(key); return typeof defaultValue === 'function' ? (defaultValue as () => T)() : defaultValue; }; // If bustStorageOnInit is true, ignore localStorage and use default value if (bustStorageOnInit === true) { - return letsBusterTheStorageBaby(); + return gonnaBustTheStorage(); } try { const item = window.localStorage.getItem(key); if (item === null) { - return letsBusterTheStorageBaby(); + return gonnaBustTheStorage(); } // Parse the stored data which includes value and timestamp @@ -65,7 +66,7 @@ export function useLocalStorageState( !('timestamp' in storageData) ) { // If the data doesn't have the expected structure (legacy data), treat as expired - return letsBusterTheStorageBaby(); + return gonnaBustTheStorage(); } // Check if the data has expired @@ -74,20 +75,20 @@ export function useLocalStorageState( if (timeDifference > expirationTime) { // Data has expired, remove it and return default value - return letsBusterTheStorageBaby(); + return gonnaBustTheStorage(); } // Data is still valid, deserialize and return the value const deserializedValue = deserializer(JSON.stringify(storageData.value)); if (typeof bustStorageOnInit === 'function' && bustStorageOnInit(deserializedValue)) { - return letsBusterTheStorageBaby(); + return gonnaBustTheStorage(); } return deserializedValue; } catch (error) { onError?.(error); - return letsBusterTheStorageBaby(); + return gonnaBustTheStorage(); } }); @@ -101,7 +102,7 @@ export function useLocalStorageState( // Update localStorage when state changes useEffect(() => { try { - if (state === undefined) { + if (state === undefined && !isServer) { window.localStorage.removeItem(key); } else { // Create storage data with current timestamp