All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.resources.js.data_set.actions.components.ActionForm.tsx Maven / Gradle / Ivy

The newest version!
/**
 * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
 * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
 */

import ClayButton, {ClayButtonWithIcon} from '@clayui/button';
import ClayForm, {ClayInput, ClaySelectWithOption} from '@clayui/form';
import ClayIcon from '@clayui/icon';
import ClayLayout from '@clayui/layout';
import ClayPanel from '@clayui/panel';
import ClayTabs from '@clayui/tabs';
import classNames from 'classnames';
import {InputLocalized, openModal} from 'frontend-js-components-web';
import {fetch} from 'frontend-js-web';
import React, {useEffect, useState} from 'react';

import RequiredMark from '../../../components/RequiredMark';
import Search from '../../../components/Search';
import ValidationFeedback from '../../../components/ValidationFeedback';
import {
	API_URL,
	DEFAULT_FETCH_HEADERS,
	OBJECT_RELATIONSHIP,
} from '../../../utils/constants';
import openDefaultFailureToast from '../../../utils/openDefaultFailureToast';
import openDefaultSuccessToast from '../../../utils/openDefaultSuccessToast';
import {IDataSet} from '../../../utils/types';
import {EActionTarget, EActionType, IAction} from '../Actions';

enum EAsyncActionMethod {
	DELETE = 'DELETE',
	GET = 'GET',
	PATCH = 'PATCH',
	POST = 'POST',
	PUT = 'PUT',
}

const ACTION_TARGETS = [
	{
		label: Liferay.Language.get('link'),
		value: EActionTarget.LINK,
	},
	{
		label: Liferay.Language.get('modal'),
		value: EActionTarget.MODAL,
	},
	{
		label: Liferay.Language.get('side-panel'),
		value: EActionTarget.SIDEPANEL,
	},
];

const ITEM_ACTION_TARGETS = [
	{
		label: Liferay.Language.get('async'),
		value: EActionTarget.ASYNC,
	},
	{
		label: Liferay.Language.get('headless'),
		value: EActionTarget.HEADLESS,
	},
].concat(ACTION_TARGETS);

const MESSAGE_TYPES = [
	{
		label: Liferay.Language.get('info'),
		value: 'info',
	},
	{
		label: Liferay.Language.get('secondary'),
		value: 'secondary',
	},
	{
		label: Liferay.Language.get('success'),
		value: 'success',
	},
	{
		label: Liferay.Language.get('danger'),
		value: 'danger',
	},
	{
		label: Liferay.Language.get('warning'),
		value: 'warning',
	},
];

const MODAL_SIZES = [
	{
		label: Liferay.Language.get('full-screen'),
		value: 'full-screen',
	},
	{
		label: Liferay.Language.get('large'),
		value: 'lg',
	},
	{
		label: Liferay.Language.get('small'),
		value: 'sm',
	},
];

const translationExists = ({translations}: {translations: any}) => {
	return Boolean(Object.keys(translations).find((key) => translations[key]));
};

