diff --git a/.changeset/mighty-drinks-hide.md b/.changeset/mighty-drinks-hide.md new file mode 100644 index 000000000000..955d1ed760cc --- /dev/null +++ b/.changeset/mighty-drinks-hide.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/fuselage-ui-kit": patch +--- + +Fixes multiple selection for MultiStaticSelectElement in UiKit diff --git a/apps/meteor/tests/e2e/apps/apps-modal.spec.ts b/apps/meteor/tests/e2e/apps/apps-modal.spec.ts index 53a4d479bb27..a74a439183d1 100644 --- a/apps/meteor/tests/e2e/apps/apps-modal.spec.ts +++ b/apps/meteor/tests/e2e/apps/apps-modal.spec.ts @@ -7,7 +7,7 @@ import { expect, test } from '../utils/test'; test.use({ storageState: Users.user1.state }); -test.describe.serial('Apps > ContextualBar', () => { +test.describe.serial('Apps > Modal', () => { let poHomeChannel: HomeChannel; let poModal: Modal; diff --git a/packages/fuselage-ui-kit/src/hooks/useUiKitState.spec.ts b/packages/fuselage-ui-kit/src/hooks/useUiKitState.spec.ts new file mode 100644 index 000000000000..4a62fcbda98b --- /dev/null +++ b/packages/fuselage-ui-kit/src/hooks/useUiKitState.spec.ts @@ -0,0 +1,69 @@ +import { + BlockContext, + type MultiStaticSelectElement, +} from '@rocket.chat/ui-kit'; +import { act, renderHook } from '@testing-library/react'; + +import { useUiKitState } from './useUiKitState'; + +describe('state function', () => { + const context = BlockContext.NONE; + + it('should handle arrays', async () => { + const element: MultiStaticSelectElement = { + type: 'multi_static_select', + placeholder: { type: 'plain_text', text: '' }, + options: [], + initialValue: ['A', 'B'], + appId: 'app-id', + blockId: 'block-id', + actionId: 'action-id', + }; + + const { result } = renderHook(() => useUiKitState(element, context), { + legacyRoot: true, + }); + + await act(async () => { + const [, state] = result.current; + await state({ + target: { + value: ['C', 'D'], + }, + }); + }); + + expect(result.current[0].value).toEqual(['C', 'D']); + }); +}); + +describe('action function', () => { + const context = BlockContext.ACTION; + + it('should handle arrays', async () => { + const element: MultiStaticSelectElement = { + type: 'multi_static_select', + placeholder: { type: 'plain_text', text: '' }, + options: [], + initialValue: ['A', 'B'], + appId: 'app-id', + blockId: 'block-id', + actionId: 'action-id', + }; + + const { result } = renderHook(() => useUiKitState(element, context), { + legacyRoot: true, + }); + + await act(async () => { + const [, action] = result.current; + await action({ + target: { + value: ['C', 'D'], + }, + }); + }); + + expect(result.current[0].value).toEqual(['C', 'D']); + }); +}); diff --git a/packages/fuselage-ui-kit/src/hooks/useUiKitState.ts b/packages/fuselage-ui-kit/src/hooks/useUiKitState.ts index 6af9245f9a51..be2813e5d28a 100644 --- a/packages/fuselage-ui-kit/src/hooks/useUiKitState.ts +++ b/packages/fuselage-ui-kit/src/hooks/useUiKitState.ts @@ -42,7 +42,7 @@ export const useUiKitState = ( | Event | { target: EventTarget } | { target: { value: UiKit.ActionOf } } - ) => void + ) => Promise ] => { const { blockId, actionId, appId, dispatchActionConfig } = element; const { @@ -70,15 +70,20 @@ export const useUiKitState = ( const { target: { value: elValue }, } = e; + setLoading(true); if (Array.isArray(value)) { - const idx = value.findIndex((value) => value === elValue); - - if (idx > -1) { - setValue(value.filter((_, i) => i !== idx)); + if (Array.isArray(elValue)) { + setValue(elValue); } else { - setValue([...value, elValue]); + const idx = value.findIndex((value) => value === elValue); + + if (idx > -1) { + setValue(value.filter((_, i) => i !== idx)); + } else { + setValue([...value, elValue]); + } } } else { setValue(elValue);