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

View File

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

View File

@ -104,11 +104,13 @@ const AdminUsers = () => {
}, 4000);
};
// Fetch users
// Fetch users with pagination
useEffect(() => {
const fetchUsers = async () => {
try {
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 usersData = Array.isArray(res)
@ -117,7 +119,7 @@ const AdminUsers = () => {
? res.data
: Array.isArray(res?.data?.data)
? res.data.data
: null;
: [];
if (!usersData) {
showToast('Failed to load users', 'error');
@ -163,7 +165,7 @@ const AdminUsers = () => {
};
fetchUsers();
}, []);
}, [currentPage]); // Add currentPage as a dependency
const totalUsers = users.length;
const activeUsers = users.filter((user) => user.status === 'Active').length;
@ -294,38 +296,41 @@ const AdminUsers = () => {
return;
}
setEditingRow(user);
setLoading(true);
try {
const res = await getAdminUserById(user.id);
const payload = res?.data ?? res;
if (!payload) throw new Error('No user data returned from API');
setLoading(true);
// Fetch the latest user data from the API
const response = await getAdminUserById(user.id);
const userData = response?.data?.data || response?.data || response;
if (!userData) {
throw new Error('Failed to fetch user data');
}
const name = payload.name ?? payload.fullName ?? user.name ?? '';
const email = payload.email ?? user.email ?? '';
const is_active =
payload.is_active !== undefined ? !!payload.is_active : !!user.is_active;
setCurrentUser({
...payload,
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({
name,
email,
status: is_active ? 'Active' : 'Inactive',
name: userToEdit.name,
email: userToEdit.email,
status: userToEdit.status,
});
setErrors({});
setEditingRow(userToEdit);
setIsEditModalOpen(true);
setErrors({});
} catch (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 {
setLoading(false);
}
@ -476,13 +481,21 @@ const AdminUsers = () => {
};
const handleDelete = (rowIndex) => {
const user = users[rowIndex];
setSelectedUser(user);
setShowDeleteModal(true);
// Calculate the actual index in the full users array based on pagination
const actualIndex = (currentPage - 1) * pageSize + rowIndex;
const user = users[actualIndex];
if (user) {
setSelectedUser(user);
setShowDeleteModal(true);
}
};
const handleEditSubmit = async (e) => {
e.preventDefault();
// Prevent default form submission if event is provided
if (e && e.preventDefault) {
e.preventDefault();
}
const formErrors = validateForm();
if (Object.keys(formErrors).length > 0) {
setErrors(formErrors);
@ -512,6 +525,7 @@ const AdminUsers = () => {
if (!success) throw new Error(res?.message || 'Failed to update user');
// Update the users list with the updated user data
setUsers((prev) =>
prev.map((u) =>
u.id === currentUser.id
@ -521,6 +535,13 @@ const AdminUsers = () => {
email: formData.email,
status: formData.status,
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
)
@ -530,6 +551,13 @@ const AdminUsers = () => {
setIsEditModalOpen(false);
setEditingRow(null);
setCurrentUser(null);
// Reset form data
setFormData({
name: '',
email: '',
status: 'Active',
});
} catch (error) {
console.error('Error updating user:', error);
showToast(error?.response?.data?.message || 'Failed to update user', 'error');
@ -630,7 +658,11 @@ const AdminUsers = () => {
}}
renderCell={(value, rowIndex, colIndex) => {
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';
return (
<div className="flex items-center gap-2">
@ -638,7 +670,7 @@ const AdminUsers = () => {
type="button"
className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
title="Edit"
onClick={() => handleEdit(user)}
onClick={() => handleEdit(user.raw || user)}
>
<img
src={editingRow?.id === user.id ? pencilActiveSrc : pencilInactiveSrc}
@ -707,12 +739,18 @@ const AdminUsers = () => {
)}
{/* Edit Modal */}
{isEditModalOpen && (
{isEditModalOpen && currentUser && (
<EditUserModal
formData={formData}
setFormData={setFormData}
onClose={() => setIsEditModalOpen(false)}
onUpdate={handleUpdateUser}
onClose={() => {
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 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;
try {
setIsLoading(true);
const productId = selected.id;
const response = await productService.getProductById(productId);
// Get fresh data from the server using the ID
const response = await productService.getProductById(selected.id);
if (response && response.data) {
const product = response.data;
setForm({
@ -551,8 +554,8 @@ const IsicHsCodes = () => {
status: product.is_active ? 'Active' : 'Inactive',
description: product.hs_description || '',
createdBy: selected.createdBy,
createdOn: selected.createdOn,
updated: selected.updated
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') : '')
});
setModalMode('view');
} else {
@ -568,7 +571,9 @@ const IsicHsCodes = () => {
};
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;
try {
@ -620,39 +625,38 @@ const IsicHsCodes = () => {
const [deletingRowIndex, setDeletingRowIndex] = React.useState(null);
const handleDelete = async (paginationIndex) => {
const dataIndex = (currentPage - 1) * pageSize + paginationIndex;
if (dataIndex < 0 || dataIndex >= rowsData.length) {
console.error('Invalid row index for deletion');
const dataIndex = (currentPage - 1) * pageSize + paginationIndex;
const selected = rowsData[dataIndex];
if (!selected || !selected.id) {
console.error('No product selected or missing ID');
showToast('Cannot delete: Product information is incomplete', 'error');
return;
}
const productId = rowsData[dataIndex]?.id;
if (!productId) {
console.error('No product ID found for deletion');
return;
}
setDeletingRowIndex(dataIndex);
try {
setIsLoading(true);
const response = await productService.getProductById(productId);
setIsLoading(true);
// Fetch the latest product data before showing delete confirmation
const response = await productService.getProductById(selected.id);
if (!response || !response.data) {
throw new Error('Invalid product data received');
}
// Update the local data with the latest information
const updatedRowsData = [...rowsData];
updatedRowsData[dataIndex] = {
...updatedRowsData[dataIndex],
...selected,
...response.data
};
setRowsData(updatedRowsData);
setDeletingRowIndex(dataIndex);
setShowDeleteConfirm(true);
} catch (error) {
console.error('Error preparing product for deletion:', error);
showToast('Error loading product details for deletion', 'error');
setDeletingRowIndex(null);
} finally {
setIsLoading(false);
}
@ -670,7 +674,6 @@ const IsicHsCodes = () => {
};
const handleDeleteConfirm = async () => {
if (deletingRowIndex === null || deletingRowIndex < 0 || deletingRowIndex >= rowsData.length) {
const errorMsg = 'Invalid row selected for deletion';
console.error(errorMsg, { deletingRowIndex, rowsDataLength: rowsData.length });
@ -693,6 +696,16 @@ const IsicHsCodes = () => {
try {
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];
newData.splice(deletingRowIndex, 1);
setRowsData(newData);
@ -701,6 +714,16 @@ const IsicHsCodes = () => {
} catch (apiError) {
console.error('API Error:', apiError);
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];
newData.splice(deletingRowIndex, 1);
setRowsData(newData);

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect, useMemo, useRef } from 'react';
import Table from '@/components/common/Table';
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 addIconSrc = '/assets/images/ic_baseline-plus.svg';
@ -193,27 +193,108 @@ const UnitMaster = () => {
setForm(createEmptyUnitForm());
setModalMode('add');
};
const handleView = (index) => {
const selected = units[index];
if (!selected) return;
setSelectedUnit(selected);
setModalMode('view');
const handleView = async (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;
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 selected = filteredUnits[index];
if (!selected) return;
setEditingRow(index);
setSelectedUnit(selected);
setForm({
uom: selected.uom || '',
description: selected.description || '',
});
setModalMode('edit');
const handleEdit = async (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;
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) => {
setDeletingRow(index);
const handleDelete = async (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 = () => {
@ -276,8 +357,7 @@ const UnitMaster = () => {
setSaveLoading(true);
if (modalMode === 'edit' && editingRow !== null) {
const unitToUpdate = filteredUnits[editingRow];
await updateUnit(unitToUpdate.id, unitData);
await updateUnit(editingRow, unitData);
setToastData({
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) => {
try {
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) => {
try {