This commit is contained in:
Malini 2026-02-06 12:48:28 +05:30
parent 34ebb5d622
commit 63c7fb461d
4 changed files with 74 additions and 37 deletions

View File

@ -433,7 +433,7 @@ const handleDeleteDraft = async (e, submission) => {
handleDeleteDraft(e, draftToDelete); handleDeleteDraft(e, draftToDelete);
setShowDeleteConfirm(false); setShowDeleteConfirm(false);
}} }}
className="px-4 py-2 bg-[#B52520] text-white rounded-md hover:bg-[#9D1F1B] focus:outline-none" className="px-4 py-2 bg-[#92722A] text-white rounded-md hover:bg-[#A88632] focus:outline-none"
> >
Delete Delete
</button> </button>

View File

@ -395,7 +395,8 @@ const ProductData = ({
const [showDataDefinitions, setShowDataDefinitions] = React.useState(true); const [showDataDefinitions, setShowDataDefinitions] = React.useState(true);
const [showEntryRules, setShowEntryRules] = React.useState(true); const [showEntryRules, setShowEntryRules] = React.useState(true);
const [showInfoCard, setShowInfoCard] = React.useState(true); const [showInfoCard, setShowInfoCard] = React.useState(true);
const MAX_PRODUCTS = 10; const [availableProductsCount, setAvailableProductsCount] = React.useState(0);
const [maxProducts, setMaxProducts] = React.useState(0);
const nextId = React.useRef(products.length + 1); const nextId = React.useRef(products.length + 1);
const [variationReasons, setVariationReasons] = React.useState([]); const [variationReasons, setVariationReasons] = React.useState([]);
const [isLoadingReasons, setIsLoadingReasons] = React.useState(false); const [isLoadingReasons, setIsLoadingReasons] = React.useState(false);
@ -407,6 +408,7 @@ const ProductData = ({
const [isLoadingProducts, setIsLoadingProducts] = React.useState(false); const [isLoadingProducts, setIsLoadingProducts] = React.useState(false);
const [productsError, setProductsError] = React.useState(''); const [productsError, setProductsError] = React.useState('');
const [showDraftSaved, setShowDraftSaved] = React.useState(false); const [showDraftSaved, setShowDraftSaved] = React.useState(false);
const MAX_PRODUCTS = maxProducts;
// Remove the unused state variables since we'll use the props directly // Remove the unused state variables since we'll use the props directly
const [unitOptions, setUnitOptions] = React.useState([]); const [unitOptions, setUnitOptions] = React.useState([]);
const [isLoadingUnits, setIsLoadingUnits] = React.useState(false); const [isLoadingUnits, setIsLoadingUnits] = React.useState(false);
@ -1439,42 +1441,64 @@ useEffect(() => {
} }
}; };
// Check if there are any products available to add // Get the total number of unique products available
const getAvailableProductsCount = () => { const getAvailableProductsCount = () => {
try { try {
const currentSubmissionStr = localStorage.getItem('currentSubmission'); const currentSubmissionStr = localStorage.getItem('currentSubmission');
let submittedProductIds = []; let submittedProductIds = new Set();
// Get submitted product IDs from current submission
if (currentSubmissionStr) { if (currentSubmissionStr) {
const currentSubmission = JSON.parse(currentSubmissionStr); const currentSubmission = JSON.parse(currentSubmissionStr);
if (currentSubmission.products && Array.isArray(currentSubmission.products)) { if (currentSubmission.products && Array.isArray(currentSubmission.products)) {
submittedProductIds = currentSubmission.products currentSubmission.products.forEach(p => {
.filter(p => p.product_id) if (p.product_id) submittedProductIds.add(p.product_id.toString());
.map(p => p.product_id.toString()); });
} }
} }
// Get all product IDs that are already selected in the current form // Get all unique product options
const selectedProductIds = products const allProductOptions = new Map();
.filter(p => p.product) productOptions.forEach(option => {
.map(p => p.product.toString()); const id = option.originalData?.product_id?.toString() || option.value;
if (id && !allProductOptions.has(id)) {
allProductOptions.set(id, option);
}
});
// Count how many products are available to add // Get selected product IDs from current form
const availableProducts = productOptions.filter(option => const selectedProductIds = new Set(
!submittedProductIds.includes(option.value) && products
!selectedProductIds.includes(option.value) && .filter(p => p.product)
!submittedProductIds.includes(option.originalData?.product_id?.toString()) .map(p => p.product.toString())
); );
return availableProducts.length; // Count available products (total unique products - submitted - selected)
let availableCount = 0;
for (const [id, option] of allProductOptions.entries()) {
if (!submittedProductIds.has(id) && !selectedProductIds.has(option.value)) {
availableCount++;
}
}
return availableCount;
} catch (error) { } catch (error) {
console.error('Error checking available products:', error); console.error('Error checking available products:', error);
return 0; return 0;
} }
}; };
const availableProductsCount = getAvailableProductsCount(); // Update availableProductsCount and maxProducts when products or options change
const canAddMoreProducts = products.length < MAX_PRODUCTS && availableProductsCount > 0; React.useEffect(() => {
const count = getAvailableProductsCount();
const totalAvailable = productOptions.length;
setAvailableProductsCount(count);
// Set max products to the total number of available products
setMaxProducts(totalAvailable);
}, [products, productOptions]);
const canAddMoreProducts = products.length < maxProducts && availableProductsCount > 0;
const isLoading = loading || isLoadingReasons || isLoadingZeroReasons || isLoadingProducts || isLoadingUnits; const isLoading = loading || isLoadingReasons || isLoadingZeroReasons || isLoadingProducts || isLoadingUnits;
const hasError = error || reasonsError || zeroReasonsError || productsError || unitsError; const hasError = error || reasonsError || zeroReasonsError || productsError || unitsError;
@ -1659,21 +1683,21 @@ useEffect(() => {
</div> </div>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<button <button
onClick={addProduct} onClick={addProduct}
disabled={!canAddMoreProducts || isLoading} disabled={!canAddMoreProducts || isLoading}
className={`inline-flex items-center gap-2 text-sm font-medium px-3 py-2 rounded ${ className={`inline-flex items-center gap-2 text-sm font-medium px-3 py-2 rounded ${
!canAddMoreProducts || isLoading !canAddMoreProducts || isLoading
? 'bg-gray-200 text-gray-500 cursor-not-allowed' ? 'bg-gray-200 text-gray-500 cursor-not-allowed'
: 'bg-[#92722A] text-white cursor-pointer hover:bg-[#9e782f]' : 'bg-[#92722A] text-white cursor-pointer hover:bg-[#9e782f]'
}`} }`}
> >
<span>+ Add Product</span> <span>+ Add Product</span>
</button> </button>
{!canAddMoreProducts && ( {!canAddMoreProducts && (
<span className="text-xs text-gray-600"> <span className="text-xs text-gray-600">
{products.length >= MAX_PRODUCTS {products.length >= MAX_PRODUCTS
? `Maximum of ${MAX_PRODUCTS} products reached.` ? 'No more products available to add.'
: 'No more products available to add.'} : 'No more products available to add.'}
</span> </span>
)} )}

View File

@ -523,7 +523,18 @@ const QuarterlyWindows = () => {
}; };
const handleFormChange = (field) => (value) => { const handleFormChange = (field) => (value) => {
setForm(prev => ({ ...prev, [field]: value })); setForm(prev => {
// If year is being changed, reset the date fields
if (field === 'year' && prev.year !== value) {
return {
...prev,
[field]: value,
startDate: '',
endDate: ''
};
}
return { ...prev, [field]: value };
});
// Clear validation error when user starts typing // Clear validation error when user starts typing
if (validationErrors[field]) { if (validationErrors[field]) {
@ -940,7 +951,8 @@ const QuarterlyWindows = () => {
} }
value={form.startDate} value={form.startDate}
required required
minDate={new Date().toISOString().split('T')[0]} minDate={form.year ? `${form.year}-01-01` : new Date().toISOString().split('T')[0]}
maxDate={form.year ? `${form.year}-12-31` : undefined}
onChange={(e) => handleFormChange('startDate')(e.target.value)} onChange={(e) => handleFormChange('startDate')(e.target.value)}
placeholder="Select Date" placeholder="Select Date"
error={validationErrors.startDate} error={validationErrors.startDate}
@ -960,7 +972,8 @@ const QuarterlyWindows = () => {
} }
value={form.endDate} value={form.endDate}
required required
minDate={form.startDate || new Date().toISOString().split('T')[0]} minDate={form.startDate || (form.year ? `${form.year}-01-01` : new Date().toISOString().split('T')[0])}
maxDate={form.year ? `${form.year}-12-31` : undefined}
onChange={(e) => handleFormChange('endDate')(e.target.value)} onChange={(e) => handleFormChange('endDate')(e.target.value)}
placeholder="Select Date" placeholder="Select Date"
error={validationErrors.endDate} error={validationErrors.endDate}
@ -977,8 +990,8 @@ const QuarterlyWindows = () => {
label="Grace Period (Days)" label="Grace Period (Days)"
value={form.gracePeriod} value={form.gracePeriod}
onChange={(e) => handleFormChange('gracePeriod')(e.target.value)} onChange={(e) => handleFormChange('gracePeriod')(e.target.value)}
options={['5 days', '10 days', '15 days', '20 days', '30 days'].map((item) => ({ options={['0 day', '5 days', '10 days', '15 days', '20 days', '30 days'].map((item) => ({
label: item, label: item === '0 day' ? 'No Grace Period' : item,
value: item, value: item,
}))} }))}
placeholder="Select Grace Period" placeholder="Select Grace Period"

View File

@ -11,7 +11,7 @@ const downloadIconSrc = '/assets/images/DownloadSimple.svg';
const pencilActiveSrc = '/assets/images/PencilSimple.svg'; const pencilActiveSrc = '/assets/images/PencilSimple.svg';
const pencilInactiveSrc = '/assets/images/pencilsimple-inactive.svg'; const pencilInactiveSrc = '/assets/images/pencilsimple-inactive.svg';
import CustomToast from '@/components/common/CustomToast'; import CustomToast from '@/components/common/CustomToast';
const deleteIconSrc = '/assets/images/Trash - active.svg'; const trashActiveSrc = '/assets/images/Trash - active.svg';
const trashInactiveSrc = '/assets/images/Trash - Inactive.svg'; const trashInactiveSrc = '/assets/images/Trash - Inactive.svg';
import { deleteDraftSubmission } from '@/services/submissions/submissionService'; import { deleteDraftSubmission } from '@/services/submissions/submissionService';
import { HiMiniArrowPathRoundedSquare } from 'react-icons/hi2'; import { HiMiniArrowPathRoundedSquare } from 'react-icons/hi2';
@ -207,7 +207,7 @@ const showToast = (message, type = 'success') => {
onMouseLeave={() => setHoveredDelete(null)} onMouseLeave={() => setHoveredDelete(null)}
> >
<img <img
src={hoveredDelete === record.id ? deleteIconSrc : trashInactiveSrc} src={hoveredDelete === record.id ? trashInactiveSrc : trashActiveSrc}
alt="Delete" alt="Delete"
className="h-5 w-5 transition-colors" className="h-5 w-5 transition-colors"
/> />
@ -465,7 +465,7 @@ const showToast = (message, type = 'success') => {
e.stopPropagation(); e.stopPropagation();
confirmDeleteDraft(); confirmDeleteDraft();
}} }}
className="px-4 py-2 bg-[#B52520] text-white rounded-md hover:bg-[#9D1F1B] focus:outline-none" className="px-4 py-2 bg-[#92722A] text-white rounded-md hover:bg-[#A88632] focus:outline-none"
> >
Delete Delete
</button> </button>