import {startTransition, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import renderHtmlAttributes from "../../utils/renderHtmlAttributes"; import extractFieldId from "../../utils/extractFieldId"; import dateDiffInDays from "../../utils/dateDiffInDays"; import evaluateMathExpression from "../../utils/evaluateMathExpression"; import dateDiffInYears from "../../utils/dateDiffInYears"; import dateDiffInMonths from "../../utils/dateDiffInMonths"; import dateDiffInWeeks from "../../utils/dateDiffInWeeks"; import addDaysToDate from "../../utils/addDaysToDate"; import subtractDaysFromDate from "../../utils/subtractDaysFromDate"; import formatDate from "../../utils/formatDate"; import numberFormat from "../../utils/numberFormat"; import type {FreemiusProps} from "../../types/freemius"; import UpgradeOverlay from "../../components/UpgradeOverlay"; import useFormSubmitSuccess from '../../hooks/useFormSubmitSuccess'; type FieldProps = { itemId: string formId: string attrs: Record formula: string listenFields: string[] prefix: string suffix: string isHidden: boolean numberFormat: boolean decimalPoints: number decimalSeparator: string thousandSeparator: string } & FreemiusProps const Field = (props: FieldProps) => { const inputRef = useRef(null); const attrs = useMemo(() => renderHtmlAttributes(props.attrs), [props.attrs]); const [value, setValue] = useState(0); const [values, setValues] = useState<{ [key: string]: string }>({}); // Reset after form submit useFormSubmitSuccess(inputRef, () => { const form = inputRef.current?.closest('.elementor-form'); if (!form) { return; } setTimeout(function () { props.listenFields.forEach((id) => { let elements = form.querySelectorAll(`[name="form_fields[${id}]"]`); if (!elements.length) { const elements2 = form.querySelectorAll(`[name="form_fields[${id}][]"]`); if (!elements2.length) { return; } elements = elements2; } elements.forEach((el) => { el.dispatchEvent(new Event('change', {bubbles: true})); el.dispatchEvent(new Event('input', {bubbles: true})); }); }); }, 400); }, []); const listenFieldsObject = useMemo(() => props.listenFields.reduce>((acc, key) => { acc[key] = 0; return acc; }, {}), [props.listenFields] ); const handleInputChange = useCallback((e: any) => { const {name, value: val} = e.target; const id = extractFieldId(name); if (!id) { return; } let trimVal = String(val).trim(); if (e.target.classList.contains('elementor-date-field')) { const date = Date.parse(trimVal); trimVal = isNaN(date) ? '0' : date.toString(); } else if (e.target.type === 'radio' && !e.target.checked) { trimVal = '0'; } else if (e.target.type === 'checkbox') { const checkboxes = e.target .closest('.elementor-field-type-checkbox') .querySelectorAll('input[type="checkbox"]'); const checked = Array .from(checkboxes) .filter((checkbox: HTMLInputElement) => checkbox.checked); const checkedVal = checked.map((checkbox: HTMLInputElement) => checkbox.value); trimVal = checkedVal.join('+'); } else if (e.target.classList.contains('irs-hidden-input')) { trimVal = trimVal.split(',').join('+'); } else if (e.target.classList.contains('hulk_affef_image_choices_field')) { trimVal = trimVal.split(',').join('+'); } setValues(prevState => ({...prevState, [id]: trimVal})); }, []); useEffect(() => { const fields: Element[] = []; setTimeout(function () { const form = inputRef.current?.closest('.elementor-form'); if (!form) { return; } if (!props.freemius.can_use_premium_code) { return; } props.listenFields.forEach((id) => { let elements = form.querySelectorAll(`[name="form_fields[${id}]"]`); if (!elements.length) { const elements2 = form.querySelectorAll(`[name="form_fields[${id}][]"]`); if (!elements2.length) { return; } elements = elements2; } elements.forEach((el) => { fields.push(el); el.addEventListener("change", handleInputChange); el.addEventListener("input", handleInputChange); el.dispatchEvent(new Event('change', {bubbles: true})); el.dispatchEvent(new Event('input', {bubbles: true})); }); }); }, 400); // Cleanup return () => { fields.forEach((input) => { input.removeEventListener("change", handleInputChange); input.removeEventListener("input", handleInputChange); }); }; }, [handleInputChange, props.freemius.can_use_premium_code, props.listenFields]); useEffect(() => { startTransition(() => { // Function to replace placeholders with actual values const updatePlaceholder = (template: string, data: { [key: string]: string }) => { return template.replace(/[a-zA-Z0-9-_]+/g, (key) => data[key] || key); }; // Regular expression to match unquoted placeholders const updatedFormula = props.formula.replace(/(,\s*)([A-Za-z0-9_-]+)(\s*\))/g, '$1"$2"$3'); const updatedString = updatePlaceholder(updatedFormula, values); setValue(evaluateMathExpression(updatedString, { dateDiffInDays, dateDiffInYears, dateDiffInMonths, dateDiffInWeeks, addDaysToDate, subtractDaysFromDate, formatDate, ...listenFieldsObject })); }); }, [listenFieldsObject, props.formula, props.listenFields, values]); const newVal = useMemo(() => { if (props.numberFormat) { return numberFormat( value, props.decimalPoints, props.decimalSeparator, props.thousandSeparator ); } return value; }, [props.decimalPoints, props.decimalSeparator, props.numberFormat, props.thousandSeparator, value]); return ( <> {!props.freemius.can_use_premium_code && } {!props.isHidden && (
{props.prefix && {props.prefix}} {newVal} {props.suffix && {props.suffix}}
)} ); }; export default Field;