diff --git a/src/app/(main)/boards/[boardId]/BoardComponentSelect.tsx b/src/app/(main)/boards/[boardId]/BoardComponentSelect.tsx index 0849a7818..08650b9cc 100644 --- a/src/app/(main)/boards/[boardId]/BoardComponentSelect.tsx +++ b/src/app/(main)/boards/[boardId]/BoardComponentSelect.tsx @@ -20,6 +20,7 @@ import { type BoardEntityType, type BoardType, getComponentEntity, + isBoardComponentSupported, isOpenBoardType, } from '@/lib/boards'; import { @@ -64,6 +65,10 @@ export function BoardComponentSelect({ () => CATEGORIES.flatMap(category => getComponentsByCategory(category.key)), [], ); + const activeEntityType = isOpenBoardType(boardType) ? selectedEntityType : boardEntityType; + const isSelectedDefSupported = selectedDef + ? isBoardComponentSupported(selectedDef.type, activeEntityType) + : false; const getDefaultConfigValues = (def: ComponentDefinition, config?: BoardComponentConfig) => { const defaults: Record = {}; @@ -90,7 +95,11 @@ export function BoardComponentSelect({ const definition = allDefinitions.find(def => def.type === initialConfig.type); - if (!definition) { + if (!definition || !isBoardComponentSupported(definition.type, activeEntityType)) { + setSelectedDef(null); + setConfigValues({}); + setTitle(''); + setDescription(''); return; } @@ -105,12 +114,24 @@ export function BoardComponentSelect({ }, [ initialConfig, allDefinitions, + activeEntityType, boardEntityId, boardEntityType, initialEntity.entityId, initialEntity.entityType, ]); + useEffect(() => { + if (!selectedDef || isSelectedDefSupported) { + return; + } + + setSelectedDef(null); + setConfigValues({}); + setTitle(''); + setDescription(''); + }, [isSelectedDefSupported, selectedDef]); + const handleSelectComponent = (def: ComponentDefinition) => { setSelectedDef(def); setConfigValues(getDefaultConfigValues(def)); @@ -141,7 +162,7 @@ export function BoardComponentSelect({ }; const handleAdd = () => { - if (!selectedDef || (needsWebsite && !resolvedEntityId)) return; + if (!selectedDef || !isSelectedDefSupported || (needsWebsite && !resolvedEntityId)) return; const props: Record = {}; @@ -182,14 +203,20 @@ export function BoardComponentSelect({ } : null; - const canSave = !!selectedDef && (!needsWebsite || !!resolvedEntityId); + const canSave = !!selectedDef && isSelectedDefSupported && (!needsWebsite || !!resolvedEntityId); return ( {CATEGORIES.map(category => { - const components = getComponentsByCategory(category.key); + const components = getComponentsByCategory(category.key).filter(def => + isBoardComponentSupported(def.type, activeEntityType), + ); + + if (!components.length) { + return null; + } return ( diff --git a/src/lib/__tests__/boards.test.ts b/src/lib/__tests__/boards.test.ts new file mode 100644 index 000000000..5b43ba428 --- /dev/null +++ b/src/lib/__tests__/boards.test.ts @@ -0,0 +1,18 @@ +import { + BOARD_ENTITY_TYPES, + isBoardComponentSupported, +} from '../boards'; + +test('isBoardComponentSupported allows events chart on website boards', () => { + expect(isBoardComponentSupported('EventsChart', BOARD_ENTITY_TYPES.website)).toBe(true); +}); + +test('isBoardComponentSupported rejects events chart on pixel and link boards', () => { + expect(isBoardComponentSupported('EventsChart', BOARD_ENTITY_TYPES.pixel)).toBe(false); + expect(isBoardComponentSupported('EventsChart', BOARD_ENTITY_TYPES.link)).toBe(false); +}); + +test('isBoardComponentSupported leaves other components available for all board entities', () => { + expect(isBoardComponentSupported('WebsiteChart', BOARD_ENTITY_TYPES.pixel)).toBe(true); + expect(isBoardComponentSupported('TextBlock', BOARD_ENTITY_TYPES.link)).toBe(true); +}); diff --git a/src/lib/boards.ts b/src/lib/boards.ts index eadfdedf1..7fdae85be 100644 --- a/src/lib/boards.ts +++ b/src/lib/boards.ts @@ -18,6 +18,9 @@ export type BoardType = (typeof BOARD_TYPES)[keyof typeof BOARD_TYPES]; export type BoardEntityType = (typeof BOARD_ENTITY_TYPES)[keyof typeof BOARD_ENTITY_TYPES]; const boardTypes = new Set(Object.values(BOARD_TYPES)); +const boardComponentEntityTypes: Partial> = { + EventsChart: [BOARD_ENTITY_TYPES.website], +}; export function getLegacyBoardType(parameters?: BoardParameters): BoardType { if (parameters?.pixelId) { @@ -140,6 +143,19 @@ export function getResolvedComponentEntity( return getComponentEntity(config); } +export function isBoardComponentSupported( + componentType: string, + entityType?: BoardEntityType, +) { + const supportedEntityTypes = boardComponentEntityTypes[componentType]; + + if (!entityType || !supportedEntityTypes) { + return true; + } + + return supportedEntityTypes.includes(entityType); +} + export function getFirstBoardComponentEntity( board?: Pick | Partial, ) {