bug fixed

This commit is contained in:
Malini 2025-11-13 09:43:18 +05:30
parent 24fcea6189
commit 2edb38db14
6 changed files with 119 additions and 34 deletions

View File

@ -132,8 +132,9 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
if (type === 'approve') { if (type === 'approve') {
setShowApproveModal(true); setShowApproveModal(true);
} else { } else {
// Clear previous state
setRejectionReason(''); setRejectionReason('');
setShowRejectError(false); setShowRejectError(false); // Don't show error immediately
setShowRejectModal(true); setShowRejectModal(true);
} }
}; };
@ -320,22 +321,42 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
<div className="relative group"> <div className="relative group">
<CheckCircle2 <CheckCircle2
size={22} size={22}
className={`${item.status?.toLowerCase() === 'approved' ? 'text-gray-400 cursor-not-allowed' : 'text-green-600 cursor-pointer hover:scale-110'} transition-transform`} className={`${
onClick={item.status?.toLowerCase() !== 'approved' ? () => handleActionClick(item, 'approve') : undefined} item.status?.toLowerCase() === 'approved' || item.status?.toLowerCase() === 'rejected'
? 'text-gray-400 cursor-not-allowed'
: 'text-green-600 cursor-pointer hover:scale-110'
} transition-transform`}
onClick={['submitted', 'resubmitted'].includes(item.status?.toLowerCase())
? () => handleActionClick(item, 'approve')
: undefined}
/> />
<span className="absolute bottom-full mb-1 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-[2px] rounded opacity-0 group-hover:opacity-100 transition"> <span className="absolute bottom-full mb-1 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-[2px] rounded opacity-0 group-hover:opacity-100 transition">
{item.status?.toLowerCase() === 'approved' ? 'Already Approved' : 'Approve'} {item.status?.toLowerCase() === 'approved'
? 'Already Approved'
: item.status?.toLowerCase() === 'rejected'
? 'Cannot approve rejected'
: 'Approve'}
</span> </span>
</div> </div>
<div className="relative group"> <div className="relative group">
<XCircle <XCircle
size={22} size={22}
className={`${item.status?.toLowerCase() === 'rejected' ? 'text-gray-400 cursor-not-allowed' : 'text-red-600 cursor-pointer hover:scale-110'} transition-transform`} className={`${
onClick={item.status?.toLowerCase() !== 'rejected' ? () => handleActionClick(item, 'reject') : undefined} ['approved', 'rejected'].includes(item.status?.toLowerCase())
? 'text-gray-400 cursor-not-allowed'
: 'text-red-600 cursor-pointer hover:scale-110'
} transition-transform`}
onClick={!['approved', 'rejected'].includes(item.status?.toLowerCase())
? () => handleActionClick(item, 'reject')
: undefined}
/> />
<span className="absolute bottom-full mb-1 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-[2px] rounded opacity-0 group-hover:opacity-100 transition"> <span className="absolute bottom-full mb-1 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-[2px] rounded opacity-0 group-hover:opacity-100 transition whitespace-nowrap">
{item.status?.toLowerCase() === 'rejected' ? 'Already Rejected' : 'Reject'} {item.status?.toLowerCase() === 'rejected'
? 'Already Rejected'
: item.status?.toLowerCase() === 'approved'
? 'Cannot reject approved'
: 'Reject'}
</span> </span>
</div> </div>
@ -486,9 +507,15 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
</button> </button>
<button <button
type="button" type="button"
onClick={handleRejectConfirm} onClick={() => {
className="px-4 py-2 text-sm font-medium text-white bg-[#92722A] border border-transparent rounded-md shadow-sm hover:bg-[#7c5e24] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#92722A] flex items-center gap-2" if (!rejectionReason.trim()) {
disabled={isProcessing || !rejectionReason.trim()} setShowRejectError(true);
return;
}
handleRejectConfirm();
}}
className="px-4 py-2 text-sm font-medium text-white bg-[#92722A] border border-transparent rounded-md shadow-sm hover:bg-[#7c5e24] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#92722A] flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
disabled={isProcessing}
> >
{isProcessing ? ( {isProcessing ? (
<> <>

View File

@ -579,7 +579,7 @@ const ValidationReview = () => {
</label> </label>
<textarea <textarea
rows="2" rows="2"
className="w-[1100px] rounded-[10px] border border-[#D1D5DB] bg-[#FFFCF2] px-4 py-2 mb-4 text-sm text-[#232528] focus:ring-2 focus:ring-[#92722A] focus:outline-none" className="w-[580px] rounded-[10px] border border-[#D1D5DB] bg-[#FFFCF2] px-4 py-2 mb-4 text-sm text-[#232528] focus:ring-2 focus:ring-[#92722A] focus:outline-none"
placeholder="Please enter remarks here" placeholder="Please enter remarks here"
></textarea> ></textarea>
</div> </div>
@ -727,7 +727,7 @@ const ValidationReview = () => {
<div className="flex justify-end gap-3 mt-6"> <div className="flex justify-end gap-3 mt-6">
<button <button
type="button" type="button"
className="rounded-md border border-gray-300 bg-[#92722A] px-4 py-2 text-sm font-medium text-[#92722A] hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" className="rounded-md border border-gray-300 bg-[#fffff] px-4 py-2 text-sm font-medium text-[#92722A] hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-[#92722A] focus:ring-offset-2"
onClick={() => setIsApproveOpen(false)} onClick={() => setIsApproveOpen(false)}
disabled={actionLoading} disabled={actionLoading}
> >

View File

@ -523,13 +523,13 @@ React.useEffect(() => {
data.forEach((item) => { data.forEach((item) => {
const normalized = String(item.status || '').toLowerCase(); const normalized = String(item.status || '').toLowerCase();
let status = '—'; let status = '—';
if (normalized === 'pending') status = 'Under Review'; if (normalized === 'submitted') status = 'Submitted';
else if (normalized === 'rejected') status = 'Returned'; else if (normalized === 'rejected') status = 'Rejected';
else if (['submitted', 'approved'].includes(normalized)) status = 'Approved'; else if (['approved'].includes(normalized)) status = 'Approved';
else status = item.status || '—'; else status = item.status || '—';
const productCount = Number(item.products) || 0; const productCount = Number(item.products) || 0;
const products = `${productCount} ${productCount === 1 ? 'product' : 'products'}`; const products = `${productCount} `;
const row = [ const row = [
item.establishment || '—', item.establishment || '—',
@ -680,22 +680,42 @@ React.useEffect(() => {
<div className="relative group"> <div className="relative group">
<CheckCircle2 <CheckCircle2
size={22} size={22}
className={`${item.status?.toLowerCase() === 'approved' ? 'text-gray-400 cursor-not-allowed' : 'text-green-600 cursor-pointer hover:scale-110'} transition-transform`} className={`${
onClick={item.status?.toLowerCase() !== 'approved' ? () => handleApproveClick(item) : undefined} item.status?.toLowerCase() === 'approved' || item.status?.toLowerCase() === 'rejected'
? 'text-gray-400 cursor-not-allowed'
: 'text-green-600 cursor-pointer hover:scale-110'
} transition-transform`}
onClick={['submitted', 'resubmitted'].includes(item.status?.toLowerCase())
? () => handleApproveClick(item)
: undefined}
/> />
<span className="absolute bottom-full mb-1 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-[2px] rounded opacity-0 group-hover:opacity-100 transition"> <span className="absolute bottom-full mb-1 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-[2px] rounded opacity-0 group-hover:opacity-100 transition whitespace-nowrap">
{item.status?.toLowerCase() === 'approved' ? 'Already Approved' : 'Approve'} {item.status?.toLowerCase() === 'approved'
? 'Already Approved'
: item.status?.toLowerCase() === 'rejected'
? 'Cannot approve rejected'
: 'Approve'}
</span> </span>
</div> </div>
<div className="relative group"> <div className="relative group">
<XCircle <XCircle
size={22} size={22}
className={`${item.status?.toLowerCase() === 'rejected' ? 'text-gray-400 cursor-not-allowed' : 'text-red-600 cursor-pointer hover:scale-110'} transition-transform`} className={`${
onClick={item.status?.toLowerCase() !== 'rejected' ? () => handleRejectClick(item) : undefined} ['approved', 'rejected'].includes(item.status?.toLowerCase())
? 'text-gray-400 cursor-not-allowed'
: 'text-red-600 cursor-pointer hover:scale-110'
} transition-transform`}
onClick={!['approved', 'rejected'].includes(item.status?.toLowerCase())
? () => handleRejectClick(item)
: undefined}
/> />
<span className="absolute bottom-full mb-1 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-[2px] rounded opacity-0 group-hover:opacity-100 transition"> <span className="absolute bottom-full mb-1 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-[2px] rounded opacity-0 group-hover:opacity-100 transition whitespace-nowrap">
{item.status?.toLowerCase() === 'rejected' ? 'Already Rejected' : 'Reject'} {item.status?.toLowerCase() === 'rejected'
? 'Already Rejected'
: item.status?.toLowerCase() === 'approved'
? 'Cannot reject approved'
: 'Reject'}
</span> </span>
</div> </div>

View File

@ -1943,8 +1943,25 @@ const loadProfiles = async () => {
// Website URL validation // Website URL validation
if ((field === 'contactWebsite' || field === 'corporateWebsite') && value) { if ((field === 'contactWebsite' || field === 'corporateWebsite') && value) {
if (!/^https?:\/\/.+\..+/.test(value)) { // Supports:
return 'Please enter a valid URL (e.g., https://example.com)'; // - http://example.com
// - https://example.com
// - www.example.com
// - example.com
// - subdomain.example.com
// - localhost:3000 (for development)
// - IP addresses (e.g., 192.168.1.1)
// - With or without path/query parameters
const urlRegex = /^(https?:\/\/)?(www\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?(\/\S*)?$/;
// Also allow localhost with optional port for development
// const localhostRegex = /^https?:\/\/localhost(:\d+)?(\/\S*)?$/;
// Also allow IP addresses with optional port
const ipRegex = /^https?:\/\/(\d{1,3}\.){3}\d{1,3}(:\d+)?(\/\S*)?$/;
if (!urlRegex.test(value)&& !ipRegex.test(value)) {
return 'Please enter a valid URL (e.g., https://example.com, example.com, or www.example.com)';
} }
} }

View File

@ -485,7 +485,7 @@ const IsicHsCodes = () => {
'HS Code', 'HS Code',
'Product Name', 'Product Name',
'Unit', 'Unit',
'Estimated Mapped', 'Establishment Mapped',
'Created By', 'Created By',
'Last Updated', 'Last Updated',
'Action', 'Action',

View File

@ -38,13 +38,13 @@ const CustomToast = ({ message, type, onClose }) => {
const getIcon = () => { const getIcon = () => {
switch (type) { switch (type) {
case 'success': case 'success':
return ''; return '';
case 'error': case 'error':
return ''; return '';
case 'warning': case 'warning':
return '⚠️'; return '';
default: default:
return ''; return '';
} }
}; };
@ -399,11 +399,21 @@ const QuarterlyWindows = () => {
type: 'success' type: 'success'
}); });
} else { } else {
console.error('Failed to add quarterly window'); // Show error message from API response if available
const errorMessage = response.message || 'Failed to add quarterly window';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Failed to add quarterly window:', errorMessage);
} }
} else if (modalMode === 'edit' && editingRow !== null) { } else if (modalMode === 'edit' && editingRow !== null) {
const itemId = quarterData[editingRow]?.id; const itemId = quarterData[editingRow]?.id;
if (!itemId) { if (!itemId) {
setToastData({
message: 'Error: Could not find the item to update',
type: 'error'
});
console.error('Error: Could not find the item to update'); console.error('Error: Could not find the item to update');
return; return;
} }
@ -430,11 +440,22 @@ const QuarterlyWindows = () => {
type: 'success' type: 'success'
}); });
} else { } else {
console.error('Failed to update quarterly window'); // Show error message from API response if available
const errorMessage = response.message || 'Failed to update quarterly window';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Failed to update quarterly window:', errorMessage);
} }
} }
handleCloseModal(); handleCloseModal();
} catch (error) { } catch (error) {
const errorMessage = error.response?.data?.message || error.message || 'An error occurred while saving';
setToastData({
message: errorMessage,
type: 'error'
});
console.error('Error saving quarterly window:', error); console.error('Error saving quarterly window:', error);
} }
}; };