diff --git a/ipi-survey-platform/src/components/overview/DetailedOverview.jsx b/ipi-survey-platform/src/components/overview/DetailedOverview.jsx index 615cbd6..6e35e0f 100644 --- a/ipi-survey-platform/src/components/overview/DetailedOverview.jsx +++ b/ipi-survey-platform/src/components/overview/DetailedOverview.jsx @@ -17,6 +17,13 @@ export const DetailedOverview = ({ submission, onBack }) => { const [submissionData, setSubmissionData] = useState(null); const [quarterPeriods, setQuarterPeriods] = useState(null); const [loadingProduct, setLoadingProduct] = useState(false); + const [showToast, setShowToast] = useState(false); + const [pagination, setPagination] = useState({ + currentPage: 1, + pageSize: 10, + totalItems: 0, + pageSizeOptions: [10, 20, 50, 100] + }); // Add state for tracking loading and error states const [isLoading, setIsLoading] = useState(true); @@ -71,6 +78,11 @@ export const DetailedOverview = ({ submission, onBack }) => { return []; } + // Log is_active status for each product + submissionData.products.forEach((product, index) => { + console.log(`Product ${index + 1} is_active status:`, product?.is_active); + }); + const normalizedTerm = searchTerm.trim().toLowerCase(); const filtered = submissionData.products.filter((product) => { // Add null checks for product and product.product @@ -84,7 +96,7 @@ export const DetailedOverview = ({ submission, onBack }) => { !normalizedTerm || productName.toString().toLowerCase().includes(normalizedTerm) || hsCode.toString().toLowerCase().includes(normalizedTerm) || - status.toLowerCase().includes(ormalizedTerm) || + status.toLowerCase().includes(normalizedTerm) || 'pending'.includes(normalizedTerm); const matchesStatus = selectedStatus === '' || @@ -94,6 +106,13 @@ export const DetailedOverview = ({ submission, onBack }) => { return matchesSearch && matchesStatus; }); + // Update pagination total items and reset to first page when filters change + setPagination(prev => ({ + ...prev, + totalItems: filtered.length, + currentPage: 1 // Reset to first page when filters change + })); + console.log('Filtered products:', filtered); return filtered; }, [searchTerm, selectedStatus, submissionData]); @@ -133,9 +152,9 @@ export const DetailedOverview = ({ submission, onBack }) => { product.current_cost || '0', product.forecast_quantity || '0', product.forecast_cost || '0', - product.is_active ? 'Approved' : 'Pending' + product.status || 'Pending' ].map((value) => `"${String(value).replace(/"/g, '""')}"`).join(',')); - }); + }); const blob = new Blob([csvRows.join('\n')], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); @@ -149,19 +168,45 @@ export const DetailedOverview = ({ submission, onBack }) => { }, [filteredProducts]); const handleViewDetails = (product) => { - // Use the product data we already have from the submission setSelectedProduct(product); + setShowToast(true); }; + const handleToastShown = () => { + setShowToast(false); + }; + + const handlePageChange = (newPage) => { + setPagination(prev => ({ + ...prev, + currentPage: newPage + })); + }; + + const handlePageSizeChange = (newSize) => { + setPagination(prev => ({ + ...prev, + pageSize: newSize, + currentPage: 1 // Reset to first page when changing page size + })); + }; + + // Apply pagination to filtered products + const paginatedProducts = useMemo(() => { + if (!filteredProducts || !Array.isArray(filteredProducts)) return []; + const startIndex = (pagination.currentPage - 1) * pagination.pageSize; + return filteredProducts.slice(startIndex, startIndex + pagination.pageSize); + }, [filteredProducts, pagination.currentPage, pagination.pageSize]); + const rows = useMemo(() => { if (!filteredProducts || !Array.isArray(filteredProducts)) { console.log('No filtered products available'); return []; } - console.log('Generating rows for filtered products:', filteredProducts); + console.log('Generating rows for filtered products:', paginatedProducts); - return filteredProducts.map((product, index) => { + return paginatedProducts.map((product, index) => { // Add null checks for product and product properties const productData = product.product || {}; const unit = product.unit || {}; @@ -179,7 +224,8 @@ export const DetailedOverview = ({ submission, onBack }) => { 'text-[#7C5E24] bg-[#F9F7ED]' }`} > - {product.is_active ? 'Approved' : 'Pending'} + {product.is_active ? 'Submitted' : 'Pending'} + {/* {product.is_active ? 'Rejected' : 'Rejected'} */} , new Date(product.updated_at || product.created_at).toLocaleString('en-US', { year: 'numeric', @@ -202,6 +248,16 @@ export const DetailedOverview = ({ submission, onBack }) => { }); }, [filteredProducts]); + // Add pagination props to the Table component + const tablePagination = { + currentPage: pagination.currentPage, + onPageChange: handlePageChange, + pageSize: pagination.pageSize, + totalItems: filteredProducts.length, + pageSizeOptions: pagination.pageSizeOptions, + onPageSizeChange: handlePageSizeChange + }; + // Show loading state for initial data load if (isLoading) { return ( @@ -311,9 +367,12 @@ export const DetailedOverview = ({ submission, onBack }) => { if (selectedProduct) { return ( setSelectedProduct(null)} + showToast={showToast} + onToastShown={handleToastShown} + submissionDate={submissionData?.created_at || submissionData?.updated_at || new Date().toISOString()} + // submissionStatus={'R'} // Static status for testing /> ); } @@ -385,6 +444,7 @@ export const DetailedOverview = ({ submission, onBack }) => { separated rowGapClass="border-spacing-y-2" className="w-full border-collapse [&_td]:whitespace-nowrap [&_th]:whitespace-nowrap [&_th]:px-3 [&_td]:px-3 [&_th:last-child]:text-right [&_td:last-child]:text-right [&_th:last-child]:pr-4 [&_td:last-child]:pr-4" + pagination={tablePagination} /> diff --git a/ipi-survey-platform/src/components/overview/ProductDetails.jsx b/ipi-survey-platform/src/components/overview/ProductDetails.jsx index af00db1..e73bb51 100644 --- a/ipi-survey-platform/src/components/overview/ProductDetails.jsx +++ b/ipi-survey-platform/src/components/overview/ProductDetails.jsx @@ -1,32 +1,84 @@ -import React from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; -// Mock data for the quarterly details - replace with actual data from props -const quarterlyData = { - q4_oct_quantity: '1,000', - q4_nov_quantity: '1,200', - q4_dec_quantity: '1,500', - q1_jan_quantity: '1,300', - q1_feb_quantity: '1,400', - q1_mar_quantity: '1,600', - q2_apr_quantity: '1,700', - q2_may_quantity: '1,800', - q2_jun_quantity: '2,000', - q4_oct_cost: '10,000', - q4_nov_cost: '12,000', - q4_dec_cost: '15,000', - q1_jan_cost: '13,000', - q1_feb_cost: '14,000', - q1_mar_cost: '16,000', - q2_apr_cost: '17,000', - q2_may_cost: '18,000', - q2_jun_cost: '20,000', - variationReason: 'Seasonal demand increase', - zeroTargetReason: 'Expected market expansion', - remarks: 'Product shows steady growth with seasonal variations.' -}; -const ProductDetails = ({ product, onBack }) => { +const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastShown, submissionDate, submissionStatus = 'approved' }) => { + const [toast, setToast] = useState(null); + const toastShownRef = useRef(false); + + // Format date to 'DD-MM-YYYY, hh:mm A' format + const formatDate = (dateString) => { + if (!dateString) return ''; + const date = new Date(dateString); + return date.toLocaleString('en-GB', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + hour12: true + }); + }; + + useEffect(() => { + if (shouldShowToast && !toastShownRef.current) { + const formattedDate = formatDate(submissionDate); + + if (product?.is_active) { + const status = String(product.is_active).toLowerCase(); + console.log("statuschecking",status) + const toastConfig = { + approved: { + type: 'approved', + bgColor: 'bg-[#F3FAF4]', + textColor: 'text-[#3F8E50]', + iconColor: 'text-[#4A9D5C]', + message: 'Your survey was successfully submitted and is waiting for approval.' + }, + rejected: { + type: 'rejected', + bgColor: 'bg-red-50', + textColor: 'text-red-700', + iconColor: 'text-red-500', + message: 'Your survey has been rejected. Please review and resubmit.' + }, + submitted: { + type: 'submitted', + bgColor: 'bg-[#E7F5FF]', + textColor: 'text-[#043DFF]', + iconColor: 'text-[#286CFF]', + message: 'Your survey was successfully submitted and is waiting for approval.' + } + }; + + const toastType = status in toastConfig ? status : 'submitted'; + setToast(toastConfig[toastType]); + } else { + // Default pending state (amber) + setToast({ + type: 'pending', + message: 'Your survey is in draft status. Please complete and submit it for review.', + bgColor: 'bg-amber-50', + textColor: 'text-amber-700', + iconColor: 'text-amber-500' + }); + } + + toastShownRef.current = true; + onToastShown?.(); + } + }, [shouldShowToast, product?.is_active, onToastShown, submissionDate, submissionStatus]); + + const closeToast = () => { + setToast(null); + }; + + // Debug log to check product status and is_active + useEffect(() => { + console.log('Product Status:', product?.status); + console.log('Product is_active:', product?.is_active); + }, [product?.status, product?.is_active]); + const navigate = useNavigate(); if (!product) return null; @@ -58,14 +110,76 @@ const ProductDetails = ({ product, onBack }) => { q2_jun_cost: product.forecast_cost_period_three || '—', variationReason: product.variation_reason?.reason || '—', zeroTargetReason: product.zero_target_reason?.reason || '—', - remarks: product.remarks || 'No remarks provided for this product.' + remarks: product.remarks || 'NA' }); const formattedProduct = formatProductData(product); return ( -
-
+
+ {/* Toast Notification */} +{toast && ( +
+
+ {toast.type === 'approved' ? ( + + + + ) : toast.type === 'submitted' ? ( + + + + ) : toast.type === 'rejected' ? ( + + + + ) : ( + + + + )} + {toast.message} +
+
+)} + +
-

Product Details - {formattedProduct.name}

+

Product Details

- -
+ +
{/* Basic Information */}
@@ -114,7 +228,7 @@ const ProductDetails = ({ product, onBack }) => {
{formattedProduct.status} @@ -225,13 +339,13 @@ const ProductDetails = ({ product, onBack }) => { {/* Remarks */}

Remarks

-
+
{formattedProduct.remarks}
{/* Submission Info */} -
+ {/*

Submitted by: @@ -254,7 +368,7 @@ const ProductDetails = ({ product, onBack }) => {

-
+
*/}
); diff --git a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx index 5a483e2..c3419f9 100644 --- a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx +++ b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx @@ -926,37 +926,25 @@ const ProductData = ({ - updateProductField(p.id, 'octQuantity', e.target.value)} - /> +
+ {p.octQuantity || '0'} +
- updateProductField(p.id, 'novQuantity', e.target.value)} - /> +
+ {p.novQuantity || '0'} +
- updateProductField(p.id, 'decQuantity', e.target.value)} - /> +
+ {p.decQuantity || '0'} +
@@ -964,37 +952,25 @@ const ProductData = ({ - updateProductField(p.id, 'octCost', e.target.value)} - /> +
+ {p.octCost || '0'} +
- updateProductField(p.id, 'novCost', e.target.value)} - /> +
+ {p.novCost || '0'} +
- updateProductField(p.id, 'decCost', e.target.value)} - /> +
+ {p.decCost || '0'} +
@@ -1119,6 +1095,14 @@ const ProductData = ({

{reasonsError}

)}
+
+ +