Source: dynamic-data-mapping-form-builder/src/main/resources/META-INF/resources/js/components/RuleBuilder/RuleBuilder.es.js

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

import {makeFetch} from 'dynamic-data-mapping-form-renderer/js/util/fetch.es';
import Component from 'metal-jsx';
import {Config} from 'metal-state';

import RuleEditor from '../../components/RuleEditor/RuleEditor.es';
import RuleList from '../../components/RuleList/RuleList.es';

/**
 * Builder.
 * @extends Component
 */

class RuleBuilder extends Component {
	created() {
		this._fetchDataProvider();
		this._fetchRoles();
	}

	isViewMode() {
		const {mode} = this.state;

		return mode === 'view';
	}

	render() {
		const {
			dataProviderInstanceParameterSettingsURL,
			dataProviderInstancesURL,
			functionsMetadata,
			functionsURL,
			pages,
			spritemap,
		} = this.props;

		const {dataProvider, index, mode, roles, rules} = this.state;

		return (
			<div class="container">
				{mode === 'create' && (
					<RuleEditor
						actions={[]}
						conditions={[]}
						dataProvider={dataProvider}
						dataProviderInstanceParameterSettingsURL={
							dataProviderInstanceParameterSettingsURL
						}
						dataProviderInstancesURL={dataProviderInstancesURL}
						events={{
							ruleAdded: this._handleRuleAdded.bind(this),
							ruleCancelled: this._handleRuleCancelled.bind(this),
							ruleDeleted: this._handleRuleDeleted.bind(this),
							ruleEdited: this._handleRuleEdited.bind(this),
						}}
						functionsMetadata={functionsMetadata}
						functionsURL={functionsURL}
						key={'create'}
						pages={pages}
						ref="RuleEditor"
						roles={roles}
						spritemap={spritemap}
					/>
				)}
				{mode === 'edit' && (
					<RuleEditor
						dataProvider={dataProvider}
						dataProviderInstanceParameterSettingsURL={
							dataProviderInstanceParameterSettingsURL
						}
						dataProviderInstancesURL={dataProviderInstancesURL}
						events={{
							ruleAdded: this._handleRuleSaved.bind(this),
							ruleCancelled: this._handleRuleCancelled.bind(this),
						}}
						functionsMetadata={functionsMetadata}
						functionsURL={functionsURL}
						key={'edit'}
						pages={pages}
						ref="RuleEditor"
						roles={roles}
						rule={rules[index]}
						ruleEditedIndex={index}
						spritemap={spritemap}
					/>
				)}
				{mode === 'view' && (
					<RuleList
						dataProvider={dataProvider}
						events={{
							ruleAdded: this._handleRuleAdded.bind(this),
							ruleCancelled: this._handleRuleCancelled.bind(this),
							ruleDeleted: this._handleRuleDeleted.bind(this),
							ruleEdited: this._handleRuleEdited.bind(this),
						}}
						pages={pages}
						ref="RuleList"
						roles={roles}
						rules={rules}
						spritemap={spritemap}
					/>
				)}
			</div>
		);
	}

	showRuleCreation() {
		this.setState({
			mode: 'create',
		});
	}

	showRuleList() {
		this.setState({
			mode: 'view',
		});
	}

	willReceiveProps({rules}) {
		if (rules && rules.newVal) {
			this.setState({
				rules: rules.newVal,
			});
		}
	}

	_fetchDataProvider() {
		const {dataProviderInstancesURL} = this.props;

		makeFetch({
			method: 'GET',
			url: `${dataProviderInstancesURL}?languageId=${themeDisplay.getLanguageId()}&scopeGroupId=${themeDisplay.getScopeGroupId()}`,
		})
			.then((responseData) => {
				if (!this.isDisposed()) {
					this.setState({
						dataProvider: responseData.map((data) => {
							return {
								...data,
								label: data.name,
								value: data.id,
							};
						}),
					});
				}
			})
			.catch((error) => {
				throw new Error(error);
			});
	}

	_fetchRoles() {
		const {rolesURL} = this.props;

		makeFetch({
			method: 'GET',
			url: rolesURL,
		})
			.then((responseData) => {
				if (!this.isDisposed()) {
					this.setState({
						roles: responseData.map((data) => {
							return {
								...data,
								label: data.name,
								value: data.name,
							};
						}),
					});
				}
			})
			.catch((error) => {
				throw new Error(error);
			});
	}

