From 95e0c8d7b5f68534885b2bffc4723ef1ebcb9c0a Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Fri, 18 Jul 2025 12:34:39 -0600 Subject: [PATCH] move currency around to dictionary --- .../api/v2/dictionaries/currency/config.ts | 2 +- .../src/api/v2/dictionaries/currency/index.ts | 2 +- .../web/src/api/buster_rest/currency/index.ts | 1 - .../api/buster_rest/currency/queryRequests.ts | 26 --- .../buster_rest/dictionaries/queryRequests.ts | 23 ++- .../api/buster_rest/dictionaries/requests.ts | 5 + apps/web/src/api/query_keys/currency.ts | 13 -- apps/web/src/api/query_keys/dictionaries.ts | 17 +- apps/web/src/api/query_keys/index.ts | 2 - .../DefaultThemeSelector.tsx | 12 +- .../settings/DefaultColorThemeCard.tsx | 4 - apps/web/src/context-hooks/usePalettes.ts | 15 +- .../SelectAxisColumnContent/EditCurrency.tsx | 2 +- .../SelectAxisDropdownContent.tsx | 2 +- packages/server-shared/package.json | 4 - .../src/currency/currency.types.test.ts | 192 ------------------ packages/server-shared/src/currency/index.ts | 2 - .../server-shared/src/currency/responses.ts | 6 - .../currency.ts} | 4 + .../server-shared/src/dictionary/index.ts | 1 + 20 files changed, 62 insertions(+), 273 deletions(-) delete mode 100644 apps/web/src/api/buster_rest/currency/index.ts delete mode 100644 apps/web/src/api/buster_rest/currency/queryRequests.ts delete mode 100644 apps/web/src/api/query_keys/currency.ts delete mode 100644 packages/server-shared/src/currency/currency.types.test.ts delete mode 100644 packages/server-shared/src/currency/index.ts delete mode 100644 packages/server-shared/src/currency/responses.ts rename packages/server-shared/src/{currency/currency.types.ts => dictionary/currency.ts} (58%) diff --git a/apps/server/src/api/v2/dictionaries/currency/config.ts b/apps/server/src/api/v2/dictionaries/currency/config.ts index a5f961bda..18885d2f4 100644 --- a/apps/server/src/api/v2/dictionaries/currency/config.ts +++ b/apps/server/src/api/v2/dictionaries/currency/config.ts @@ -1,4 +1,4 @@ -import type { Currency } from '@buster/server-shared/currency'; +import type { Currency } from '@buster/server-shared/dictionary'; const codeToFlag = { AED: 'πŸ‡¦πŸ‡ͺ', diff --git a/apps/server/src/api/v2/dictionaries/currency/index.ts b/apps/server/src/api/v2/dictionaries/currency/index.ts index 362e70599..1b9eecb93 100644 --- a/apps/server/src/api/v2/dictionaries/currency/index.ts +++ b/apps/server/src/api/v2/dictionaries/currency/index.ts @@ -1,4 +1,4 @@ -import type { CurrencyResponse } from '@buster/server-shared/currency'; +import type { CurrencyResponse } from '@buster/server-shared/dictionary'; import { Hono } from 'hono'; import { CURRENCIES_MAP } from './config'; diff --git a/apps/web/src/api/buster_rest/currency/index.ts b/apps/web/src/api/buster_rest/currency/index.ts deleted file mode 100644 index 30857d639..000000000 --- a/apps/web/src/api/buster_rest/currency/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './queryRequests'; diff --git a/apps/web/src/api/buster_rest/currency/queryRequests.ts b/apps/web/src/api/buster_rest/currency/queryRequests.ts deleted file mode 100644 index d50739d4a..000000000 --- a/apps/web/src/api/buster_rest/currency/queryRequests.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { queryKeys } from '@/api/query_keys'; -import { QueryClient, usePrefetchQuery, useQuery } from '@tanstack/react-query'; -import { mainApiV2 } from '../instances'; -import { Currency } from '@buster/server-shared/currency'; - -export const useGetCurrencies = () => { - return useQuery({ - ...queryKeys.getCurrencies, - queryFn: async () => { - return mainApiV2.get('/dictionaries/currency').then(async (res) => res.data); - } - }); -}; - -export const prefetchGetCurrencies = async (queryClientProp?: QueryClient) => { - const queryClient = queryClientProp || new QueryClient(); - - await queryClient.prefetchQuery({ - ...queryKeys.getCurrencies, - queryFn: async () => { - return mainApiV2.get('/dictionaries/currency').then(async (res) => res.data); - } - }); - - return queryClient; -}; diff --git a/apps/web/src/api/buster_rest/dictionaries/queryRequests.ts b/apps/web/src/api/buster_rest/dictionaries/queryRequests.ts index ff7cf76ec..6bfb415f5 100644 --- a/apps/web/src/api/buster_rest/dictionaries/queryRequests.ts +++ b/apps/web/src/api/buster_rest/dictionaries/queryRequests.ts @@ -1,11 +1,10 @@ import { useQuery, QueryClient } from '@tanstack/react-query'; -import { getColorThemes } from './requests'; -import { dictionariesQueryKeys } from '../../query_keys/dictionaries'; +import { getColorThemes, getCurrencies } from './requests'; +import { dictionariesQueryKeys } from '@/api/query_keys/dictionaries'; export const useColorDictionaryThemes = () => { return useQuery({ ...dictionariesQueryKeys.colorThemes, - initialData: [], queryFn: getColorThemes }); }; @@ -20,3 +19,21 @@ export const prefetchColorThemes = async (queryClientProp?: QueryClient) => { return queryClient; }; + +export const useGetCurrencies = () => { + return useQuery({ + ...dictionariesQueryKeys.getCurrencies, + queryFn: getCurrencies + }); +}; + +export const prefetchGetCurrencies = async (queryClientProp?: QueryClient) => { + const queryClient = queryClientProp || new QueryClient(); + + await queryClient.prefetchQuery({ + ...dictionariesQueryKeys.getCurrencies, + queryFn: getCurrencies + }); + + return queryClient; +}; diff --git a/apps/web/src/api/buster_rest/dictionaries/requests.ts b/apps/web/src/api/buster_rest/dictionaries/requests.ts index 40b6dec96..6fd1254e7 100644 --- a/apps/web/src/api/buster_rest/dictionaries/requests.ts +++ b/apps/web/src/api/buster_rest/dictionaries/requests.ts @@ -1,8 +1,13 @@ import type { ColorThemeDictionariesResponse } from '@buster/server-shared/dictionary'; import { mainApiV2 } from '../instances'; +import type { CurrencyResponse } from '@buster/server-shared/dictionary'; export const getColorThemes = async () => { return await mainApiV2 .get('/dictionaries/color-themes') .then((res) => res.data); }; + +export const getCurrencies = async () => { + return await mainApiV2.get('/dictionaries/currency').then((res) => res.data); +}; diff --git a/apps/web/src/api/query_keys/currency.ts b/apps/web/src/api/query_keys/currency.ts deleted file mode 100644 index 349e2b8fd..000000000 --- a/apps/web/src/api/query_keys/currency.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { queryOptions } from '@tanstack/react-query'; -import { CurrencyResponse } from '@buster/server-shared/currency'; - -export const getCurrencies = queryOptions({ - queryKey: ['nextjs', 'list', 'currencies'], - initialData: [], - initialDataUpdatedAt: 0, - staleTime: 1000 * 60 * 60 * 24 * 7 //7 days -}); - -export const currencyQueryKeys = { - getCurrencies -}; diff --git a/apps/web/src/api/query_keys/dictionaries.ts b/apps/web/src/api/query_keys/dictionaries.ts index 23402293f..5abb790fd 100644 --- a/apps/web/src/api/query_keys/dictionaries.ts +++ b/apps/web/src/api/query_keys/dictionaries.ts @@ -1,11 +1,22 @@ +import type { CurrencyResponse } from '@buster/server-shared/dictionary'; import type { ColorThemeDictionariesResponse } from '@buster/server-shared/dictionary'; import { queryOptions } from '@tanstack/react-query'; export const colorThemes = queryOptions({ - queryKey: ['color-themes', 'list'], - staleTime: 60 * 1000 * 60 * 24 * 3 // 3 days + queryKey: ['dictionaries', 'color-themes', 'list'] as const, + initialData: [], + initialDataUpdatedAt: 0, + staleTime: 1000 * 60 * 60 * 24 * 7 // 7 days +}); + +export const getCurrencies = queryOptions({ + queryKey: ['dictionaries', 'currencies', 'list'] as const, + initialData: [], + initialDataUpdatedAt: 0, + staleTime: 1000 * 60 * 60 * 24 * 7 // 7 days }); export const dictionariesQueryKeys = { - colorThemes + colorThemes, + getCurrencies }; diff --git a/apps/web/src/api/query_keys/index.ts b/apps/web/src/api/query_keys/index.ts index 8f0f11e80..d5f983e0a 100644 --- a/apps/web/src/api/query_keys/index.ts +++ b/apps/web/src/api/query_keys/index.ts @@ -5,7 +5,6 @@ import { datasetGroupQueryKeys } from './dataset_groups'; import { datasetQueryKeys } from './datasets'; import { datasourceQueryKeys } from './datasources'; import { metricsQueryKeys } from './metric'; -import { currencyQueryKeys } from './currency'; import { permissionGroupQueryKeys } from './permission_groups'; import { searchQueryKeys } from './search'; import { termsQueryKeys } from './terms'; @@ -26,7 +25,6 @@ export const queryKeys = { ...datasourceQueryKeys, ...datasetGroupQueryKeys, ...permissionGroupQueryKeys, - ...currencyQueryKeys, ...securityQueryKeys, ...slackQueryKeys, ...dictionariesQueryKeys diff --git a/apps/web/src/components/features/colors/DefaultThemeSelector/DefaultThemeSelector.tsx b/apps/web/src/components/features/colors/DefaultThemeSelector/DefaultThemeSelector.tsx index 457f32442..0bfea7b03 100644 --- a/apps/web/src/components/features/colors/DefaultThemeSelector/DefaultThemeSelector.tsx +++ b/apps/web/src/components/features/colors/DefaultThemeSelector/DefaultThemeSelector.tsx @@ -1,7 +1,5 @@ import React from 'react'; import { DefaultThemeSelectorBase } from './DefaultThemeSelectorBase'; -import { useGetMyUserInfo } from '@/api/buster_rest/users/queryRequests'; -import { useColorDictionaryThemes } from '@/api/buster_rest/dictionaries'; import { StatusCard } from '@/components/ui/card/StatusCard'; import { CircleSpinnerLoader } from '../../../ui/loaders'; import { useThemeOperations } from '@/context-hooks/useThemeOperations'; @@ -9,11 +7,8 @@ import { useGetPalettes } from '@/context-hooks/usePalettes'; export const DefaultThemeSelector = React.memo( ({ className, themeListClassName }: { className?: string; themeListClassName?: string }) => { - const { data: userData } = useGetMyUserInfo(); - const { isErrorDictionaryPalettes, - isFetchedDictionaryPalettes, organizationPalettes, dictionaryPalettes, selectedPaletteId @@ -22,7 +17,12 @@ export const DefaultThemeSelector = React.memo( const { onCreateCustomTheme, onDeleteCustomTheme, onModifyCustomTheme, onSelectTheme } = useThemeOperations(); - if (!isFetchedDictionaryPalettes) return ; + if (dictionaryPalettes.length === 0 && !isErrorDictionaryPalettes) + return ( +
+ +
+ ); if (isErrorDictionaryPalettes) return ( diff --git a/apps/web/src/components/features/settings/DefaultColorThemeCard.tsx b/apps/web/src/components/features/settings/DefaultColorThemeCard.tsx index 38466894f..e61a9a78a 100644 --- a/apps/web/src/components/features/settings/DefaultColorThemeCard.tsx +++ b/apps/web/src/components/features/settings/DefaultColorThemeCard.tsx @@ -40,10 +40,6 @@ const PickButton = React.memo(() => { const hasDefaultPalette = !!defaultPalette; - useMount(() => { - prefetchColorThemes(); - }); - return ( { const { data: userData } = useGetMyUserInfo(); @@ -27,11 +28,11 @@ const useGetOrganizationPalettes = () => { export const useGetPalettes = () => { const { organizationPalettes, selectedPaletteId } = useGetOrganizationPalettes(); - const { - data: dictionaryPalettes, - isFetched: isFetchedDictionaryPalettes, - isError: isErrorDictionaryPalettes - } = useColorDictionaryThemes(); + const { data: dictionaryPalettes, isError: isErrorDictionaryPalettes } = + useColorDictionaryThemes(); + const { data: currencies } = useGetCurrencies(); + + console.log(currencies, dictionaryPalettes); return useMemo(() => { const allPalettes = [...dictionaryPalettes, ...organizationPalettes]; @@ -43,10 +44,10 @@ export const useGetPalettes = () => { dictionaryPalettes, selectedPaletteId, defaultPalette, - isFetchedDictionaryPalettes, + isErrorDictionaryPalettes }; - }, [dictionaryPalettes, organizationPalettes, selectedPaletteId, isFetchedDictionaryPalettes]); + }, [dictionaryPalettes, organizationPalettes, selectedPaletteId]); }; export const useSelectedColorPalette = (colors: string[] | undefined | null): string[] => { diff --git a/apps/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppVisualize/SelectAxis/SelectAxisColumnContent/EditCurrency.tsx b/apps/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppVisualize/SelectAxis/SelectAxisColumnContent/EditCurrency.tsx index e677dd6d9..ab99f6e74 100644 --- a/apps/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppVisualize/SelectAxis/SelectAxisColumnContent/EditCurrency.tsx +++ b/apps/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppVisualize/SelectAxis/SelectAxisColumnContent/EditCurrency.tsx @@ -1,6 +1,6 @@ import React, { useMemo } from 'react'; import type { ColumnLabelFormat } from '@buster/server-shared/metrics'; -import { useGetCurrencies } from '@/api/buster_rest/currency'; +import { useGetCurrencies } from '@/api/buster_rest/dictionaries'; import { Select, type SelectItem } from '@/components/ui/select'; import { Text } from '@/components/ui/typography'; import { useMemoizedFn } from '@/hooks'; diff --git a/apps/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppVisualize/SelectAxis/SelectAxisColumnContent/SelectAxisDropdownContent.tsx b/apps/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppVisualize/SelectAxis/SelectAxisColumnContent/SelectAxisDropdownContent.tsx index 595a3cde4..1f3d6946f 100644 --- a/apps/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppVisualize/SelectAxis/SelectAxisColumnContent/SelectAxisDropdownContent.tsx +++ b/apps/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricStylingApp/StylingAppVisualize/SelectAxis/SelectAxisColumnContent/SelectAxisDropdownContent.tsx @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'; import type { ChartConfigProps } from '@buster/server-shared/metrics'; import { type ChartEncodes, type ColumnSettings } from '@buster/server-shared/metrics'; import type { ColumnLabelFormat } from '@buster/server-shared/metrics'; -import { prefetchGetCurrencies } from '@/api/buster_rest/currency'; +import { prefetchGetCurrencies } from '@/api/buster_rest/dictionaries'; import { ErrorBoundary } from '@/components/ui/error'; import { Text } from '@/components/ui/typography'; import { useUpdateMetricChart } from '@/context/Metrics'; diff --git a/packages/server-shared/package.json b/packages/server-shared/package.json index 5e8c26c35..2e3e5e95c 100644 --- a/packages/server-shared/package.json +++ b/packages/server-shared/package.json @@ -36,10 +36,6 @@ "types": "./dist/dashboards/index.d.ts", "default": "./dist/dashboards/index.js" }, - "./currency": { - "types": "./dist/currency/index.d.ts", - "default": "./dist/currency/index.js" - }, "./slack": { "types": "./dist/slack/index.d.ts", "default": "./dist/slack/index.js" diff --git a/packages/server-shared/src/currency/currency.types.test.ts b/packages/server-shared/src/currency/currency.types.test.ts deleted file mode 100644 index c8452a461..000000000 --- a/packages/server-shared/src/currency/currency.types.test.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { CurrencySchema } from './currency.types'; - -describe('CurrencySchema', () => { - it('should parse valid currency object', () => { - const validCurrency = { - code: 'USD', - description: 'United States Dollar', - flag: 'πŸ‡ΊπŸ‡Έ', - }; - - const result = CurrencySchema.safeParse(validCurrency); - expect(result.success).toBe(true); - - if (result.success) { - expect(result.data.code).toBe('USD'); - expect(result.data.description).toBe('United States Dollar'); - expect(result.data.flag).toBe('πŸ‡ΊπŸ‡Έ'); - } - }); - - it('should require all fields', () => { - const incompleteObjects = [ - { - // missing code - description: 'Euro', - flag: 'πŸ‡ͺπŸ‡Ί', - }, - { - code: 'EUR', - // missing description - flag: 'πŸ‡ͺπŸ‡Ί', - }, - { - code: 'EUR', - description: 'Euro', - // missing flag - }, - ]; - - for (const obj of incompleteObjects) { - const result = CurrencySchema.safeParse(obj); - expect(result.success).toBe(false); - } - }); - - it('should validate that all fields are strings', () => { - const invalidTypes = [ - { - code: 123, // should be string - description: 'Invalid Code', - flag: 'πŸ‡ΊπŸ‡Έ', - }, - { - code: 'USD', - description: true, // should be string - flag: 'πŸ‡ΊπŸ‡Έ', - }, - { - code: 'USD', - description: 'United States Dollar', - flag: null, // should be string - }, - ]; - - for (const obj of invalidTypes) { - const result = CurrencySchema.safeParse(obj); - expect(result.success).toBe(false); - } - }); - - it('should handle various currency examples', () => { - const currencies = [ - { - code: 'EUR', - description: 'Euro', - flag: 'πŸ‡ͺπŸ‡Ί', - }, - { - code: 'GBP', - description: 'British Pound Sterling', - flag: 'πŸ‡¬πŸ‡§', - }, - { - code: 'JPY', - description: 'Japanese Yen', - flag: 'πŸ‡―πŸ‡΅', - }, - { - code: 'CAD', - description: 'Canadian Dollar', - flag: 'πŸ‡¨πŸ‡¦', - }, - { - code: 'AUD', - description: 'Australian Dollar', - flag: 'πŸ‡¦πŸ‡Ί', - }, - ]; - - for (const currency of currencies) { - const result = CurrencySchema.safeParse(currency); - expect(result.success).toBe(true); - - if (result.success) { - expect(result.data.code).toBe(currency.code); - expect(result.data.description).toBe(currency.description); - expect(result.data.flag).toBe(currency.flag); - } - } - }); - - it('should handle empty strings', () => { - const currencyWithEmptyStrings = { - code: '', - description: '', - flag: '', - }; - - const result = CurrencySchema.safeParse(currencyWithEmptyStrings); - expect(result.success).toBe(true); - - if (result.success) { - expect(result.data.code).toBe(''); - expect(result.data.description).toBe(''); - expect(result.data.flag).toBe(''); - } - }); - - it('should handle long strings', () => { - const currencyWithLongStrings = { - code: 'VERYLONGCURRENCYCODE', - description: - 'This is a very long description for a currency that might not exist in real life but should still be valid according to our schema', - flag: 'πŸ³οΈβ€πŸŒˆπŸ³οΈβ€βš§οΈπŸ‡ΊπŸ‡³', // Multiple flag emojis - }; - - const result = CurrencySchema.safeParse(currencyWithLongStrings); - expect(result.success).toBe(true); - - if (result.success) { - expect(result.data.code).toBe('VERYLONGCURRENCYCODE'); - expect(result.data.description).toBe( - 'This is a very long description for a currency that might not exist in real life but should still be valid according to our schema' - ); - expect(result.data.flag).toBe('πŸ³οΈβ€πŸŒˆπŸ³οΈβ€βš§οΈπŸ‡ΊπŸ‡³'); - } - }); - - it('should handle special characters and unicode', () => { - const currencyWithSpecialChars = { - code: 'BTC-β‚Ώ', - description: 'Bitcoin (β‚Ώ) - Digital Currency with special chars: @#$%^&*()[]{}', - flag: 'β‚Ώ', - }; - - const result = CurrencySchema.safeParse(currencyWithSpecialChars); - expect(result.success).toBe(true); - - if (result.success) { - expect(result.data.code).toBe('BTC-β‚Ώ'); - expect(result.data.description).toBe( - 'Bitcoin (β‚Ώ) - Digital Currency with special chars: @#$%^&*()[]{}' - ); - expect(result.data.flag).toBe('β‚Ώ'); - } - }); - - it('should reject additional properties', () => { - const currencyWithExtraProps = { - code: 'USD', - description: 'United States Dollar', - flag: 'πŸ‡ΊπŸ‡Έ', - extraProperty: 'This should not be allowed', - anotherExtra: 123, - }; - - const result = CurrencySchema.safeParse(currencyWithExtraProps); - // Zod by default allows additional properties unless .strict() is used - // Since the schema doesn't use .strict(), extra properties are allowed but ignored - expect(result.success).toBe(true); - - if (result.success) { - // Extra properties should not be included in the result - expect('extraProperty' in result.data).toBe(false); - expect('anotherExtra' in result.data).toBe(false); - expect(result.data.code).toBe('USD'); - expect(result.data.description).toBe('United States Dollar'); - expect(result.data.flag).toBe('πŸ‡ΊπŸ‡Έ'); - } - }); -}); diff --git a/packages/server-shared/src/currency/index.ts b/packages/server-shared/src/currency/index.ts deleted file mode 100644 index 31f9dd1a3..000000000 --- a/packages/server-shared/src/currency/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './currency.types'; -export * from './responses'; diff --git a/packages/server-shared/src/currency/responses.ts b/packages/server-shared/src/currency/responses.ts deleted file mode 100644 index c04531a7b..000000000 --- a/packages/server-shared/src/currency/responses.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { z } from 'zod'; -import { CurrencySchema } from './currency.types'; - -export const CurrencyResponseSchema = z.array(CurrencySchema); - -export type CurrencyResponse = z.infer; diff --git a/packages/server-shared/src/currency/currency.types.ts b/packages/server-shared/src/dictionary/currency.ts similarity index 58% rename from packages/server-shared/src/currency/currency.types.ts rename to packages/server-shared/src/dictionary/currency.ts index 1b6f1ca94..0f6c68898 100644 --- a/packages/server-shared/src/currency/currency.types.ts +++ b/packages/server-shared/src/dictionary/currency.ts @@ -7,3 +7,7 @@ export const CurrencySchema = z.object({ }); export type Currency = z.infer; + +export const CurrencyResponseSchema = z.array(CurrencySchema); + +export type CurrencyResponse = z.infer; diff --git a/packages/server-shared/src/dictionary/index.ts b/packages/server-shared/src/dictionary/index.ts index 3ef6f18e6..2366631d0 100644 --- a/packages/server-shared/src/dictionary/index.ts +++ b/packages/server-shared/src/dictionary/index.ts @@ -1 +1,2 @@ export * from './color-themes'; +export * from './currency';