From ab562f0a03660e60e7d373d0bf7edc9828fc289f Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Tue, 8 Oct 2024 14:24:25 -0400 Subject: [PATCH 1/4] add Checkbox question type --- components/Checkboxes.tsx | 61 +++++++++++++++++++++++++ components/QuestionRenderer.tsx | 10 ++++ components/stories/Checkboxes.story.tsx | 27 +++++++++++ package.json | 4 +- styles/Checkboxes.module.css | 21 +++++++++ 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 components/Checkboxes.tsx create mode 100644 components/stories/Checkboxes.story.tsx create mode 100644 styles/Checkboxes.module.css diff --git a/components/Checkboxes.tsx b/components/Checkboxes.tsx new file mode 100644 index 0000000..19a6ed8 --- /dev/null +++ b/components/Checkboxes.tsx @@ -0,0 +1,61 @@ +import React, { useEffect, useState } from 'react' +import { v4 } from 'uuid' + +import styles from '../styles/Checkboxes.module.css' + +export type CheckboxesProps = { + disabled?: boolean + options: string[] + updateCallback?: (update: string) => void +} +const Checkboxes = ({ + disabled = false, + options, + updateCallback +}: CheckboxesProps) => { + const [selectedOptions, updateSelectedOptions] = useState( + options.map(() => false) + ) + + useEffect( + () => { + if (!updateCallback) return + updateCallback(selectedOptions.toString()) + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [selectedOptions] + ) + + const uuid = v4() + + const onSelectionChange = (e) => { + const index = parseInt((e.target as HTMLInputElement).value) + const clonedSelectedOptions = Array.from(selectedOptions) + clonedSelectedOptions[index] = !clonedSelectedOptions[index] + updateSelectedOptions(clonedSelectedOptions) + } + + return ( +
+ {options?.map((option, index) => ( + + ))} +
+ ) +} +export { Checkboxes } diff --git a/components/QuestionRenderer.tsx b/components/QuestionRenderer.tsx index 18df686..9072105 100644 --- a/components/QuestionRenderer.tsx +++ b/components/QuestionRenderer.tsx @@ -1,6 +1,7 @@ /* eslint-disable complexity */ import { useTranslations } from 'next-intl' +import { Checkboxes } from './Checkboxes' import { RadioButtonProps, RadioButtons } from './RadioButtons' import { SatisfactionSlider, @@ -48,6 +49,15 @@ const QuestionRenderer = ({ const renderQuestion = (type: string) => { switch (type) { + case 'checkbox': + if (!('options' in question)) return failure + return ( + + ) case 'radio': if (!('options' in question)) return failure return ( diff --git a/components/stories/Checkboxes.story.tsx b/components/stories/Checkboxes.story.tsx new file mode 100644 index 0000000..a7b4163 --- /dev/null +++ b/components/stories/Checkboxes.story.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import { action } from '@storybook/addon-actions' +import { ComponentMeta } from '@storybook/react' + +import { Checkboxes } from '../Checkboxes' + +export default { + component: Checkboxes, + title: 'Check Boxes' +} as ComponentMeta + +export const Default = () => ( + +) + +export const WithTitle = () => ( + <> +

How many stars are there in the sky?

+ + +) diff --git a/package.json b/package.json index 91b8e6b..c548ba1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,9 @@ { "name": "survey", "version": "0.1.0", - "engines": { "node": "18.x" }, + "engines": { + "node": ">=18.x" + }, "scripts": { "dev": "next dev", "build": "next build", diff --git a/styles/Checkboxes.module.css b/styles/Checkboxes.module.css new file mode 100644 index 0000000..7a7643b --- /dev/null +++ b/styles/Checkboxes.module.css @@ -0,0 +1,21 @@ +.container { + font-size: 25px; + width: 100%; +} + +.container label { + display: grid; + align-items: baseline; + grid-template-columns: 25px 1fr; + grid-gap: 1ch; + padding-bottom: 0.33333ch; +} +.container label input { + height: 25px; + width: 25px; +} + +.button ~ .label { + color: #333; + transition: all 0.1s ease-in-out; +} From acd90e365e21f20d71ac68521c0c2dfa91706ef6 Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Tue, 8 Oct 2024 14:25:57 -0400 Subject: [PATCH 2/4] add example --- config.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config.yaml b/config.yaml index 64c2eb9..c8ca13f 100644 --- a/config.yaml +++ b/config.yaml @@ -16,6 +16,14 @@ questions: type: "textarea" # This is an example of a non-internationalized question title: "What do you think of this survey?" + - + type: "checkbox" + title: "Which emotions does this survey bring out within you?" + options: + - "Joy" + - "Delight" + - "Ecstasy" + - "Happy" - # This question type provides a slider and a corresponding emoji-based # satisfaction display From a0a5a5b3ec013def32f938c7c13c50fbb4b3f9d2 Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Tue, 8 Oct 2024 14:30:14 -0400 Subject: [PATCH 3/4] fix type errors --- components/Checkboxes.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/Checkboxes.tsx b/components/Checkboxes.tsx index 19a6ed8..3564455 100644 --- a/components/Checkboxes.tsx +++ b/components/Checkboxes.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { ChangeEvent, useEffect, useState } from 'react' import { v4 } from 'uuid' import styles from '../styles/Checkboxes.module.css' @@ -28,7 +28,7 @@ const Checkboxes = ({ const uuid = v4() - const onSelectionChange = (e) => { + const onSelectionChange = (e: ChangeEvent) => { const index = parseInt((e.target as HTMLInputElement).value) const clonedSelectedOptions = Array.from(selectedOptions) clonedSelectedOptions[index] = !clonedSelectedOptions[index] From e530269a58b539a9f28635d96f7080efd6d6d7ff Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Mon, 14 Oct 2024 12:35:12 -0400 Subject: [PATCH 4/4] address pr feedback --- styles/Checkboxes.module.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/styles/Checkboxes.module.css b/styles/Checkboxes.module.css index 7a7643b..fdce6c2 100644 --- a/styles/Checkboxes.module.css +++ b/styles/Checkboxes.module.css @@ -1,11 +1,10 @@ .container { font-size: 25px; - width: 100%; } .container label { display: grid; - align-items: baseline; + align-items: center; grid-template-columns: 25px 1fr; grid-gap: 1ch; padding-bottom: 0.33333ch;