import bug fixed

This commit is contained in:
Malini 2025-11-19 07:26:01 +05:30
parent 722d9fcaae
commit 142bd4f21f
7 changed files with 257 additions and 91 deletions

View File

@ -77,7 +77,7 @@ const AddAdminUsers = ({ isOpen, onClose, onSave }) => {
if (!/[a-z]/.test(password)) return 'Must contain at least one lowercase letter'; if (!/[a-z]/.test(password)) return 'Must contain at least one lowercase letter';
if (!/\d/.test(password)) return 'Must contain at least one number'; if (!/\d/.test(password)) return 'Must contain at least one number';
if (!/[!@#$%^&*]/.test(password)) return 'Must contain at least one special character (!@#$%^&*)'; if (!/[!@#$%^&*]/.test(password)) return 'Must contain at least one special character (!@#$%^&*)';
return ''; return ''; // Return empty string if password is valid
}; };
const handleChange = (e) => { const handleChange = (e) => {
@ -85,20 +85,27 @@ const AddAdminUsers = ({ isOpen, onClose, onSave }) => {
setFormData((prev) => ({ ...prev, [name]: value })); setFormData((prev) => ({ ...prev, [name]: value }));
// Clear any existing error for this field // Clear any existing error for this field
if (errors[name]) setErrors((prev) => ({ ...prev, [name]: '' })); if (errors[name]) {
setErrors(prev => ({ ...prev, [name]: '' }));
}
// Real-time password validation // Handle password field changes
if (name === 'password') { if (name === 'password') {
setPasswordTouched(true); setPasswordTouched(true);
const error = validatePassword(value); const error = validatePassword(value);
setPasswordError(error); setPasswordError(error);
// If password is valid and matches confirm password, clear confirm password error
if (!error && formData.confirmPassword && value === formData.confirmPassword) {
setErrors(prev => ({ ...prev, confirmPassword: '' }));
}
} }
// Clear confirm password error when either password changes // Handle confirm password field changes
if ((name === 'password' || name === 'confirmPassword') && formData.password && formData.confirmPassword) { if (name === 'confirmPassword') {
if (formData.password !== formData.confirmPassword) { if (value && formData.password !== value) {
setErrors(prev => ({ ...prev, confirmPassword: 'Passwords do not match' })); setErrors(prev => ({ ...prev, confirmPassword: 'Passwords do not match' }));
} else { } else if (value && formData.password === value) {
setErrors(prev => ({ ...prev, confirmPassword: '' })); setErrors(prev => ({ ...prev, confirmPassword: '' }));
} }
} }
@ -211,9 +218,9 @@ const AddAdminUsers = ({ isOpen, onClose, onSave }) => {
placeholder="Confirm password" placeholder="Confirm password"
showToggle showToggle
/> />
{formData.confirmPassword && !errors.confirmPassword && ( {/* {formData.confirmPassword && !errors.confirmPassword && (
<p className="mt-1 text-xs text-green-600">Passwords match</p> <p className="mt-1 text-xs text-green-600">Passwords match</p>
)} )} */}
</div> </div>
<div className="md:col-span-2 space-y-2"> <div className="md:col-span-2 space-y-2">

View File

@ -17,10 +17,7 @@ const EditUserModal = ({ formData, setFormData, onClose, onUpdate }) => {
{/* Form */} {/* Form */}
<form <form
onSubmit={(e) => { onSubmit={onUpdate}
e.preventDefault();
onUpdate();
}}
className="flex flex-col gap-4" className="flex flex-col gap-4"
> >
{/* Name & Email in one row */} {/* Name & Email in one row */}

View File

@ -104,11 +104,13 @@ const AdminUsers = () => {
}, 4000); }, 4000);
}; };
// Fetch users // Fetch users with pagination
useEffect(() => { useEffect(() => {
const fetchUsers = async () => { const fetchUsers = async () => {
try { try {
setLoading(true); setLoading(true);
// Pass currentPage and pageSize to the API if it supports pagination
// If not, we'll handle pagination client-side
const res = await getAdminUser(); const res = await getAdminUser();
const usersData = Array.isArray(res) const usersData = Array.isArray(res)
@ -117,7 +119,7 @@ const AdminUsers = () => {
? res.data ? res.data
: Array.isArray(res?.data?.data) : Array.isArray(res?.data?.data)
? res.data.data ? res.data.data
: null; : [];
if (!usersData) { if (!usersData) {
showToast('Failed to load users', 'error'); showToast('Failed to load users', 'error');
@ -163,7 +165,7 @@ const AdminUsers = () => {
}; };
fetchUsers(); fetchUsers();
}, []); }, [currentPage]); // Add currentPage as a dependency
const totalUsers = users.length; const totalUsers = users.length;
const activeUsers = users.filter((user) => user.status === 'Active').length; const activeUsers = users.filter((user) => user.status === 'Active').length;
@ -294,38 +296,41 @@ const AdminUsers = () => {
return; return;
} }
setEditingRow(user);
setLoading(true);
try { try {
const res = await getAdminUserById(user.id); setLoading(true);
const payload = res?.data ?? res;
if (!payload) throw new Error('No user data returned from API');
const name = payload.name ?? payload.fullName ?? user.name ?? ''; // Fetch the latest user data from the API
const email = payload.email ?? user.email ?? ''; const response = await getAdminUserById(user.id);
const is_active = const userData = response?.data?.data || response?.data || response;
payload.is_active !== undefined ? !!payload.is_active : !!user.is_active;
setCurrentUser({ if (!userData) {
...payload, throw new Error('Failed to fetch user data');
id: user.id, }
name,
email,
is_active,
});
// Map the API response to match our form data structure
const userToEdit = {
id: userData.id || userData._id || user.id,
name: userData.name || userData.fullName || '',
email: userData.email || '',
status: userData.is_active ? 'Active' : 'Inactive',
is_active: userData.is_active !== undefined ? userData.is_active : true
};
// Set the current user and form data
setCurrentUser(userToEdit);
setFormData({ setFormData({
name, name: userToEdit.name,
email, email: userToEdit.email,
status: is_active ? 'Active' : 'Inactive', status: userToEdit.status,
}); });
setErrors({}); setEditingRow(userToEdit);
setIsEditModalOpen(true); setIsEditModalOpen(true);
setErrors({});
} catch (error) { } catch (error) {
console.error('Error fetching user data:', error); console.error('Error fetching user data:', error);
showToast(error?.response?.data?.message || 'Failed to load user data', 'error'); showToast('Failed to load user data. Please try again.', 'error');
} finally { } finally {
setLoading(false); setLoading(false);
} }
@ -476,13 +481,21 @@ const AdminUsers = () => {
}; };
const handleDelete = (rowIndex) => { const handleDelete = (rowIndex) => {
const user = users[rowIndex]; // Calculate the actual index in the full users array based on pagination
setSelectedUser(user); const actualIndex = (currentPage - 1) * pageSize + rowIndex;
setShowDeleteModal(true); const user = users[actualIndex];
if (user) {
setSelectedUser(user);
setShowDeleteModal(true);
}
}; };
const handleEditSubmit = async (e) => { const handleEditSubmit = async (e) => {
e.preventDefault(); // Prevent default form submission if event is provided
if (e && e.preventDefault) {
e.preventDefault();
}
const formErrors = validateForm(); const formErrors = validateForm();
if (Object.keys(formErrors).length > 0) { if (Object.keys(formErrors).length > 0) {
setErrors(formErrors); setErrors(formErrors);
@ -512,6 +525,7 @@ const AdminUsers = () => {
if (!success) throw new Error(res?.message || 'Failed to update user'); if (!success) throw new Error(res?.message || 'Failed to update user');
// Update the users list with the updated user data
setUsers((prev) => setUsers((prev) =>
prev.map((u) => prev.map((u) =>
u.id === currentUser.id u.id === currentUser.id
@ -521,6 +535,13 @@ const AdminUsers = () => {
email: formData.email, email: formData.email,
status: formData.status, status: formData.status,
is_active: formData.status === 'Active', is_active: formData.status === 'Active',
lastLogin: u.lastLogin, // Preserve the last login time
raw: {
...(u.raw || {}),
name: formData.name,
email: formData.email,
is_active: formData.status === 'Active'
}
} }
: u : u
) )
@ -530,6 +551,13 @@ const AdminUsers = () => {
setIsEditModalOpen(false); setIsEditModalOpen(false);
setEditingRow(null); setEditingRow(null);
setCurrentUser(null); setCurrentUser(null);
// Reset form data
setFormData({
name: '',
email: '',
status: 'Active',
});
} catch (error) { } catch (error) {
console.error('Error updating user:', error); console.error('Error updating user:', error);
showToast(error?.response?.data?.message || 'Failed to update user', 'error'); showToast(error?.response?.data?.message || 'Failed to update user', 'error');
@ -630,7 +658,11 @@ const AdminUsers = () => {
}} }}
renderCell={(value, rowIndex, colIndex) => { renderCell={(value, rowIndex, colIndex) => {
if (colIndex === 4) { if (colIndex === 4) {
const user = users[rowIndex]; // Calculate the actual index in the full users array based on pagination
const actualIndex = (currentPage - 1) * pageSize + rowIndex;
const user = users[actualIndex];
if (!user) return null;
const isActive = user.status === 'Active'; const isActive = user.status === 'Active';
return ( return (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -638,7 +670,7 @@ const AdminUsers = () => {
type="button" type="button"
className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer" className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
title="Edit" title="Edit"
onClick={() => handleEdit(user)} onClick={() => handleEdit(user.raw || user)}
> >
<img <img
src={editingRow?.id === user.id ? pencilActiveSrc : pencilInactiveSrc} src={editingRow?.id === user.id ? pencilActiveSrc : pencilInactiveSrc}
@ -707,12 +739,18 @@ const AdminUsers = () => {
)} )}
{/* Edit Modal */} {/* Edit Modal */}
{isEditModalOpen && ( {isEditModalOpen && currentUser && (
<EditUserModal <EditUserModal
formData={formData} formData={formData}
setFormData={setFormData} setFormData={setFormData}
onClose={() => setIsEditModalOpen(false)} onClose={() => {
onUpdate={handleUpdateUser} setIsEditModalOpen(false);
setCurrentUser(null);
setFormData({ name: '', email: '', status: 'Active' });
setErrors({});
}}
onUpdate={handleEditSubmit}
key={currentUser.id} // Add key to force re-render when user changes
/> />
)} )}

View File

@ -535,13 +535,16 @@ const IsicHsCodes = () => {
}); });
const handleView = async (index) => { const handleView = async (index) => {
const selected = rowsData[index]; // Calculate the actual index in the filtered data based on pagination
const actualIndex = (currentPage - 1) * pageSize + index;
const selected = filteredData[actualIndex];
if (!selected) return; if (!selected) return;
try { try {
setIsLoading(true); setIsLoading(true);
const productId = selected.id; // Get fresh data from the server using the ID
const response = await productService.getProductById(productId); const response = await productService.getProductById(selected.id);
if (response && response.data) { if (response && response.data) {
const product = response.data; const product = response.data;
setForm({ setForm({
@ -551,8 +554,8 @@ const IsicHsCodes = () => {
status: product.is_active ? 'Active' : 'Inactive', status: product.is_active ? 'Active' : 'Inactive',
description: product.hs_description || '', description: product.hs_description || '',
createdBy: selected.createdBy, createdBy: selected.createdBy,
createdOn: selected.createdOn, createdOn: selected.createdOn || new Date(product.created_at).toLocaleDateString('en-GB'),
updated: selected.updated updated: selected.updated || (product.updated_at ? new Date(product.updated_at).toLocaleDateString('en-GB') : '')
}); });
setModalMode('view'); setModalMode('view');
} else { } else {
@ -568,7 +571,9 @@ const IsicHsCodes = () => {
}; };
const handleEdit = async (index) => { const handleEdit = async (index) => {
const selected = rowsData[index]; // Calculate the actual index in the filtered data based on pagination
const actualIndex = (currentPage - 1) * pageSize + index;
const selected = filteredData[actualIndex];
if (!selected) return; if (!selected) return;
try { try {
@ -621,38 +626,37 @@ const IsicHsCodes = () => {
const handleDelete = async (paginationIndex) => { const handleDelete = async (paginationIndex) => {
const dataIndex = (currentPage - 1) * pageSize + paginationIndex; const dataIndex = (currentPage - 1) * pageSize + paginationIndex;
if (dataIndex < 0 || dataIndex >= rowsData.length) { const selected = rowsData[dataIndex];
console.error('Invalid row index for deletion');
if (!selected || !selected.id) {
console.error('No product selected or missing ID');
showToast('Cannot delete: Product information is incomplete', 'error');
return; return;
} }
const productId = rowsData[dataIndex]?.id;
if (!productId) {
console.error('No product ID found for deletion');
return;
}
setDeletingRowIndex(dataIndex);
try { try {
setIsLoading(true); setIsLoading(true);
const response = await productService.getProductById(productId);
// Fetch the latest product data before showing delete confirmation
const response = await productService.getProductById(selected.id);
if (!response || !response.data) { if (!response || !response.data) {
throw new Error('Invalid product data received'); throw new Error('Invalid product data received');
} }
// Update the local data with the latest information
const updatedRowsData = [...rowsData]; const updatedRowsData = [...rowsData];
updatedRowsData[dataIndex] = { updatedRowsData[dataIndex] = {
...updatedRowsData[dataIndex], ...selected,
...response.data ...response.data
}; };
setRowsData(updatedRowsData); setRowsData(updatedRowsData);
setDeletingRowIndex(dataIndex);
setShowDeleteConfirm(true); setShowDeleteConfirm(true);
} catch (error) { } catch (error) {
console.error('Error preparing product for deletion:', error); console.error('Error preparing product for deletion:', error);
showToast('Error loading product details for deletion', 'error'); showToast('Error loading product details for deletion', 'error');
setDeletingRowIndex(null);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@ -670,7 +674,6 @@ const IsicHsCodes = () => {
}; };
const handleDeleteConfirm = async () => { const handleDeleteConfirm = async () => {
if (deletingRowIndex === null || deletingRowIndex < 0 || deletingRowIndex >= rowsData.length) { if (deletingRowIndex === null || deletingRowIndex < 0 || deletingRowIndex >= rowsData.length) {
const errorMsg = 'Invalid row selected for deletion'; const errorMsg = 'Invalid row selected for deletion';
console.error(errorMsg, { deletingRowIndex, rowsDataLength: rowsData.length }); console.error(errorMsg, { deletingRowIndex, rowsDataLength: rowsData.length });
@ -693,6 +696,16 @@ const IsicHsCodes = () => {
try { try {
await productService.deleteProduct(productId); await productService.deleteProduct(productId);
// Calculate the current page after deletion
const currentItemsCount = rowsData.length - 1; // After deletion
const maxPage = Math.max(1, Math.ceil(currentItemsCount / pageSize));
// If we're on a page that no longer exists after deletion, go to the previous page
// But only if we're not already on the first page
if (currentPage > maxPage && maxPage > 0) {
setCurrentPage(maxPage);
}
const newData = [...rowsData]; const newData = [...rowsData];
newData.splice(deletingRowIndex, 1); newData.splice(deletingRowIndex, 1);
setRowsData(newData); setRowsData(newData);
@ -701,6 +714,16 @@ const IsicHsCodes = () => {
} catch (apiError) { } catch (apiError) {
console.error('API Error:', apiError); console.error('API Error:', apiError);
if (apiError.response && apiError.response.status === 204) { if (apiError.response && apiError.response.status === 204) {
// Calculate the current page after deletion for 204 response
const currentItemsCount = rowsData.length - 1; // After deletion
const maxPage = Math.max(1, Math.ceil(currentItemsCount / pageSize));
// If we're on a page that no longer exists after deletion, go to the previous page
// But only if we're not already on the first page
if (currentPage > maxPage && maxPage > 0) {
setCurrentPage(maxPage);
}
const newData = [...rowsData]; const newData = [...rowsData];
newData.splice(deletingRowIndex, 1); newData.splice(deletingRowIndex, 1);
setRowsData(newData); setRowsData(newData);

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect, useMemo, useRef } from 'react'; import React, { useState, useEffect, useMemo, useRef } from 'react';
import Table from '@/components/common/Table'; import Table from '@/components/common/Table';
import { TextField } from '@/components/common/FormControls'; import { TextField } from '@/components/common/FormControls';
import { getUnits, createUnit, updateUnit, deleteUnit, uploadUnitCSV } from '@/services/configuration/unitService'; import { getUnits, getUnitById, createUnit, updateUnit, deleteUnit, uploadUnitCSV } from '@/services/configuration/unitService';
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';
@ -193,27 +193,108 @@ const UnitMaster = () => {
setForm(createEmptyUnitForm()); setForm(createEmptyUnitForm());
setModalMode('add'); setModalMode('add');
}; };
const handleView = (index) => { const handleView = async (index) => {
const selected = units[index]; try {
if (!selected) return; setLoading(true);
setSelectedUnit(selected);
setModalMode('view'); // Get the actual index in the full units array based on pagination
const actualIndex = (currentPage - 1) * pageSize + index;
const selected = filteredUnits[actualIndex];
if (!selected) return;
// Fetch the latest unit data by ID using the getUnitById function
const response = await getUnitById(selected.id);
if (!response) {
throw new Error('Failed to fetch unit data');
}
// The API returns data in response.data
const unitData = response.data || response;
setSelectedUnit(unitData);
setModalMode('view');
} catch (error) {
console.error('Error fetching unit data:', error);
setToastData({
message: 'Failed to load unit data. Please try again.',
type: 'error'
});
} finally {
setLoading(false);
}
}; };
const handleEdit = (index) => { const handleEdit = async (index) => {
const selected = filteredUnits[index]; try {
if (!selected) return; setLoading(true);
setEditingRow(index);
setSelectedUnit(selected); // Get the actual index in the full units array based on pagination
setForm({ const actualIndex = (currentPage - 1) * pageSize + index;
uom: selected.uom || '', const selected = filteredUnits[actualIndex];
description: selected.description || '',
}); if (!selected) return;
setModalMode('edit');
// Fetch the latest unit data by ID using the getUnitById function
const response = await getUnitById(selected.id);
if (!response) {
throw new Error('Failed to fetch unit data');
}
// The API returns data in response.data
const unitData = response.data || response;
setEditingRow(selected.id);
setSelectedUnit(unitData);
setForm({
uom: unitData.uom || '',
description: unitData.description || '',
});
setModalMode('edit');
} catch (error) {
console.error('Error fetching unit data:', error);
setToastData({
message: 'Failed to load unit data. Please try again.',
type: 'error'
});
} finally {
setLoading(false);
}
}; };
const handleDelete = (index) => { const handleDelete = async (index) => {
setDeletingRow(index); try {
setLoading(true);
// Get the actual index in the full units array based on pagination
const actualIndex = (currentPage - 1) * pageSize + index;
const selected = filteredUnits[actualIndex];
if (!selected) return;
// Fetch the latest unit data by ID using the getUnitById function
const response = await getUnitById(selected.id);
if (!response) {
throw new Error('Failed to fetch unit data');
}
// The API returns data in response.data
const unitData = response.data || response;
// Set the actual index in the filtered array for deletion
setDeletingRow(actualIndex);
} catch (error) {
console.error('Error fetching unit data:', error);
setToastData({
message: 'Failed to load unit data. Please try again.',
type: 'error'
});
} finally {
setLoading(false);
}
}; };
const closeModal = () => { const closeModal = () => {
@ -276,8 +357,7 @@ const UnitMaster = () => {
setSaveLoading(true); setSaveLoading(true);
if (modalMode === 'edit' && editingRow !== null) { if (modalMode === 'edit' && editingRow !== null) {
const unitToUpdate = filteredUnits[editingRow]; await updateUnit(editingRow, unitData);
await updateUnit(unitToUpdate.id, unitData);
setToastData({ setToastData({
message: 'Unit updated successfully!', message: 'Unit updated successfully!',

View File

@ -10,6 +10,16 @@ export const getQuarterlyWindows = async () => {
} }
}; };
export const getQuarterlyWindowById = async (id) => {
try {
const response = await getRequest(`/quarterly_windows/${id}`);
return response.data;
} catch (error) {
console.error(`Error fetching quarterly window with ID ${id}:`, error);
throw error;
}
};
export const createQuarterlyWindow = async (data) => { export const createQuarterlyWindow = async (data) => {
try { try {
const response = await postRequest('/quarterly_windows', data); const response = await postRequest('/quarterly_windows', data);

View File

@ -13,6 +13,17 @@ export const getUnits = async () => {
} }
}; };
export const getUnitById = async (id) => {
try {
const response = await getRequest(`${UNIT_MASTER_ENDPOINT}/${id}`);
// Handle nested data structure
return response.data || response;
} catch (error) {
console.error(`Error fetching unit with ID ${id}:`, error);
throw error;
}
};
export const createUnit = async (unitData) => { export const createUnit = async (unitData) => {
try { try {