reusable hook implenation

This commit is contained in:
Nate Kelley 2025-07-18 09:53:12 -06:00
parent 9048b6dad0
commit 21d1743fee
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
6 changed files with 63 additions and 45 deletions

View File

@ -2,11 +2,10 @@ import { useQuery, QueryClient } from '@tanstack/react-query';
import { getColorThemes } from './requests';
import { dictionariesQueryKeys } from '../../query_keys/dictionaries';
export const useColorThemes = () => {
export const useColorDictionaryThemes = () => {
return useQuery({
...dictionariesQueryKeys.colorThemes,
initialData: [],
initialDataUpdatedAt: 0,
queryFn: getColorThemes
});
};

View File

@ -3,7 +3,7 @@ import { queryOptions } from '@tanstack/react-query';
export const colorThemes = queryOptions<ColorThemeDictionariesResponse>({
queryKey: ['color-themes', 'list'],
staleTime: 60 * 1000 * 60 * 24 * 7 // 7 days
staleTime: 60 * 1000 * 60 * 24 * 3 // 3 days
});
export const dictionariesQueryKeys = {

View File

@ -1,27 +1,30 @@
import React from 'react';
import { DefaultThemeSelectorBase } from './DefaultThemeSelectorBase';
import { useGetMyUserInfo } from '@/api/buster_rest/users/queryRequests';
import { useColorThemes } from '@/api/buster_rest/dictionaries';
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';
import { useGetPalettes } from '@/context-hooks/useGetOrganizationPalettes';
export const DefaultThemeSelector = React.memo(
({ className, themeListClassName }: { className?: string; themeListClassName?: string }) => {
const { data: userData } = useGetMyUserInfo();
const { data: themes, isFetched: isFetchedThemes, isError: isErrorThemes } = useColorThemes();
const {
isErrorDictionaryPalettes,
isFetchedDictionaryPalettes,
organizationPalettes,
dictionaryPalettes,
selectedPaletteId
} = useGetPalettes();
const { onCreateCustomTheme, onDeleteCustomTheme, onModifyCustomTheme, onSelectTheme } =
useThemeOperations();
const organization = userData?.organizations?.[0];
const organizationColorPalettes = organization?.organizationColorPalettes;
if (!isFetchedDictionaryPalettes) return <CircleSpinnerLoader />;
if (!organizationColorPalettes || !organization) return null;
if (!isFetchedThemes) return <CircleSpinnerLoader />;
if (isErrorThemes)
if (isErrorDictionaryPalettes)
return (
<StatusCard
title="Error fetching themes"
@ -32,9 +35,9 @@ export const DefaultThemeSelector = React.memo(
return (
<DefaultThemeSelectorBase
customThemes={organizationColorPalettes.palettes}
selectedThemeId={organizationColorPalettes.selectedId}
themes={themes || []}
customThemes={organizationPalettes}
selectedThemeId={selectedPaletteId}
themes={dictionaryPalettes || []}
onCreateCustomTheme={onCreateCustomTheme}
onDeleteCustomTheme={onDeleteCustomTheme}
onModifyCustomTheme={onModifyCustomTheme}

View File

@ -1,15 +1,15 @@
'use client';
import React, { useMemo } from 'react';
import React from 'react';
import { SettingsCards } from './SettingsCard';
import { Text } from '@/components/ui/typography';
import { useGetMyUserInfo } from '@/api/buster_rest/users/queryRequests';
import { useMount } from '../../../hooks';
import { prefetchColorThemes, useColorThemes } from '../../../api/buster_rest/dictionaries';
import { prefetchColorThemes } from '../../../api/buster_rest/dictionaries';
import { ThemeColorDots } from '../colors/ThemeList/ThemeColorDots';
import { Popover } from '../../ui/popover';
import { DefaultThemeSelector } from '../colors/DefaultThemeSelector';
import { ChevronDown } from '../../ui/icons';
import { useGetPalettes } from '@/context-hooks/useGetOrganizationPalettes';
export const DefaultColorThemeCard = React.memo(() => {
return (
@ -36,22 +36,9 @@ export const DefaultColorThemeCard = React.memo(() => {
DefaultColorThemeCard.displayName = 'DefaultColorThemeCard';
const PickButton = React.memo(() => {
const { data: userData } = useGetMyUserInfo();
const { data: colorThemes } = useColorThemes();
const { defaultPalette } = useGetPalettes();
const organization = userData?.organizations?.[0];
const customThemes = organization?.organizationColorPalettes.palettes ?? [];
const defaultColorThemeId = organization?.organizationColorPalettes.selectedId;
const allThemes = useMemo(() => {
return [...colorThemes, ...customThemes];
}, [colorThemes, customThemes]);
const defaultColorTheme = useMemo(() => {
return allThemes.find((theme) => theme.id === defaultColorThemeId);
}, [allThemes, defaultColorThemeId]);
const hasDefaultColorTheme = !!defaultColorTheme;
const hasDefaultPalette = !!defaultPalette;
useMount(() => {
prefetchColorThemes();
@ -68,8 +55,8 @@ const PickButton = React.memo(() => {
}>
<div className="hover:bg-item-hover flex h-7 min-h-7 cursor-pointer items-center space-x-1.5 overflow-hidden rounded border px-2 py-1 pl-2.5">
<div>
{hasDefaultColorTheme ? (
<ThemeColorDots colors={defaultColorTheme.colors} numberOfColors={'all'} />
{hasDefaultPalette ? (
<ThemeColorDots colors={defaultPalette.colors} numberOfColors={'all'} />
) : (
<Text variant="secondary" size={'xs'}>
No default color theme

View File

@ -0,0 +1,32 @@
import { useGetMyUserInfo } from '@/api/buster_rest/users/queryRequests';
import type { ColorPalette } from '@buster/server-shared/organization';
import { useMemo } from 'react';
import { useColorDictionaryThemes } from '../api/buster_rest/dictionaries';
export const useGetPalettes = () => {
const { data: userData } = useGetMyUserInfo();
const {
data: dictionaryPalettes,
isFetched: isFetchedDictionaryPalettes,
isError: isErrorDictionaryPalettes
} = useColorDictionaryThemes();
const organization = userData?.organizations?.[0];
const organizationPalettes: ColorPalette[] =
organization?.organizationColorPalettes.palettes || [];
const selectedPaletteId = organization?.organizationColorPalettes.selectedId;
return useMemo(() => {
const allPalettes = [...dictionaryPalettes, ...organizationPalettes];
const defaultPalette = allPalettes.find((palette) => palette.id === selectedPaletteId);
return {
allPalettes,
organizationPalettes,
dictionaryPalettes,
selectedPaletteId: selectedPaletteId || null,
defaultPalette,
isFetchedDictionaryPalettes,
isErrorDictionaryPalettes
};
}, [dictionaryPalettes, organizationPalettes, selectedPaletteId, isFetchedDictionaryPalettes]);
};

View File

@ -4,26 +4,21 @@ import type { ChartConfigProps } from '@buster/server-shared/metrics';
import { useMemoizedFn } from '@/hooks';
import type { IColorPalette } from '@/components/features/colors/ThemeList';
import { ThemeList } from '@/components/features/colors/ThemeList';
import { useColorThemes } from '@/api/buster_rest/dictionaries';
import { useGetMyUserInfo } from '@/api/buster_rest/users';
import { EditCustomThemeMenu } from '@/components/features/colors/DefaultThemeSelector/EditCustomThemeMenu';
import { AddThemeProviderWrapper } from '@/components/features/colors/DefaultThemeSelector/AddThemeProviderWrapper';
import { useThemeOperations } from '@/context-hooks/useThemeOperations';
import { useGetPalettes } from '@/context-hooks/useGetOrganizationPalettes';
export const ColorsApp: React.FC<{
colors: ChartConfigProps['colors'];
onUpdateChartConfig: (chartConfig: Partial<ChartConfigProps>) => void;
}> = ({ colors, onUpdateChartConfig }) => {
const { data: themes } = useColorThemes();
const { data: userConfig } = useGetMyUserInfo();
const { onCreateCustomTheme, onDeleteCustomTheme, onModifyCustomTheme } = useThemeOperations();
const organizationPalettes =
userConfig?.organizations?.[0]?.organizationColorPalettes?.palettes || [];
const { organizationPalettes, dictionaryPalettes } = useGetPalettes();
const iThemes: Required<IColorPalette>[] = useMemo(() => {
let hasSelectedTheme = false;
const organizationThemes = organizationPalettes.map((theme: any) => {
const organizationThemes = organizationPalettes.map((theme) => {
const isSelected = isEqual(theme.colors, colors);
if (isSelected) {
hasSelectedTheme = true;
@ -35,7 +30,7 @@ export const ColorsApp: React.FC<{
};
});
const dictionaryThemes = themes.map((theme: any) => {
const dictionaryThemes = dictionaryPalettes.map((theme) => {
const isSelected = !hasSelectedTheme && isEqual(theme.colors, colors);
if (isSelected) {
hasSelectedTheme = true;
@ -49,10 +44,12 @@ export const ColorsApp: React.FC<{
if (!hasSelectedTheme && organizationPalettes.length > 0) {
organizationThemes[0].selected = true;
} else if (!hasSelectedTheme && dictionaryPalettes.length > 0) {
dictionaryThemes[0].selected = true;
}
return [...organizationThemes, ...dictionaryThemes];
}, [themes, organizationPalettes, colors, userConfig]);
}, [dictionaryPalettes, organizationPalettes, colors]);
const onChangeColorTheme = useMemoizedFn((theme: IColorPalette) => {
onUpdateChartConfig({ colors: theme.colors });