Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui-editor): enable component poc and feedback form #14210

Merged
merged 23 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const buttonTexts: ButtonTexts = {
};

const heading = 'Heading';
const description = 'Description';

describe('FeedbackForm', () => {
it('should render FeedbackForm', () => {
Expand Down Expand Up @@ -102,8 +103,10 @@ const renderFeedbackForm = ({
render(
<FeedbackFormContext.Provider value={{ answers: {}, setAnswers: setAnswers || jest.fn() }}>
<FeedbackForm
id='test'
buttonTexts={buttonTexts}
heading={heading}
description={description}
questions={questions}
position={position || 'inline'}
onSubmit={jest.fn()}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useRef } from 'react';
import { StudioButton, StudioModal } from '@studio/components';
import { StudioButton, StudioModal, StudioParagraph } from '@studio/components';
import type { ButtonTexts, QuestionConfig, QuestionsProps } from '../types/QuestionsProps';
import { YesNoQuestion } from './Question/YesNoQuestion';
import { useFeedbackFormContext } from '../contexts/FeedbackFormContext';
Expand All @@ -9,17 +9,21 @@ import { getDefaultAnswerValueForQuestion } from '../utils/questionUtils';
import type { AnswerType } from '../types/AnswerType';

type FeedbackFormProps = {
id: string;
buttonTexts: ButtonTexts;
heading: string;
description: string;
questions: QuestionConfig[];
position?: 'inline' | 'fixed';
onSubmit: (answers: Record<string, AnswerType>) => void;
};

export function FeedbackForm({
id,
questions,
buttonTexts,
heading,
description,
position = 'inline',
onSubmit,
}: FeedbackFormProps): React.ReactElement {
Expand All @@ -42,7 +46,10 @@ export function FeedbackForm({
};

const handleSubmit = () => {
onSubmit(answers);
onSubmit({
...answers,
feedbackFormId: id,
});
handleCloseModal();
};

Expand Down Expand Up @@ -77,6 +84,7 @@ export function FeedbackForm({
closeButtonTitle={buttonTexts.close}
ref={modalRef}
>
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
<StudioParagraph spacing={true}>{description}</StudioParagraph>
{questions.map((question) => {
return renderQuestion(question);
})}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import React, { type ChangeEvent } from 'react';
import type { QuestionsProps } from '../../types/QuestionsProps';
import { StudioTextfield } from '@studio/components';
import { StudioTextarea } from '@studio/components';
import { useDebounce } from '@studio/hooks';

export function TextQuestion({ id, label, value, onChange }: QuestionsProps): React.ReactElement {
const { debounce } = useDebounce({ debounceTimeInMs: 500 });
const debouncedOnChange = (newValue: string) => debounce(() => onChange(id, newValue));
return (
<StudioTextfield
<StudioTextarea
id={id}
label={label}
value={value}
onChange={(e: ChangeEvent<HTMLInputElement>) => debouncedOnChange(e.target.value)}
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => debouncedOnChange(e.target.value)}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { StudioButton, StudioParagraph } from '@studio/components';
import { StudioButton, StudioLabelAsParagraph } from '@studio/components';
import { ThumbDownFillIcon, ThumbDownIcon, ThumbUpFillIcon, ThumbUpIcon } from '@studio/icons';
import type { QuestionsProps } from '../../types/QuestionsProps';
import classes from './YesNoQuestion.module.css';
Expand All @@ -26,7 +26,7 @@ export function YesNoQuestion({ id, label, value, buttonLabels, onChange }: YesN

return (
<div>
<StudioParagraph>{label}</StudioParagraph>
<StudioLabelAsParagraph>{label}</StudioLabelAsParagraph>
nkylstad marked this conversation as resolved.
Show resolved Hide resolved
<div className={classes.buttons}>
<StudioButton
variant='tertiary'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ describe('FeedbackFormImpl', () => {
it('should render FeedbackFormImpl', () => {
const feedbackForm = new FeedbackFormImpl({
onSubmit: jest.fn(),
id: 'test',
buttonTexts: {
submit: 'Submit',
trigger: 'Give feedback',
close: 'Close',
},
heading: 'Give feedback - heading',
description: 'Description',
questions: mockQuestions,
});

Expand All @@ -25,13 +27,15 @@ describe('FeedbackFormImpl', () => {
it('should open form modal when trigger button is clicked', async () => {
const user = userEvent.setup();
const feedbackForm = new FeedbackFormImpl({
id: 'test',
onSubmit: jest.fn(),
buttonTexts: {
submit: 'Submit',
trigger: 'Give feedback',
close: 'Close',
},
heading: 'Give feedback - heading',
description: 'Description',
questions: mockQuestions,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@ import { FeedbackForm } from '../FeedbackForm/FeedbackForm';
import type { AnswerType } from '../types/AnswerType';

export class FeedbackFormImpl {
private readonly id: string;
private readonly buttonTexts: ButtonTexts;
private readonly heading: string;
private readonly description: string;
private readonly questions: QuestionConfig[];
private readonly position: 'inline' | 'fixed' = 'inline';
private readonly onSubmit: (answers: Record<string, any>) => void;

constructor(config: {
id: string;
buttonTexts: ButtonTexts;
heading: string;
description: string;
questions: QuestionConfig[];
position?: 'inline' | 'fixed';
onSubmit: (answers: Record<string, AnswerType>) => void;
}) {
this.id = config.id;
this.buttonTexts = config.buttonTexts;
this.heading = config.heading;
this.description = config.description;
this.questions = config.questions;
this.getFeedbackForm = this.getFeedbackForm.bind(this);
this.position = config.position || 'inline';
Expand All @@ -30,8 +36,10 @@ export class FeedbackFormImpl {
return (
<FeedbackFormContextProvider>
<FeedbackForm
id={this.id}
buttonTexts={this.buttonTexts}
heading={this.heading}
description={this.description}
questions={this.questions}
position={this.position}
onSubmit={this.onSubmit}
Expand Down
3 changes: 3 additions & 0 deletions frontend/packages/shared/src/api/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export const dataModelAddXsdFromRepoPath = (org, app, filePath) => `${basePath}/
// Deployment
// See frontend/app-development/utils/urlHelper.ts Deployments

// Feedback form
export const submitFeedbackPath = (org, app) => `${basePath}/${org}/${app}/feedbackform/submit`; // Post

// FormEditor
export const ruleHandlerPath = (org, app, layoutSetName) => `${basePath}/${org}/${app}/app-development/rule-handler?${s({ layoutSetName })}`; // Get, Post
export const widgetSettingsPath = (org, app) => `${basePath}/${org}/${app}/app-development/widget-settings`; // Get
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type React from 'react';
import { submitFeedbackPath } from 'app-shared/api/paths';
import { useStudioEnvironmentParams } from 'app-shared/hooks/useStudioEnvironmentParams';
import { post } from 'app-shared/utils/networking';
import { FeedbackFormImpl } from '@studio/feedback-form';
import { toast } from 'react-toastify';

export function FeedbackForm(): React.ReactNode {
nkylstad marked this conversation as resolved.
Show resolved Hide resolved
const { org, app } = useStudioEnvironmentParams();

const submitFeedback = async (answers: Record<string, string>) => {
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
// Using explicit texts here to avoid adding these potentially
// temporary and unnecessary translations to the translation files.
try {
// Using regular axios post rather than a mutation hook, since we are not storing
// the feedback in the cache, nor are we updating any state.
await post(submitFeedbackPath(org, app), { answers: { ...answers } });
toast.success('Takk for tilbakemeldingen!');
wrt95 marked this conversation as resolved.
Show resolved Hide resolved
nkylstad marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
console.error('Failed to submit feedback', error);
toast.error('Noe gikk galt. Prøv igjen senere.');
}
};

// Using explicit texts here to avoid adding these potentially
// temporary and unnecessary translations to the translation files.
const feedbackForm = new FeedbackFormImpl({
id: 'add-component-poc-feedback',
onSubmit: submitFeedback,
buttonTexts: {
submit: 'Send',
trigger: 'Gi tilbakemelding',
close: 'Lukk',
},
heading: 'Gi tilbakemelding',
description:
'Hei! Vi ser du tester et nytt design for å legge til komponenter og vil gjerne høre hva du synes!',
nkylstad marked this conversation as resolved.
Show resolved Hide resolved
position: 'fixed',
questions: [
{
id: 'bedreJaNei',
type: 'yesNo',
questionText: 'Likte du dette designet bedre?',
buttonLabels: {
yes: 'Ja',
no: 'Nei',
},
},
{
id: 'kommentar',
type: 'text',
questionText: 'Har du kommentarer eller forslag til forbedringer?',
},
],
});

return feedbackForm.getFeedbackForm();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,51 @@
import classes from './FormDesignerToolbar.module.css';
import { useLayoutSetsQuery } from 'app-shared/hooks/queries/useLayoutSetsQuery';
import { LayoutSetsContainer } from '../components/Elements/LayoutSetsContainer';
import { FeedbackForm } from './DesignView/AddItem/FeedbackForm';
import {
addFeatureFlagToLocalStorage,
removeFeatureFlagFromLocalStorage,
shouldDisplayFeature,
} from 'app-shared/utils/featureToggleUtils';
import { StudioParagraph, StudioSwitch } from '@studio/components';
import { HelpText } from '@digdir/designsystemet-react';

export const FormDesignerToolbar = () => {
const { org, app } = useStudioEnvironmentParams();
const layoutSetsQuery = useLayoutSetsQuery(org, app);
const layoutSetNames = layoutSetsQuery?.data?.sets;

return <section className={classes.toolbar}>{layoutSetNames && <LayoutSetsContainer />}</section>;
const toggleComponentModalPocAndReload = () => {
if (shouldDisplayFeature('addComponentModal')) {
removeFeatureFlagFromLocalStorage('addComponentModal');
} else {
addFeatureFlagToLocalStorage('addComponentModal');
}
window.location.reload();
};

return (
<section className={classes.toolbar}>
{layoutSetNames && <LayoutSetsContainer />}
<div style={{ display: 'flex', flexDirection: 'row', gap: 'var(--fds-spacing-2)' }}>
nkylstad marked this conversation as resolved.
Show resolved Hide resolved
<StudioSwitch
checked={shouldDisplayFeature('addComponentModal')}
onChange={toggleComponentModalPocAndReload}
>
Prøv nytt design
nkylstad marked this conversation as resolved.
Show resolved Hide resolved
</StudioSwitch>
<HelpText title='Prøv vårt nye design for å legge til komponenter' placement='bottom-start'>
<StudioParagraph spacing size='small'>
nkylstad marked this conversation as resolved.
Show resolved Hide resolved
Vi jobber med brukeropplevelsen i Studio. Vil du prøve vårt forslag til nytt design for
å legge til komponenter?
</StudioParagraph>
<StudioParagraph spacing size='small'>
Du kan fortelle oss hva du synes om det nye designet ved å trykke på "Gi tilbakemelding"

Check failure on line 45 in frontend/packages/ux-editor/src/containers/FormDesignerToolbar.tsx

View workflow job for this annotation

GitHub Actions / Typechecking and linting

`"` can be escaped with `&quot;`, `&ldquo;`, `&#34;`, `&rdquo;`

Check failure on line 45 in frontend/packages/ux-editor/src/containers/FormDesignerToolbar.tsx

View workflow job for this annotation

GitHub Actions / Typechecking and linting

`"` can be escaped with `&quot;`, `&ldquo;`, `&#34;`, `&rdquo;`
nederst til høyre på siden.
</StudioParagraph>
</HelpText>
</div>
{shouldDisplayFeature('addComponentModal') && <FeedbackForm />}
</section>
);
};
Loading