-
Notifications
You must be signed in to change notification settings - Fork 8
feat(frontend): implement question type components (#540) #541
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
Open
minhle35
wants to merge
7
commits into
CHAOS-224-KHAOS-rewrite
Choose a base branch
from
feature/question-type-component
base: CHAOS-224-KHAOS-rewrite
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
2fdf9d7
feat(frontend): implement question type components (#540)
minhle35 8008752
fix(): use React DnD for ranking options
minhle35 07dbc3d
fix(dropdown): add borderline, improve hover effects, and highlight s…
minhle35 7955980
fix(shortanswer): enlarge textarea to span 77 columns and 3 rows
minhle35 e583f67
chore(deps): update yarn.lock with automatic modifications
minhle35 5b65667
feat(shortAnswer): enhance textarea focus visibility and border styling
minhle35 b025cdb
refactor: update question components structure and remove unneccsary …
minhle35 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
frontend/src/components/QuestionComponents/Dropdown/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| import React, { useState } from 'react'; | ||
| import tw from 'twin.macro'; | ||
| import { ChevronDownIcon, CheckIcon } from '@heroicons/react/24/solid'; | ||
|
|
||
| interface DropdownOption { | ||
| id: string | number; | ||
| label: string; | ||
| } | ||
|
|
||
| interface DropdownProps { | ||
| id: number; | ||
| question: string; | ||
| description?: string; | ||
| options: DropdownOption[]; | ||
| required?: boolean; | ||
| defaultValue?: string | number; | ||
| onChange?: (value: string | number) => void; | ||
| onSubmit?: (questionId: number, value: string | number) => void; | ||
| disabled?: boolean; | ||
| } | ||
|
|
||
| const Dropdown: React.FC<DropdownProps> = ({ | ||
| id, | ||
| question, | ||
| description, | ||
| options, | ||
| required = false, | ||
| defaultValue, | ||
| onChange, | ||
| onSubmit, | ||
| disabled = false, | ||
| }) => { | ||
| const [value, setValue] = useState<string | number | undefined>(defaultValue); | ||
| const [isOpen, setIsOpen] = useState(false); | ||
|
|
||
| const handleSelect = (optionId: string | number) => { | ||
| setValue(optionId); | ||
| setIsOpen(false); | ||
|
|
||
| if (onChange) onChange(optionId); | ||
| if (onSubmit) onSubmit(id, optionId); | ||
| }; | ||
|
|
||
| const selectedOption = options.find(option => option.id === value); | ||
|
|
||
| return ( | ||
| <div tw="mb-6 max-w-4xl w-full"> | ||
| <div tw="flex items-center mb-1"> | ||
| <label tw="text-lg font-medium text-gray-900">{question}</label> | ||
| {required && <span tw="ml-1 text-red-500">*</span>} | ||
| </div> | ||
|
|
||
| {description && ( | ||
| <p tw="mb-2 text-sm text-gray-600">{description}</p> | ||
| )} | ||
|
|
||
| <div tw="relative"> | ||
| <button | ||
| type="button" | ||
| onClick={() => !disabled && setIsOpen(!isOpen)} | ||
| disabled={disabled} | ||
| tw="w-full py-1 px-4 text-left rounded-md border-2 border-gray-400 shadow-md bg-white focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 hover:border-blue-400" | ||
| > | ||
| <div tw="flex items-center justify-between"> | ||
| <span>{selectedOption ? selectedOption.label : 'Select an option'}</span> | ||
| <ChevronDownIcon tw="h-3 w-5 text-gray-400" /> | ||
| </div> | ||
| </button> | ||
|
|
||
| {isOpen && ( | ||
| <div tw="absolute z-10 mt-1 w-full bg-white shadow-lg rounded-md py-1 max-h-60 overflow-auto border-2 border-gray-300"> | ||
| {options.map((option) => { | ||
| // Check if this option is selected | ||
| const isSelected = option.id === value; | ||
|
|
||
| return ( | ||
| <div | ||
| key={option.id} | ||
| onClick={() => handleSelect(option.id)} | ||
| // Basic styling for all options | ||
| tw="px-4 py-1 cursor-pointer hover:bg-blue-50 text-sm flex items-center justify-between" | ||
| // Apply conditional styling based on selection state | ||
| css={isSelected ? tw`bg-blue-50 font-medium` : undefined} | ||
| > | ||
| <span>{option.label}</span> | ||
| {/* Show checkmark for selected option */} | ||
| {isSelected && ( | ||
| <CheckIcon tw="h-4 w-4 text-blue-500 ml-2" /> | ||
| )} | ||
| </div> | ||
| ); | ||
| })} | ||
| </div> | ||
| )} | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Dropdown; |
78 changes: 78 additions & 0 deletions
78
frontend/src/components/QuestionComponents/MultiChoice/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import React, { useState } from 'react'; | ||
| import tw from 'twin.macro'; | ||
|
|
||
| interface Option { | ||
| id: string | number; | ||
| label: string; | ||
| } | ||
|
|
||
| interface MultiChoiceProps { | ||
| id: number; | ||
| question: string; | ||
| description?: string; | ||
| options: Option[]; | ||
| required?: boolean; | ||
| defaultValue?: string | number; | ||
| onChange?: (value: string | number) => void; | ||
| onSubmit?: (questionId: number, value: string | number) => void; | ||
| disabled?: boolean; | ||
| } | ||
|
|
||
| const MultiChoice: React.FC<MultiChoiceProps> = ({ | ||
| id, | ||
| question, | ||
| description, | ||
| options, | ||
| required = false, | ||
| defaultValue, | ||
| onChange, | ||
| onSubmit, | ||
| disabled = false, | ||
| }) => { | ||
| const [selectedOption, setSelectedOption] = useState<string | number | undefined>(defaultValue); | ||
|
|
||
| const handleChange = (optionId: string | number) => { | ||
| setSelectedOption(optionId); | ||
|
|
||
| if (onChange) onChange(optionId); | ||
| if (onSubmit) onSubmit(id, optionId); | ||
| }; | ||
|
|
||
| return ( | ||
| <div tw="mb-6"> | ||
| <div tw="flex items-center mb-1"> | ||
| <label tw="text-lg font-medium text-gray-900">{question}</label> | ||
| {required && <span tw="ml-1 text-red-500">*</span>} | ||
| </div> | ||
|
|
||
| {description && ( | ||
| <p tw="mb-2 text-sm text-gray-600">{description}</p> | ||
| )} | ||
|
|
||
| <div tw="space-y-2"> | ||
| {options.map((option) => ( | ||
| <div key={option.id} tw="flex items-center"> | ||
| <input | ||
| type="radio" | ||
| id={`option-${id}-${option.id}`} | ||
| name={`question-${id}`} | ||
| value={option.id.toString()} | ||
| checked={selectedOption === option.id} | ||
| onChange={() => handleChange(option.id)} | ||
| disabled={disabled} | ||
| tw="h-4 w-4 text-blue-600 border-gray-300 focus:ring-blue-500" | ||
| /> | ||
| <label | ||
| htmlFor={`option-${id}-${option.id}`} | ||
| tw="ml-3 block text-sm font-medium text-gray-700" | ||
| > | ||
| {option.label} | ||
| </label> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default MultiChoice; |
86 changes: 86 additions & 0 deletions
86
frontend/src/components/QuestionComponents/MultiSelect/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import React, { useState } from 'react'; | ||
| import tw from 'twin.macro'; | ||
|
|
||
| interface Option { | ||
| id: string | number; | ||
| label: string; | ||
| } | ||
|
|
||
| interface MultiSelectProps { | ||
| id: number; | ||
| question: string; | ||
| description?: string; | ||
| options: Option[]; | ||
| required?: boolean; | ||
| defaultValue?: Array<string | number>; | ||
| onChange?: (value: Array<string | number>) => void; | ||
| onSubmit?: (questionId: number, value: Array<string | number>) => void; | ||
| disabled?: boolean; | ||
| } | ||
|
|
||
| const MultiSelect: React.FC<MultiSelectProps> = ({ | ||
| id, | ||
| question, | ||
| description, | ||
| options, | ||
| required = false, | ||
| defaultValue = [], | ||
| onChange, | ||
| onSubmit, | ||
| disabled = false, | ||
| }) => { | ||
| const [selectedOptions, setSelectedOptions] = useState<Array<string | number>>(defaultValue); | ||
|
|
||
| const handleChange = (optionId: string | number) => { | ||
| let newSelectedOptions: Array<string | number> = []; | ||
|
|
||
| if (selectedOptions.includes(optionId)) { | ||
| newSelectedOptions = selectedOptions.filter(id => id !== optionId); | ||
| } else { | ||
| newSelectedOptions = [...selectedOptions, optionId]; | ||
| } | ||
|
|
||
| setSelectedOptions(newSelectedOptions); | ||
|
|
||
| if (onChange) onChange(newSelectedOptions); | ||
| if (onSubmit) onSubmit(id, newSelectedOptions); | ||
| }; | ||
|
|
||
| return ( | ||
| <div tw="mb-6"> | ||
| <div tw="flex items-center mb-1"> | ||
| <label tw="text-lg font-medium text-gray-900">{question}</label> | ||
| {required && <span tw="ml-1 text-red-500">*</span>} | ||
| </div> | ||
|
|
||
| {description && ( | ||
| <p tw="mb-2 text-sm text-gray-600">{description}</p> | ||
| )} | ||
|
|
||
| <div tw="space-y-2"> | ||
| {options.map((option) => ( | ||
| <div key={option.id} tw="flex items-center"> | ||
| <input | ||
| type="checkbox" | ||
| id={`option-${id}-${option.id}`} | ||
| name={`question-${id}-${option.id}`} | ||
| value={option.id.toString()} | ||
| checked={selectedOptions.includes(option.id)} | ||
| onChange={() => handleChange(option.id)} | ||
| disabled={disabled} | ||
| tw="h-4 w-4 text-blue-600 rounded border-gray-300 focus:ring-blue-500" | ||
| /> | ||
| <label | ||
| htmlFor={`option-${id}-${option.id}`} | ||
| tw="ml-3 block text-sm font-medium text-gray-700" | ||
| > | ||
| {option.label} | ||
| </label> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default MultiSelect; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.