diff --git a/Survey/src/components/SurveyQuestions.tsx b/Survey/src/components/SurveyQuestions.tsx index 582c8c6a..27344f12 100644 --- a/Survey/src/components/SurveyQuestions.tsx +++ b/Survey/src/components/SurveyQuestions.tsx @@ -38,6 +38,7 @@ import { IconButton, TableRow, TableCell, + TableHead } from "@material-ui/core" import classnames from "classnames" import i18n from "../i18n" @@ -76,7 +77,7 @@ const BorderLinearProgress = withStyles((theme: Theme) => const useStyles = makeStyles((theme) => ({ textCenter: { - textAlign : "center" + textAlign: "center" }, root: { width: "100%", @@ -110,7 +111,7 @@ const useStyles = makeStyles((theme) => ({ color: "white", textAlign: "center", "& p": { - margin : "0", + margin: "0", } }, marginBottom40: { @@ -204,35 +205,43 @@ const useStyles = makeStyles((theme) => ({ "0px 2px 4px -1px rgba(0,0,0,0.2), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12)", }, }, - formLabelMatrix : { alignItems: "center", margin : "0 auto" }, - timeMatrix:{ - "& div":{ + formLabelMatrix: { alignItems: "center", margin: "0 auto" }, + timeMatrix: { + "& div": { marginTop: "0px" }, }, - firstTr : { + firstTr: { fontWeight: "bold", + position: "sticky", + top: 0, "& td": { padding: 0, verticalAlign: "top", border: 0, - } + } }, secondTr: { + position: "sticky", + top: 0, + zIndex: 2, + background: "#fff", + boxShadow: "0 0 6px rgba(0,0,0,0.25)", "& td": { padding: "5px 0", - } + zIndex: 2 + } }, - matrix : { - "& td" :{ - paddingLeft : "3px !important", - paddingRight : "3px !important", - width: "3%" + matrix: { + "& td": { + paddingLeft: "3px !important", + paddingRight: "3px !important", + width: "3%" }, - "& tr" : { - padding:"25px 0", + "& tr": { + padding: "25px 0", }, - "& p" : {marginTop : "0px !important", marginBottom : "3px !important"}, + "& p": { marginTop: "0px !important", marginBottom: "3px !important" }, "& tr td:first-child": { position: "sticky", left: 0, @@ -290,7 +299,7 @@ const useStyles = makeStyles((theme) => ({ fontSize: "14px", color: "#2F9D7E", fontWeight: "normal", - margin: "-10px 0 50px 0", + margin: "-10px 0 20px 0", }, radioGroup: { // marginLeft: -15, @@ -310,9 +319,9 @@ const useStyles = makeStyles((theme) => ({ borderRadius: "10px", "& fieldset": { borderWidth: 0 }, }, - required : { - "& span" : { color: "red"}, - "& sup" : { color: "red"} + required: { + "& span": { color: "red" }, + "& sup": { color: "red" } }, sliderResponse: { marginTop: "60px", @@ -329,6 +338,8 @@ const useStyles = makeStyles((theme) => ({ }, }, questionhead: { + textAlign: "center", + padding: "8px", "& h5": { fontSize: 18, fontWeight: 600 }, "& span": { marginTop: 15, @@ -337,9 +348,9 @@ const useStyles = makeStyles((theme) => ({ lineHeight: "16px !important", }, }, - checkP:{ + checkP: { maxWidth: 65, - display:"block" + display: "block" }, timeHours: { padding: 0, @@ -352,7 +363,7 @@ const useStyles = makeStyles((theme) => ({ centerBar: { height: 4, background: "#BCEFDD" }, customTrack: { width: 4, height: 4, borderRadius: "50%", background: "#65DEB4" }, customThumb: { width: 24, height: 24, marginTop: -10, marginLeft: -10 }, - noInitialVal: {display:"none"}, + noInitialVal: { display: "none" }, menuPaper: { background: "#F5F5F5", boxShadow: "none", @@ -381,14 +392,14 @@ const useStyles = makeStyles((theme) => ({ listSelected: { background: "#E7F8F2 !important", }, - surveyQuestionNav: { textAlign: "center", position: "fixed", width: "100%", bottom: 75, + surveyQuestionNav: { + textAlign: "center", position: "fixed", width: "100%", bottom: 50, [`${theme.breakpoints.down('md')} and (orientation: landscape)`]: { position: "relative", bottom: 30, } - }, + }, surveyQuestionAlign: { - textAlign: "center", "& blockquote": { borderLeft: "5px solid #ccc", margin: "1.5em 10px", padding: "0.5em 10px" }, "& code": { padding: ".2rem .5rem", @@ -397,9 +408,9 @@ const useStyles = makeStyles((theme) => ({ whiteSpace: "noWrap", background: "#F1F1F1", border: "1px solid #E1E1E1", - borderRadius: "4px", + borderRadius: "4px", }, - "& ol":{ + "& ol": { display: "inline-block", }, [theme.breakpoints.down("xs")]: { @@ -420,8 +431,9 @@ const useStyles = makeStyles((theme) => ({ chatDrawerCustom: { minWidth: 411 }, questionScroll: { - marginTop: 30, - overflow: "auto", + textAlign: "center", + maxHeight: "60vh", + overflow: "auto", [theme.breakpoints.down("xs")]: { overflow: "auto", }, @@ -447,6 +459,12 @@ const useStyles = makeStyles((theme) => ({ mrgBtm: { marginBottom: 15 }, countlabel: { left: "calc(-50% - -8px)" }, + thStick: { + position: "sticky", + left: 0, + background: "#fff", + zIndex:2, + }, })) function range(start, stop, step = 1) { @@ -462,17 +480,19 @@ function RateAnswer({ checked, onChange, value }) { return (
onChange(value)} className={checked ? classes.checkedContainer : classes.uncheckContainer}> {checked && - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> }
) } -function LinkRenderer(data:any) { +function LinkRenderer(data: any) { return {data.children} } @@ -519,18 +539,22 @@ function RadioOption({ onChange, options, value, ...props }) { variant="body2" style={{ color: selectedValue === `${x.value}` ? "black" : "rgba(0, 0, 0, 0.7)" }} > - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> } @@ -550,17 +574,17 @@ function TimeSelection({ onChange, options, value, ...props }) { const [anchorE3, setAnchorE3] = React.useState(null) const currentValue = !!value ? value?.split(":") : "" const [hourSelectedIndex, setHourSelectedIndex] = React.useState(!!value ? currentValue[0] : "01") - const [minuteSelectedIndex, setMinuteSelectedIndex] = React.useState(!!value ? currentValue[1].substr(0,2) : "00") - const [ampmSelectedIndex, setAmPmSelectedIndex] = React.useState(!!value ? (currentValue[1].substr(2,3) ?? "") : "AM") + const [minuteSelectedIndex, setMinuteSelectedIndex] = React.useState(!!value ? currentValue[1].substr(0, 2) : "00") + const [ampmSelectedIndex, setAmPmSelectedIndex] = React.useState(!!value ? (currentValue[1].substr(2, 3) ?? "") : "AM") const { t } = useTranslation() useEffect(() => { - onChange((hourSelectedIndex.length === 1 ? "0" + hourSelectedIndex : hourSelectedIndex ) + ":" + - (minuteSelectedIndex.length === 1 ? "0" + minuteSelectedIndex : minuteSelectedIndex ) + - ((!!options?.timePattern && options?.timePattern === "standard") || - (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard") ? ampmSelectedIndex : "")) - }, [hourSelectedIndex, minuteSelectedIndex, ampmSelectedIndex]) - + onChange((hourSelectedIndex.length === 1 ? "0" + hourSelectedIndex : hourSelectedIndex) + ":" + + (minuteSelectedIndex.length === 1 ? "0" + minuteSelectedIndex : minuteSelectedIndex) + + ((!!options?.timePattern && options?.timePattern === "standard") || + (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard") ? ampmSelectedIndex : "")) + }, [hourSelectedIndex, minuteSelectedIndex, ampmSelectedIndex]) + const handleClickHours = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget) } @@ -588,9 +612,9 @@ function TimeSelection({ onChange, options, value, ...props }) { break } onChange((hourSelectedIndex.length === 1 ? "0" + hourSelectedIndex : hourSelectedIndex) + - ":" + (minuteSelectedIndex.length === 1 ? "0" + minuteSelectedIndex : minuteSelectedIndex) + - ((!!options?.timePattern && options?.timePattern === "standard") || - (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard") ? ampmSelectedIndex : "")) + ":" + (minuteSelectedIndex.length === 1 ? "0" + minuteSelectedIndex : minuteSelectedIndex) + + ((!!options?.timePattern && options?.timePattern === "standard") || + (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard") ? ampmSelectedIndex : "")) } const handleHoursClose = () => { setAnchorEl(null) @@ -604,10 +628,10 @@ function TimeSelection({ onChange, options, value, ...props }) { const ampm = [] const hourvalues = (!!options?.timePattern && options?.timePattern === "standard") || - (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard")? range(1,13): range(0, 24) + (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard") ? range(1, 13) : range(0, 24) const minutevalues = ["00", "15", "30", "45"] - if((!!options?.timePattern && options?.timePattern === "standard") || - (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard")) { + if ((!!options?.timePattern && options?.timePattern === "standard") || + (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard")) { ampm.push( ) } - + return ( @@ -654,7 +678,7 @@ function TimeSelection({ onChange, options, value, ...props }) { onClick={(event) => handleMenuItemClick(event, option, 0)} classes={{ selected: classes.listSelected }} > - {option.length === 1 ? "0" + option : option } + {option.length === 1 ? "0" + option : option} ))} @@ -681,29 +705,29 @@ function TimeSelection({ onChange, options, value, ...props }) { onClick={(event) => handleMenuItemClick(event, option, 1)} classes={{ selected: classes.listSelected }} > - {option.length === 1 ? "0" + option : option } + {option.length === 1 ? "0" + option : option} ))} {((!!options?.timePattern && options?.timePattern === "standard") || - (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard")) && ( - - - - - - - {ampm} - - )} + (Array.isArray(options) && !!options[0] && !!options[0]?.value && options[0]?.value === "standard")) && ( + + + + + + + {ampm} + + )} ) @@ -798,13 +822,15 @@ function RadioRating({ onChange, options, value, mtValue, type, ...props }) { /> {type !== "matrix" && ( - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}}/> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> - )} + )} ))} @@ -816,7 +842,7 @@ function Rating({ onChange, options, value, ...props }) { const classes = useStyles() const getText = (val) => { let sliderValue = null - // !!options[0].description && options[0].description.trim().length > 0 ? options[0].description : options[0].value + // !!options[0].description && options[0].description.trim().length > 0 ? options[0].description : options[0].value options.map((mark) => { if (mark.value === val) { sliderValue = !!mark.description && mark.description.trim().length > 0 ? mark.description : mark.value @@ -831,9 +857,9 @@ function Rating({ onChange, options, value, ...props }) { !!value ? getText(value) : null - // : !!options[0].description && options[0].description.trim().length > 0 - // ? options[0].description - // : options[0].value + // : !!options[0].description && options[0].description.trim().length > 0 + // ? options[0].description + // : options[0].value ) const [sliderValue, setSliderValue] = useState(!!value ? value : null) @@ -846,7 +872,7 @@ function Rating({ onChange, options, value, ...props }) { } const getSliderValue = (val) => { let sliderValue = null - // !!options[0].description && options[0].description.trim().length > 0 ? options[0].description : options[0].value + // !!options[0].description && options[0].description.trim().length > 0 ? options[0].description : options[0].value const slValue = val options.map((mark) => { if (parseInt(mark.value, 10) === slValue) { @@ -870,8 +896,8 @@ function Rating({ onChange, options, value, ...props }) { parseInt(options[0].value, 10) < 0 && parseInt(options[1]?.value, 10 ?? 0) < 0 ? Math.abs(parseInt(options[0].value, 10)) + parseInt(options[1]?.value ?? 0, 10) : parseInt(options[0].value, 10) < 0 && parseInt(options[1].value ?? 0, 10) > 0 - ? Math.abs(parseInt(options[0].value, 10)) - parseInt(options[1]?.value ?? 0, 10) - : parseInt(options[1]?.value ?? 0, 10) - parseInt(options[0].value, 10) + ? Math.abs(parseInt(options[0].value, 10)) - parseInt(options[1]?.value ?? 0, 10) + : parseInt(options[1]?.value ?? 0, 10) - parseInt(options[0].value, 10) } marks={options} min={parseInt(options[0].value, 10)} @@ -881,7 +907,7 @@ function Rating({ onChange, options, value, ...props }) { root: classes.slider, rail: classes.centerBar, mark: classes.customTrack, - thumb: classes.customThumb + (sliderValue !== null ? "" : " " + classes.noInitialVal), + thumb: classes.customThumb + (sliderValue !== null ? "" : " " + classes.noInitialVal), valueLabel: classes.countlabel, }} onChange={(evt, val) => { @@ -891,39 +917,45 @@ function Rating({ onChange, options, value, ...props }) { - { - return {props?.children}; - }, sup: (props) => { - return {props?.children}; - }}} /> + : options[0].description} skipHtml={false} plugins={[gfm, emoji]} renderers={{ + link: LinkRenderer, sub: (props) => { + return {props?.children}; + }, sup: (props) => { + return {props?.children}; + } + }} /> {options.length > 2 && ( { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + : options[Math.ceil(options.length / 2) - 1].description} skipHtml={false} plugins={[gfm, emoji]} renderers={{ + link: LinkRenderer, sub: (props) => { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> )} - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> - + : options[options.length - 1].description} skipHtml={false} plugins={[gfm, emoji]} renderers={{ + link: LinkRenderer, sub: (props) => { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> + @@ -932,11 +964,13 @@ function Rating({ onChange, options, value, ...props }) { {t("Your response")}: - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> @@ -955,7 +989,7 @@ function Rating({ onChange, options, value, ...props }) { const csvParse = (x) => (Array.isArray(JSON.parse(`[${x}]`)) ? JSON.parse(`[${x}]`) : []) const csvStringify = (x) => (Array.isArray(x) ? JSON.stringify(x).slice(1, -1) : "") -function Matrix({ x, responses, onResponse, activityId, total,index, idx,startTime, setActiveStep,settingsQuestions, handleBack, +function Matrix({ x, responses, onResponse, activityId, total, index, idx, startTime, setActiveStep, settingsQuestions, handleBack, handleNext, onComplete, ...props }) { const classes = useStyles() const { t } = useTranslation() @@ -963,214 +997,225 @@ function Matrix({ x, responses, onResponse, activityId, total,index, idx,startTi const [selectedValue, setSelectedValue] = useState(responses?.current ?? null) const getSorted = (options) => { return options.sort((a, b) => - parseInt(a.value, 10) > parseInt(b.value, 10) ? 1 : parseInt(a.value, 10) < parseInt(b.value, 10) ? -1 : 0 - ) + parseInt(a.value, 10) > parseInt(b.value, 10) ? 1 : parseInt(a.value, 10) < parseInt(b.value, 10) ? -1 : 0 + ) } return ( - - - - {`${t("Question")}`} {(index + 1)} {`${t("of")}`} {settingsQuestions} - - - - + + + + {`${t("Question")}`} {(index + 1)} {`${t("of")}`} {settingsQuestions} + + - - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> - - - - - - {Array.isArray(x.options) && x.options.length > 0 && (x.type === "likert" || x.type === "rating" || x.type === "list" ||x.type === "boolean" || x.type === "multiselect") && ( - - {null} - {(x.options || []).map((x) => ( - - {(x.description || "").length > 0 && { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} />} - - ))} - )} - {Array.isArray(x.options) && x.options.length > 0 && (x.type === "likert" || x.type === "rating" || x.type === "list" ||x.type === "boolean" || x.type === "multiselect") && ( - - {null} - {(x.options || []).map((x) => ( - - 0 && (x.value || "").length > 0 ? `(${t(x.value?.toString())})` : `${t(x.value?.toString())}`} skipHtml={false} plugins={[gfm, emoji]} renderers={{ link: LinkRenderer, sub: (props) => { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> - - ))} - )} - {(x.questions || []).map((question, qindex) => ( - - - *`:`${t(question.text)}`} allowDangerousHtml={true} plugins={[gfm, emoji]} renderers={{ link: LinkRenderer, span: (props) => { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> - - {(Array.isArray(x.options) && (x.options || []).length > 0) ?( - x.type === "list" ||x.type === "boolean" || x.type === "likert" ? ( - (x.options || []).map((op, k) => ( - - } - icon={} - onClick={() => { - setSelectedValue({...selectedValue, [idx+qindex]: {item: question.text, value:csvStringify([op.value])}}) - const response = { item: question.text, value: csvStringify([op.value]) } - const data = updateResponses(x, response,activityId, responses, idx+qindex, startTime, setActiveStep, total) - onResponse(data) - }} - /> - } - label={null} - /> - - )) -) :x.type === "multiselect" ? ((x.options || []).map((op, j) => ( - - { - let values = csvParse(selectedValue[idx+qindex]?.value || []) - - if(!csvParse(selectedValue[idx+qindex]?.value || []).includes(op.value)) { - values.push(op.value) - values = (values || []).filter((elem, i, self) => { - return i === self.indexOf(elem); - }) - } else { - const key = values.indexOf(op.value); - if (key !== -1) { - values.splice(key, 1); - } - } - setSelectedValue({...selectedValue, [idx+qindex]: {item: question.text,value:csvStringify(values)}}) - const response = { item: question.text, value: csvStringify(values) } - const data = updateResponses(x, response, activityId,responses, idx+qindex, startTime, setActiveStep, total) - onResponse(data) - }} - /> - } - label={null} - /> - - )) -) - : x.type === "slider" ? ( - - { - setSelectedValue({...selectedValue, [idx+qindex]: {item: question.text, value:csvStringify([val])}}) - const response = { item: question.text, value: val !== null ? csvStringify([val]) : null } - const data = updateResponses(x, response, activityId,responses, idx+qindex, startTime, setActiveStep, total) - onResponse(data) - }} value={csvParse(selectedValue[idx+qindex]?.value || [])[0]?? null} /> - - ) : x.type === "rating" ? - ((x.options || []).map((op, j) => ( - - { - setSelectedValue({...selectedValue, [idx+qindex]: {item: question.text, value:csvStringify([val])}}) - const response = { item: question.text, value: val !== null ? csvStringify([val]) : null } - const data = updateResponses(x, response, activityId,responses, idx+qindex, startTime, setActiveStep, total) - onResponse(data) - }} - value={op.value} - /> - - - ))):x.type === "time"?( - - { - const response = { item: question.text, value: val } - const data = updateResponses(x, response, activityId,responses, idx+qindex, startTime, setActiveStep, total) - onResponse(data) - }} options={x.options} value={!!responses?.current[idx+qindex]?.value ? responses?.current[idx+qindex]?.value : undefined} /> - ) : null ) : - ( - - { - - x?.type === "short" ? - ( - { - const response = { item: question.text, value: val } - const data = updateResponses(x, response, activityId,responses, idx+qindex, startTime, setActiveStep, total) - onResponse(data) - }} value={!!responses?.current[idx+qindex]?.value ? responses?.current[idx+qindex]?.value : undefined} /> - ) - :x.type === "text"?( - { - const response = { item: question.text, value: val } - const data = updateResponses(x, response, activityId,responses, idx+qindex, startTime, setActiveStep, total) - onResponse(data) - }} charLimit={CHARACTER_LIMIT} value={!!responses?.current[idx+qindex]?.value ? responses?.current[idx+qindex]?.value : undefined} /> - ): - x.type === "time"?( - - { - const response = { item: question.text, value: val } - const data = updateResponses(x, response, activityId,responses, idx+qindex, startTime, setActiveStep, total) - onResponse(data) - }} options={x.options} value={!!responses?.current[idx+qindex]?.value ? responses?.current[idx+qindex]?.value : undefined} /> - ): - null + + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; } - - ) - } - - - ))} -
-
-
+ }} /> + + + + + + + + + {Array.isArray(x.options) && x.options.length > 0 && (x.type === "likert" || x.type === "rating" || x.type === "list" || x.type === "boolean" || x.type === "multiselect") && ( + + {null} + {(x.options || []).map((x) => ( + + {(x.description || "").length > 0 && { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} />} + + ))} + )} + + {Array.isArray(x.options) && x.options.length > 0 && (x.type === "likert" || x.type === "rating" || x.type === "list" || x.type === "boolean" || x.type === "multiselect") && ( + + {null} + {(x.options || []).map((x) => ( + + 0 && (x.value || "").length > 0 ? `(${t(x.value?.toString())})` : `${t(x.value?.toString())}`} skipHtml={false} plugins={[gfm, emoji]} renderers={{ + link: LinkRenderer, sub: (props) => { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> + + ))} + )} + + {(x.questions || []).map((question, qindex) => ( + + + *` : `${t(question.text)}`} allowDangerousHtml={true} plugins={[gfm, emoji]} renderers={{ + link: LinkRenderer, span: (props) => { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> + + {(Array.isArray(x.options) && (x.options || []).length > 0) ? ( + x.type === "list" || x.type === "boolean" || x.type === "likert" ? ( + (x.options || []).map((op, k) => ( + + } + icon={} + onClick={() => { + setSelectedValue({ ...selectedValue, [idx + qindex]: { item: question.text, value: csvStringify([op.value]) } }) + const response = { item: question.text, value: csvStringify([op.value]) } + const data = updateResponses(x, response, activityId, responses, idx + qindex, startTime, setActiveStep, total) + onResponse(data) + }} + /> + } + label={null} + /> + + )) + ) : x.type === "multiselect" ? ((x.options || []).map((op, j) => ( + + { + let values = csvParse(selectedValue[idx + qindex]?.value || []) + + if (!csvParse(selectedValue[idx + qindex]?.value || []).includes(op.value)) { + values.push(op.value) + values = (values || []).filter((elem, i, self) => { + return i === self.indexOf(elem); + }) + } else { + const key = values.indexOf(op.value); + if (key !== -1) { + values.splice(key, 1); + } + } + setSelectedValue({ ...selectedValue, [idx + qindex]: { item: question.text, value: csvStringify(values) } }) + const response = { item: question.text, value: csvStringify(values) } + const data = updateResponses(x, response, activityId, responses, idx + qindex, startTime, setActiveStep, total) + onResponse(data) + }} + /> + } + label={null} + /> + + )) + ) + : x.type === "slider" ? ( + + { + setSelectedValue({ ...selectedValue, [idx + qindex]: { item: question.text, value: csvStringify([val]) } }) + const response = { item: question.text, value: val !== null ? csvStringify([val]) : null } + const data = updateResponses(x, response, activityId, responses, idx + qindex, startTime, setActiveStep, total) + onResponse(data) + }} value={csvParse(selectedValue[idx + qindex]?.value || [])[0] ?? null} /> + + ) : x.type === "rating" ? + ((x.options || []).map((op, j) => ( + + { + setSelectedValue({ ...selectedValue, [idx + qindex]: { item: question.text, value: csvStringify([val]) } }) + const response = { item: question.text, value: val !== null ? csvStringify([val]) : null } + const data = updateResponses(x, response, activityId, responses, idx + qindex, startTime, setActiveStep, total) + onResponse(data) + }} + value={op.value} + /> + + + ))) : x.type === "time" ? ( + + { + const response = { item: question.text, value: val } + const data = updateResponses(x, response, activityId, responses, idx + qindex, startTime, setActiveStep, total) + onResponse(data) + }} options={x.options} value={!!responses?.current[idx + qindex]?.value ? responses?.current[idx + qindex]?.value : undefined} /> + ) : null) : + ( + + { + + x?.type === "short" ? + ( + { + const response = { item: question.text, value: val } + const data = updateResponses(x, response, activityId, responses, idx + qindex, startTime, setActiveStep, total) + onResponse(data) + }} value={!!responses?.current[idx + qindex]?.value ? responses?.current[idx + qindex]?.value : undefined} /> + ) + : x.type === "text" ? ( + { + const response = { item: question.text, value: val } + const data = updateResponses(x, response, activityId, responses, idx + qindex, startTime, setActiveStep, total) + onResponse(data) + }} charLimit={CHARACTER_LIMIT} value={!!responses?.current[idx + qindex]?.value ? responses?.current[idx + qindex]?.value : undefined} /> + ) : + x.type === "time" ? ( + + { + const response = { item: question.text, value: val } + const data = updateResponses(x, response, activityId, responses, idx + qindex, startTime, setActiveStep, total) + onResponse(data) + }} options={x.options} value={!!responses?.current[idx + qindex]?.value ? responses?.current[idx + qindex]?.value : undefined} /> + ) : + null + } + + ) + } + + + ))} +
+
+
+
{supportsSidebar && index === settingsQuestions - 1 && ( {t("Submit")} )}
-
- - + + ) } @@ -1188,7 +1233,7 @@ function MultiSelectResponse({ onChange, options, value, ...props }) { root: classes.fieldGroup, }} > - {options.map((x) => ( + {options.map((x) => ( - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> } @@ -1301,33 +1350,35 @@ function Question({ onResponse, text, desc, required, type, options, value, star - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> {!!required && *} - + 0 - ? options[0].description - : options[0].value - }, - ${options[options.length - 1].value} being ${ - !!options[options.length - 1].description && options[options.length - 1].description.trim().length > 0 - ? options[options.length - 1].description - : options[options.length - 1].value - }` - ) - : !!desc && t(`${desc}`) } skipHtml={false} plugins={[gfm, emoji]} renderers={{ link: LinkRenderer, sub: (props) => { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + `${options[0].value} being ${!!options[0].description && options[0].description.trim().length > 0 + ? options[0].description + : options[0].value + }, + ${options[options.length - 1].value} being ${!!options[options.length - 1].description && options[options.length - 1].description.trim().length > 0 + ? options[options.length - 1].description + : options[options.length - 1].value + }` + ) + : !!desc && t(`${desc}`)} skipHtml={false} plugins={[gfm, emoji]} renderers={{ + link: LinkRenderer, sub: (props) => { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> {component} @@ -1357,7 +1408,7 @@ function Questions({ - {`${t("Question")}`} {(index + 1)} {`${t("of")}`} {settings.length} + {`${t("Question")}`} {(index + 1)} {`${t("of")}`} {settings.length} @@ -1371,7 +1422,7 @@ function Questions({ options={Array.isArray(x.options) ? x.options?.map((y) => ({ ...y, label: y.value })) : x.options} value={responses.current[idx] ?? null} onResponse={(response) => { - const data = updateResponses(x, response, activityId,responses, idx, startTime, setActiveStep, totalQuestions) + const data = updateResponses(x, response, activityId, responses, idx, startTime, setActiveStep, totalQuestions) onResponse(data) }} startTime={new Date().getTime()} @@ -1390,27 +1441,27 @@ function Questions({ } const updateResponses = (x, response, activityId, responses, idx, startTime, setActiveStep, total) => { - responses.current[idx] = response - if (x.type !== "multiselect") { - setActiveStep((prev) => prev + 1) - } - response.duration = new Date().getTime() - startTime + responses.current[idx] = response + if (x.type !== "multiselect") { + setActiveStep((prev) => prev + 1) + } + response.duration = new Date().getTime() - startTime - response.endTime = new Date().getTime() - response.type = null - response.level = null - - localStorage.setItem("activity-survey-"+ activityId, JSON.stringify(Array.from({ + response.endTime = new Date().getTime() + response.type = null + response.level = null + + localStorage.setItem("activity-survey-" + activityId, JSON.stringify(Array.from({ + ...responses.current, + length: total, + }))) + return ( + Array.from({ ...responses.current, length: total, - }))) - return ( - Array.from({ - ...responses.current, - length: total, - }) - ) - } + }) + ) +} function Section({ onResponse, @@ -1423,9 +1474,9 @@ function Section({ ...props }) { const activityId = value?.id - const base = value.settings.map((x, index) => ( - !!activityVal && activityVal[index] ? - activityVal[index] : { item: x.text, value: null, duration: 0 })) + const base = value.settings.map((x, index) => ( + !!activityVal && activityVal[index] ? + activityVal[index] : { item: x.text, value: null, duration: 0 })) const responses = useRef(base) const [activeStep, setActiveStep] = useState(0) const classes = useStyles() @@ -1440,46 +1491,46 @@ function Section({ const calcIndex = (idx) => { let index = 0 - ;(settings || []).map((x, i) => { - if(i < idx) { - if(!!x.questions && x.questions.length > 0) { - index = index + x.questions.length - } else { - index++ + ; (settings || []).map((x, i) => { + if (i < idx) { + if (!!x.questions && x.questions.length > 0) { + index = index + x.questions.length + } else { + index++ + } } - } - }) + }) return index } // Force creation of result data whether survey was interacted with or not. useEffect(() => { - if (slideElements === null) { - let index = 0 + if (slideElements === null) { + let index = 0 const slideElements = (settings || []).map((x, idx) => { setElementIn(true) index = calcIndex(idx) return ( - {!!x.questions && x.questions.length > 0 ? - 0 ? + : + /> : - } + } - ) + ) }) setSlideElements(slideElements) } @@ -1522,43 +1573,43 @@ function Section({ const handleNext = () => { const actualIndex = calcIndex(index) - if(settings[index].subType === "matrix") { + if (settings[index].subType === "matrix") { let i = 0; let status = true - for (const element of settings[index].questions){ - if(!(!element.required || (element.required && (responses?.current[actualIndex+i]?.value !== null && typeof responses?.current[actualIndex+i]?.value !== "undefined" && - (typeof responses?.current[actualIndex+i]?.value !== "string" || (typeof responses?.current[actualIndex+i]?.value === "string" && - responses?.current[actualIndex+i]?.value?.trim().length !== 0)))))) { + for (const element of settings[index].questions) { + if (!(!element.required || (element.required && (responses?.current[actualIndex + i]?.value !== null && typeof responses?.current[actualIndex + i]?.value !== "undefined" && + (typeof responses?.current[actualIndex + i]?.value !== "string" || (typeof responses?.current[actualIndex + i]?.value === "string" && + responses?.current[actualIndex + i]?.value?.trim().length !== 0)))))) { enqueueSnackbar(t("Please enter your response."), { variant: "error", - }) + }) status = false break } i++ } - if(!!status) { + if (!!status) { slideElementChange(1) } } else { - if(!value.settings[actualIndex].required || (value.settings[actualIndex].required && (responses?.current[actualIndex]?.value !== null && typeof responses.current[actualIndex].value !== "undefined" && - (typeof responses?.current[actualIndex]?.value !== "string" || (typeof responses?.current[actualIndex]?.value === "string" && - responses?.current[actualIndex]?.value?.trim().length !== 0))))) { - slideElementChange(1) - } else { - enqueueSnackbar(t("Please enter your response."), { - variant: "error", - }) + if (!value.settings[actualIndex].required || (value.settings[actualIndex].required && (responses?.current[actualIndex]?.value !== null && typeof responses.current[actualIndex].value !== "undefined" && + (typeof responses?.current[actualIndex]?.value !== "string" || (typeof responses?.current[actualIndex]?.value === "string" && + responses?.current[actualIndex]?.value?.trim().length !== 0))))) { + slideElementChange(1) + } else { + enqueueSnackbar(t("Please enter your response."), { + variant: "error", + }) + } } } - } const tabDirection = (currentTab) => { return supportsSidebar ? "up" : "left" } const handleChange = (event) => { const target = event.target - // if (target.getAttribute("role") === "dialog") { + // if (target.getAttribute("role") === "dialog") { // const progressVal = (target.scrollTop / (target.scrollHeight - target.clientHeight)) * 100 // setProgressValue(progressVal + 10 > 100 ? progressVal : progressVal + 10) // } @@ -1566,17 +1617,19 @@ function Section({ return ( - + {!noBack && onResponse(null)}> arrow_back } - { - return {props?.children}; - }, sup: (props) => { - return {props.children}; - }}} /> + { + return {props?.children}; + }, sup: (props) => { + return {props.children}; + } + }} /> @@ -1584,37 +1637,37 @@ function Section({ {supportsSidebar ? ( settings.map((x, idx) => ( - {!!x.questions && x.questions.length > 0 ? - 0 ? + : - } + /> : + } )) ) : ( @@ -1645,7 +1698,7 @@ function Section({ ) } -export default function SurveyQuestions({...props}) { +export default function SurveyQuestions({ ...props }) { const classes = useStyles() const { t } = useTranslation() const [responses, setResponses] = useState(null) @@ -1661,39 +1714,39 @@ export default function SurveyQuestions({...props}) { let status = true const questions = activity.settings let i = 0 - if(response === null) { + if (response === null) { return false } for (const question of questions) { - if(!question.required || (!!question.required && (!!response && !!response[i] && response[i]?.value !== null && + if (!question.required || (!!question.required && (!!response && !!response[i] && response[i]?.value !== null && typeof response[i]?.value !== "undefined" && (typeof response[i]?.value !== "string" || - (typeof response[i]?.value === "string" && response[i]?.value?.trim().length !== 0))))) { - status = true + (typeof response[i]?.value === "string" && response[i]?.value?.trim().length !== 0))))) { + status = true } else { status = false break } i++ } - return status + return status } const postSubmit = (response) => { - if(validator(response)) { + if (validator(response)) { response.map((r) => { delete r.endTime }) const result = { temporal_slices: response, - duration : new Date().getTime() - startTime, + duration: new Date().getTime() - startTime, static_data: {}, timestamp: startTime } - onResponse(result) + onResponse(result) } else { enqueueSnackbar(t("Some responses are missing. Please complete all required questions before submitting."), { variant: "error", - }) + }) } } const onResponse = (response) => { @@ -1704,31 +1757,31 @@ export default function SurveyQuestions({...props}) { } const loadData = (statusVal: boolean) => { - if(!!statusVal) { - const val = localStorage.getItem("activity-survey-" +(props.data?.activity?.id ?? "")) + if (!!statusVal) { + const val = localStorage.getItem("activity-survey-" + (props.data?.activity?.id ?? "")) setActivityVal(JSON.parse(val)) } else { - localStorage.setItem('activity-survey-'+(props.data?.activity?.id ?? ""), "") + localStorage.setItem('activity-survey-' + (props.data?.activity?.id ?? ""), "") } const activity = props.data.activity ?? (props.data ?? {}); setActivity(activity); setConfirm(false) } - + useEffect(() => { - if(typeof localStorage.getItem('activity-survey-'+(props.data?.activity?.id ?? "")) !== 'undefined' && - (localStorage.getItem('activity-survey-'+(props.data?.activity?.id ?? ""))?.trim()?.length ?? 0) > 0) { + if (typeof localStorage.getItem('activity-survey-' + (props.data?.activity?.id ?? "")) !== 'undefined' && + (localStorage.getItem('activity-survey-' + (props.data?.activity?.id ?? ""))?.trim()?.length ?? 0) > 0) { setConfirm(true) - } else { + } else { const activity = props.data.activity ?? (props.data ?? {}); setActivity(activity); } - const configuration = props.data.configuration; + const configuration = props.data.configuration; i18n.changeLanguage(!!configuration ? configuration?.language : "en-US"); }, []) useEffect(() => { - if(!!activity) { + if (!!activity) { setQuestions() } }, [activity]) @@ -1737,7 +1790,7 @@ export default function SurveyQuestions({...props}) { { description: t("Yes"), value: "Yes" /* true */ }, { description: t("No"), value: "No" /* false */ }, ] - + const likertOpts = [ { description: t("Nearly All the Time"), value: 3 }, { description: t("More than Half the Time"), value: 2 }, @@ -1746,57 +1799,57 @@ export default function SurveyQuestions({...props}) { ] const setQuestions = () => { - const settings = [] - const processed = [] - ;(activity.settings || []).map((question, index) => { - if( !processed.includes(index)) { - if(activity.settings[index+1]?.type === "matrix" || (index === 0 && question?.type === "matrix")) { + const settings = [] + const processed = [] + ; (activity.settings || []).map((question, index) => { + if (!processed.includes(index)) { + if (activity.settings[index + 1]?.type === "matrix" || (index === 0 && question?.type === "matrix")) { const desc = question?.description ?? "" const options = question?.type === "boolean" ? binaryOpts : question?.type === "likert" ? likertOpts : question?.options ?? [] const questions = [] - for (let k=index; k < activity.settings.length; k++) { - if(k === index || (activity.settings[k]?.type === "matrix")){ - questions.push({text: activity.settings[k].text, required: activity.settings[k].required}) + for (let k = index; k < activity.settings.length; k++) { + if (k === index || (activity.settings[k]?.type === "matrix")) { + questions.push({ text: activity.settings[k].text, required: activity.settings[k].required }) processed.push(k) } else { break } } const type = index === 0 && question?.type === "matrix" ? "text" : question.type - settings.push({type, subType:"matrix", description: desc, options, questions}) + settings.push({ type, subType: "matrix", description: desc, options, questions }) } else { settings.push(question) } } }) - setSettings(settings) + setSettings(settings) } return ( - - + setConfirm(false)} open={confirm} - confirmAction={loadData} - confirmationMsg={t("Would you like to resume this activity where you left off?")}/> - + confirmAction={loadData} + confirmationMsg={t("Would you like to resume this activity where you left off?")} /> + {(activity !== null && settings !== null) ?
+ onResponse={(response) => (response === null) ? onResponse(null) : - setResponses(response) + setResponses(response) } value={activity} activityVal={activityVal} settings={settings} totalQuestions={(activity?.settings || []).length} - noBack= {props.data.noBack} - onComplete={() =>{ + noBack={props.data.noBack} + onComplete={() => { postSubmit(responses) }} - /> : null } + /> : null} ) } \ No newline at end of file