const ActionForm = ({
	activeTab,
	dataSet,
	editing = false,
	initialValues,
	namespace,
	onCancel,
	onSave,
	spritemap,
}: {
	activeTab: number;
	dataSet: IDataSet;
	editing?: boolean;
	initialValues?: IAction;
	namespace: string;
	onCancel: () => void;
	onSave: () => void;
	spritemap: string;
}) => {
	const [activeMessageTab, setActiveMessageTab] = useState(0);
	const [availableIconSymbols, setAvailableIconSymbols] = useState<
		Array<{label: string; value: string}>
	>([]);
	const [
		confirmationMessageTranslations,
		setConfirmationMessageTranslations,
	] = useState(initialValues?.confirmationMessage_i18n ?? {});
	const [errorMessageTranslations, setErrorMessageTranslations] = useState(
		initialValues?.errorMessage_i18n ?? {}
	);
	const [labelTranslations, setLabelTranslations] = useState(
		initialValues?.label_i18n ?? {}
	);
	const [requestBodyValidationError, setRequestBodyValidationError] =
		useState(false);
	const [labelValidationError, setLabelValidationError] = useState(false);
	const [permissionKeyValidationError, setPermissionKeyValidationError] =
		useState(false);
	const [saveButtonDisabled, setSaveButtonDisabled] = useState(false);
	const [successMessageTranslations, setSuccessMessageTranslations] =
		useState(initialValues?.successMessage_i18n ?? {});
	const [titleTranslations, setTitleTranslations] = useState(
		initialValues?.title_i18n ?? {}
	);
	const [urlValidationError, setURLValidationError] = useState(false);

	const [actionData, setActionData] = useState({
		confirmationMessage: initialValues?.confirmationMessage ?? '',
		confirmationMessageType:
			initialValues?.confirmationMessageType ?? 'warning',
		icon: initialValues?.icon ?? '',
		label: initialValues?.label ?? '',
		method: initialValues?.method ?? '',
		modalSize: initialValues?.modalSize ?? '',
		permissionKey: initialValues?.permissionKey ?? '',
		requestBody: initialValues?.requestBody ?? '',
		target: initialValues?.target ?? 'link',
		title: initialValues?.title ?? '',
		type: initialValues?.type ?? '',
		url: initialValues?.url ?? '',
	} as IAction);

	const isRequestBodyInputValid = (value: string | undefined) => {
		if (!value) {
			return true;
		}

		if (!value.match(/{[^}]*}/)) {
			return false;
		}

		try {
			JSON.parse(value);

			return true;
		}
		catch {
			return false;
		}
	};

	const onActionTargetChange = (event: any) => {
		const target = event.target.value;

		setActionData({
			...actionData,
			method:
				target === EActionTarget.ASYNC ? EAsyncActionMethod.DELETE : '',
			modalSize:
				target === EActionTarget.MODAL ? MODAL_SIZES[0].value : '',
			target,
		});

		if (target !== EActionTarget.HEADLESS) {
			setPermissionKeyValidationError(false);
		}
	};

	const saveAction = async () => {
		setSaveButtonDisabled(true);

		const {
			confirmationMessageType,
			icon,
			method,
			modalSize,
			permissionKey,
			requestBody,
			target,
			url,
		} = actionData;

		const type: string =
			activeTab === 0 ? EActionType.ITEM : EActionType.CREATION;

		const body = {
			confirmationMessage_i18n: confirmationMessageTranslations,
			icon,
			label_i18n: labelTranslations,
			method,
			modalSize,
			permissionKey,
			[OBJECT_RELATIONSHIP.DATA_SET_ACTIONS_ID]: dataSet.id,
			requestBody,
			target,
			title_i18n: titleTranslations,
			type,
			url,
		} as any;

		if (Object.keys(confirmationMessageTranslations).length) {
			body.confirmationMessageType = confirmationMessageType;
		}

		if (
			actionData.target === EActionTarget.ASYNC ||
			actionData.target === EActionTarget.HEADLESS
		) {
			body.errorMessage_i18n = errorMessageTranslations;
			body.successMessage_i18n = successMessageTranslations;
		}

		if (actionData.target === EActionTarget.ASYNC) {
			body.method = method;
		}

		let apiURL = API_URL.ACTIONS;
		let fetchMethod = 'POST';

		if (editing) {
			apiURL = `${apiURL}/${initialValues?.id}`;
			fetchMethod = 'PUT';
		}

		const response = await fetch(apiURL, {
			body: JSON.stringify(body),
			headers: DEFAULT_FETCH_HEADERS,
			method: fetchMethod,
		});

		if (!response.ok) {
			setSaveButtonDisabled(false);

			openDefaultFailureToast();

			return;
		}

		setSaveButtonDisabled(false);

		openDefaultSuccessToast();

		onSave();
	};

	const validate = () => {
		let valid: boolean = true;

		const {permissionKey, requestBody, target, url} = actionData;

		if (
			!translationExists({
				translations: labelTranslations,
			})
		) {
			valid = false;

			setLabelValidationError(true);
		}

		if (!url && target !== EActionTarget.HEADLESS) {
			valid = false;

			setURLValidationError(true);
		}

		if (
			target === EActionTarget.ASYNC ||
			target === EActionTarget.HEADLESS
		) {
			if (!isRequestBodyInputValid(requestBody)) {
				valid = false;

				setRequestBodyValidationError(true);
			}
		}

		if (!permissionKey && target === EActionTarget.HEADLESS) {
			valid = false;

			setPermissionKeyValidationError(true);
		}

		return valid;
	};

	useEffect(() => {
		const getIcons = async () => {
			const response = await fetch(spritemap);

			const responseText = await response.text();

			if (responseText.length) {
				const spritemapDocument = new DOMParser().parseFromString(
					responseText,
					'text/xml'
				);

				const symbolElements =
					spritemapDocument.querySelectorAll('symbol');

				const iconSymbols = Array.from(symbolElements!).map(
					(element) => ({
						label: element.id,
						value: element.id,
					})
				);

				setAvailableIconSymbols(iconSymbols);
			}
		};

		getIcons();
	}, [spritemap]);

	const confirmationMessageFormElementId = `${namespace}ConfirmationMessage`;
	const confirmationMessageTypeFormElementId = `${namespace}ConfirmationMessageType`;
	const errorMessageFormElementId = `${namespace}ErrorMessage`;
	const iconFormElementId = `${namespace}Icon`;
	const labelFormElementId = `${namespace}Label`;
	const methodFormElementId = `${namespace}Method`;
	const modalSizeFormElementId = `${namespace}ModalSize`;
	const permissionKeyFormElementId = `${namespace}PermissionKey`;
	const requestBodyFormElementId = `${namespace}RequestBody`;
	const successMessageFormElementId = `${namespace}SuccessMessage`;
	const titleFormElementId = `${namespace}Title`;
	const typeFormElementId = `${namespace}Type`;
	const urlFormElementId = `${namespace}URL`;

	const ModalBody = ({closeModal}: {closeModal: Function}) => {
		const [filteredIconSymbols, setFilteredIconSymbols] =
			useState>(
				availableIconSymbols
			);
		const [query, setQuery] = useState('');

		const onSearch = (query: string) => {
			setQuery(query);

			const regexp = new RegExp(query, 'i');

			setFilteredIconSymbols(
				query
					? availableIconSymbols.filter((item) =>
							String(item.value).match(regexp)
						)
					: availableIconSymbols
			);
		};

		return (
			<>
				

				
					
    {filteredIconSymbols.map((item) => { return (
  • { setActionData({ ...actionData, icon: item.value, }); closeModal(); }} > {item.label}
  • ); })}
); }; return ( <>

{editing && initialValues?.label} {!editing && activeTab === 0 && Liferay.Language.get('new-item-action')} {!editing && activeTab === 1 && Liferay.Language.get('new-creation-action')}

{ setLabelTranslations(translations); setLabelValidationError( !translationExists({ translations, }) ); }} placeholder={Liferay.Language.get( 'action-name' )} required translations={labelTranslations} /> setActionData({ ...actionData, icon: value, }) } placeholder={Liferay.Language.get( 'no-icon-selected' )} type="text" value={actionData.icon} /> openModal({ bodyComponent: ModalBody, containerProps: { className: 'dsm-actions-icon-selection-modal', }, size: 'lg', title: Liferay.Language.get( 'select-an-icon' ), }) } symbol={ actionData.icon !== '' ? 'change' : 'plus' } /> {actionData.icon !== '' && ( setActionData({ ...actionData, icon: '', }) } symbol="trash" /> )} {actionData.target === EActionTarget.ASYNC && ( setActionData({ ...actionData, method: event.target.value, }) } options={Object.values( EAsyncActionMethod ).map((method) => ({ label: method, value: method, }))} placeholder={Liferay.Language.get( 'please-select-an-option' )} value={actionData.method} /> )} {actionData.target === EActionTarget.MODAL && ( setActionData({ ...actionData, modalSize: event.target.value, }) } options={MODAL_SIZES} placeholder={Liferay.Language.get( 'please-select-an-option' )} value={actionData.modalSize} /> )} {(actionData.target === EActionTarget.MODAL || actionData.target === EActionTarget.SIDEPANEL) && ( { setTitleTranslations(translations); }} placeholder={ actionData.target === EActionTarget.MODAL ? Liferay.Language.get( 'add-the-title-of-the-modal' ) : Liferay.Language.get( 'add-the-title-of-the-side-panel' ) } translations={titleTranslations} /> )} {actionData.target !== EActionTarget.HEADLESS && ( { const url = event.target.value; setActionData({ ...actionData, url, }); setURLValidationError(!url); }} placeholder={Liferay.Language.get( 'add-a-url-here' )} value={actionData.url} /> {urlValidationError && ( )} )} {(actionData.target === EActionTarget.HEADLESS || actionData.target === EActionTarget.ASYNC) && ( { const requestBody = event.target.value; setActionData({ ...actionData, requestBody, }); setRequestBodyValidationError( !isRequestBodyInputValid( requestBody ) ); }} placeholder={Liferay.Language.get( 'add-a-request-body-here' )} value={actionData.requestBody} /> {requestBodyValidationError && ( )} )} { const permissionKey = event.target.value; setActionData({ ...actionData, permissionKey, }); if ( actionData.target === EActionTarget.HEADLESS ) { setPermissionKeyValidationError( !permissionKey ); } }} placeholder={Liferay.Language.get( 'add-a-value-here' )} value={actionData.permissionKey} /> {permissionKeyValidationError && ( )} {activeTab === 0 && ( setActionData({ ...actionData, confirmationMessageType: event.target.value, }) } options={MESSAGE_TYPES} value={ actionData.confirmationMessageType } /> )} {(actionData.target === EActionTarget.ASYNC || actionData.target === EActionTarget.HEADLESS) && ( {Liferay.Language.get( 'you-can-write-status-messages-related-to-this-action' )} { setActiveMessageTab(tab); }} > {Liferay.Language.get('success')} {Liferay.Language.get('error')} )} { const valid = validate(); if (valid) { saveAction(); } }} > {Liferay.Language.get('save')} {Liferay.Language.get('cancel')} ); }; export default ActionForm;




© 2015 - 2025 Weber Informatics LLC | Privacy Policy