# disco/1.4.19/backend/views/components/Main/utilities/utilities.js

Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO, version 1.4.19. 365 lines.

- Page: https://pluginprobe.com/plugins/disco/1.4.19/code/backend/views/components/Main/utilities/utilities.js
- Raw: https://pluginprobe.com/plugins/disco/1.4.19/raw/backend/views/components/Main/utilities/utilities.js
- Modified: 2026-07-23T05:26:10+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/disco/1.4.19/code/backend/views/components/Main/utilities/utilities.js#L10-L20`.

```javascript
import { __ } from '@wordpress/i18n';
import { format } from 'date-fns';
import { toast } from 'react-toastify';

export const getSelectedFilterData = (items, current) => {
	let value = {};
	items.forEach((group) => {
		if (group.options[current]) {
			value = group.options[current];
		}
	});

	return value;
};

export const dateTimeFormatter = (datetime) => {
	if (!datetime) {
		return '-';
	}

	return format(new Date(datetime), 'do MMM, yyyy h:mm a');
};

export const dateStringToTimestamp = (dateString) => {
	const date = new Date(dateString);

	if (isNaN(date.getTime())) {
		return false;
	}

	return date.getTime();
};

export const prepareCampaignForRequest = (campaign, prefix = '') => {
	const dataForRequest = { ...campaign };

	if (dataForRequest.id) {
		delete dataForRequest.id;
	}
	if (dataForRequest.created_by) {
		delete dataForRequest.created_by;
	}
	if (dataForRequest.created_date) {
		delete dataForRequest.created_date;
	}
	if (dataForRequest.modified_by) {
		delete dataForRequest.modified_by;
	}
	if (dataForRequest.modified_date) {
		delete dataForRequest.modified_date;
	}
	if (dataForRequest._links) {
		delete dataForRequest._links;
	}
	if (dataForRequest.name) {
		dataForRequest.name = dataForRequest.name + ' - ' + prefix;
	}
	if (dataForRequest.priority) {
		dataForRequest.priority = '1';
	}

	return dataForRequest;
};

export const buildQueryUrl = (base, query) => {
	const separator = DISCO.is_pretty_url ? '?' : '&';
	return `${base}${separator}${query}`;
};

export const scrollToEmptyField = (fieldName, errorMessage) => {
	const fields = document.getElementsByName(fieldName);
	// Check if multiple fields are present
	if (fields.length > 1) {
		// Loop through all the fields and scroll to the first empty one
		for (let i = 0; i < fields.length; i++) {
			const field = fields[i];
			if (field && field.value.trim().length === 0) {
				// Scroll and focus on the first empty field
				field.scrollIntoView({ behavior: 'smooth', block: 'center' });
				field.focus();
				toast.error(errorMessage);
				return true; // Error found
			}
		}
	} else if (fields.length === 1) {
		// Handle single field case
		const field = fields[0];
		if (field && field.value.trim().length === 0) {
			field.scrollIntoView({ behavior: 'smooth', block: 'center' });
			field.focus();
			toast.error(errorMessage);
			return true; // Error found
		}
	}

	return false; // No error found
};

export const cleanFilters = (data) => {
	return data
		.map((group) => {
			const cleanedBaseFilters = (group.base_filters || []).filter(
				(filter) => {
					return (
						filter.compare !== undefined && filter.compare !== ''
					);
				}
			);

			if (cleanedBaseFilters.length === 0) {
				return null; // Mark this group for removal
			}

			return {
				...group,
				base_filters: cleanedBaseFilters,
			};
		})
		.filter((group) => group !== null); // Remove groups that are null
};

// utils/validateRule.js

export function validateRule(rule, prevRule = {}, index = 0) {
	const errors = {};

	const min = Number(rule.min);
	const max = rule.max !== '' ? Number(rule.max) : null;
	const prevMin = Number(prevRule.min);
	const prevMax = prevRule.max !== '' ? Number(prevRule.max) : null;

	// Min must be greater than 0
	if (!rule.min || min <= 0) {
		errors.min = 'Minimum must be greater than 0';
	}

	if (rule.recursive === 'no' && max !== null && min > max) {
		errors.max = 'Maximum must be greater than Minimum';
	}

	if (index > 0) {
		if (rule.recursive === 'no') {
			if (prevRule.recursive === 'no') {
				if (prevMax !== null ? min <= prevMax : min <= prevMin) {
					errors.min = 'Minimum must be greater than previous rule';
				}
			} else if (min <= prevMin) {
				errors.min = 'Minimum must be greater than previous rule';
			}
		} else if (rule.recursive === 'yes' && min <= prevMin) {
			errors.min = 'Minimum must be greater than previous rule';
		}
	}

	// Only show error toast for the first error (optional)
	if (Object.keys(errors).length > 0) {
		toast.error(Object.values(errors)[0]);
	}

	return {
		isValid: Object.keys(errors).length === 0,
		errors,
		message: Object.values(errors)[0] || '',
	};
}

// NEW: validate all rules at once
export function validateAllRules(rules) {
	for (let i = 0; i < rules.length; i++) {
		const current = rules[i];
		const previous = rules[i - 1] || {};
		const result = validateRule(current, previous, i);

		if (!result.isValid) {
			return {
				isValid: false,
				index: i,
				field: Object.keys(result.errors)[0],
				message: result.message,
			};
		}
	}

	return { isValid: true };
}

//Validate conditions, check the values is empty or not.
export function validateConditions(conditions) {
	if (!conditions || conditions.length === 0) {
		return true;
	}

	for (const group of conditions) {
		const filters = group.base_filters || [];
		for (const filter of filters) {
			if (!filter.compare_with) {
				toast.error(
					__(
						'Please select a condition type or remove the empty condition.',
						'disco'
					)
				);
				return false;
			}

			const value = filter.compare;

			if (value === undefined || value === null || value === '') {
				toast.error(
					__(
						'Please fill in the condition value or remove the empty condition.',
						'disco'
					)
				);
				return false;
			}

			if (Array.isArray(value)) {
				const isEmpty =
					value.length === 0 ||
					value.every(
						(v) => v === '' || v === undefined || v === null
					);
				if (isEmpty) {
					toast.error(
						__(
							'Please fill in the condition value or remove the empty condition.',
							'disco'
						)
					);
					return false;
				}
			}
		}
	}

	return true;
}

export function validateEmptyField(discount) {
	const { products, discount_intent, discount_rules } = discount;
	if (products.length === 0) {
		if (
			scrollToEmptyField(
				'search_products',
				__('Please select few products!', 'disco')
			)
		)
			return false;
	}

	//Field validation for name
	if (
		scrollToEmptyField(
			'campaign_name',
			__('Campaign Name is Required', 'disco')
		)
	)
		return false;

	//Field validation for Minimum quantity
	if (
		discount_intent === 'Bulk' ||
		discount_intent === 'Bundle' ||
		discount_intent === 'BOGO'
	) {
		if (
			scrollToEmptyField(
				'min',
				__('Minimum Quantity is Required', 'disco')
			)
		)
			return false;
	}

	if (
		discount_intent === 'BOGO' &&
		scrollToEmptyField(
			'get_quantity',
			__('Get quantity is Required', 'disco')
		)
	)
		return false;

	if (
		discount_intent === 'BOGO' ||
		discount_intent === 'Bulk' ||
		(discount_intent === 'Bundle' && discount_rules.length > 0)
	) {
		const result = validateAllRules(discount_rules);

		if (!result.isValid) {
			return false;
		}
	}

	//Field validation for discount_value
	if (
		discount_intent !== 'Shipping' &&
		scrollToEmptyField(
			'discount_value',
			__('Discount Value is Required', 'disco')
		)
	)
		return false;

	// Conditions validation
	if (!validateConditions(discount.conditions)) {
		return false;
	}

	return true;
}

export function discountRulesToTableData(discount_rules) {
	const data = discount_rules.map((rule) => {
		const range = rule.max ? `${rule.min}-${rule.max}` : rule.min;
		return {
			title: rule.discount_label,
			discount: rule.discount_value,
			range,
			buy_now: 'Add To Cart',
		};
	});
	return data;
}

/**
 * To truncate text and add an ellipsis
 * @param {string} str
 * @param {number} maxLength
 * @returns {string}
 */
export function truncate(str, maxLength = 30) {
	if (str.length > maxLength) {
		return str.slice(0, maxLength) + '...';
	}
	return str;
}

/**
 *
 * @param {String} rawText
 * @returns {String}
 */
export const renderBadgeText = (rawText) => {
	const text = typeof rawText === 'string' ? rawText : '';
	return text
		.replace(/\[discounted_percentage\]/g, '20%')
		.replace(/\[discounted_amount\]/g, '$10')
		.replace(/\[remaining_quantity\]/g, '5')
		.replace(/\[remaining_amount\]/g, '$50')
		.replace(/\[remaining_cart_items\]/g, '2');
};

/**
 *
 * @param {Object} radius
 * @returns {String}
 */
export const getBorderRadius = (radius) => {
	if (!radius) return undefined;
	return `${radius['top-left'] || '0px'} ${radius['top-right'] || '0px'} ${radius['bottom-right'] || '0px'} ${radius['bottom-left'] || '0px'}`;
};

```
