Skip to content
Snippets Groups Projects
SurveyComponent.tsx 4.15 KiB
import React, { useCallback } from "react";
import { Question, FunctionFactory } from "survey-core";
import { Survey } from "survey-react-ui";
import { VerificationStatus } from './Schema';


function customDescriptionCallback(_, options) {
    // get the customDescription for matrix rows and set it in the title
    // attribute so that it shows up as a hover popup
    if (options.column['indexValue'] == 0 && 'item' in options.row) {
        const item = options.row['item'] as object;
        if (item['customDescription'] !== undefined) {
            options.htmlElement.parentElement?.children[0].setAttribute("title", item['customDescription']);
        }
    }
}

function validateWebsiteUrl(params) {
    const value = params[0];
    if (value === undefined || value == null || value == '') {
        return true;
    }
    try {
        const url = new URL(value);
        return url.protocol === 'http:' || url.protocol === 'https:';
    } catch (err) {
        return false;
    }
}

function hideCheckboxLabels(_, options) {
    if (options.question.hideCheckboxLabels) {
        const classes = options.cssClasses;
        classes.root += " hidden-checkbox-labels";
    }
}

function setVerifyButton(question: Question, state: VerificationStatus, surveyModel) {

    surveyModel.verificationStatus.set(question.name, state);

    const btn = document.createElement("button");
    btn.type = "button";
    btn.className = "sv-action-bar-item verification";
    btn.innerHTML = state;

    if (state == VerificationStatus.Unverified) {
        btn.innerHTML = "No change from previous year";
        btn.className += " verification-required";
        btn.onclick = function () {
            if (surveyModel.mode == "display") {
                return;
            }
            question.validate();
            setVerifyButton(question, VerificationStatus.Verified, surveyModel);
        }
    } else {
        btn.innerHTML = "Answer updated"
        btn.className += " verification-ok";
    }

    const selector = '[data-name="' + question.name + '"]';
    const header = document.querySelector(selector)?.querySelector('h5');

    const old = header?.querySelector(".verification");
    if (old) {
        old.replaceWith(btn);
    } else {
        header?.appendChild(btn);
    }
}


function SurveyComponent({ surveyModel }) {

    const alwaysSetVerify = useCallback((_, options) => {
        const status = surveyModel.verificationStatus.get(options.question.name);
        if (status) {
            setVerifyButton(options.question, status, surveyModel);
        }
    }, [surveyModel])

    const updateFromUnverified = useCallback((_, options) => {
        const currentStatus = surveyModel.verificationStatus.get(options.question.name);
        if (currentStatus == VerificationStatus.Unverified) {
            setVerifyButton(options.question, VerificationStatus.Edited, surveyModel);
        }
    }, [surveyModel])

    if (!FunctionFactory.Instance.hasFunction("validateWebsiteUrl")) {
        FunctionFactory.Instance.register("validateWebsiteUrl", validateWebsiteUrl);
    }

    if (!surveyModel.css.question.title.includes("sv-header-flex")) {
        surveyModel.css.question.title = "sv-title sv-question__title sv-header-flex";
        surveyModel.css.question.titleOnError = "sv-question__title--error sv-error-color-fix";
    }

    if (!surveyModel.onAfterRenderQuestion.hasFunc(alwaysSetVerify)) {
        surveyModel.onAfterRenderQuestion.add(alwaysSetVerify);
    }

    if (!surveyModel.onValueChanged.hasFunc(updateFromUnverified)) {
        surveyModel.onValueChanged.add(updateFromUnverified);
    }

    if (!surveyModel.onUpdateQuestionCssClasses.hasFunc(hideCheckboxLabels)) {
        surveyModel.onUpdateQuestionCssClasses.add(hideCheckboxLabels);
    }

    if (!surveyModel.onMatrixAfterCellRender.hasFunc(customDescriptionCallback)) {
        // NB I would have preferred using onAfterRenderQuestion, but unfortunately that is
        // not always triggered on re-renders (specifically when extra column become visble or invisible)
        surveyModel.onMatrixAfterCellRender.add(customDescriptionCallback);
    }

    return <Survey model={surveyModel} />
}

export default SurveyComponent;