Skip to content

Commit

Permalink
[#30] Fill the data into the Question page
Browse files Browse the repository at this point in the history
  • Loading branch information
manh-t committed Sep 7, 2023
1 parent da6188c commit 5810dc1
Show file tree
Hide file tree
Showing 18 changed files with 419 additions and 37 deletions.
176 changes: 176 additions & 0 deletions src/components/Answer/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import React from 'react';

import { render, screen } from '@testing-library/react';

import { Question } from 'types/question';

import Answer from '.';

describe('Answer', () => {
describe('given the display type is star', () => {
it('renders Rating component', () => {
const question: Question = {
id: 'id',
resourceType: 'question',
displayType: 'star',
answers: [],
};
const dataTestId = 'answer';
render(<Answer question={question} data-test-id={dataTestId} />);

const star = screen.getByTestId(dataTestId);

expect(star).toBeVisible();
expect(star).toHaveAttribute('id', 'rating-id');
});
});

describe('given the display type is choice', () => {
it('renders MultiChoice component', () => {
const question: Question = {
id: 'id',
resourceType: 'question',
displayType: 'choice',
answers: [],
};
const dataTestId = 'answer';
render(<Answer question={question} data-test-id={dataTestId} />);

const multiChoice = screen.getByTestId(dataTestId);

expect(multiChoice).toBeVisible();
expect(multiChoice).toHaveAttribute('id', 'multi-choice-id');
});
});

describe('given the display type is nps', () => {
it('renders Nps component', () => {
const question: Question = {
id: 'id',
resourceType: 'question',
displayType: 'nps',
answers: [],
};
const dataTestId = 'answer';
render(<Answer question={question} data-test-id={dataTestId} />);

const nps = screen.getByTestId(dataTestId);

expect(nps).toBeVisible();
expect(nps).toHaveAttribute('id', 'nps-id');
});
});

describe('given the display type is textarea', () => {
it('renders TextArea component', () => {
const question: Question = {
id: 'id',
resourceType: 'question',
displayType: 'textarea',
answers: [
{
id: 'id',
resourceType: 'answer',
text: '',
},
],
};
const dataTestId = 'answer';
render(<Answer question={question} data-test-id={dataTestId} />);

const textArea = screen.getByTestId(dataTestId);

expect(textArea).toBeVisible();
expect(textArea).toHaveAttribute('id', 'text-area-id');
});
});

describe('given the display type is textfield', () => {
it('renders MultiInputs component', () => {
const question: Question = {
id: 'id',
resourceType: 'question',
displayType: 'textfield',
answers: [
{
id: 'id',
resourceType: 'answer',
text: '',
},
],
};
const dataTestId = 'answer';
render(<Answer question={question} data-test-id={dataTestId} />);

const multiInputs = screen.getByTestId(dataTestId);

expect(multiInputs).toBeVisible();
expect(multiInputs).toHaveAttribute('id', 'multi-inputs-id');
});
});

describe('given the display type is dropdown', () => {
it('renders Dropdown component', () => {
const question: Question = {
id: 'id',
resourceType: 'question',
displayType: 'dropdown',
answers: [
{
id: 'id',
resourceType: 'answer',
text: '',
},
],
};
const dataTestId = 'answer';
render(<Answer question={question} data-test-id={dataTestId} />);

const dropdown = screen.getByTestId(dataTestId);

expect(dropdown).toBeVisible();
expect(dropdown).toHaveAttribute('id', 'dropdown-id');
});
});

describe('given the display type is slider', () => {
it('renders Dropdown component', () => {
const question: Question = {
id: 'id',
resourceType: 'question',
displayType: 'slider',
answers: [
{
id: 'id',
resourceType: 'answer',
text: '',
},
],
};
const dataTestId = 'answer';
render(<Answer question={question} data-test-id={dataTestId} />);

const slider = screen.getByTestId(dataTestId);

expect(slider).toBeVisible();
expect(slider).toHaveAttribute('id', 'slider-id');
});
});

describe('given the display type is intro', () => {
it('renders Dropdown component', () => {
const question: Question = {
id: 'id',
resourceType: 'question',
displayType: 'intro',
answers: [],
};
const dataTestId = 'answer';
render(<Answer question={question} data-test-id={dataTestId} />);

const intro = screen.getByTestId(dataTestId);

expect(intro).toBeVisible();
});
});
});
59 changes: 59 additions & 0 deletions src/components/Answer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';

import AppSlider from 'components/AppSlider';
import Dropdown from 'components/Dropdown';
import MultiChoice from 'components/MultiChoice';
import MultiInputs from 'components/MultiInputs';
import Nps from 'components/Nps';
import Rating from 'components/Rating';
import TextArea from 'components/TextArea';
import { DisplayType, Question, getDisplayTypeEnum } from 'types/question';

interface AnswerProps {
question: Question;
'data-test-id'?: string;
}
const Answer = ({ question, ...rest }: AnswerProps): JSX.Element => {
const displayTypeEnum = getDisplayTypeEnum(question);

switch (displayTypeEnum) {
case DisplayType.Heart:
case DisplayType.Smiley:
case DisplayType.Thumbs:
case DisplayType.Star:
return (
<Rating
questionId={question.id}
items={question.answers}
displayType={displayTypeEnum}
data-test-id={rest['data-test-id']}
/>
);
case DisplayType.Choice:
return (
<MultiChoice
questionId={question.id}
items={question.answers}
isPickOne={question?.pick === 'one'}
data-test-id={rest['data-test-id']}
/>
);
case DisplayType.Nps:
return <Nps questionId={question.id} items={question.answers} data-test-id={rest['data-test-id']} />;
case DisplayType.Textarea:
return <TextArea questionId={question.id} items={question.answers} data-test-id={rest['data-test-id']} />;
case DisplayType.Textfield:
return <MultiInputs questionId={question.id} items={question.answers} data-test-id={rest['data-test-id']} />;
case DisplayType.Dropdown:
return <Dropdown questionId={question.id} items={question.answers} data-test-id={rest['data-test-id']} />;
case DisplayType.Slider:
return <AppSlider questionId={question.id} items={question.answers} data-test-id={rest['data-test-id']} />;
case DisplayType.Unknown:
case DisplayType.Intro:
case DisplayType.Outro:
default:
return <div {...rest}></div>;
}
};

export default Answer;
6 changes: 5 additions & 1 deletion src/components/AppSlider/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import AppSlider, { appSliderDataTestIds } from '.';

describe('AppSlider', () => {
it('renders AppSlider component', () => {
render(<AppSlider onValueChanged={jest.fn()} />);
const onValueChanged = () => {
// Do nothing
};

render(<AppSlider onValueChanged={onValueChanged} />);

const appSlider = screen.getByTestId(appSliderDataTestIds.base);
const slider = screen.getByRole('slider');
Expand Down
10 changes: 5 additions & 5 deletions src/components/AppSlider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';

import Slider from 'rc-slider';

Expand All @@ -14,9 +14,9 @@ interface SliderProps {
}

const AppSlider = ({ min = 1, max = 100, step = 1, onValueChanged }: SliderProps): JSX.Element => {
const handleOnChange = (value: number) => {
onValueChanged(value);
};
useEffect(() => {
onValueChanged(min);
}, [min, onValueChanged]);

return (
<div className="flex w-full h-[56px] justify-center items-center" data-test-id={appSliderDataTestIds.base}>
Expand Down Expand Up @@ -45,7 +45,7 @@ const AppSlider = ({ min = 1, max = 100, step = 1, onValueChanged }: SliderProps
min={min}
max={max}
step={step}
onChange={(value) => handleOnChange(value as number)}
onChange={(value) => onValueChanged(value as number)}
/>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/components/Dropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface DropdownProps {
items: Answer[];
onValueChanged: (value: Answer) => void;
}

const Dropdown = ({ questionId, items, onValueChanged }: DropdownProps): JSX.Element => {
const [isOpen, setIsOpen] = useState(false);
const [selectedValue, setSelectedValue] = useState(items[0].text);
Expand Down
2 changes: 1 addition & 1 deletion src/components/ElevatedButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const ElevatedButton = ({ children, isFullWidth, ...rest }: ElevatedButtonProps)
'bg-white text-black-chinese font-bold text-regular tracking-survey-tight rounded-[10px] focus:outline-none focus:shadow-outline h-14';

return (
<button type="button" className={classNames(DEFAULT_CLASS_NAMES, { 'w-full': isFullWidth })} {...rest}>
<button type="button" className={classNames(DEFAULT_CLASS_NAMES, { 'w-full': isFullWidth, 'px-8': !isFullWidth })} {...rest}>
{children}
</button>
);
Expand Down
6 changes: 5 additions & 1 deletion src/components/MultiChoice/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';

import classNames from 'classnames';

Expand Down Expand Up @@ -43,6 +43,10 @@ const MultiChoice = ({ items, isPickOne, onValuesChanged }: MultiChoiceProps): J
onValuesChanged(newSelectedValues);
};

useEffect(() => {
setSelectedValues([]);
}, []);

return (
<div className="flex flex-col w-full" data-test-id={multiChoiceDataTestIds.base}>
{items.map((item, index) => (
Expand Down
25 changes: 25 additions & 0 deletions src/components/MultiInputs/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';

import { render, screen, within } from '@testing-library/react';

import MultiInputs from '.';

describe('MultiInputs', () => {
const multiInputsDataTestId = 'multiInputs';

it('renders a multi inputs component', () => {
const answers = [
{ id: '1', resourceType: 'answer', text: 'Test 1' },
{ id: '2', resourceType: 'answer', text: 'Test 2' },
{ id: '3', resourceType: 'answer', text: 'Test 3' },
];
render(<MultiInputs questionId="question id" items={answers} data-test-id={multiInputsDataTestId} />);

const multiInputs = screen.getByTestId(multiInputsDataTestId);

expect(multiInputs).toBeVisible();
expect(within(multiInputs).getByPlaceholderText('Test 1')).toBeVisible();
expect(within(multiInputs).getByPlaceholderText('Test 2')).toBeVisible();
expect(within(multiInputs).getByPlaceholderText('Test 3')).toBeVisible();
});
});
56 changes: 56 additions & 0 deletions src/components/MultiInputs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useEffect, useState } from 'react';

import TextInput from 'components/TextInput';
import { Answer } from 'types/answer';
import { AnswerRequest } from 'types/request/surveySubmitRequest';

interface MultiInputProps {
questionId: string;
items: Answer[];
onValuesChanged?: (answers: AnswerRequest[]) => void;
'data-test-id'?: string;
}
const MultiInputs = ({ questionId, items, onValuesChanged, ...rest }: MultiInputProps): JSX.Element => {
const [selectedValues, setSelectedValues] = useState<AnswerRequest[]>([]);

const handleValuesChanged = (answer: Answer, content: string) => {
const newSelectedValues = selectedValues;
const itemIndex = newSelectedValues.findIndex((value) => value.id === answer.id);
if (itemIndex !== -1) {
newSelectedValues[itemIndex].answer = content;
}
setSelectedValues(newSelectedValues);
onValuesChanged?.(newSelectedValues);
};

useEffect(() => {
const newSelectedValues: AnswerRequest[] = [];
for (let i = 0; i < items.length; i++) {
newSelectedValues.push({
id: items[i].id,
answer: '',
});
}
setSelectedValues(newSelectedValues);
}, [questionId, items]);

return (
<div id={`multi-inputs-${questionId}`} {...rest}>
{items.map((item) => (
<div key={item.id}>
<TextInput
inputAttributes={{
id: `answer-text-input__${item.id}`,
required: true,
type: 'text',
placeholder: item.text,
onChange: (event) => handleValuesChanged(item, event.target.value),
}}
/>
</div>
))}
</div>
);
};

export default MultiInputs;
Loading

0 comments on commit 5810dc1

Please sign in to comment.