	_handleRuleAdded(event) {
		const {dispatch} = this.context;

		dispatch('ruleAdded', event);

		this.showRuleList();
	}

	_handleRuleCancelled() {
		const {dispatch} = this.context;
		const {index} = this.state;
		const rules = this.state.rules.map((rule, ruleIndex) => {
			return index === ruleIndex ? this.state.originalRule : rule;
		});

		this.setState({
			mode: 'view',
			rules,
		});

		dispatch('ruleCancelled');
	}

	_handleRuleDeleted({ruleId}) {
		const {dispatch} = this.context;

		dispatch('ruleDeleted', {
			ruleId,
		});
	}

	_handleRuleEdited({ruleId}) {
		const {rules} = this.state;

		ruleId = parseInt(ruleId, 10);

		this.setState({
			index: ruleId,
			mode: 'edit',
			originalRule: JSON.parse(JSON.stringify(rules[ruleId])),
		});
	}

	_handleRuleSaved(event) {
		const {dispatch} = this.context;

		dispatch('ruleSaved', {
			...event,
			ruleId: event.ruleEditedIndex,
		});

		this.showRuleList();
	}

	_setRulesValueFn() {
		return this.props.rules;
	}
}

RuleBuilder.PROPS = {
	dataProviderInstanceParameterSettingsURL: Config.string().required(),

	dataProviderInstancesURL: Config.string().required(),

	functionsMetadata: Config.object({
		number: Config.arrayOf(
			Config.shapeOf({
				label: Config.string(),
				name: Config.string(),
				parameterTypes: Config.array(),
				returnType: Config.string(),
			})
		),
		text: Config.arrayOf(
			Config.shapeOf({
				label: Config.string(),
				name: Config.string(),
				parameterTypes: Config.array(),
				returnType: Config.string(),
			})
		),
		user: Config.arrayOf(
			Config.shapeOf({
				label: Config.string(),
				name: Config.string(),
				parameterTypes: Config.array(),
				returnType: Config.string(),
			})
		),
	}),

	functionsURL: Config.string().required(),

	pages: Config.array().required(),

	rolesURL: Config.string().required(),

	rules: Config.arrayOf(
		Config.shapeOf({
			actions: Config.arrayOf(
				Config.shapeOf({
					action: Config.string(),
					label: Config.string(),
					target: Config.string(),
				})
			),
			conditions: Config.arrayOf(
				Config.shapeOf({
					operands: Config.arrayOf(
						Config.shapeOf({
							label: Config.string(),
							repeatable: Config.bool(),
							type: Config.string(),
							value: Config.string(),
						})
					),
					operator: Config.string(),
				})
			),
			logicalOperator: Config.string(),
		})
	).value([]),

	/**
	 * The path to the SVG spritemap file containing the icons.
	 * @default undefined
	 * @instance
	 * @memberof Form
	 * @type {!string}
	 */

	spritemap: Config.string().required(),
};

RuleBuilder.STATE = {
	dataProvider: Config.arrayOf(
		Config.shapeOf({
			id: Config.string(),
			name: Config.string(),
			uuid: Config.string(),
		})
	).internal(),

	/**
	 * @default
	 * @instance
	 * @memberof RuleBuilder
	 *
	 */

	index: Config.number(),

	mode: Config.oneOf(['view', 'edit', 'create']).value('view'),

	originalRule: Config.object(),

	roles: Config.arrayOf(
		Config.shapeOf({
			id: Config.string(),
			name: Config.string(),
		})
	).internal(),

	rules: Config.arrayOf(
		Config.shapeOf({
			actions: Config.arrayOf(
				Config.shapeOf({
					action: Config.string(),
					label: Config.string(),
					target: Config.string(),
				})
			),
			conditions: Config.arrayOf(
				Config.shapeOf({
					operands: Config.arrayOf(
						Config.shapeOf({
							label: Config.string(),
							repeatable: Config.bool(),
							type: Config.string(),
							value: Config.string(),
						})
					),
					operator: Config.string(),
				})
			),
			logicalOperator: Config.string(),
		})
	).valueFn('_setRulesValueFn'),
};

export default RuleBuilder;
export {RuleBuilder};