fcsc bug fix

This commit is contained in:
Malini 2025-11-21 20:39:59 +05:30
parent f78534b258
commit 236743053e
13 changed files with 535 additions and 226 deletions

View File

@ -119,7 +119,7 @@ export const SurveyStatus = () => {
return { return {
title: `${quarter} ${year} Survey`, title: `${quarter} ${year} Survey`,
subtitle: 'Complete your quarterly Industrial Production Index (IPI) data submission', subtitle: 'Complete your quarterly Index of Industrial Production (IIP) data submission',
dueDate: formatDate(end_date), dueDate: formatDate(end_date),
relativeDue: formatRelativeDays(end_date), relativeDue: formatRelativeDays(end_date),
estTime: '1520 minutes', estTime: '1520 minutes',

View File

@ -1,4 +1,8 @@
import React from 'react'; import React, { useEffect, useState, useMemo } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { getEstablishmentProducts } from '../../../services/submissions/submissionService';
import Table from '@/components/common/Table';
const caretDownSrc = '/assets/images/CaretDown.svg'; const caretDownSrc = '/assets/images/CaretDown.svg';
const backVectorSrc = '/assets/images/BackVector.svg'; const backVectorSrc = '/assets/images/BackVector.svg';
const mailIconSrc = '/assets/images/material-symbols_mail-outline.svg'; const mailIconSrc = '/assets/images/material-symbols_mail-outline.svg';
@ -6,7 +10,6 @@ const phoneIconSrc = '/assets/images/line-md_phone.svg';
const calendarIcon = '/assets/images/Duedate.svg'; const calendarIcon = '/assets/images/Duedate.svg';
const clockIcon = '/assets/images/mingcute_time-line.svg'; const clockIcon = '/assets/images/mingcute_time-line.svg';
const nextIcon = '/assets/images/mdi_page-next-outline.svg'; const nextIcon = '/assets/images/mdi_page-next-outline.svg';
import { useNavigate, useLocation } from 'react-router-dom';
const Field = ({ label, placeholder = '', type = 'text', value = '', onChange = () => {}, disabled = true }) => ( const Field = ({ label, placeholder = '', type = 'text', value = '', onChange = () => {}, disabled = true }) => (
<div> <div>
@ -95,11 +98,40 @@ const EstablishmentInfo = ({
isComplete = false, isComplete = false,
}) => { }) => {
const [showInfoCard, setShowInfoCard] = React.useState(true); const [showInfoCard, setShowInfoCard] = React.useState(true);
const [products, setProducts] = React.useState([]);
const [loadingProducts, setLoadingProducts] = React.useState(false);
const [productsError, setProductsError] = React.useState('');
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
// Use a ref to persist the survey data across re-renders // Use a ref to persist the survey data across re-renders
const surveyDataRef = React.useRef(null); const surveyDataRef = React.useRef(null);
// Fetch establishment products
React.useEffect(() => {
const fetchProducts = async () => {
const establishmentId = sessionStorage.getItem('establishment_id');
if (!establishmentId) return;
setLoadingProducts(true);
try {
const response = await getEstablishmentProducts(establishmentId);
if (response.status === 'success') {
console.log('Products data:', response.data); // Log the products data
setProducts(response.data || []);
} else {
setProductsError(response.message || 'Failed to load products');
}
} catch (error) {
console.error('Error fetching products:', error);
setProductsError('Failed to load products. Please try again later.');
} finally {
setLoadingProducts(false);
}
};
fetchProducts();
}, []);
const [surveyData, setSurveyData] = React.useState(() => { const [surveyData, setSurveyData] = React.useState(() => {
// Initialize from location state if available, otherwise use defaults // Initialize from location state if available, otherwise use defaults
if (location.state?.survey) { if (location.state?.survey) {
@ -280,7 +312,7 @@ const EstablishmentInfo = ({
</div> </div>
)} )}
<h2 className="text-xl font-semibold text-[#232528] mb-2"> <h2 className="text-xl font-semibold text-[#232528] mb-2">
Industrial Production Index (IPI) Survey: {surveyData.quarter} {surveyData.year} IIP (Index of Industrial Production): {surveyData.quarter} {surveyData.year}
</h2> </h2>
{/* Survey Information */} {/* Survey Information */}
@ -309,7 +341,7 @@ const EstablishmentInfo = ({
<div className="space-y-4"> <div className="space-y-4">
<p className="text-sm text-[#6C4527] mb-4"> <p className="text-sm text-[#6C4527] mb-4">
You're completing the <b>IPI Quarterly Survey</b> for <b>{surveyData.quarter} {surveyData.year}</b>. This step shows establishment details already registered with us. <b>Step 1 is read-only.</b> To make corrections, update them in <b>Profile Edit Profile</b>, then return to this survey. You're completing the <b>IIP Quarterly Survey</b> for <b>{surveyData.quarter} {surveyData.year}</b>. This step shows establishment details already registered with us. <b>Step 1 is read-only.</b> To make corrections, update them in <b>Profile Edit Profile</b>, then return to this survey.
</p> </p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
@ -365,54 +397,7 @@ const EstablishmentInfo = ({
</div> </div>
</div> </div>
)} )}
{/* Blue Info Box */}
<div className="bg-[#E8F3FF] border border-[#2F80ED] text-[#0B4DA2] px-4 py-2 rounded-md mt-3 flex items-center gap-2 text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2}
stroke="#0B4DA2"
className="w-5 h-5 flex-shrink-0"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
{/* <p>
<span className="font-medium">Need to update details?</span> Go to{' '}
<b>Profile Edit Profile</b>. Changes saved there will appear{' '}
<a href="#" className="underline font-medium text-[#0B4DA2] hover:text-[#063B82]">
here
</a>.
</p> */}
{/* <p className="text-sm text-[#043DFF] bg-[#E7F5FF]">
<span className="font-medium">Need to update details?</span> Go to Profile {' '}
<a
href={`/admin/configuration/profile/edit=${sessionStorage.getItem('establishment_id') || ''}`}
className="underline font-medium text-[#043DFF] hover:text-[#063B82]"
onClick={handleEditProfile}
>
Edit Profile
</a>
. Changes saved there will appear here.
</p> */}
<p className="text-sm text-[#043DFF] bg-[#E7F5FF]">
<span className="font-medium">Need to update details?</span> Go to Profile {' '}
<a
href={`/admin/configuration/edit-profile/${sessionStorage.getItem('establishment_id') || ''}`}
className="underline font-medium text-[#043DFF] hover:text-[#063B82]"
onClick={handleEditProfile}
>
Edit Profile
</a>
. Changes saved there will appear here.
</p>
</div>
<div className="flex items-center gap-2 mb-2"> <div className="flex items-center gap-2 mb-2">
<h2 className="text-lg font-semibold text-[#232528]">Step 1: Review Establishment Information</h2> <h2 className="text-lg font-semibold text-[#232528]">Step 1: Review Establishment Information</h2>
{isComplete && ( {isComplete && (
@ -532,6 +517,31 @@ const EstablishmentInfo = ({
</div> </div>
</Card> </Card>
<Card className="mt-10">
<h3 className="text-sm font-semibold text-gray-900 mb-4">Products</h3>
{loadingProducts ? (
<div className="flex justify-center py-4">
<div className="h-6 w-6 animate-spin rounded-full border-b-2 border-[#92722A]" />
</div>
) : productsError ? (
<div className="text-red-600 text-sm py-2">{productsError}</div>
) : products.length > 0 ? (
<Table
headers={['Product Name', 'HS Code', 'Description']}
rows={products.map(product => [
product['product.product_name'] || 'N/A',
product['product.hs_code'] || 'N/A',
product['product.hs_description'] || 'N/A'
])}
columnWidths={['33.33%', '33.33%', '33.33%']}
separated={true}
className="w-full"
/>
) : (
<div className="text-gray-500 text-sm py-2">No products found for this establishment.</div>
)}
</Card>
<div className="mt-6"> <div className="mt-6">
{/* Employee Information */} {/* Employee Information */}
<Card> <Card>
@ -588,6 +598,109 @@ const EstablishmentInfo = ({
</div> </div>
</Card> </Card>
{/* <Card className="mt-10">
<h3 className="text-sm font-semibold text-gray-900 mb-4">Products</h3>
{loadingProducts ? (
<div className="flex justify-center py-4">
<div className="h-6 w-6 animate-spin rounded-full border-b-2 border-[#92722A]" />
</div>
) : productsError ? (
<div className="text-red-600 text-sm py-2">{productsError}</div>
) : products.length > 0 ? (
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Product Name
</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
HS Code
</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Unit
</th>
<th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
UOM
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{products.map((product, index) => (
<tr key={product.id || index} className={index % 2 === 0 ? 'bg-white' : 'bg-gray-50'}>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{product['product.product_name'] || 'N/A'}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{product['product.hs_code'] || 'N/A'}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{product['product.unit.uom_short_name'] || 'N/A'}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{product['product.unit.uom'] || 'N/A'}
</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div className="text-gray-500 text-sm py-2">No products found for this establishment.</div>
)}
</Card> */}
{/* Products Table */}
{/* Blue Info Box */}
<div className="bg-[#E8F3FF] border border-[#2F80ED] text-[#0B4DA2] px-4 py-2 rounded-md mt-3 flex items-center gap-2 text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2}
stroke="#0B4DA2"
className="w-5 h-5 flex-shrink-0"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
{/* <p>
<span className="font-medium">Need to update details?</span> Go to{' '}
<b>Profile Edit Profile</b>. Changes saved there will appear{' '}
<a href="#" className="underline font-medium text-[#0B4DA2] hover:text-[#063B82]">
here
</a>.
</p> */}
{/* <p className="text-sm text-[#043DFF] bg-[#E7F5FF]">
<span className="font-medium">Need to update details?</span> Go to Profile {' '}
<a
href={`/admin/configuration/profile/edit=${sessionStorage.getItem('establishment_id') || ''}`}
className="underline font-medium text-[#043DFF] hover:text-[#063B82]"
onClick={handleEditProfile}
>
Edit Profile
</a>
. Changes saved there will appear here.
</p> */}
<p className="text-sm text-[#043DFF] bg-[#E7F5FF]">
<span className="font-medium">Need to update details?</span> Go to Profile {' '}
<a
href={`/admin/configuration/edit-profile/${sessionStorage.getItem('establishment_id') || ''}`}
className="underline font-medium text-[#043DFF] hover:text-[#063B82]"
onClick={handleEditProfile}
>
Edit Profile
</a>
. Changes saved there will appear here.
</p>
</div>
{/* Footer actions */} {/* Footer actions */}
<div className="mt-8 flex flex-col sm:flex-row justify-between gap-3"> <div className="mt-8 flex flex-col sm:flex-row justify-between gap-3">
<button <button

View File

@ -1108,7 +1108,7 @@ const location = useLocation();
<div className="text-[#6C4527] space-y-2"> <div className="text-[#6C4527] space-y-2">
<h3 className="text-base font-semibold mb-2">Why we collect monthly product data</h3> <h3 className="text-base font-semibold mb-2">Why we collect monthly product data</h3>
<p className="text-sm mb-4"> <p className="text-sm mb-4">
This step collects <strong>monthly output quantity and production cost</strong> for each product you manufacture or process. The data inform the <strong>Industrial Production Index (IPI)</strong> and capacity-utilization statistics. Results are published <strong>only in aggregated form</strong> and your information is protected by national statistics confidentiality provisions. This step collects <strong>monthly output quantity and production cost</strong> for each product you manufacture or process. The data inform the <strong>Index of Industrial Production (IIP)</strong> and capacity-utilization statistics. Results are published <strong>only in aggregated form</strong> and your information is protected by national statistics confidentiality provisions.
</p> </p>
<div className="flex gap-2 text-sm"> <div className="flex gap-2 text-sm">

View File

@ -70,7 +70,7 @@ const AdminUsers = () => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const pageSize = 10; // const pageSize = 10;
const [showDeleteModal, setShowDeleteModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false);
const [selectedUser, setSelectedUser] = useState(null); const [selectedUser, setSelectedUser] = useState(null);
@ -92,6 +92,7 @@ const AdminUsers = () => {
const [confirmPassword, setConfirmPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState('');
const [resettingPassword, setResettingPassword] = useState(false); const [resettingPassword, setResettingPassword] = useState(false);
const [resetErrors, setResetErrors] = useState({}); const [resetErrors, setResetErrors] = useState({});
const [pageSize, setPageSize] = React.useState(10);
// Helper: show toast // Helper: show toast
const showToast = (message, type = 'success') => { const showToast = (message, type = 'success') => {
@ -655,6 +656,10 @@ const AdminUsers = () => {
pageSize, pageSize,
totalItems: users.length, totalItems: users.length,
pageSizeOptions: [10, 20, 50, 100], pageSizeOptions: [10, 20, 50, 100],
onPageSizeChange: (size) => {
setPageSize(size);
setCurrentPage(1);
}
}} }}
renderCell={(value, rowIndex, colIndex) => { renderCell={(value, rowIndex, colIndex) => {
if (colIndex === 4) { if (colIndex === 4) {

View File

@ -19,6 +19,7 @@ const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
const downloadIconSrc = '/assets/images/DownloadSimple.svg'; const downloadIconSrc = '/assets/images/DownloadSimple.svg';
const addIconSrc = '/assets/images/ic_baseline-plus.svg'; const addIconSrc = '/assets/images/ic_baseline-plus.svg';
const pencilActiveSrc = '/assets/images/PencilSimple.svg'; const pencilActiveSrc = '/assets/images/PencilSimple.svg';
const viewIconSrc = '/assets/images/Eye.svg';
const pencilInactiveSrc = '/assets/images/pencilsimple-inactive.svg'; const pencilInactiveSrc = '/assets/images/pencilsimple-inactive.svg';
const trashActiveSrc = '/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';
@ -323,13 +324,13 @@ const validateCSVFile = (file, existingEstablishments = []) => {
} }
// Check Factory Name // Check Factory Name
// if (factoryNameIndex >= 0 && !values[factoryNameIndex]) { if (factoryNameIndex >= 0 && !values[factoryNameIndex]) {
// rowErrors.push({ rowErrors.push({
// column: 'Factory Name', column: 'Factory Name',
// message: 'Factory Name is required', message: 'Factory Name is required',
// value: '' value: ''
// }); });
// } }
// Check Email // Check Email
if (emailIndex >= 0) { if (emailIndex >= 0) {
@ -414,6 +415,35 @@ const validateCSVFile = (file, existingEstablishments = []) => {
} }
}; };
// Log detailed validation errors to console
console.group('CSV Validation Errors');
if (duplicateErrors.length > 0) {
console.group('Duplicate Errors');
duplicateErrors.forEach((error, index) => {
console.group(`Error ${index + 1} (Row ${error.row})`);
console.log('Type:', error.isSystemDuplicate ? 'System Duplicate' : 'File Duplicate');
console.log('Establishment ID:', error.value);
console.log('Message:', error.message);
if (error.duplicateRows) {
console.log('Duplicate Rows:', error.duplicateRows.join(', '));
}
console.groupEnd();
});
console.groupEnd();
}
if (otherErrors.length > 0) {
console.group('Validation Errors');
otherErrors.forEach((error, index) => {
console.group(`Error ${index + 1} (Row ${error.row})`);
console.log('Column:', error.column);
console.log('Value:', error.value);
console.log('Message:', error.message);
console.groupEnd();
});
console.groupEnd();
}
// Customize message based on error types // Customize message based on error types
if (duplicateErrors.length > 0 && otherErrors.length === 0) { if (duplicateErrors.length > 0 && otherErrors.length === 0) {
if (duplicateErrors.some(e => e.isSystemDuplicate)) { if (duplicateErrors.some(e => e.isSystemDuplicate)) {
@ -499,6 +529,8 @@ const CompanyProfile = () => {
const [isRefreshing, setIsRefreshing] = React.useState(false); const [isRefreshing, setIsRefreshing] = React.useState(false);
const [isUpdating, setIsUpdating] = React.useState(false); const [isUpdating, setIsUpdating] = React.useState(false);
const [formSubmitted, setFormSubmitted] = React.useState(false); const [formSubmitted, setFormSubmitted] = React.useState(false);
const [isViewMode, setIsViewMode] = React.useState(false);
// Import CSV state // Import CSV state
const [importModalOpen, setImportModalOpen] = React.useState(false); const [importModalOpen, setImportModalOpen] = React.useState(false);
@ -510,6 +542,10 @@ const CompanyProfile = () => {
const [toastData, setToastData] = React.useState(null); const [toastData, setToastData] = React.useState(null);
const [validationResults, setValidationResults] = React.useState(null); const [validationResults, setValidationResults] = React.useState(null);
const filteredAvailableProducts = availableProducts.filter(
(product) => !selectedProducts.some((sp) => sp.id === product.id)
);
// Load current user from session storage // Load current user from session storage
React.useEffect(() => { React.useEffect(() => {
try { try {
@ -526,6 +562,7 @@ const CompanyProfile = () => {
const handleCloseModal = () => { const handleCloseModal = () => {
setModalMode(null); setModalMode(null);
setEditingRow(null); setEditingRow(null);
setIsViewMode(false);
setForm(createEmptyProfile()); setForm(createEmptyProfile());
setActiveStep(0); setActiveStep(0);
setFieldErrors({}); setFieldErrors({});
@ -860,61 +897,79 @@ const CompanyProfile = () => {
</div> </div>
); );
case 1: case 1:
return ( return (
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<h4 className="text-[16px] font-semibold text-[#232528]">Identification Particulars</h4> <h4 className="text-[16px] font-semibold text-[#232528]">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"> Identification Particulars
<TextField </h4>
label="Permanent Factory Code"
value={form.permanentFactoryCode} <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
onChange={handleFormChange('permanentFactoryCode')}
placeholder="Enter Factory Code" <TextField
width="100%" label="Permanent Factory Code"
// required value={form.permanentFactoryCode}
// error={fieldErrors.permanentFactoryCode} onChange={handleFormChange('permanentFactoryCode')}
/> placeholder="Enter Factory Code"
<TextField width="100%"
label="Unique License Number" />
value={form.uniqueLicenseNumber}
onChange={handleFormChange('uniqueLicenseNumber')} <TextField
placeholder="Enter License Number" label="Unique License Number"
width="100%" value={form.uniqueLicenseNumber}
required onChange={handleFormChange('uniqueLicenseNumber')}
error={fieldErrors.uniqueLicenseNumber} placeholder="Enter License Number"
/> width="100%"
<TextField required
label="Industry Code (Business Register)" error={fieldErrors.uniqueLicenseNumber}
value={form.industryCodeBusiness} />
onChange={handleFormChange('industryCodeBusiness')}
placeholder="Enter Code" <TextField
width="100%" label="Industry Code (Business Register)"
// required value={form.industryCodeBusiness}
// error={fieldErrors.industryCodeBusiness} onChange={handleFormChange('industryCodeBusiness')}
/> placeholder="Enter Code"
<TextField width="100%"
label="Industry Code (Current Production)" />
value={form.industryCodeProduction}
onChange={handleFormChange('industryCodeProduction')} <TextField
placeholder="Enter Code" label="Industry Code (Current Production)"
width="100%" value={form.industryCodeProduction}
// required onChange={handleFormChange('industryCodeProduction')}
// error={fieldErrors.industryCodeProduction} placeholder="Enter Code"
/> width="100%"
</div> />
<div className="mt-4"> </div>
<TextField
label="Description" {/* Description Field */}
value={form.industryDescription} <div className="mt-4">
onChange={handleFormChange('industryDescription')} <TextField
placeholder="Enter Description" label="Description"
width="100%" value={form.industryDescription}
style={{ height: '72px' }} onChange={handleFormChange('industryDescription')}
/> placeholder="Enter Description"
</div> width="100%"
</div> style={{ height: '72px' }}
</div> />
); </div>
{/* 🟡 Show Remarks ONLY IF Current Production code is filled AND different from Business Register */}
{form.industryCodeProduction && form.industryCodeBusiness !== form.industryCodeProduction && (
<div className="mt-4">
<TextField
label="Remarks"
value={form.remarks}
onChange={handleFormChange('remarks')}
placeholder="Add Remarks"
width="100%"
style={{ height: '72px' }}
/>
</div>
)}
</div>
</div>
);
case 2: case 2:
return ( return (
<div className="space-y-4"> <div className="space-y-4">
@ -1007,7 +1062,7 @@ const CompanyProfile = () => {
onChange={handleFormChange('contactPersonName')} onChange={handleFormChange('contactPersonName')}
placeholder="Enter Name" placeholder="Enter Name"
width="100%" width="100%"
// error={fieldErrors.contactPersonName} error={fieldErrors.contactPersonName}
/> />
<TextField <TextField
label="Contact Person Designation" label="Contact Person Designation"
@ -1143,26 +1198,26 @@ const CompanyProfile = () => {
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-[#92722A]"></div> <div className="animate-spin rounded-full h-6 w-6 border-b-2 border-[#92722A]"></div>
</div> </div>
) : availableProducts.length > 0 ? ( ) : availableProducts.length > 0 ? (
<ul className="divide-y divide-[#E5E7EB] max-h-96 overflow-y-auto"> <ul className="divide-y divide-[#E5E7EB] max-h-96 overflow-y-auto">
{availableProducts.map((product) => ( {filteredAvailableProducts.map((product) => (
<li key={product.id} className="p-3 hover:bg-[#F9FAFB] flex justify-between items-center"> <li key={product.id} className="p-3 hover:bg-[#F9FAFB] flex justify-between items-center">
<div> <div className="text-sm font-medium text-[#111827]">
<div className="text-sm font-medium text-[#111827]"> {product.hsCode || product.hs_code || ''}
{product.hsCode || product.hs_code || ''} {(product.hsCode || product.hs_code) && (product.productName || product.label || product.product_name) ? ' - ' : ''}
{(product.hsCode || product.hs_code) && (product.productName || product.label || product.product_name) ? ' - ' : ''} {product.productName || product.label || product.product_name || ''}
{product.productName || product.label || product.product_name || ''} </div>
</div>
</div> <button
<button type="button"
type="button" onClick={() => handleAddProduct(product)}
onClick={() => handleAddProduct(product)} className="text-[#92722A] hover:text-[#7A5F1E] text-sm font-medium"
className="text-[#92722A] hover:text-[#7A5F1E] text-sm font-medium" >
> Add
Add </button>
</button> </li>
</li> ))}
))} </ul>
</ul>
) : ( ) : (
<div className="p-4 text-center text-sm text-[#6B7280]"> <div className="p-4 text-center text-sm text-[#6B7280]">
{productSearchTerm ? 'No matching products found' : 'No products available'} {productSearchTerm ? 'No matching products found' : 'No products available'}
@ -1258,6 +1313,8 @@ const CompanyProfile = () => {
); );
setAvailableProducts(available); setAvailableProducts(available);
} catch (error) { } catch (error) {
console.error('Error loading products:', error); console.error('Error loading products:', error);
showToast('error', 'Failed to load products'); showToast('error', 'Failed to load products');
@ -1433,53 +1490,112 @@ const CompanyProfile = () => {
); );
}; };
const displayedRows = filteredProfiles.map((item) => { const displayedRows = filteredProfiles.map((item) => {
return [ return [
item.establishmentName, // Establishment Name
item.userProfileName || item.contactPersonName || item.createdBy || '', item.establishmentName || "-",
item.emirate,
item.isicCode, // Contact Name (userProfileName contactPersonName createdBy "-")
item.establishmentId, item.userProfileName || item.contactPersonName || "-",
item.productCount ?? '0',
item.totalEmployees, // Emirate
item.createdBy, item.emirate || "-",
item.createdOn,
item.updated_at ? formatDate(item.updated_at) : (item.lastUpdated || '-'), // ISIC Code
renderStatusBadge(item.status), item.isicCode || "-",
(
<div className="flex items-center gap-2" key={`actions-${item.establishmentId}`}> // Establishment ID
<button item.establishmentId || "-",
type="button"
className="h-[24px] w-[24px] grid place-items-center rounded hover:bg-gray-50 cursor-pointer" // Product Count
title="Edit" item.productCount ?? "0",
aria-label="Edit profile"
onClick={() => handleEdit(item.apiId ?? item.establishmentId)} // Total Employees
> item.totalEmployees || "-",
<img
src={pencilActiveSrc} // Created By
alt="Edit" item.createdBy || "-",
className="h-[24px] w-[24px]"
/> // Created On
</button> item.createdOn || "-",
<button
type="button" // Updated On (formatted or fallback)
className="h-[20px] w-[40px] grid place-items-center rounded hover:bg-gray-50 cursor-pointer" item.updated_at
title={item.status === 'Active' ? 'Deactivate' : 'Activate'} ? formatDate(item.updated_at)
onClick={(e) => { : (item.lastUpdated || "-"),
e.stopPropagation();
handleToggleStatus(item.apiId, item.status === 'Active'); // Status
}} renderStatusBadge(item.status),
>
<img // Action Buttons
src={item.status === 'Active' ? activeToggleSrc : inactiveToggleSrc} (
alt={item.status === 'Active' ? 'Active' : 'Inactive'} <div
className="h-[20px] w-[40px] object-contain" className="flex items-center gap-2"
/> key={`actions-${item.establishmentId}`}
</button> >
</div> {/* Edit */}
), <button
]; type="button"
}); className="h-[24px] w-[24px] grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
title="Edit"
aria-label="Edit profile"
onClick={() =>
handleEdit(item.apiId ?? item.establishmentId)
}
>
<img
src={pencilActiveSrc}
alt="Edit"
className="h-[24px] w-[24px]"
/>
</button>
{/* View */}
<button
type="button"
className="h-[24px] w-[24px] grid place-items-center rounded hover:bg-gray-50 cursor-pointer ml-1"
title="View"
aria-label="View profile"
onClick={(e) => {
e.stopPropagation();
handleView(item.apiId ?? item.establishmentId);
}}
>
<img
src={viewIconSrc}
alt="View"
className="h-[24px] w-[24px]"
/>
</button>
{/* Toggle Status */}
<button
type="button"
className="h-[20px] w-[40px] grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
title={item.status === "Active" ? "Deactivate" : "Activate"}
onClick={(e) => {
e.stopPropagation();
handleToggleStatus(
item.apiId,
item.status === "Active"
);
}}
>
<img
src={
item.status === "Active"
? activeToggleSrc
: inactiveToggleSrc
}
alt={item.status === "Active" ? "Active" : "Inactive"}
className="h-[20px] w-[40px] object-contain"
/>
</button>
</div>
),
];
});
React.useEffect(() => { React.useEffect(() => {
const handle = setTimeout(() => { const handle = setTimeout(() => {
@ -1670,13 +1786,13 @@ const CompanyProfile = () => {
let creatorName = '-'; let creatorName = '-';
if (currentUser && item?.created_by && currentUser.id === item.created_by) { if (currentUser && item?.created_by && currentUser.id === item.created_by) {
const name = currentUser.name || currentUser.username || `User ${item.created_by}`; const name = currentUser.name || currentUser.username || ` ${item.created_by_name}`;
creatorName = name.replace(/([a-zA-Z])([A-Z])/g, '$1 $2'); creatorName = name.replace(/([a-zA-Z])([A-Z])/g, '$1 $2');
} else if (item?.created_by) { } else if (item?.created_by) {
const name = item?.created_by_name || const name = item?.created_by_name ||
item?.created_by_user?.name || item?.created_by_user?.name ||
item?.creator?.name || item?.creator?.name ||
`User ${item.created_by}`; ` ${item.created_by_name}`;
creatorName = name.replace(/([a-zA-Z])([A-Z])/g, '$1 $2'); creatorName = name.replace(/([a-zA-Z])([A-Z])/g, '$1 $2');
} }
@ -2000,6 +2116,24 @@ const CompanyProfile = () => {
} }
}; };
const handleView = async (id) => {
try {
setIsLoading(true);
const response = await fetchEstablishmentDetail(id);
const establishment = mapApiEstablishmentToProfile(response.data);
setForm(establishment);
setSelectedProducts(establishment.products || []);
setModalMode('view');
setIsViewMode(true);
setEditingRow(id);
} catch (error) {
console.error('Error fetching establishment details:', error);
showToast('error', 'Failed to load establishment details');
} finally {
setIsLoading(false);
}
};
const handleDelete = (establishmentId) => { const handleDelete = (establishmentId) => {
if (!establishmentId) return; if (!establishmentId) return;
const originalIndex = profiles.findIndex((item) => { const originalIndex = profiles.findIndex((item) => {
@ -2798,7 +2932,7 @@ const handleImport = async () => {
</h3> </h3>
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className="relative min-w-[150px]"> <div className="relative min-w-[100px] ">
<input <input
type="text" type="text"
placeholder="Search By Establishment Name" placeholder="Search By Establishment Name"
@ -2837,7 +2971,7 @@ const handleImport = async () => {
<button <button
type="button" type="button"
onClick={openImportModal} onClick={openImportModal}
className="h-10 px-2 rounded-[6px] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 bg-[#F7F7F7] text-[#232528] hover:bg-gray-50" className="h-10 px-2 rounded-[6px] border border-[#C3C6CB] text-sm inline-flex items-center gap-1 bg-[#F7F7F7] text-[#232528] hover:bg-gray-50"
> >
<img src={uploadImportIconSrc} alt="Import" className="h-5 w-5" /> <img src={uploadImportIconSrc} alt="Import" className="h-5 w-5" />
<span className="font-medium">Import CSV</span> <span className="font-medium">Import CSV</span>

View File

@ -92,6 +92,7 @@ const EditCompanyProfile = () => {
const [contactCityOptions, setContactCityOptions] = useState([]); const [contactCityOptions, setContactCityOptions] = useState([]);
const [availableProducts, setAvailableProducts] = useState([]); const [availableProducts, setAvailableProducts] = useState([]);
const [selectedProducts, setSelectedProducts] = useState([]); const [selectedProducts, setSelectedProducts] = useState([]);
const [newlyAddedProductIds, setNewlyAddedProductIds] = useState(new Set());
const [productSearchTerm, setProductSearchTerm] = useState(''); const [productSearchTerm, setProductSearchTerm] = useState('');
const [isLoadingProducts, setIsLoadingProducts] = useState(false); const [isLoadingProducts, setIsLoadingProducts] = useState(false);
const [productError, setProductError] = useState(""); const [productError, setProductError] = useState("");
@ -289,6 +290,9 @@ const EditCompanyProfile = () => {
return updated; return updated;
}); });
// Mark this product as newly added
setNewlyAddedProductIds(prev => new Set([...prev, product.value]));
// Remove from available products // Remove from available products
setAvailableProducts(prev => prev.filter(p => p.value !== product.value)); setAvailableProducts(prev => prev.filter(p => p.value !== product.value));
@ -298,6 +302,10 @@ const EditCompanyProfile = () => {
// Remove product handler // Remove product handler
const handleRemoveProduct = (product) => { const handleRemoveProduct = (product) => {
// Only allow removing newly added products
if (!newlyAddedProductIds.has(product.value)) {
return;
}
setSelectedProducts(prev => prev.filter(p => p.value !== product.value)); setSelectedProducts(prev => prev.filter(p => p.value !== product.value));
// Add back to available products if not already there and matches search // Add back to available products if not already there and matches search
@ -408,11 +416,14 @@ const EditCompanyProfile = () => {
value: String(productId), value: String(productId),
label: productData.product_name || productData.name || 'Unnamed Product', label: productData.product_name || productData.name || 'Unnamed Product',
hs_code: productData.hs_code || '', hs_code: productData.hs_code || '',
product_name: productData.product_name || productData.name || 'Unnamed Product' product_name: productData.product_name || productData.name || 'Unnamed Product',
isExisting: true // Mark as existing product
}; };
}); });
setSelectedProducts(formattedSelectedProducts); setSelectedProducts(formattedSelectedProducts);
// Initialize newly added products as empty since we're loading existing data
setNewlyAddedProductIds(new Set());
} }
} catch (error) { } catch (error) {
@ -850,22 +861,33 @@ const EditCompanyProfile = () => {
<div className="p-4"> <div className="p-4">
{selectedProducts.length > 0 ? ( {selectedProducts.length > 0 ? (
<ul className="divide-y divide-[#E5E7EB] max-h-96 overflow-y-auto"> <ul className="divide-y divide-[#E5E7EB] max-h-96 overflow-y-auto">
{selectedProducts.map((product) => ( {selectedProducts.map((product) => {
<li key={product.value} className="p-3 hover:bg-[#F9FAFB] flex justify-between items-center"> const isNewlyAdded = newlyAddedProductIds.has(product.value);
<div> return (
<div className="text-sm font-medium text-[#111827]"> <li key={product.value} className="p-3 hover:bg-[#F9FAFB] flex justify-between items-center">
{product.label} <div>
<div className="text-sm font-medium text-[#111827]">
{product.label}
</div>
{product.hs_code && (
<div className="text-xs text-gray-500 mt-1">
HS Code: {product.hs_code}
</div>
)}
</div> </div>
</div> {isNewlyAdded && (
<button <button
type="button" type="button"
onClick={() => handleRemoveProduct(product)} onClick={() => handleRemoveProduct(product)}
className="text-[#EF4444] hover:text-[#DC2626] text-sm font-medium" className="text-[#EF4444] hover:text-[#DC2626] text-sm font-medium"
> title="Remove product"
Remove >
</button> Remove
</li> </button>
))} )}
</li>
);
})}
</ul> </ul>
) : ( ) : (
<div className="p-4 text-center text-sm text-[#6B7280] border border-[#E5E7EB] rounded-md"> <div className="p-4 text-center text-sm text-[#6B7280] border border-[#E5E7EB] rounded-md">

View File

@ -350,7 +350,7 @@ const IsicHsCodes = () => {
const [deletingRow, setDeletingRow] = React.useState(null); const [deletingRow, setDeletingRow] = React.useState(null);
const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);
const [currentPage, setCurrentPage] = React.useState(1); const [currentPage, setCurrentPage] = React.useState(1);
const pageSize = 10; const [pageSize, setPageSize] = React.useState(10);
const [modalMode, setModalMode] = React.useState(null); const [modalMode, setModalMode] = React.useState(null);
const [form, setForm] = React.useState(createEmptyCodeForm()); const [form, setForm] = React.useState(createEmptyCodeForm());
const [unitOptions, setUnitOptions] = React.useState([]); const [unitOptions, setUnitOptions] = React.useState([]);
@ -484,6 +484,7 @@ const IsicHsCodes = () => {
const headers = [ const headers = [
'HS Code', 'HS Code',
'Product Name', 'Product Name',
'Description',
'Unit', 'Unit',
'Establishment Mapped', 'Establishment Mapped',
'Created By', 'Created By',
@ -500,7 +501,8 @@ const IsicHsCodes = () => {
const filtered = rowsData.filter( const filtered = rowsData.filter(
(item) => (item) =>
item.code.toLowerCase().includes(lowercasedSearch) || item.code.toLowerCase().includes(lowercasedSearch) ||
item.product.toLowerCase().includes(lowercasedSearch) item.product.toLowerCase().includes(lowercasedSearch) ||
item.description.toLowerCase().includes(lowercasedSearch)
); );
setFilteredData(filtered); setFilteredData(filtered);
} }
@ -526,6 +528,7 @@ const IsicHsCodes = () => {
return [ return [
item.code, item.code,
item.product, item.product,
item.description || '-',
item.unit, item.unit,
item.estimatedMapped, item.estimatedMapped,
displayName, displayName,
@ -550,9 +553,9 @@ const IsicHsCodes = () => {
setForm({ setForm({
code: product.hs_code || '', code: product.hs_code || '',
product: product.product_name || '', product: product.product_name || '',
description: product.hs_description || '',
unit: product.unit_id ? String(product.unit_id) : '', unit: product.unit_id ? String(product.unit_id) : '',
status: product.is_active ? 'Active' : 'Inactive', status: product.is_active ? 'Active' : 'Inactive',
description: product.hs_description || '',
createdBy: selected.createdBy, createdBy: selected.createdBy,
createdOn: selected.createdOn || new Date(product.created_at).toLocaleDateString('en-GB'), createdOn: selected.createdOn || new Date(product.created_at).toLocaleDateString('en-GB'),
updated: selected.updated || (product.updated_at ? new Date(product.updated_at).toLocaleDateString('en-GB') : '') updated: selected.updated || (product.updated_at ? new Date(product.updated_at).toLocaleDateString('en-GB') : '')
@ -599,9 +602,9 @@ const IsicHsCodes = () => {
id: productData.id, id: productData.id,
code: productData.hs_code || '', code: productData.hs_code || '',
product: productData.product_name || '', product: productData.product_name || '',
description: productData.hs_description || '',
unit: productData.unit_id ? String(productData.unit_id) : '', unit: productData.unit_id ? String(productData.unit_id) : '',
status: productData.is_active ? 'Active' : 'Inactive', status: productData.is_active ? 'Active' : 'Inactive',
description: productData.hs_description || ''
}; };
console.log('Mapped form data:', formData); console.log('Mapped form data:', formData);
@ -801,6 +804,7 @@ const IsicHsCodes = () => {
return [ return [
item.code, item.code,
item.product, item.product,
item.description || '-',
item.unit, item.unit,
item.estimatedMapped, item.estimatedMapped,
item.createdBy, item.createdBy,
@ -854,6 +858,7 @@ const IsicHsCodes = () => {
const productData = { const productData = {
hs_code: form.code, hs_code: form.code,
product_name: form.product, product_name: form.product,
hs_description: form.description || '',
unit_id: form.unit ? parseInt(form.unit) : null, unit_id: form.unit ? parseInt(form.unit) : null,
// Preserve the original created_by value for updates, or use current user for new records // Preserve the original created_by value for updates, or use current user for new records
created_by: modalMode === 'edit' ? (existingProduct?.created_by || userProfile?.id) : (userProfile?.id || null) created_by: modalMode === 'edit' ? (existingProduct?.created_by || userProfile?.id) : (userProfile?.id || null)
@ -890,6 +895,7 @@ const IsicHsCodes = () => {
// Only update these specific fields // Only update these specific fields
code: form.code, code: form.code,
product: form.product, product: form.product,
description: form.description || '',
unit: selectedUnit ? selectedUnit.label : existingProduct?.unit || 'N/A', unit: selectedUnit ? selectedUnit.label : existingProduct?.unit || 'N/A',
unit_id: form.unit ? parseInt(form.unit) : existingProduct?.unit_id || null, unit_id: form.unit ? parseInt(form.unit) : existingProduct?.unit_id || null,
updated: new Date().toLocaleDateString('en-GB'), updated: new Date().toLocaleDateString('en-GB'),
@ -940,6 +946,7 @@ const IsicHsCodes = () => {
id: response.data?.id || Date.now(), id: response.data?.id || Date.now(),
code: form.code, code: form.code,
product: form.product, product: form.product,
description: form.description || '',
unit: selectedUnit ? selectedUnit.label : 'N/A', unit: selectedUnit ? selectedUnit.label : 'N/A',
unit_id: form.unit ? parseInt(form.unit) : null, unit_id: form.unit ? parseInt(form.unit) : null,
estimatedMapped: 0, estimatedMapped: 0,
@ -1031,6 +1038,7 @@ const IsicHsCodes = () => {
id: product.id, id: product.id,
code: product.hs_code || 'N/A', code: product.hs_code || 'N/A',
product: product.product_name || 'N/A', product: product.product_name || 'N/A',
description: product.hs_description || '',
unit: product.unit?.uom || 'N/A', unit: product.unit?.uom || 'N/A',
estimatedMapped: 0, estimatedMapped: 0,
createdBy: creatorName, createdBy: creatorName,
@ -1188,17 +1196,17 @@ const IsicHsCodes = () => {
headers={headers} headers={headers}
rows={rows} rows={rows}
renderCell={(value, rowIndex, colIndex) => { renderCell={(value, rowIndex, colIndex) => {
// Handle product name column (index 1) with text wrapping // Handle product name and description columns with text wrapping
if (colIndex === 1) { if (colIndex === 1 || colIndex === 2) {
return ( return (
<div className="max-w-[300px] whitespace-normal break-words"> <div className="max-w-[200px] whitespace-normal break-words">
{value} {value}
</div> </div>
); );
} }
// Handle action buttons column (index 6) // Handle action buttons column (index 7)
if (colIndex === 6) { if (colIndex === 7) {
return ( return (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<button <button
@ -1257,6 +1265,11 @@ const IsicHsCodes = () => {
onPageChange: setCurrentPage, onPageChange: setCurrentPage,
pageSize, pageSize,
totalItems: filteredData.length, totalItems: filteredData.length,
pageSizeOptions: [10, 20, 50, 100],
onPageSizeChange: (size) => {
setPageSize(size);
setCurrentPage(1);
}
}} }}
/> />
</div> </div>
@ -1394,8 +1407,10 @@ const IsicHsCodes = () => {
placeholder="Enter Product Name" placeholder="Enter Product Name"
/> />
</div> </div>
</div> </div>
<div className="grid grid-cols-2 gap-4 mt-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
<div> <div>
<label className="block text-sm font-medium text-[#374151] mb-1"> <label className="block text-sm font-medium text-[#374151] mb-1">
Unit <span className="text-[#EF4444]">*</span> Unit <span className="text-[#EF4444]">*</span>
@ -1425,6 +1440,20 @@ const IsicHsCodes = () => {
)} )}
</div> </div>
<div>
<label className="block text-sm font-medium text-[#374151] mb-1">
Description
</label>
<textarea
value={form.description || ''}
onChange={handleFormChange("description")}
disabled={modalMode === "view"}
rows={1}
className="w-full px-3 py-2 text-sm border border-[#CBA344] rounded-md focus:outline-none focus:ring-1 focus:ring-[#92722A] focus:border-[#92722A] min-h-[38px]"
placeholder="Enter product description"
style={{ resize: 'vertical' }}
/>
</div>
{/* <div> {/* <div>
<label className="block text-sm font-medium text-[#374151] mb-1"> <label className="block text-sm font-medium text-[#374151] mb-1">
Status <span className="text-[#EF4444]">*</span> Status <span className="text-[#EF4444]">*</span>

View File

@ -88,8 +88,9 @@ const UnitMaster = () => {
const [importLoading, setImportLoading] = useState(false); const [importLoading, setImportLoading] = useState(false);
const [importError, setImportError] = useState(''); const [importError, setImportError] = useState('');
const fileInputRef = useRef(null); const fileInputRef = useRef(null);
const [pageSize, setPageSize] = React.useState(10);
const pageSize = 10; // const pageSize = 10;
// Fetch units on component mount // Fetch units on component mount
useEffect(() => { useEffect(() => {
@ -779,6 +780,11 @@ const UnitMaster = () => {
onPageChange: setCurrentPage, onPageChange: setCurrentPage,
pageSize, pageSize,
totalItems: filteredUnits.length, totalItems: filteredUnits.length,
pageSizeOptions: [10, 20, 50, 100],
onPageSizeChange: (size) => {
setPageSize(size);
setCurrentPage(1);
}
}} }}
/> />
)} )}

View File

@ -13,7 +13,7 @@ const Banner = () => {
{/* Title */} {/* Title */}
<h1 className="text-2xl md:text-3xl font-semibold text-gray-800 mb-6"> <h1 className="text-2xl md:text-3xl font-semibold text-gray-800 mb-6">
Industrial Production Index (IPI) Survey UAE IIP (Index of Industrial Production) UAE
</h1> </h1>
{/* Description */} {/* Description */}

View File

@ -6,10 +6,10 @@ const Industrial = () => {
{/* Left Side: Content */} {/* Left Side: Content */}
<div> <div>
<h2 className="text-2xl font-semibold text-gray-900 mb-4"> <h2 className="text-2xl font-semibold text-gray-900 mb-4">
What is the Industrial Production Index (IPI)? What is the Index of Industrial Production (IIP)?
</h2> </h2>
<p className="text-gray-700 leading-relaxed text-justify"> <p className="text-gray-700 leading-relaxed text-justify">
The Industrial Production Index (IPI) measures changes in the volume The Index of Industrial Production (IIP) measures changes in the volume
of industrial output over time. It tracks production across of industrial output over time. It tracks production across
manufacturing activities classified by ISIC and is a key official manufacturing activities classified by ISIC and is a key official
indicator used to monitor economic activity and inform policy. indicator used to monitor economic activity and inform policy.

View File

@ -76,7 +76,7 @@ const Navbar = () => {
{/* Desktop Menu */} {/* Desktop Menu */}
<nav className="hidden md:flex items-center space-x-8 text-[15px] font-medium"> <nav className="hidden md:flex items-center space-x-8 text-[15px] font-medium">
<button onClick={() => handleClick("about-ipi")} className={linkClass("about-ipi")}> <button onClick={() => handleClick("about-ipi")} className={linkClass("about-ipi")}>
About IPI About IIP
</button> </button>
<button onClick={() => handleClick("how-it-works")} className={linkClass("how-it-works")}> <button onClick={() => handleClick("how-it-works")} className={linkClass("how-it-works")}>
How it works How it works
@ -116,7 +116,7 @@ const Navbar = () => {
onClick={() => handleClick(id)} onClick={() => handleClick(id)}
className={`${linkClass(id)} block w-full text-left`} className={`${linkClass(id)} block w-full text-left`}
> >
{id === "about-ipi" && "About IPI"} {id === "about-ipi" && "About IIP"}
{id === "how-it-works" && "How it works"} {id === "how-it-works" && "How it works"}
{id === "eligibility" && "Eligibility"} {id === "eligibility" && "Eligibility"}
{id === "faqs" && "FAQs"} {id === "faqs" && "FAQs"}

View File

@ -5,7 +5,7 @@ const Survey = () => {
<section className="mx-auto px-6 md:px-10 lg:px-24 py-12"> <section className="mx-auto px-6 md:px-10 lg:px-24 py-12">
{/* Heading */} {/* Heading */}
<h2 className="text-2xl font-semibold text-gray-900 mb-4"> <h2 className="text-2xl font-semibold text-gray-900 mb-4">
Who should complete the IPI <span className="text-gray-900">survey</span>? Who should complete the IIP <span className="text-gray-900">survey</span>?
</h2> </h2>
{/* Content */} {/* Content */}

View File

@ -318,7 +318,7 @@ const Login = () => {
<img src={logoSrc} alt="FCSC Logo" className="mx-auto h-16 w-auto" /> <img src={logoSrc} alt="FCSC Logo" className="mx-auto h-16 w-auto" />
</div> </div>
<h1 className="text-[17px] font-semibold text-[#1F2937] mt-0"> <h1 className="text-[17px] font-semibold text-[#1F2937] mt-0">
Industrial Production Index (IPI) Survey Portal IIP (Index of Industrial Production)
</h1> </h1>
</div> </div>