diff --git a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx
index 34fb2f6..9133f8a 100644
--- a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx
+++ b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx
@@ -92,7 +92,8 @@ const SearchableSelect = ({
error = false,
className = '',
displayValue = undefined,
- allowNull = false // New prop to allow null values for no selection
+ allowNull = false, // New prop to allow null values for no selection
+ allowClear = false // New prop to show clear button
}) => {
const [isOpen, setIsOpen] = React.useState(false);
const [searchTerm, setSearchTerm] = React.useState('');
@@ -176,6 +177,28 @@ const SearchableSelect = ({
const displayValueToShow = internalDisplayValue;
+ // Handle clear functionality
+ const handleClear = (event) => {
+ event.preventDefault();
+ event.stopPropagation();
+ if (onChange) {
+ const event = {
+ target: {
+ value: allowNull ? null : ''
+ }
+ };
+ onChange(event);
+ }
+ setSearchTerm('');
+ setIsOpen(false);
+ };
+
+ // Check if clear button should be shown
+ // Show clear button when value is not null, not undefined, and not empty string
+ // Note: value can be 0 (user-selected) but should still show clear button
+ const hasValue = value !== null && value !== undefined && value !== '';
+ const showClear = allowClear && hasValue && !disabled && !loading;
+
// Handle option selection
const handleSelect = (option) => {
if (onChange) {
@@ -211,12 +234,24 @@ const SearchableSelect = ({
className={`flex items-center justify-between h-10 px-4 py-2 text-sm rounded-md border-2 ${borderColor} ${bgColor} ${disabled ? 'bg-gray-50 cursor-not-allowed' : 'cursor-pointer'}`}
onClick={() => !disabled && !loading && setIsOpen(!isOpen)}
>
- {displayValueToShow || placeholder}
- {loading ? (
-
- ) : (
-
- )}
+ {displayValueToShow || placeholder}
+
+ {showClear ? (
+
+ ) : loading ? (
+
+ ) : null}
+ {!showClear && !loading && (
+

+ )}
+
{isOpen && (
@@ -1424,56 +1459,49 @@ useEffect(() => {
const errors = {};
let isValid = true;
+ // Check if all available products have been added
+ const availableProductsCount = productOptions.length;
+ const currentProductsCount = products.length;
+ const remainingProducts = availableProductsCount - currentProductsCount;
+
+ if (currentProductsCount < availableProductsCount) {
+ errors['products_general'] = `Please fill remaining ${remainingProducts} product${remainingProducts > 1 ? 's' : ''} before proceeding`;
+ isValid = false;
+ }
+
products.forEach((product, index) => {
- // Validate product selection
+ // Only validate fields that are marked as mandatory (with asterisk in UI)
+ // Product selection is mandatory
if (!product.product) {
errors[`product_${index}`] = 'Product is required';
isValid = false;
}
- // Validate unit selection
+ // Unit selection is mandatory
if (!product.unit) {
errors[`unit_${index}`] = 'Unit is required';
isValid = false;
}
- // Validate capacity
- if (!product.capacity) {
+ // Annual installed capacity is mandatory
+ if (!product.capacity || product.capacity === '0' || parseFloat(product.capacity) === 0) {
errors[`capacity_${index}`] = 'Capacity is required';
isValid = false;
}
- // Validate current quarter quantities
- const currentQuantityFields = ['janQuantity', 'febQuantity', 'marQuantity'];
- currentQuantityFields.forEach(field => {
- if (!product[field] && product[field] !== 0) {
+ // Only quantity fields with asterisk (*) are mandatory (current and next quarter)
+ const mandatoryQuantityFields = ['janQuantity', 'febQuantity', 'marQuantity', 'aprQuantity', 'mayQuantity', 'junQuantity'];
+ mandatoryQuantityFields.forEach(field => {
+ if (!product[field] || product[field] === '0' || parseFloat(product[field]) === 0) {
errors[`${field}_${index}`] = 'Required';
isValid = false;
}
});
- // Validate current quarter costs
- const currentCostFields = ['janCost', 'febCost', 'marCost'];
- currentCostFields.forEach(field => {
- if (!product[field] && product[field] !== 0) {
- errors[`${field}_${index}`] = 'Required';
- isValid = false;
- }
- });
-
- // Validate forecast quantities
- const forecastQuantityFields = ['aprQuantity', 'mayQuantity', 'junQuantity'];
- forecastQuantityFields.forEach(field => {
- if (!product[field] && product[field] !== 0) {
- errors[`${field}_${index}`] = 'Required';
- isValid = false;
- }
- });
-
- // Validate forecast costs
- const forecastCostFields = ['aprCost', 'mayCost', 'junCost'];
- forecastCostFields.forEach(field => {
- if (!product[field] && product[field] !== 0) {
+ // Only value fields with asterisk (*) are mandatory (current and next quarter)
+ const mandatoryCostFields = ['janCost', 'febCost', 'marCost', 'aprCost', 'mayCost', 'junCost'];
+ mandatoryCostFields.forEach(field => {
+ if (!product[field] || product[field] === '0' || parseFloat(product[field]) === 0) {
errors[`${field}_${index}`] = 'Required';
isValid = false;
}
@@ -2613,6 +2641,7 @@ useEffect(() => {
value={p.novCost || ''}
error={!!formErrors[`novCost_${idx}`]}
onChange={(e) => updateProductField(p.id, 'novCost', e.target.value)}
+ allowClear={true}
/>
{formErrors[`novCost_${idx}`] && (
{formErrors[`novCost_${idx}`]}
@@ -2761,6 +2790,7 @@ useEffect(() => {
loading={isLoadingReasons}
error={!!formErrors[`variationReason_${idx}`]}
allowNull={true}
+ allowClear={true}
/>
{formErrors[`variationReason_${idx}`] && (
{formErrors[`variationReason_${idx}`]}
@@ -2920,6 +2950,7 @@ useEffect(() => {
onChange={(e) => updateProductField(p.id, 'zeroTargetReason', e.target.value, zeroTargetReasons)}
loading={isLoadingZeroReasons}
allowNull={true}
+ allowClear={true}
/>
{(showOtherZeroTargetReason[p.id] || (p.zeroTargetReason && (p.zeroTargetReason.toString().toLowerCase().includes('other') || (zeroTargetReasons.find(r => r.value === p.zeroTargetReason)?.name?.toLowerCase().includes('other') || zeroTargetReasons.find(r => r.value === p.zeroTargetReason)?.label?.toLowerCase().includes('other'))))) && (
@@ -3008,6 +3039,7 @@ useEffect(() => {
{productsError &&
{productsError}
}
{unitsError &&
{unitsError}
}
{formErrors['draft_general'] &&
{formErrors['draft_general']}
}
+ {formErrors['products_general'] &&
{formErrors['products_general']}
}
)}