fixed
This commit is contained in:
parent
396567cada
commit
df6e81a2af
@ -113,13 +113,25 @@ const HeaderBar = () => {
|
|||||||
`inline-flex items-center gap-2 pb-1 border-b-2 ${
|
`inline-flex items-center gap-2 pb-1 border-b-2 ${
|
||||||
isActive
|
isActive
|
||||||
? 'text-[#92722A] font-medium border-[#92722A]'
|
? 'text-[#92722A] font-medium border-[#92722A]'
|
||||||
: 'text-[#232528] hover:text-gray-900 border-transparent'
|
: window.location.pathname === '/survey'
|
||||||
|
? 'text-[#232528] hover:text-gray-900 border-transparent'
|
||||||
|
: 'text-gray-400 cursor-not-allowed'
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (window.location.pathname !== '/survey') {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{({ isActive }) => (
|
{({ isActive }) => (
|
||||||
<>
|
<>
|
||||||
<img src={isActive ? surveyIconActiveSrc : surveyIconInactiveSrc} className="h-[18px] w-[18px]" />
|
<img
|
||||||
|
src={isActive ? surveyIconActiveSrc : surveyIconInactiveSrc}
|
||||||
|
className={`h-[18px] w-[18px] ${
|
||||||
|
window.location.pathname !== '/survey' ? 'opacity-50' : ''
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
<span>Survey</span>
|
<span>Survey</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -239,6 +239,7 @@ React.useEffect(() => {
|
|||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
setError(null); // Reset error state before fetching
|
||||||
const data = await fetchDashboardData(selectedQuarter, selectedYear);
|
const data = await fetchDashboardData(selectedQuarter, selectedYear);
|
||||||
const mapped = (data || []).map((item) => ({
|
const mapped = (data || []).map((item) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
@ -255,11 +256,12 @@ React.useEffect(() => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
setSubmissions(mapped);
|
setSubmissions(mapped);
|
||||||
setError(null);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to load submissions', err);
|
console.error('Failed to load submissions', err);
|
||||||
|
// Only show error if there are no existing submissions and it's not the initial load
|
||||||
|
if (submissions.length === 0 && !isInitialLoad) {
|
||||||
setError('Unable to load submissions. Please try again later.');
|
setError('Unable to load submissions. Please try again later.');
|
||||||
setSubmissions([]);
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setIsInitialLoad(false);
|
setIsInitialLoad(false);
|
||||||
@ -334,11 +336,9 @@ React.useEffect(() => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
setSubmissions(mapped);
|
setSubmissions(mapped);
|
||||||
setError(null);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to load initial data:', err);
|
console.error('Failed to load initial data:', err);
|
||||||
setError('Unable to load submissions. Please try again later.');
|
// Don't show error during initial load
|
||||||
setSubmissions([]);
|
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setIsInitialLoad(false);
|
setIsInitialLoad(false);
|
||||||
|
|||||||
@ -111,6 +111,18 @@ const AdminUsers = () => {
|
|||||||
}, 4000);
|
}, 4000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Filter users based on search term
|
||||||
|
const filteredUsers = React.useMemo(() => {
|
||||||
|
if (!searchTerm.trim()) return users;
|
||||||
|
|
||||||
|
const searchLower = searchTerm.toLowerCase();
|
||||||
|
return users.filter(user =>
|
||||||
|
user.name.toLowerCase().includes(searchLower) ||
|
||||||
|
user.email.toLowerCase().includes(searchLower) ||
|
||||||
|
user.status.toLowerCase().includes(searchLower)
|
||||||
|
);
|
||||||
|
}, [users, searchTerm]);
|
||||||
|
|
||||||
// Fetch users with pagination
|
// Fetch users with pagination
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchUsers = async () => {
|
const fetchUsers = async () => {
|
||||||
@ -118,7 +130,7 @@ const AdminUsers = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
// Pass currentPage and pageSize to the API if it supports pagination
|
// Pass currentPage and pageSize to the API if it supports pagination
|
||||||
// If not, we'll handle pagination client-side
|
// If not, we'll handle pagination client-side
|
||||||
const res = await getAdminUser();
|
const res = await getAdminUser(searchTerm);
|
||||||
|
|
||||||
const usersData = Array.isArray(res)
|
const usersData = Array.isArray(res)
|
||||||
? res
|
? res
|
||||||
@ -172,10 +184,10 @@ const AdminUsers = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fetchUsers();
|
fetchUsers();
|
||||||
}, [currentPage]); // Add currentPage as a dependency
|
}, [currentPage, searchTerm]); // Add currentPage and searchTerm as dependencies
|
||||||
|
|
||||||
const totalUsers = users.length;
|
const totalUsers = searchTerm ? filteredUsers.length : users.length;
|
||||||
const activeUsers = users.filter((user) => user.status === 'Active').length;
|
const activeUsers = (searchTerm ? filteredUsers : users).filter((user) => user.status === 'Active').length;
|
||||||
const inactiveUsers = totalUsers - activeUsers;
|
const inactiveUsers = totalUsers - activeUsers;
|
||||||
|
|
||||||
const summaryItems = [
|
const summaryItems = [
|
||||||
@ -307,17 +319,8 @@ const AdminUsers = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Filter users based on search term
|
|
||||||
const filteredUsers = searchTerm
|
|
||||||
? users.filter(
|
|
||||||
(user) =>
|
|
||||||
user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
user.email.toLowerCase().includes(searchTerm.toLowerCase())
|
|
||||||
)
|
|
||||||
: users;
|
|
||||||
|
|
||||||
// Apply sorting to filtered users
|
// Apply sorting to filtered users
|
||||||
const sortedUsers = getSortedData(filteredUsers);
|
const sortedUsers = getSortedData(searchTerm ? filteredUsers : users);
|
||||||
|
|
||||||
const rows = sortedUsers.map((user) => [
|
const rows = sortedUsers.map((user) => [
|
||||||
user.name,
|
user.name,
|
||||||
@ -405,12 +408,20 @@ const AdminUsers = () => {
|
|||||||
|
|
||||||
showToast("User deleted successfully!", "success");
|
showToast("User deleted successfully!", "success");
|
||||||
|
|
||||||
|
// Update both the main users list and filtered list
|
||||||
setUsers((prev) => prev.filter((u) => u.id !== selectedUser.id));
|
setUsers((prev) => prev.filter((u) => u.id !== selectedUser.id));
|
||||||
|
|
||||||
|
// If we're in search mode, also update the filtered list
|
||||||
|
if (searchTerm) {
|
||||||
|
setSearchTerm(''); // Clear search to show updated list
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast("Failed to delete user!", "error");
|
console.error('Error deleting user:', error);
|
||||||
|
showToast(error?.response?.data?.message || "Failed to delete user!", "error");
|
||||||
} finally {
|
} finally {
|
||||||
setDeletingRow(null);
|
setDeletingRow(null);
|
||||||
setShowDeleteModal(false);
|
setShowDeleteModal(false);
|
||||||
|
setSelectedUser(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -423,7 +434,7 @@ const AdminUsers = () => {
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
// Fetch the latest user data from the API
|
// Fetch the latest user data from the API using the user's ID
|
||||||
const response = await getAdminUserById(user.id);
|
const response = await getAdminUserById(user.id);
|
||||||
const userData = response?.data?.data || response?.data || response;
|
const userData = response?.data?.data || response?.data || response;
|
||||||
|
|
||||||
@ -437,7 +448,8 @@ const AdminUsers = () => {
|
|||||||
name: userData.name || userData.fullName || '',
|
name: userData.name || userData.fullName || '',
|
||||||
email: userData.email || '',
|
email: userData.email || '',
|
||||||
status: userData.is_active ? 'Active' : 'Inactive',
|
status: userData.is_active ? 'Active' : 'Inactive',
|
||||||
is_active: userData.is_active !== undefined ? userData.is_active : true
|
is_active: userData.is_active !== undefined ? userData.is_active : true,
|
||||||
|
raw: userData // Store the raw data for reference
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the current user and form data
|
// Set the current user and form data
|
||||||
@ -606,9 +618,11 @@ const AdminUsers = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = (rowIndex) => {
|
const handleDelete = (rowIndex) => {
|
||||||
// Calculate the actual index in the full users array based on pagination
|
// Get the current data source based on search
|
||||||
|
const dataSource = searchTerm ? filteredUsers : users;
|
||||||
|
// Calculate the actual index in the current data source based on pagination
|
||||||
const actualIndex = (currentPage - 1) * pageSize + rowIndex;
|
const actualIndex = (currentPage - 1) * pageSize + rowIndex;
|
||||||
const user = users[actualIndex];
|
const user = dataSource[actualIndex];
|
||||||
if (user) {
|
if (user) {
|
||||||
setSelectedUser(user);
|
setSelectedUser(user);
|
||||||
setShowDeleteModal(true);
|
setShowDeleteModal(true);
|
||||||
@ -699,15 +713,23 @@ const AdminUsers = () => {
|
|||||||
<img
|
<img
|
||||||
src={searchIconSrc}
|
src={searchIconSrc}
|
||||||
alt="Search"
|
alt="Search"
|
||||||
className="absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2 transform"
|
className="absolute left-3 top-1/2 h-5 w-5 -translate-y-1/2"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search by Names, Email"
|
|
||||||
className="h-10 w-[400px] rounded-lg border border-[#E6EAF5] pl-10 pr-4 text-sm focus:outline-none focus:ring-2 focus:ring-[#B68A35] focus:ring-opacity-50"
|
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
placeholder="Search by name, email, or status"
|
||||||
|
className="h-10 w-[350px] rounded-lg border border-[#E6EAF5] pl-10 pr-4 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
/>
|
/>
|
||||||
|
{searchTerm && (
|
||||||
|
<button
|
||||||
|
onClick={() => setSearchTerm('')}
|
||||||
|
className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<button
|
<button
|
||||||
@ -780,7 +802,7 @@ const AdminUsers = () => {
|
|||||||
currentPage,
|
currentPage,
|
||||||
onPageChange: setCurrentPage,
|
onPageChange: setCurrentPage,
|
||||||
pageSize,
|
pageSize,
|
||||||
totalItems: users.length,
|
totalItems: searchTerm ? filteredUsers.length : users.length,
|
||||||
pageSizeOptions: [10, 20, 50, 100],
|
pageSizeOptions: [10, 20, 50, 100],
|
||||||
onPageSizeChange: (size) => {
|
onPageSizeChange: (size) => {
|
||||||
setPageSize(size);
|
setPageSize(size);
|
||||||
@ -789,9 +811,11 @@ const AdminUsers = () => {
|
|||||||
}}
|
}}
|
||||||
renderCell={(value, rowIndex, colIndex) => {
|
renderCell={(value, rowIndex, colIndex) => {
|
||||||
if (colIndex === 4) {
|
if (colIndex === 4) {
|
||||||
// Calculate the actual index in the full users array based on pagination
|
// Get the current data source based on search
|
||||||
|
const dataSource = searchTerm ? filteredUsers : users;
|
||||||
|
// Calculate the actual index in the current data source based on pagination
|
||||||
const actualIndex = (currentPage - 1) * pageSize + rowIndex;
|
const actualIndex = (currentPage - 1) * pageSize + rowIndex;
|
||||||
const user = users[actualIndex];
|
const user = dataSource[actualIndex];
|
||||||
if (!user) return null;
|
if (!user) return null;
|
||||||
|
|
||||||
const isActive = user.status === 'Active';
|
const isActive = user.status === 'Active';
|
||||||
@ -800,8 +824,15 @@ const AdminUsers = () => {
|
|||||||
<button
|
<button
|
||||||
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"
|
onClick={() => {
|
||||||
onClick={() => handleEdit(user.raw || user)}
|
// Make sure we're using the full user object from the current data source
|
||||||
|
const dataSource = searchTerm ? filteredUsers : users;
|
||||||
|
const actualIndex = (currentPage - 1) * pageSize + rowIndex;
|
||||||
|
const currentUser = dataSource[actualIndex];
|
||||||
|
if (currentUser) {
|
||||||
|
handleEdit(currentUser.raw || currentUser);
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={editingRow?.id === user.id ? pencilActiveSrc : pencilInactiveSrc}
|
src={editingRow?.id === user.id ? pencilActiveSrc : pencilInactiveSrc}
|
||||||
|
|||||||
@ -3056,12 +3056,25 @@ const handleImport = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SUCCESS
|
// SUCCESS
|
||||||
setToastData({
|
const successMessage = message || "File uploaded successfully!";
|
||||||
message: message || "File uploaded successfully!",
|
|
||||||
type: "success",
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// Close the import modal
|
||||||
|
closeImportModal();
|
||||||
|
|
||||||
|
// Show success toast
|
||||||
|
// setToastData({
|
||||||
|
// message: successMessage,
|
||||||
|
// type: "success",
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Show the toast before reload
|
||||||
|
showToast('success', successMessage);
|
||||||
|
|
||||||
|
// Wait a bit for user to see the success message, then reload
|
||||||
|
setTimeout(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Upload error:", error);
|
console.error("Upload error:", error);
|
||||||
|
|
||||||
@ -3088,11 +3101,6 @@ const handleImport = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white w-full rounded-lg shadow-sm ring-1 ring-[#E5E7EB]">
|
<div className="bg-white w-full rounded-lg shadow-sm ring-1 ring-[#E5E7EB]">
|
||||||
{toast && (
|
{toast && (
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user