diff --git a/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx b/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx index 7ccd52b..2e1af63 100644 --- a/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx +++ b/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx @@ -433,7 +433,7 @@ const handleDeleteDraft = async (e, submission) => { handleDeleteDraft(e, draftToDelete); 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 diff --git a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx index 6f073e6..8880382 100644 --- a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx +++ b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx @@ -395,7 +395,8 @@ const ProductData = ({ const [showDataDefinitions, setShowDataDefinitions] = React.useState(true); const [showEntryRules, setShowEntryRules] = 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 [variationReasons, setVariationReasons] = React.useState([]); const [isLoadingReasons, setIsLoadingReasons] = React.useState(false); @@ -407,6 +408,7 @@ const ProductData = ({ const [isLoadingProducts, setIsLoadingProducts] = React.useState(false); const [productsError, setProductsError] = React.useState(''); const [showDraftSaved, setShowDraftSaved] = React.useState(false); + const MAX_PRODUCTS = maxProducts; // Remove the unused state variables since we'll use the props directly const [unitOptions, setUnitOptions] = React.useState([]); 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 = () => { try { const currentSubmissionStr = localStorage.getItem('currentSubmission'); - let submittedProductIds = []; + let submittedProductIds = new Set(); + // Get submitted product IDs from current submission if (currentSubmissionStr) { const currentSubmission = JSON.parse(currentSubmissionStr); if (currentSubmission.products && Array.isArray(currentSubmission.products)) { - submittedProductIds = currentSubmission.products - .filter(p => p.product_id) - .map(p => p.product_id.toString()); + currentSubmission.products.forEach(p => { + if (p.product_id) submittedProductIds.add(p.product_id.toString()); + }); } } - // Get all product IDs that are already selected in the current form - const selectedProductIds = products - .filter(p => p.product) - .map(p => p.product.toString()); + // Get all unique product options + const allProductOptions = new Map(); + productOptions.forEach(option => { + 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 - const availableProducts = productOptions.filter(option => - !submittedProductIds.includes(option.value) && - !selectedProductIds.includes(option.value) && - !submittedProductIds.includes(option.originalData?.product_id?.toString()) + // Get selected product IDs from current form + const selectedProductIds = new Set( + products + .filter(p => p.product) + .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) { console.error('Error checking available products:', error); return 0; } }; - const availableProductsCount = getAvailableProductsCount(); - const canAddMoreProducts = products.length < MAX_PRODUCTS && availableProductsCount > 0; + // Update availableProductsCount and maxProducts when products or options change + 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 hasError = error || reasonsError || zeroReasonsError || productsError || unitsError; @@ -1659,21 +1683,21 @@ useEffect(() => {
- {!canAddMoreProducts && ( {products.length >= MAX_PRODUCTS - ? `Maximum of ${MAX_PRODUCTS} products reached.` + ? 'No more products available to add.' : 'No more products available to add.'} )} diff --git a/ipi-survey-platform/src/pages/Admin/configuration/QuarterlyWindows.jsx b/ipi-survey-platform/src/pages/Admin/configuration/QuarterlyWindows.jsx index 3f920b3..5eb3d80 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/QuarterlyWindows.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/QuarterlyWindows.jsx @@ -523,7 +523,18 @@ const QuarterlyWindows = () => { }; 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 if (validationErrors[field]) { @@ -940,7 +951,8 @@ const QuarterlyWindows = () => { } value={form.startDate} 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)} placeholder="Select Date" error={validationErrors.startDate} @@ -960,7 +972,8 @@ const QuarterlyWindows = () => { } value={form.endDate} 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)} placeholder="Select Date" error={validationErrors.endDate} @@ -977,8 +990,8 @@ const QuarterlyWindows = () => { label="Grace Period (Days)" value={form.gracePeriod} onChange={(e) => handleFormChange('gracePeriod')(e.target.value)} - options={['5 days', '10 days', '15 days', '20 days', '30 days'].map((item) => ({ - label: item, + options={['0 day', '5 days', '10 days', '15 days', '20 days', '30 days'].map((item) => ({ + label: item === '0 day' ? 'No Grace Period' : item, value: item, }))} placeholder="Select Grace Period" diff --git a/ipi-survey-platform/src/pages/Overview/Overview.jsx b/ipi-survey-platform/src/pages/Overview/Overview.jsx index 3ef548c..3536fa4 100644 --- a/ipi-survey-platform/src/pages/Overview/Overview.jsx +++ b/ipi-survey-platform/src/pages/Overview/Overview.jsx @@ -11,7 +11,7 @@ const downloadIconSrc = '/assets/images/DownloadSimple.svg'; const pencilActiveSrc = '/assets/images/PencilSimple.svg'; const pencilInactiveSrc = '/assets/images/pencilsimple-inactive.svg'; 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'; import { deleteDraftSubmission } from '@/services/submissions/submissionService'; import { HiMiniArrowPathRoundedSquare } from 'react-icons/hi2'; @@ -207,7 +207,7 @@ const showToast = (message, type = 'success') => { onMouseLeave={() => setHoveredDelete(null)} > Delete @@ -465,7 +465,7 @@ const showToast = (message, type = 'success') => { e.stopPropagation(); 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