diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/feedback-options.spec.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/feedback-options.spec.ts new file mode 100644 index 00000000000..8503bcc20b5 --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/feedback-options.spec.ts @@ -0,0 +1,69 @@ +import {describe, expect, it} from 'vitest'; +import {feedbackOptions} from './feedback-options'; + +describe('feedbackOptions', () => { + it('should export feedback options array', () => { + expect(feedbackOptions).toBeDefined(); + expect(Array.isArray(feedbackOptions)).toBe(true); + }); + + it('should contain 4 feedback options', () => { + expect(feedbackOptions).toHaveLength(4); + }); + + it('should have correct structure for each option', () => { + feedbackOptions.forEach((option) => { + expect(option).toHaveProperty('id'); + expect(option).toHaveProperty('localeKey'); + expect(option).toHaveProperty('correspondingAnswer'); + expect(typeof option.id).toBe('string'); + expect(typeof option.localeKey).toBe('string'); + }); + }); + + it('should include "does_not_answer" option', () => { + const option = feedbackOptions.find( + (opt) => opt.correspondingAnswer === 'does_not_answer' + ); + + expect(option).toBeDefined(); + expect(option?.id).toBe('does-not-answer'); + expect(option?.localeKey).toBe( + 'smart-snippet-feedback-reason-does-not-answer' + ); + }); + + it('should include "partially_answers" option', () => { + const option = feedbackOptions.find( + (opt) => opt.correspondingAnswer === 'partially_answers' + ); + + expect(option).toBeDefined(); + expect(option?.id).toBe('partially-answers'); + expect(option?.localeKey).toBe( + 'smart-snippet-feedback-reason-partially-answers' + ); + }); + + it('should include "was_not_a_question" option', () => { + const option = feedbackOptions.find( + (opt) => opt.correspondingAnswer === 'was_not_a_question' + ); + + expect(option).toBeDefined(); + expect(option?.id).toBe('was-not-a-question'); + expect(option?.localeKey).toBe( + 'smart-snippet-feedback-reason-was-not-a-question' + ); + }); + + it('should include "other" option', () => { + const option = feedbackOptions.find( + (opt) => opt.correspondingAnswer === 'other' + ); + + expect(option).toBeDefined(); + expect(option?.id).toBe('other'); + expect(option?.localeKey).toBe('smart-snippet-feedback-reason-other'); + }); +}); diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/feedback-options.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/feedback-options.ts new file mode 100644 index 00000000000..9d8e0cf6af7 --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/feedback-options.ts @@ -0,0 +1,28 @@ +import type {SmartSnippetFeedback} from '@coveo/headless'; + +export const feedbackOptions: { + id: string; + localeKey: string; + correspondingAnswer: SmartSnippetFeedback | 'other'; +}[] = [ + { + id: 'does-not-answer', + localeKey: 'smart-snippet-feedback-reason-does-not-answer', + correspondingAnswer: 'does_not_answer', + }, + { + id: 'partially-answers', + localeKey: 'smart-snippet-feedback-reason-partially-answers', + correspondingAnswer: 'partially_answers', + }, + { + id: 'was-not-a-question', + localeKey: 'smart-snippet-feedback-reason-was-not-a-question', + correspondingAnswer: 'was_not_a_question', + }, + { + id: 'other', + localeKey: 'smart-snippet-feedback-reason-other', + correspondingAnswer: 'other', + }, +]; diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-body.spec.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-body.spec.ts new file mode 100644 index 00000000000..2cea8e82220 --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-body.spec.ts @@ -0,0 +1,48 @@ +import {html} from 'lit'; +import {describe, expect, it, vi} from 'vitest'; +import {renderFunctionFixture} from '@/vitest-utils/testing-helpers/fixture'; +import {renderModalBody} from './modal-body'; + +describe('#renderModalBody', () => { + const formId = 'test-form-id'; + const onSubmit = vi.fn((e: Event) => e.preventDefault()); + + const renderComponent = async () => { + return await renderFunctionFixture( + html`${renderModalBody({ + props: {formId, onSubmit}, + })(html`
Child content
`)}` + ); + }; + + it('should render with valid props', async () => { + const element = await renderComponent(); + expect(element).toBeDefined(); + }); + + it('should render form element with correct attributes', async () => { + const element = await renderComponent(); + const form = element.querySelector('form'); + + expect(form).not.toBeNull(); + expect(form?.getAttribute('id')).toBe(formId); + expect(form?.getAttribute('slot')).toBe('body'); + expect(form?.part).toContain('form'); + }); + + it('should render children inside form', async () => { + const element = await renderComponent(); + const form = element.querySelector('form'); + + expect(form).toHaveTextContent('Child content'); + }); + + it('should call onSubmit when form is submitted', async () => { + const element = await renderComponent(); + const form = element.querySelector('form') as HTMLFormElement; + + form.dispatchEvent(new Event('submit')); + + expect(onSubmit).toHaveBeenCalled(); + }); +}); diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-body.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-body.ts new file mode 100644 index 00000000000..6751d93afb8 --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-body.ts @@ -0,0 +1,20 @@ +import {html} from 'lit'; +import type {FunctionalComponentWithChildren} from '@/src/utils/functional-component-utils'; + +export interface ModalBodyProps { + formId: string; + onSubmit: (e: Event) => void; +} + +export const renderModalBody: FunctionalComponentWithChildren = + ({props: {formId, onSubmit}}) => + (children) => + html`
+ ${children} +
`; diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-details.spec.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-details.spec.ts new file mode 100644 index 00000000000..f51fb9c7be6 --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-details.spec.ts @@ -0,0 +1,89 @@ +import type {SmartSnippetFeedback} from '@coveo/headless'; +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import {beforeAll, describe, expect, it, vi} from 'vitest'; +import {renderFunctionFixture} from '@/vitest-utils/testing-helpers/fixture'; +import {createTestI18n} from '@/vitest-utils/testing-helpers/i18n-utils'; +import {renderModalDetails} from './modal-details'; + +describe('#renderModalDetails', () => { + let i18n: i18n; + + beforeAll(async () => { + i18n = await createTestI18n(); + }); + + const renderComponent = async ( + currentAnswer?: SmartSnippetFeedback | 'other', + detailsInputRef?: (el: Element | undefined) => void + ) => { + return await renderFunctionFixture( + html`${renderModalDetails({ + props: {currentAnswer, i18n, detailsInputRef}, + })}` + ); + }; + + it('should render with valid props when currentAnswer is "other"', async () => { + const element = await renderComponent('other'); + expect(element).toBeDefined(); + }); + + it('should not render when currentAnswer is not "other"', async () => { + const element = await renderComponent('does_not_answer'); + const fieldset = element.querySelector('fieldset'); + + expect(fieldset).toBeNull(); + }); + + it('should not render when currentAnswer is undefined', async () => { + const element = await renderComponent(); + const fieldset = element.querySelector('fieldset'); + + expect(fieldset).toBeNull(); + }); + + it('should render fieldset when currentAnswer is "other"', async () => { + const element = await renderComponent('other'); + const fieldset = element.querySelector('fieldset'); + + expect(fieldset).not.toBeNull(); + expect(fieldset?.tagName).toBe('FIELDSET'); + }); + + it('should render legend with correct attributes and classes', async () => { + const element = await renderComponent('other'); + const legend = element.querySelector('legend'); + + expect(legend).not.toBeNull(); + expect(legend?.part).toContain('details-title'); + expect(legend).toHaveClass('text-on-background', 'text-lg', 'font-bold'); + }); + + it('should render translated legend text', async () => { + const element = await renderComponent('other'); + const legend = element.querySelector('legend'); + + expect(legend).toHaveTextContent(i18n.t('details')); + }); + + it('should render textarea with correct attributes', async () => { + const element = await renderComponent('other'); + const textarea = element.querySelector('textarea'); + + expect(textarea).not.toBeNull(); + expect(textarea?.getAttribute('name')).toBe('answer-details'); + expect(textarea?.part).toContain('details-input'); + expect(textarea?.getAttribute('rows')).toBe('4'); + expect(textarea?.hasAttribute('required')).toBe(true); + }); + + it('should apply ref when detailsInputRef is provided', async () => { + const detailsInputRef = vi.fn(); + + const element = await renderComponent('other', detailsInputRef); + const textarea = element.querySelector('textarea'); + + expect(detailsInputRef).toHaveBeenCalledWith(textarea); + }); +}); diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-details.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-details.ts new file mode 100644 index 00000000000..e193f7bb753 --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-details.ts @@ -0,0 +1,36 @@ +import type {SmartSnippetFeedback} from '@coveo/headless'; +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import {type RefOrCallback, ref} from 'lit/directives/ref.js'; +import {when} from 'lit/directives/when.js'; +import type {FunctionalComponent} from '@/src/utils/functional-component-utils'; + +export interface ModalDetailsProps { + currentAnswer: SmartSnippetFeedback | 'other'; + i18n: i18n; + detailsInputRef: RefOrCallback; +} + +export const renderModalDetails: FunctionalComponent = ({ + props: {currentAnswer, i18n, detailsInputRef}, +}) => + when( + currentAnswer === 'other', + () => + html`
+ + ${i18n.t('details')} + + +
` + ); diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-footer.spec.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-footer.spec.ts new file mode 100644 index 00000000000..cd33951922f --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-footer.spec.ts @@ -0,0 +1,85 @@ +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import {beforeAll, describe, expect, it, vi} from 'vitest'; +import {renderFunctionFixture} from '@/vitest-utils/testing-helpers/fixture'; +import {createTestI18n} from '@/vitest-utils/testing-helpers/i18n-utils'; +import {renderModalFooter} from './modal-footer'; + +vi.mock('@/src/utils/ripple-utils', {spy: true}); + +describe('#renderModalFooter', () => { + let i18n: i18n; + + beforeAll(async () => { + i18n = await createTestI18n(); + }); + + const formId = 'test-form-id'; + const onClick = vi.fn(); + + const renderComponent = async () => { + return await renderFunctionFixture( + html`${renderModalFooter({ + props: {formId, i18n, onClick}, + })}` + ); + }; + + it('should render with valid props', async () => { + const element = await renderComponent(); + expect(element).toBeDefined(); + }); + + it('should render container div with correct attributes', async () => { + const element = await renderComponent(); + const container = element.querySelector('[part="buttons"]'); + + expect(container).not.toBeNull(); + expect(container?.tagName).toBe('DIV'); + expect(container?.getAttribute('slot')).toBe('footer'); + expect(container).toHaveClass('flex', 'justify-end', 'gap-2'); + }); + + it('should render cancel button with correct part', async () => { + const element = await renderComponent(); + const cancelButton = element.querySelector('[part="cancel-button"]'); + + expect(cancelButton).not.toBeNull(); + expect(cancelButton?.tagName).toBe('BUTTON'); + }); + + it('should render cancel button with translated text', async () => { + const element = await renderComponent(); + const cancelButton = element.querySelector('[part="cancel-button"]'); + + expect(cancelButton).toHaveTextContent(i18n.t('cancel')); + }); + + it('should call onClick when cancel button is clicked', async () => { + const element = await renderComponent(); + const cancelButton = element.querySelector( + '[part="cancel-button"]' + ) as HTMLButtonElement; + + cancelButton.click(); + + expect(onClick).toHaveBeenCalled(); + }); + + it('should render submit button with correct part and attributes', async () => { + const element = await renderComponent(); + const submitButton = element.querySelector('[part="submit-button"]'); + + expect(submitButton).not.toBeNull(); + expect(submitButton?.tagName).toBe('BUTTON'); + expect(submitButton?.getAttribute('type')).toBe('submit'); + expect(submitButton?.getAttribute('form')).toBe(formId); + }); + + it('should render submit button with translated text', async () => { + const element = await renderComponent(); + const submitButton = element.querySelector('[part="submit-button"]'); + + expect(submitButton).toHaveTextContent(i18n.t('feedback-send')); + }); +}); diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-footer.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-footer.ts new file mode 100644 index 00000000000..5e7cb35a0fd --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-footer.ts @@ -0,0 +1,32 @@ +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import {renderButton} from '@/src/components/common/button'; +import type {FunctionalComponent} from '@/src/utils/functional-component-utils'; + +export interface ModalFooterProps { + formId: string; + i18n: i18n; + onClick: (e: MouseEvent) => void; +} + +export const renderModalFooter: FunctionalComponent = ({ + props: {formId, i18n, onClick}, +}) => + html`
+ ${renderButton({ + props: { + part: 'cancel-button', + style: 'outline-neutral', + class: 'text-primary', + onClick, + }, + })(html`${i18n.t('cancel')}`)} + ${renderButton({ + props: { + part: 'submit-button', + style: 'primary', + type: 'submit', + form: formId, + }, + })(html`${i18n.t('feedback-send')}`)} +
`; diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-header.spec.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-header.spec.ts new file mode 100644 index 00000000000..be27f19c65e --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-header.spec.ts @@ -0,0 +1,44 @@ +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import {beforeAll, describe, expect, it} from 'vitest'; +import {renderFunctionFixture} from '@/vitest-utils/testing-helpers/fixture'; +import {createTestI18n} from '@/vitest-utils/testing-helpers/i18n-utils'; +import {renderModalHeader} from './modal-header'; + +describe('#renderModalHeader', () => { + let i18n: i18n; + + beforeAll(async () => { + i18n = await createTestI18n(); + }); + + const renderComponent = async () => { + return await renderFunctionFixture( + html`${renderModalHeader({ + props: {i18n}, + })}` + ); + }; + + it('should render with valid props', async () => { + const element = await renderComponent(); + expect(element).toBeDefined(); + }); + + it('should render h1 element with slot="header"', async () => { + const element = await renderComponent(); + const header = element.querySelector('h1[slot="header"]'); + + expect(header).not.toBeNull(); + expect(header?.tagName).toBe('H1'); + }); + + it('should render translated header text', async () => { + const element = await renderComponent(); + const header = element.querySelector('h1[slot="header"]'); + + expect(header).toHaveTextContent( + i18n.t('smart-snippet-feedback-explain-why') + ); + }); +}); diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-header.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-header.ts new file mode 100644 index 00000000000..3c7d115a86b --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-header.ts @@ -0,0 +1,12 @@ +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import type {FunctionalComponent} from '@/src/utils/functional-component-utils'; + +export interface ModalHeaderProps { + i18n: i18n; +} + +export const renderModalHeader: FunctionalComponent = ({ + props: {i18n}, +}) => + html`

${i18n.t('smart-snippet-feedback-explain-why')}

`; diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-option.spec.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-option.spec.ts new file mode 100644 index 00000000000..230ce7c5d04 --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-option.spec.ts @@ -0,0 +1,108 @@ +import type {SmartSnippetFeedback} from '@coveo/headless'; +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import {beforeAll, describe, expect, it, vi} from 'vitest'; +import {renderFunctionFixture} from '@/vitest-utils/testing-helpers/fixture'; +import {createTestI18n} from '@/vitest-utils/testing-helpers/i18n-utils'; +import {renderModalOption} from './modal-option'; + +describe('#renderModalOption', () => { + let i18n: i18n; + + beforeAll(async () => { + i18n = await createTestI18n(); + }); + + const correspondingAnswer: SmartSnippetFeedback = 'does_not_answer'; + const id = 'test-option-id'; + const localeKey = 'smart-snippet-feedback-reason-does-not-answer'; + const onChange = vi.fn(); + + const renderComponent = async ( + currentAnswer?: SmartSnippetFeedback | 'other' + ) => { + return await renderFunctionFixture( + html`${renderModalOption({ + props: { + correspondingAnswer, + currentAnswer, + i18n, + id, + localeKey, + onChange, + }, + })}` + ); + }; + + it('should render with valid props', async () => { + const element = await renderComponent(); + expect(element).toBeDefined(); + }); + + it('should render container div with correct part', async () => { + const element = await renderComponent(); + const container = element.querySelector('[part="reason"]'); + + expect(container).not.toBeNull(); + expect(container?.tagName).toBe('DIV'); + expect(container).toHaveClass('flex', 'items-center'); + }); + + it('should render radio input with correct attributes', async () => { + const element = await renderComponent(); + const radio = element.querySelector('input[type="radio"]'); + + expect(radio).not.toBeNull(); + expect(radio?.getAttribute('id')).toBe(id); + expect(radio?.getAttribute('name')).toBe('answer'); + expect(radio?.part).toContain('reason-radio'); + expect(radio).toHaveClass('mr-2', 'h-4', 'w-4'); + expect(radio?.hasAttribute('required')).toBe(true); + }); + + it('should render label with correct attributes', async () => { + const element = await renderComponent(); + const label = element.querySelector('label'); + + expect(label).not.toBeNull(); + expect(label?.getAttribute('for')).toBe(id); + expect(label?.part).toContain('reason-label'); + }); + + it('should render translated label text', async () => { + const element = await renderComponent(); + const label = element.querySelector('label'); + + expect(label).toHaveTextContent(i18n.t(localeKey)); + }); + + it('should not be checked when currentAnswer does not match', async () => { + const element = await renderComponent('other'); + const radio = element.querySelector( + 'input[type="radio"]' + ) as HTMLInputElement; + + expect(radio.checked).toBe(false); + }); + + it('should be checked when currentAnswer matches correspondingAnswer', async () => { + const element = await renderComponent(correspondingAnswer); + const radio = element.querySelector( + 'input[type="radio"]' + ) as HTMLInputElement; + + expect(radio.checked).toBe(true); + }); + + it('should call onChange when radio is changed', async () => { + const element = await renderComponent(); + const radio = element.querySelector( + 'input[type="radio"]' + ) as HTMLInputElement; + + radio.dispatchEvent(new Event('change')); + + expect(onChange).toHaveBeenCalled(); + }); +}); diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-option.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-option.ts new file mode 100644 index 00000000000..f8c8e211df8 --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-option.ts @@ -0,0 +1,30 @@ +import type {SmartSnippetFeedback} from '@coveo/headless'; +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import type {FunctionalComponent} from '@/src/utils/functional-component-utils'; + +export interface ModalOptionProps { + correspondingAnswer: SmartSnippetFeedback | 'other'; + currentAnswer?: SmartSnippetFeedback | 'other'; + i18n: i18n; + id: string; + localeKey: string; + onChange: (e: Event) => void; +} + +export const renderModalOption: FunctionalComponent = ({ + props: {correspondingAnswer, currentAnswer, i18n, id, localeKey, onChange}, +}) => + html`
+ + +
`; diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-options.spec.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-options.spec.ts new file mode 100644 index 00000000000..cd44c8ec57f --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-options.spec.ts @@ -0,0 +1,60 @@ +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import {beforeAll, describe, expect, it} from 'vitest'; +import {renderFunctionFixture} from '@/vitest-utils/testing-helpers/fixture'; +import {createTestI18n} from '@/vitest-utils/testing-helpers/i18n-utils'; +import {renderModalOptions} from './modal-options'; + +describe('#renderModalOptions', () => { + let i18n: i18n; + + beforeAll(async () => { + i18n = await createTestI18n(); + }); + + const renderComponent = async () => { + return await renderFunctionFixture( + html`${renderModalOptions({ + props: {i18n}, + })(html`
Child options
`)}` + ); + }; + + it('should render with valid props', async () => { + const element = await renderComponent(); + expect(element).toBeDefined(); + }); + + it('should render fieldset element', async () => { + const element = await renderComponent(); + const fieldset = element.querySelector('fieldset'); + + expect(fieldset).not.toBeNull(); + expect(fieldset?.tagName).toBe('FIELDSET'); + }); + + it('should render legend with correct attributes and classes', async () => { + const element = await renderComponent(); + const legend = element.querySelector('legend'); + + expect(legend).not.toBeNull(); + expect(legend?.part).toContain('reason-title'); + expect(legend).toHaveClass('text-on-background', 'text-lg', 'font-bold'); + }); + + it('should render translated legend text', async () => { + const element = await renderComponent(); + const legend = element.querySelector('legend'); + + expect(legend).toHaveTextContent( + i18n.t('smart-snippet-feedback-select-reason') + ); + }); + + it('should render children inside fieldset', async () => { + const element = await renderComponent(); + const fieldset = element.querySelector('fieldset'); + + expect(fieldset).toHaveTextContent('Child options'); + }); +}); diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-options.ts b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-options.ts new file mode 100644 index 00000000000..d09876d421a --- /dev/null +++ b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/modal-options.ts @@ -0,0 +1,19 @@ +import type {i18n} from 'i18next'; +import {html} from 'lit'; +import type {FunctionalComponentWithChildren} from '@/src/utils/functional-component-utils'; + +export interface ModalOptionsProps { + i18n: i18n; +} + +export const renderModalOptions: FunctionalComponentWithChildren< + ModalOptionsProps +> = + ({props: {i18n}}) => + (children) => + html`
+ + ${i18n.t('smart-snippet-feedback-select-reason')} + + ${children} +
`; diff --git a/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/smart-snippet-feedback-modal-common.tsx b/packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/stencil-smart-snippet-feedback-modal-common.tsx similarity index 100% rename from packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/smart-snippet-feedback-modal-common.tsx rename to packages/atomic/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/stencil-smart-snippet-feedback-modal-common.tsx diff --git a/packages/atomic/src/components/insight/smart-snippets/atomic-insight-smart-snippet-feedback-modal/atomic-insight-smart-snippet-feedback-modal.tsx b/packages/atomic/src/components/insight/smart-snippets/atomic-insight-smart-snippet-feedback-modal/atomic-insight-smart-snippet-feedback-modal.tsx index 5304ad00199..db746c12e7a 100644 --- a/packages/atomic/src/components/insight/smart-snippets/atomic-insight-smart-snippet-feedback-modal/atomic-insight-smart-snippet-feedback-modal.tsx +++ b/packages/atomic/src/components/insight/smart-snippets/atomic-insight-smart-snippet-feedback-modal/atomic-insight-smart-snippet-feedback-modal.tsx @@ -7,7 +7,7 @@ import { SmartSnippetFeedbackModalHeader, SmartSnippetFeedbackModalOption, smartSnippetFeedbackOptions, -} from '@/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/smart-snippet-feedback-modal-common'; +} from '@/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/stencil-smart-snippet-feedback-modal-common'; import {updateBreakpoints} from '@/src/utils/replace-breakpoint-utils'; import {randomID} from '@/src/utils/utils'; import { diff --git a/packages/atomic/src/components/search/smart-snippets/atomic-smart-snippet-feedback-modal/atomic-smart-snippet-feedback-modal.tsx b/packages/atomic/src/components/search/smart-snippets/atomic-smart-snippet-feedback-modal/atomic-smart-snippet-feedback-modal.tsx index 72e7dba5cd0..6d5dde15f55 100644 --- a/packages/atomic/src/components/search/smart-snippets/atomic-smart-snippet-feedback-modal/atomic-smart-snippet-feedback-modal.tsx +++ b/packages/atomic/src/components/search/smart-snippets/atomic-smart-snippet-feedback-modal/atomic-smart-snippet-feedback-modal.tsx @@ -7,7 +7,7 @@ import { SmartSnippetFeedbackModalHeader, SmartSnippetFeedbackModalOption, smartSnippetFeedbackOptions, -} from '@/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/smart-snippet-feedback-modal-common'; +} from '@/src/components/common/smart-snippets/atomic-smart-snippet-feedback-modal/stencil-smart-snippet-feedback-modal-common'; import {updateBreakpoints} from '@/src/utils/replace-breakpoint-utils'; import {randomID} from '@/src/utils/utils'; import {