synapse-react-client
Version:
[](https://travis-ci.com/Sage-Bionetworks/Synapse-React-Client) [](https://badge.fury.io/js/synaps
716 lines • 41.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var React = (0, tslib_1.__importStar)(require("react"));
var lodash_es_1 = (0, tslib_1.__importDefault)(require("lodash-es"));
var json_rules_engine_1 = require("json-rules-engine");
var core_1 = (0, tslib_1.__importDefault)(require("@rjsf/core"));
var types_1 = require("./types");
var Header_1 = (0, tslib_1.__importDefault)(require("./Header"));
var StepsSideNav_1 = (0, tslib_1.__importDefault)(require("./StepsSideNav"));
var NavButtons_1 = require("./NavButtons");
var DataDebug_1 = (0, tslib_1.__importDefault)(require("./DataDebug"));
var SummaryTable_1 = (0, tslib_1.__importDefault)(require("./SummaryTable"));
var WarningModal_1 = (0, tslib_1.__importDefault)(require("./WarningModal"));
var react_switch_1 = (0, tslib_1.__importDefault)(require("react-switch"));
var react_router_dom_1 = require("react-router-dom");
var SynapseForm = /** @class */ (function (_super) {
(0, tslib_1.__extends)(SynapseForm, _super);
function SynapseForm(props) {
var _this = _super.call(this, props) || this;
_this.excludeWarningText = (React.createElement("div", null,
React.createElement("p", null, "This action will clear any entered data on this page and remove this form from your submission. You can include it again at anytime. Only this page will be affected."),
React.createElement("p", null, "Are you sure you want to skip this step and clear any entered data?")));
_this.excludeWarningHeader = 'Skip This Step?';
_this.unsavedDataWarning = "You might have some unsaved data. Are you sure you want to leave?";
_this.navAction = types_1.NavActionEnum.NONE;
_this.extraErrors = [];
_this.isNewForm = function (formData) {
return ((Object.keys(formData).length == 1 &&
Object.keys(formData)[0] === 'metadata') ||
Object.keys(formData).length == 0);
};
_this.getFirstStep = function (steps, formData) {
if (!_this.isNewForm(formData)) {
return steps.find(function (step) { return step.final === true; }) || steps[0];
}
else {
return steps[0];
}
};
_this.onUnload = function (ev) {
{
if (_this.state.hasUnsavedChanges) {
ev.preventDefault();
return (ev.returnValue = _this.unsavedDataWarning);
}
return;
}
};
// Setup the `beforeunload` event listener
_this.setupBeforeUnloadListener = function () {
window.addEventListener('beforeunload', _this.onUnload);
};
_this._setIncludedPropInFormDataNonWizard = function (currentState, schemaScreens) {
var result = {};
var currentStateFormData = currentState.formData;
//if there is a top level 'included' property in schema - update the form.
Object.keys(schemaScreens).forEach(function (key) {
if (lodash_es_1.default.get(schemaScreens[key], "properties.included")) {
lodash_es_1.default.set(result, key + ".included", true);
}
});
return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, currentStateFormData), result);
};
_this._setIncludedPropInFormDataWizard = function (currentState) {
var firstStepId = currentState.currentStep.id;
var newStateData = lodash_es_1.default.cloneDeep(currentState.formData);
lodash_es_1.default.set(newStateData, firstStepId + ".included", true);
return newStateData;
};
// get the schema slice for the current screen/step
_this.getSchema = function (_a) {
var id = _a.id, final = _a.final;
if (final) {
return _this.props.schema;
}
//only get schema for current step. Only the portion of entire form is shown
var currentStepSlice = lodash_es_1.default.pick(_this.props.schema, [
'title',
'type',
"properties." + id,
]);
return currentStepSlice;
};
// find the next step
_this.getNextStepId = function (currentStep, formData, nextStepId) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
var engine, result, error_1;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
if (nextStepId) {
return [2 /*return*/, nextStepId];
}
if (!currentStep.rules || currentStep.rules.length === 0) {
return [2 /*return*/, currentStep.default];
}
engine = new json_rules_engine_1.Engine(currentStep.rules);
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, engine.run(formData)];
case 2:
result = _a.sent();
if (result.events.length > 0) {
return [2 /*return*/, result.events[0].params.next];
}
else {
return [2 /*return*/, currentStep.default];
}
return [3 /*break*/, 4];
case 3:
error_1 = _a.sent();
return [2 /*return*/, currentStep.default];
case 4: return [2 /*return*/];
}
});
}); };
// called when going next, previous or a given step
_this.moveStep = function (formData, nextStepId, isError, previousStack) {
if (previousStack === void 0) { previousStack = (0, tslib_1.__spreadArray)([], _this.state.previousStepIds, true); }
return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
var currentStep, currentStepState, isMoveForwardInWizardMode, steps, nextStep;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
currentStep = this.state.currentStep;
//we don't wnat to display errors on the page - this will be done explicitly in validation
this.formRef.current.setState({ errorSchema: {} });
isMoveForwardInWizardMode = this.props.isWizardMode && !nextStepId;
//previousStack is used for 'back' navigation is wizard mode.
//only need to do it if moving forward i.e. nextStepId is undefined
if (isMoveForwardInWizardMode) {
previousStack.push(currentStep.id);
}
if (!isError) {
currentStepState = types_1.StepStateEnum.COMPLETED;
if (!isMoveForwardInWizardMode && this.props.isWizardMode) {
currentStepState = types_1.StepStateEnum.TODO;
}
}
else {
currentStepState = types_1.StepStateEnum.ERROR;
}
return [4 /*yield*/, this.getNextStepId(currentStep, formData, nextStepId)];
case 1:
// determine next step
nextStepId = _a.sent();
steps = this.state.steps.map(function (step) {
if (step.id === currentStep.id) {
return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, step), { state: currentStepState, inProgress: false });
}
else if (step.id === nextStepId) {
return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, step), { inProgress: true });
}
return step;
});
//if we are in wizard mode we want to make sure that we include the step we are about to go to
if (isMoveForwardInWizardMode) {
lodash_es_1.default.set(formData, nextStepId + ".included", true);
}
nextStep = this.state.steps.find(function (step) { return step.id === nextStepId; });
// clean up unused screens in wizard before getting to submit
if (this.props.isWizardMode && nextStep.final) {
Object.keys(formData).forEach(function (key) {
if (formData[key].included === undefined) {
formData[key] = {};
}
});
}
this.saveStepState(previousStack, steps, nextStep, formData);
return [2 /*return*/];
}
});
});
};
//save the state of the current screen
_this.saveStepState = function (previousStepIds, steps, currentStep, formData) {
_this.setState({
previousStepIds: previousStepIds,
steps: steps,
currentStep: currentStep,
formData: formData,
hasValidated: false,
doShowErrors: false,
});
};
//--------- fns to support navigation --------------------//
_this.goPrevious = function (formData, isError) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
var previousStepId, previousStack, currentIndex;
return (0, tslib_1.__generator)(this, function (_a) {
previousStack = (0, tslib_1.__spreadArray)([], this.state.previousStepIds, true);
// in wizard mode we go to the previously visited screen.
// In regular mode go to the screen with previous index
if (this.props.isWizardMode) {
previousStepId = previousStack.pop();
if (!this.isSubmitScreen()) {
//since we don't know if we'll get back to that step again - exclude it. We will include it again if we
// get to it.
lodash_es_1.default.set(formData, this.state.currentStep.id + ".included", undefined);
}
}
else {
currentIndex = lodash_es_1.default.findIndex(this.state.steps, {
id: this.state.currentStep.id,
});
if (currentIndex > 0) {
previousStepId = this.state.steps[currentIndex - 1].id;
}
}
if (!lodash_es_1.default.isUndefined(previousStepId)) {
return [2 /*return*/, this.moveStep(formData, previousStepId, isError, previousStack)];
}
return [2 /*return*/];
});
}); };
_this.triggerAction = function (navAction) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
var _a;
return (0, tslib_1.__generator)(this, function (_b) {
switch (_b.label) {
case 0:
if (!(navAction === types_1.NavActionEnum.SAVE)) return [3 /*break*/, 1];
return [2 /*return*/, this.props.onSave(this.state.formData)];
case 1:
this.navAction = navAction;
// first run whatever custom validaton we have
_a = this;
return [4 /*yield*/, this.runCustomValidation(this.state.formData, this.state.currentStep, this.state.steps)];
case 2:
// first run whatever custom validaton we have
_a.extraErrors = _b.sent();
if (this.formRef.current) {
this.formRef.current.submit();
}
_b.label = 3;
case 3: return [2 /*return*/];
}
});
}); };
// triggered when we click on the step name in left nav (doesn't happen in wizard mode)
_this.triggerStepChange = function (step) {
_this.nextStep = step;
_this.triggerAction(types_1.NavActionEnum.GO_TO_STEP);
};
_this.onError = function (args) {
_this.setState({
doShowErrors: true,
hasValidated: false,
});
if (_this.navAction === types_1.NavActionEnum.VALIDATE) {
var modifiedSteps = _this.setStepStatusForFailedValidation(args.props, _this.state.steps, !!_this.props.isWizardMode, _this.state.formData, _this.getSchema(_this.state.currentStep).properties ||
_this.getSchema(_this.state.currentStep));
_this.setState({ steps: modifiedSteps });
_this.formDivRef.current.scrollTo(0, 0);
if (_this.state.isLoadingSaved) {
_this.moveStep(_this.state.formData, modifiedSteps[0].id, true);
_this.setState({ isLoadingSaved: false });
}
}
};
_this.setStepStatusForFailedValidation = function (errors, steps, isWizard, formData, currentSchemaProperties) {
//error property is in the format: step.somevalue.etc .welcome.submission_name example
//find all the steps where there is an error
var stepsWithError = errors.map(function (error) { return lodash_es_1.default.trimStart(error.property, '.').split('.')[0]; });
//find all steps in current schema
var stepsInCurrentSchema = Object.keys(currentSchemaProperties);
var updatedSteps = steps.map(function (step) {
//if there is an error in this step
if (stepsWithError.indexOf(step.id) > -1) {
return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, step), { state: types_1.StepStateEnum.ERROR });
//if no error and included in schema
}
else if (stepsInCurrentSchema.indexOf(step.id) > -1) {
var state = types_1.StepStateEnum.COMPLETED;
//if we are in wizard and possibly have not visited this step
if (isWizard && !lodash_es_1.default.get(formData[step.id], 'included')) {
state = step.state;
}
return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, step), { state: state });
}
else {
return step;
}
});
return updatedSteps;
};
//we need to route things through submit - otherwise validation does not kick in
// it triggers internal library validation and calls the performAction with the params for action
_this.onSubmit = function () {
_this.performAction(_this.navAction, _this.state.currentStep.state === types_1.StepStateEnum.ERROR);
};
_this.isSubmitScreen = function () {
return _this.state.currentStep.final === true && !_this.state.isLoadingSaved;
};
_this.showExcludeStateWarningModal = function (stepId, isUpdateFlattenedData) {
if (isUpdateFlattenedData === void 0) { isUpdateFlattenedData = false; }
_this.setState({
modalContext: {
action: _this.toggleExcludeStep,
arguments: [stepId, true, isUpdateFlattenedData],
},
});
};
_this.toggleExcludeStep = function (stepId, isExclude) {
_this.setState(function (prevState, props) {
var steps = prevState.steps.map(function (stp) {
if (stp.id === stepId) {
return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, stp), { excluded: isExclude });
}
return stp;
});
var formDataUpdated = lodash_es_1.default.cloneDeep(prevState.formData);
var currentStep = lodash_es_1.default.cloneDeep(prevState.currentStep);
//we need this because you can exclude on the ifnal screen so the currentStep.id
//is not always the one we need to exclude
if (currentStep.id === stepId) {
currentStep.excluded = isExclude;
}
//if exluding - blow away the data for the step
if (isExclude) {
formDataUpdated[stepId] = {};
//_.set(formDataUpdated, `${stepId}.included`, false);
}
else {
lodash_es_1.default.set(formDataUpdated, stepId + ".included", true);
}
return {
steps: steps,
formData: formDataUpdated,
modalContext: undefined,
currentStep: currentStep,
};
});
};
_this.renderNotification = function (status) {
if (status === types_1.StatusEnum.SAVE_SUCCESS) {
return React.createElement("div", { className: "notification-area" }, " Successfully saved ");
}
if (status === types_1.StatusEnum.SUBMIT_SUCCESS) {
return React.createElement("div", { className: "notification-area" }, " Successfully submitted ");
}
if (status === types_1.StatusEnum.PROGRESS) {
return React.createElement("div", { className: "notification-area" }, " working on it ....");
}
return React.createElement(React.Fragment, null);
};
// displays the text for screens that don't have any form data
_this.renderTextForStaticScreen = function () {
if (!_this.state.currentStep.copy) {
return React.createElement(React.Fragment, null);
}
var copy = _this.state.currentStep.copy;
return (React.createElement("div", { className: "static-screen", dangerouslySetInnerHTML: { __html: copy } }));
};
//displays subheader for forms that can be excluded
_this.renderOptionalFormSubheader = function (isWizard) {
if (isWizard === void 0) { isWizard = false; }
if (isWizard) {
return React.createElement(React.Fragment, null);
}
var currentStep = _this.state.currentStep;
if (currentStep.excluded === true) {
return (React.createElement("div", { className: "step-exclude-directions" },
"This form is currently not included in the submission.",
React.createElement("button", { className: "btn btn-link", onClick: function () { return _this.toggleExcludeStep(currentStep.id, false); } }, "INCLUDE")));
}
else if (currentStep.excluded === false) {
return (React.createElement("div", { className: "step-exclude-directions" },
"This form is currently included in the submission. Enter some data if you have it, or click \"Skip\".",
React.createElement("button", { className: "btn btn-link", onClick: function () {
return _this.showExcludeStateWarningModal(_this.state.currentStep.id);
} }, "SKIP")));
}
return React.createElement(React.Fragment, null);
};
_this.renderHelpToggle = function (currentStep, showHelp, callbackFn) {
if (currentStep.static || currentStep.final) {
return React.createElement(React.Fragment, null);
}
return (React.createElement(React.Fragment, null,
React.createElement("label", { className: "pull-right toggle-help-label" },
React.createElement("span", null, "Hide help"),
React.createElement(react_switch_1.default, { checkedIcon: false, uncheckedIcon: false, height: 20, width: 45, className: "toggle-help", offColor: "#ccc", onChange: function () { return callbackFn(); }, checked: showHelp }),
React.createElement("span", null, "Show help"))));
};
_this.runCustomValidation = function (formData, currentStep, allSteps) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
var errors, rules, data, allRules, engine, result, validationEvents, error_2;
var _a;
return (0, tslib_1.__generator)(this, function (_b) {
switch (_b.label) {
case 0:
errors = [];
rules = currentStep.validationRules || [];
data = (_a = {},
_a[currentStep.id] = formData[currentStep.id],
_a);
// for final step -- concatenate all rules and run on all data
if (currentStep.final) {
rules = allSteps.reduce(function (acc, value) {
return value.validationRules && value.validationRules.length > 0
? acc.concat(value.validationRules)
: acc;
}, []);
data = lodash_es_1.default.cloneDeep(formData);
}
if (rules.length === 0) {
return [2 /*return*/, []];
}
allRules = [];
rules.forEach(function (rule) {
//take a rule
var paramProp = rule.event.params.property;
// if it's just a normal rule - add it
if (paramProp.indexOf('[*]') === -1) {
allRules.push(rule);
}
else {
var path = paramProp.split('[*]')[0].substring(1);
var data_1 = lodash_es_1.default.get(formData, path);
// generate a rule for each item in the data array by substituting [*] w/ appropriate index
if (Array.isArray(data_1) && typeof data_1 !== 'string') {
for (var i = 0; i < data_1.length; i++) {
var newRule = JSON.parse(JSON.stringify(rule).replace(/\[\*\]/g, "[" + i + "]"));
allRules.push(newRule);
}
}
else {
allRules.push(rule);
}
}
});
engine = new json_rules_engine_1.Engine(allRules, {
allowUndefinedFacts: true,
});
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
return [4 /*yield*/, engine.run(data)];
case 2:
result = _b.sent();
validationEvents = result.events;
validationEvents.forEach(function (event) {
var err = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, event.params), {
params: {},
stack: event.params.property + " " + event.params.message,
});
errors.push(err);
});
return [3 /*break*/, 4];
case 3:
error_2 = _b.sent();
console.log(error_2);
return [3 /*break*/, 4];
case 4: return [2 /*return*/, errors];
}
});
}); };
_this.transformErrors = function (errors) {
// if we are not in wizard mode and not trying to submit or validate we just want to skip
// over the errors and just set the step status
// https://github.com/rjsf-team/react-jsonschema-form/issues/1263
_this.extraErrors.forEach(function (extraError) {
if (!errors.find(function (error) { return error.stack === extraError.stack; })) {
errors.push(extraError);
}
});
if (_this.navAction !== types_1.NavActionEnum.SUBMIT &&
_this.navAction !== types_1.NavActionEnum.VALIDATE &&
(!_this.props.isWizardMode || _this.state.currentStep.final)) {
var currentStep = (0, tslib_1.__assign)({}, _this.state.currentStep);
if (errors.length > 0) {
currentStep.state = types_1.StepStateEnum.ERROR;
}
else {
currentStep.state = types_1.StepStateEnum.COMPLETED;
}
_this.setState({ currentStep: currentStep });
return [];
}
// there is an odd behavior in the lib that in cases when we have additional fields depending on enum
// value if it's required and not entered we get 3 error: enum, required, and oneOf
// so if there is an error Oneof on a parent - ignore it and enum on a child. and just output 'required'
// if there is an enum error and there is required with the same prefix remove it
var reqErrors = errors.filter(function (error) { return error.name === 'required'; });
reqErrors.forEach(function (error) {
var parentPath = error.property.substring(0, error.property.lastIndexOf('.'));
lodash_es_1.default.remove(errors, function (error) {
return (error.property.indexOf(parentPath) > -1 &&
(error.name === 'enum' || error.name === 'oneOf'));
});
});
return errors.map(function (error) {
error.message = error.message.replace('property', 'field');
return error;
});
};
_this.renderErrorListTemplate = function (props) {
var errors = props.errors;
var currentLis = errors
.map(function (error, i) {
return renderTransformedErrorObject(_this.state.steps, error, _this.uiSchema, i, _this.props.schema);
})
.sort(function (a, b) { return a.order - b.order; })
.map(function (li) { return li.element; });
return (React.createElement("div", { className: "form-error-summary" },
React.createElement("ul", { className: "error-detail" }, currentLis)));
};
//will modify the ui:help to render html vs text
_this.uiSchema = stringToElementForProp(lodash_es_1.default.cloneDeep(props.uiSchema), 'ui:help');
//create steps array from the navSchema
var steps = props.navSchema.steps
.map(function (step, i) {
return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, step), { inProgress: i === 0 ? true : false });
})
.sort(function (a, b) { return a.order - b.order; });
_this.formRef = React.createRef();
_this.formDivRef = React.createRef();
var currentStep = _this.getFirstStep(steps, props.formData);
_this.state = {
currentStep: currentStep,
steps: steps,
previousStepIds: [],
formData: props.formData,
doShowErrors: false,
doShowHelp: true,
hasUnsavedChanges: false,
isSubmitted: props.isSubmitted,
isLoadingSaved: !_this.isNewForm(_this.props.formData),
};
return _this;
}
SynapseForm.prototype.componentWillUnmount = function () {
window.removeEventListener('beforeunload', this.onUnload);
};
SynapseForm.prototype.componentDidUpdate = function (prevProps) {
var shouldUpdate = this.props.callbackStatus !== prevProps.callbackStatus;
var isSuccess = this.props.callbackStatus === types_1.StatusEnum.SAVE_SUCCESS ||
this.props.callbackStatus === types_1.StatusEnum.SUBMIT_SUCCESS;
if (shouldUpdate && isSuccess) {
this.setState({ hasUnsavedChanges: false });
if (this.props.callbackStatus === types_1.StatusEnum.SUBMIT_SUCCESS) {
this.setState({ isSubmitted: true });
window.history.back();
}
}
};
SynapseForm.prototype.componentDidMount = function () {
var _this = this;
this.setupBeforeUnloadListener();
var isNewForm = this.isNewForm(this.state.formData);
if (!isNewForm) {
//when loading saved form - validate to see the steps status
this.triggerAction(types_1.NavActionEnum.VALIDATE);
}
else {
// for validation of optional forms. Validation is enforced only if included property is set.
this.setState(function (prevState) {
var newFormData = _this.props.isWizardMode
? _this._setIncludedPropInFormDataWizard(prevState)
: _this._setIncludedPropInFormDataNonWizard(prevState, _this.props.schema);
return {
formData: newFormData,
};
});
}
};
//we are constantly saving form data. Needed to overwrite on-error behavior
SynapseForm.prototype.handleOnChange = function (_a) {
var formData = _a.formData;
//this is just for form updates. submit screen goes different route
if (!this.isSubmitScreen() && !this.state.currentStep.excluded) {
var hasUnsavedChanges = !lodash_es_1.default.isEqual(this.state.formData, formData);
this.setState({ formData: formData, hasUnsavedChanges: hasUnsavedChanges });
}
};
SynapseForm.prototype.performAction = function (navAction, hasError) {
var formData = this.state.formData;
switch (navAction) {
case types_1.NavActionEnum.NEXT: {
return this.moveStep(formData, undefined, hasError);
}
case types_1.NavActionEnum.PREVIOUS: {
return this.goPrevious(formData, hasError);
}
case types_1.NavActionEnum.GO_TO_STEP: {
//nextStep is returned when clicked on the Steps left nav
if (!this.nextStep) {
return;
}
return this.moveStep(formData, this.nextStep.id, hasError);
}
case types_1.NavActionEnum.SUBMIT: {
this.props.onSubmit(formData);
return;
}
case types_1.NavActionEnum.VALIDATE: {
//we get here is we clicked validate and the data is valid.
// if it's not valid we handle it in onError fn
var steps = this.setStepStatusForFailedValidation([], this.state.steps, !!this.props.isWizardMode, this.state.formData, this.getSchema(this.state.currentStep).properties ||
this.getSchema(this.state.currentStep));
var currentStep = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, this.state.currentStep), { state: types_1.StepStateEnum.COMPLETED });
this.setState({ hasValidated: true, currentStep: currentStep, steps: steps });
if (this.state.isLoadingSaved) {
this.moveStep(this.state.formData, steps[0].id, false);
this.setState({ isLoadingSaved: false });
}
return;
}
default:
return;
}
};
SynapseForm.prototype.render = function () {
var _this = this;
return (React.createElement("div", { className: "outter-wrap" },
React.createElement(react_router_dom_1.Prompt, { when: this.state.hasUnsavedChanges, message: this.unsavedDataWarning }),
React.createElement(Header_1.default, { isSubmitted: this.state.isSubmitted, bodyText: this.state.currentStep.description, title: this.props.formTitle }),
React.createElement("div", null,
React.createElement("div", { className: "inner-wrap" },
React.createElement(StepsSideNav_1.default, { stepList: this.state.steps, isWizardMode: this.props.isWizardMode, onStepChange: this.triggerStepChange }),
this.state.isLoadingSaved && (React.createElement("div", { className: "text-center" },
React.createElement("span", { className: 'spinner' }))),
React.createElement("div", { className: "form-wrap" },
React.createElement("div", { className: "form-title" }, this.state.currentStep.title),
this.renderNotification(this.props.callbackStatus),
React.createElement("div", { className: "right-top-actions " + (this.state.isSubmitted ? 'hide' : '') },
!this.state.currentStep.static && (React.createElement("button", { type: "button", className: "btn btn-action save pull-right", onClick: function () { return _this.triggerAction(types_1.NavActionEnum.VALIDATE); } }, "VALIDATE")),
this.renderHelpToggle(this.state.currentStep, this.state.doShowHelp, function () {
return _this.setState({
doShowHelp: !_this.state.doShowHelp,
});
}),
this.isSubmitScreen() && (React.createElement("button", { type: "button", className: "btn btn-action save pull-right", disabled: this.state.isSubmitted, onClick: function () { return _this.triggerAction(types_1.NavActionEnum.SUBMIT); } }, "SUBMIT"))),
this.renderOptionalFormSubheader(this.props.isWizardMode),
React.createElement("div", { className: this.isSubmitScreen() || this.state.currentStep.static
? 'hide-form-only'
: 'wrap' },
this.state.hasValidated && (React.createElement("div", { className: "notification-area" }, "Great! All required data on this form has been entered.")),
React.createElement("div", { ref: this.formDivRef, className: "scroll-area " + (this.state.currentStep.excluded ? 'disabled' : ' ') + " " },
React.createElement(core_1.default, { className: this.state.doShowHelp
? 'submissionInputForm'
: 'submissionInputForm no-help', liveValidate: false, formData: this.state.formData, schema: this.getSchema(this.state.currentStep), uiSchema: this.uiSchema, onSubmit: this.onSubmit, onChange: function (args) { return _this.handleOnChange(args); }, onError: function (args) {
return _this.onError({
props: args,
form: _this.formRef,
});
}, showErrorList: !!this.state.doShowErrors || !!this.props.isWizardMode, ErrorList: this.renderErrorListTemplate, transformErrors: this.transformErrors, ref: this.formRef, disabled: this.state.currentStep.excluded || this.state.isSubmitted },
React.createElement("div", { style: { display: 'none' } },
React.createElement("button", { type: "submit" }))),
this.renderTextForStaticScreen(),
!this.props.isWizardMode && (React.createElement(NavButtons_1.NextStepLink, { steps: this.state.steps, nextStepId: this.state.currentStep.default, onNavAction: function (step) { return _this.triggerStepChange(step); } })))),
this.isSubmitScreen() && (React.createElement(SummaryTable_1.default, { formData: this.state.formData, steps: this.state.steps, callbackFn: function (screenId) {
return _this.showExcludeStateWarningModal(screenId, true);
}, uiSchema: this.props.uiSchema, schema: this.props.schema })),
React.createElement(NavButtons_1.NavButtons, { currentStep: this.state.currentStep, steps: this.state.steps, previousStepIds: this.state.previousStepIds, isFormSubmitted: this.state.isSubmitted, onNavAction: function (e) { return _this.triggerAction(e); } })))),
this.state.modalContext && (React.createElement(WarningModal_1.default, { show: true, title: this.excludeWarningHeader, modalBody: this.excludeWarningText, className: "theme-" + this.props.formClass, onConfirmCallbackArgs: this.state.modalContext.arguments, onCancel: function () { return _this.setState({ modalContext: undefined }); }, onConfirm: function (stepId, isExclude) {
return _this.toggleExcludeStep(stepId, isExclude);
} })),
React.createElement(DataDebug_1.default, { formData: this.state.formData, hidden: true })));
};
return SynapseForm;
}(React.Component));
exports.default = SynapseForm;
// takes in a single validation error and and displays it in more readable manner
// used by renderErrorListTemplate
function renderTransformedErrorObject(steps, error, uiSchema, i, schema) {
var propPath = lodash_es_1.default.trimStart(error.property, '.');
var propArr = propPath.split('.');
// some things require labels in schema (e.g. checkboxes) so this is preferred
var labelFromSchema = propArr.join('.properties.') + ".title";
//can be overriden by label in UI
var labelFromUi = propPath + ".ui:title";
//for array fields we need to change the property e.g.
// ld50.experiments[0].species_other should look like 'ld50.experiments.items.species_other'
var arrayLabelFromSchema = labelFromSchema.replace(/\[.*?\]/, '.items');
var arrayLabelFromUI = labelFromUi.replace(/\[.*?\]/, '.items');
var indexMatch = labelFromSchema.match(/\[.*?\]/);
var index = lodash_es_1.default.first(indexMatch);
if (index) {
index = index.substring(1, index.length - 1);
index = !isNaN(parseInt(index)) ? " [" + (parseInt(index) + 1) + "]" : '';
}
var label = lodash_es_1.default.get(uiSchema, labelFromUi) ||
lodash_es_1.default.get(schema.properties, labelFromSchema) ||
lodash_es_1.default.get(uiSchema, arrayLabelFromUI) ||
lodash_es_1.default.get(schema.properties, arrayLabelFromSchema) ||
error.property;
var screen = lodash_es_1.default.find(steps, { id: propArr[0] }) || {
title: propArr[0],
order: 0,
};
var element = (React.createElement("li", { key: i, className: "" },
React.createElement("span", null,
React.createElement("strong", null,
screen.title,
index,
":"),
label,
"\u00A0 ",
error.message)));
return { order: screen.order, element: element };
}
//recursively sets property value to dangerouslySetInnerHTML of that value
function stringToElementForProp(srcObject, key) {
lodash_es_1.default.keys(srcObject).some(function (k) {
if (k === key) {
var value = srcObject[k];
srcObject[k] = React.createElement("span", { dangerouslySetInnerHTML: { __html: value } });
return srcObject;
}
if (srcObject[k] && typeof srcObject[k] === 'object') {
stringToElementForProp(srcObject[k], key);
}
});
return srcObject;
}
//# sourceMappingURL=SynapseForm.js.map