From b2a01bb93528f24ae310c8054649d80754c80ca6 Mon Sep 17 00:00:00 2001 From: Malini Date: Sun, 9 Nov 2025 21:10:27 +0530 Subject: [PATCH] changes in admin dasboard --- .../components/dashboard/SurveyCarousel.jsx | 2 +- .../components/dashboard/WelcomeSection.jsx | 4 +- .../EstablishmentInfo/EstablishmentInfo.jsx | 6 +- .../survey/ProductData/ProductData.jsx | 5 +- .../src/pages/Admin/AdminDashboard.jsx | 48 ++- .../src/pages/Admin/Validations.jsx | 16 +- .../Admin/configuration/CompanyProfile.jsx | 57 ++- .../pages/Admin/configuration/IsicHsCodes.jsx | 362 ++++++++++++------ .../Admin/configuration/QuarterlyWindows.jsx | 155 +++++--- .../pages/Admin/configuration/UnitMaster.jsx | 94 +++-- 10 files changed, 487 insertions(+), 262 deletions(-) diff --git a/ipi-survey-platform/src/components/dashboard/SurveyCarousel.jsx b/ipi-survey-platform/src/components/dashboard/SurveyCarousel.jsx index e0a4182..358faab 100644 --- a/ipi-survey-platform/src/components/dashboard/SurveyCarousel.jsx +++ b/ipi-survey-platform/src/components/dashboard/SurveyCarousel.jsx @@ -30,7 +30,7 @@ const SurveyCarousel = ({ setCurrentIndex((prev) => (prev === surveys.length - 1 ? 0 : prev + 1)); return ( -
+

diff --git a/ipi-survey-platform/src/components/dashboard/WelcomeSection.jsx b/ipi-survey-platform/src/components/dashboard/WelcomeSection.jsx index 39197cf..21b4200 100644 --- a/ipi-survey-platform/src/components/dashboard/WelcomeSection.jsx +++ b/ipi-survey-platform/src/components/dashboard/WelcomeSection.jsx @@ -30,9 +30,9 @@ export const WelcomeSection = ({ data = null, loading = false, error = '' }) => return (
-
+
-

+

Welcome{' '} {(() => { try { diff --git a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx index f8bd3b1..6f3307a 100644 --- a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx +++ b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx @@ -127,9 +127,7 @@ const EstablishmentInfo = ({ React.useEffect(() => { // Only update if we don't already have survey data if (!surveyDataRef.current?.quarter && location.state?.survey) { - const { quarter, year, endDate } = location.state.survey; - console.log('Initial survey data:', { quarter, year, endDate }); - + const { quarter, year, endDate } = location.state.survey; const newSurveyData = { quarter: quarter || '', year: year || '', @@ -198,8 +196,6 @@ const EstablishmentInfo = ({ localStorage.setItem('returnTo', window.location.pathname); sessionStorage.setItem('edit_profile_from', 'EstablishmentUser'); - - console.log('Navigating to:', `/profile/edit/${establishmentId}`); navigate(`/profile/edit/${establishmentId}`); }; const handleEmployeeChange = (field) => (event) => { diff --git a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx index bce0000..dc3e80a 100644 --- a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx +++ b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx @@ -336,7 +336,6 @@ const location = useLocation(); // Get survey data from navigation state if available if (location.state?.survey) { const { quarter, year, endDate } = location.state.survey; - console.log('Received survey datassdd:', { quarter, year, endDate }); setSurveyData({ quarter: quarter || '', year: year || '', @@ -635,9 +634,7 @@ const location = useLocation(); }; - const handleProductSelect = async (productId, establishmentId, id) => { - console.log('handleProductSelect called with:', { productId, establishmentId, id }); - + const handleProductSelect = async (productId, establishmentId, id) => { if (!productId || !establishmentId) { console.warn('Missing required parameters in handleProductSelect:', { hasProductId: !!productId, diff --git a/ipi-survey-platform/src/pages/Admin/AdminDashboard.jsx b/ipi-survey-platform/src/pages/Admin/AdminDashboard.jsx index 967c0e8..4f69217 100644 --- a/ipi-survey-platform/src/pages/Admin/AdminDashboard.jsx +++ b/ipi-survey-platform/src/pages/Admin/AdminDashboard.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import AdminHeader from '@/components/admin/AdminHeader'; import StatCard from '@/components/admin/StatCard'; import SubmissionTable from '@/components/admin/SubmissionTable'; @@ -29,8 +29,18 @@ const AdminDashboard = () => { const [loading, setLoading] = useState(true); const [selectedQuarter, setSelectedQuarter] = useState('All'); const [selectedYear, setSelectedYear] = useState('All'); + const isMounted = useRef(false); + const prevParams = useRef({ quarter: null, year: null }); + + const fetchDashboardData = React.useCallback(async (quarter, year) => { + // Skip if params haven't changed + if (prevParams.current.quarter === quarter && prevParams.current.year === year) { + return; + } + + // Update previous params + prevParams.current = { quarter, year }; - const fetchDashboardData = async (quarter, year) => { try { setLoading(true); const params = new URLSearchParams(); @@ -44,13 +54,16 @@ const AdminDashboard = () => { } const response = await apiClient.get(`/admin_dashboard?${params.toString()}`); + + if (!isMounted.current) return; const data = response?.data?.summary || {}; const selectedQuarterFromApi = response?.data?.selected_quarter || quarter || 'All'; const selectedYearFromApi = response?.data?.selected_year || year || 'All'; const quarterlyWindowsData = response?.data?.quarterly_windows || {}; - console.log("selectedQuarter",selectedQuarterFromApi) - console.log("selectedYear",selectedYearFromApi) + + console.log("Fetching data for:", { quarter, year }); + setSummary({ total_establishments: data.total_establishments || 0, submitted: data.submitted || 0, @@ -60,30 +73,39 @@ const AdminDashboard = () => { pending: data.pending || 0, }); - setQuarterlyWindows({ + setQuarterlyWindows(prev => ({ + ...prev, end_date: quarterlyWindowsData.end_date, start_date: quarterlyWindowsData.start_date, grace_periods_days: quarterlyWindowsData.grace_periods_days || 0 - }); + })); - setSelectedQuarter(selectedQuarterFromApi); - setSelectedYear(selectedYearFromApi); + // Only update these if they're different to prevent unnecessary re-renders + setSelectedQuarter(prev => prev !== selectedQuarterFromApi ? selectedQuarterFromApi : prev); + setSelectedYear(prev => prev !== selectedYearFromApi ? selectedYearFromApi : prev); } catch (error) { console.error('Error fetching dashboard summary:', error); } finally { - setLoading(false); + if (isMounted.current) { + setLoading(false); + } } - }; + }, []); useEffect(() => { + isMounted.current = true; fetchDashboardData(selectedQuarter, selectedYear); - }, [selectedQuarter, selectedYear]); + + return () => { + isMounted.current = false; + }; + }, [fetchDashboardData, selectedQuarter, selectedYear]); return (
-
-
+
+

Admin Dashboard{' '} – Survey Overview diff --git a/ipi-survey-platform/src/pages/Admin/Validations.jsx b/ipi-survey-platform/src/pages/Admin/Validations.jsx index 37ce613..edc641b 100644 --- a/ipi-survey-platform/src/pages/Admin/Validations.jsx +++ b/ipi-survey-platform/src/pages/Admin/Validations.jsx @@ -66,7 +66,7 @@ const ManageSubmissions = () => { const [year, setYear] = React.useState(''); const [quarter, setQuarter] = React.useState(''); const [emirate, setEmirate] = React.useState(''); - const [status, setStatus] = React.useState(''); + const [status, setStatus] = React.useState('All'); const [selectedQuarter, setSelectedQuarter] = React.useState('Q1'); const [selectedYear, setSelectedYear] = React.useState(new Date().getFullYear().toString()); const [currentPage, setCurrentPage] = React.useState(1); @@ -303,8 +303,13 @@ const ManageSubmissions = () => { }, []); const yearOptions = React.useMemo(() => { - const years = ['All', ...new Set(submissions.map((i) => i.year))]; - return years.sort((a, b) => { + const currentYear = new Date().getFullYear(); + const years = []; + // Generate years from 2022 to current year + 1 (to include current year) + for (let y = 2022; y <= currentYear + 1; y++) { + years.push(y.toString()); + } + return ['All', ...years].sort((a, b) => { if (a === 'All') return -1; if (b === 'All') return 1; return b.localeCompare(a); @@ -313,7 +318,10 @@ const ManageSubmissions = () => { const quarterOptions = React.useMemo(() => ['All', 'Q1', 'Q2', 'Q3', 'Q4'], []); const emirateOptions = React.useMemo(() => ['All', ...new Set(submissions.map((i) => i.emirate))], [submissions]); - const statusOptions = React.useMemo(() => ['All', ...new Set(submissions.map((i) => i.status))], [submissions]); + const statusOptions = React.useMemo(() => { + const statuses = [...new Set(submissions.map((i) => i.status))]; + return ['All', ...statuses]; + }, [submissions]); const filtered = React.useMemo(() => { const term = search.trim().toLowerCase(); diff --git a/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx b/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx index 469f199..72ed178 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx @@ -492,7 +492,6 @@ const CompanyProfile = () => { onChange={handleFormChange('industryDescription')} placeholder="Enter Description" width="100%" - required style={{ height: '72px' }} />

@@ -585,7 +584,6 @@ const CompanyProfile = () => { onChange={handleFormChange('contactMakaniNumber')} placeholder="Enter Makani Number" width="100%" - required error={fieldErrors.contactMakaniNumber} /> { + const handleSaveForm = async (e) => { + // Prevent default form submission behavior + if (e) { + e.preventDefault(); + } if (!validateStepFields(activeStep)) { return; } @@ -2124,13 +2130,35 @@ const requiredFields = [ } await new Promise((resolve) => requestAnimationFrame(resolve)); + + // For edits, update the local state immediately if (modalMode === 'edit' && editingRow !== null) { const updatedProfiles = [...profiles]; updatedProfiles[editingRow] = nextForm; setProfiles(updatedProfiles); - } else { - setProfiles((prev) => [nextForm, ...prev]); } + + // For new records, wait for the API response before updating the UI + if (modalMode !== 'edit') { + if (apiResultData) { + // Use the API response data to update the state + const newProfile = mapApiEstablishmentToProfile(apiResultData); + setProfiles(prev => [newProfile, ...prev]); + } + } else { + // For edits, refresh the data to ensure consistency + try { + const response = await getEstablishments(); + if (response?.data) { + const mappedProfiles = response.data.map(mapApiEstablishmentToProfile); + setProfiles(mappedProfiles); + } + } catch (error) { + console.error('Error refreshing company profiles:', error); + } + } + + // Reset form and close modal const emptyProfile = createEmptyProfile(); Object.assign(emptyProfile, computeEmploymentTotals(emptyProfile)); setForm(emptyProfile); @@ -2219,10 +2247,9 @@ const requiredFields = [ )}
-

Company Profile

- - {totalItems} {totalItems === 1 ? 'record' : 'records'} - +

+ Company Profile ({totalItems}) +

@@ -2328,7 +2355,7 @@ const requiredFields = [ window.scrollTo({ top: 0, behavior: 'smooth' }); }, pageSize, - totalItems: filteredProfiles.length, // Use filtered count for pagination + totalItems: totalItems, // Use the total count from API response pageSizeOptions: [10, 20, 50, 100], onPageSizeChange: (size) => { setPageSize(size); diff --git a/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx b/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx index d9cf9c3..fe953ff 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx @@ -446,14 +446,13 @@ const IsicHsCodes = () => { }, []); const headers = [ - 'Code', + 'HS Code', 'Product Name', 'Unit', - 'Mapped Establishments', - 'Created by', + 'Estimated Mapped', + 'Created By', 'Last Updated', - 'Status', - 'Actions', + 'Action', ]; // Filter data based on search term @@ -495,7 +494,6 @@ const IsicHsCodes = () => { item.estimatedMapped, displayName, item.updated || item.createdOn || '-', - item.status, 'actions', ]; }); @@ -508,7 +506,6 @@ const IsicHsCodes = () => { setIsLoading(true); const productId = selected.id; console.log(`Fetching product details for ID: ${productId}`); - const response = await productService.getProductById(productId); console.log('Product details response:', response); @@ -769,8 +766,6 @@ const IsicHsCodes = () => { }; const handleSaveForm = async () => { - console.log('handleSaveForm called with mode:', modalMode); - if (!form.code || !form.product) { const errorMsg = 'Please fill in all required fields'; console.error(errorMsg); @@ -790,24 +785,16 @@ const IsicHsCodes = () => { created_by: userProfile?.id || null, ...(form.description && { hs_description: form.description }) }; - - console.log('Saving product data:', JSON.stringify(productData, null, 2)); - + if (modalMode === 'edit' && editingRow !== null) { const productId = rowsData[editingRow]?.id; if (!productId) { throw new Error('Product ID not found for editing'); } - - console.log(`Updating product with ID: ${productId}`); - + try { - const response = await productService.updateProduct(productId, productData); - console.log('Update response:', response); - - const selectedUnit = unitOptions.find(u => u.value === form.unit); - console.log('Selected unit for update:', selectedUnit); - + const response = await productService.updateProduct(productId, productData); + const selectedUnit = unitOptions.find(u => u.value === form.unit); const updatedProduct = { ...rowsData[editingRow], code: form.code, @@ -929,10 +916,25 @@ const IsicHsCodes = () => {
{/* Header */} -
-

HS Codes

-
-
+
+ {/* Mobile Header */} +
+
+

+ HS Codes ({rowsData.length}) +

+ +
+ + {/* Search - Mobile */} +
Search
@@ -944,114 +946,224 @@ const IsicHsCodes = () => { className="h-10 w-full rounded-md border border-[#C3C6CB] pl-9 pr-3 text-sm focus:outline-none focus:ring-1 focus:ring-[#92722A]" />
- - - + + {/* Action Buttons - Mobile */} +
+ + +
+
+ + {/* Desktop Header */} +
+

+ HS Codes ({rowsData.length}) +

+
+
+
+ Search +
+ setSearchTerm(e.target.value)} + placeholder="Search by code or name" + className="h-10 w-full rounded-md border border-[#C3C6CB] pl-9 pr-3 text-sm focus:outline-none focus:ring-1 focus:ring-[#92722A]" + /> +
+
+ + + +
+
- {/* Table */} - { - if (colIndex === 6) { - return ( - - ); - } + {/* Table - Desktop */} +
+
{ + if (colIndex === 6) { + return ( +
+ + + +
+ ); + } + return value; + }} + pagination={{ + currentPage, + onPageChange: setCurrentPage, + pageSize, + totalItems: filteredData.length, + }} + /> + - if (colIndex === 7) { - return ( -
- - - + {/* Mobile List View */} +
+ {rows.length === 0 ? ( +
No HS Codes found
+ ) : ( +
+ {rows.map((row, rowIndex) => ( +
+
+
+
{row[1]}
+
{row[0]}
+
+ Unit: + {row[2]} +
+
+ Mapped: + {row[3]} +
+
+
+ + +
+
- ); - } - - return value; - }} - pagination={{ - currentPage, - onPageChange: setCurrentPage, - pageSize, - totalItems: filteredData.length, - }} - /> + ))} +
+ )} + + {/* Mobile Pagination */} + {rows.length > 0 && ( +
+
+ + + Page {currentPage} of {Math.ceil(filteredData.length / pageSize)} + + +
+
+ )} +
{/* Add/Edit/View Modal */} {modalMode && (
-
+
{/* Header */}

@@ -1162,9 +1274,9 @@ const IsicHsCodes = () => {

-
+
{ if (colIndex === headers.length - 1) { return ( @@ -475,9 +513,18 @@ const QuarterlyWindows = () => { }} pagination={{ currentPage, - onPageChange: setCurrentPage, + onPageChange: (page) => { + setCurrentPage(page); + // Scroll to top when changing pages + window.scrollTo({ top: 0, behavior: 'smooth' }); + }, pageSize, totalItems: filteredRows.length, + pageSizeOptions: [10, 20, 50, 100], + onPageSizeChange: (size) => { + setPageSize(size); + setCurrentPage(1); // Reset to first page when changing page size + } }} /> diff --git a/ipi-survey-platform/src/pages/Admin/configuration/UnitMaster.jsx b/ipi-survey-platform/src/pages/Admin/configuration/UnitMaster.jsx index cc1e10e..f549ed4 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/UnitMaster.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/UnitMaster.jsx @@ -15,6 +15,7 @@ const caretDownIconSrc = '/assets/images/caretdown-active.svg'; const rectangleIconSrc = '/assets/images/Rectangle.svg'; const checkboxIconSrc = '/assets/images/checkbox.svg'; + // Custom Toast Component const CustomToast = ({ message, type, onClose }) => { useEffect(() => { @@ -85,6 +86,8 @@ const UnitMaster = () => { const pageSize = 10; const [currentUser, setCurrentUser] = useState(null); const [toastData, setToastData] = useState(null); + const [searchTerm, setSearchTerm] = React.useState(''); + // Fetch units on component mount useEffect(() => { @@ -110,6 +113,15 @@ const UnitMaster = () => { } }; + const filteredUnits = React.useMemo(() => { + if (!searchTerm) return units; + const term = searchTerm.toLowerCase(); + return units.filter(unit => + (unit.uom && unit.uom.toLowerCase().includes(term)) || + (unit.uom_short_name && unit.uom_short_name.toLowerCase().includes(term)) || + (unit.description && unit.description.toLowerCase().includes(term)) + ); +}, [units, searchTerm]); useEffect(() => { const userProfile = sessionStorage.getItem('user_profile'); if (userProfile) { @@ -124,7 +136,6 @@ const UnitMaster = () => { 'Created By', 'Created On', 'Last Updated', - 'Status', 'Actions', ]; @@ -148,14 +159,10 @@ const UnitMaster = () => { item.created_by_name || currentUserName || '-', createdDate, updatedDate, - , 'actions', ]; }); - }, [units, currentUser]); + }, [units, currentUser,filteredUnits]); const statusOptions = React.useMemo( () => [ @@ -165,21 +172,21 @@ const UnitMaster = () => { [] ); - const productOptions = React.useMemo( - () => [ - { label: 'Wheat', value: 'Wheat' }, - { label: 'Barley', value: 'Barley' }, - { label: 'Oats', value: 'Oats' }, - { label: 'Rice', value: 'Rice' }, - { label: 'Corn', value: 'Corn' }, - { label: 'Soybeans', value: 'Soybeans' }, - { label: 'Sorghum', value: 'Sorghum' }, - { label: 'Millet', value: 'Millet' }, - { label: 'Quinoa', value: 'Quinoa' }, - { label: 'Buckwheat', value: 'Buckwheat' }, - ], - [] - ); + // const productOptions = React.useMemo( + // () => [ + // { label: 'Wheat', value: 'Wheat' }, + // { label: 'Barley', value: 'Barley' }, + // { label: 'Oats', value: 'Oats' }, + // { label: 'Rice', value: 'Rice' }, + // { label: 'Corn', value: 'Corn' }, + // { label: 'Soybeans', value: 'Soybeans' }, + // { label: 'Sorghum', value: 'Sorghum' }, + // { label: 'Millet', value: 'Millet' }, + // { label: 'Quinoa', value: 'Quinoa' }, + // { label: 'Buckwheat', value: 'Buckwheat' }, + // ], + // [] + // ); const filteredRows = units; @@ -266,13 +273,7 @@ const UnitMaster = () => { }); return; } - if (!form.status) { - setToastData({ - message: 'Please select Status.', - type: 'error' - }); - return; - } + // Status validation removed as per request // ✅ Check for duplicate unit name const nameExists = units.some( @@ -314,7 +315,7 @@ const UnitMaster = () => { type: 'success' }); } else { - // ✅ Create new record + //Create new record await createUnit({ ...unitData, created_at: new Date().toISOString(), @@ -322,7 +323,7 @@ const UnitMaster = () => { created_by_name: currentUser?.name || '', }); - // ✅ Show success message for add + // Show success message for add setToastData({ message: 'New unit added successfully!', type: 'success' @@ -378,11 +379,26 @@ const UnitMaster = () => { return (
-

Unit Master ( - - {units.length} {units.length === 1 ? 'unit': ''} - - )

+

+ Unit Master ({units.length}{units.length === 1 ? ' unit' : ''}) +

+ {/*
+
+
+ Search +
+ setSearchTerm(e.target.value)} + placeholder="Search by code or name" + className="h-10 w-full rounded-md border border-[#C3C6CB] pl-9 pr-3 text-sm focus:outline-none focus:ring-1 focus:ring-[#92722A]" + /> +
+
*/} + + + {/*
*/}
)} -
+ */} - Status * @@ -606,7 +622,7 @@ const UnitMaster = () => { onChange={handleFormChange('status')} options={statusOptions} placeholder="Select Status" - /> + /> */}