bug fixed in admin profile
This commit is contained in:
parent
b25e35d4c9
commit
d0d8bd13f3
@ -170,15 +170,29 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
||||
<span className="text-sm font-medium">{toast.message}</span>
|
||||
{toast.type === 'rejected' && (
|
||||
<button
|
||||
onClick={() => {
|
||||
// Add your resubmit logic here
|
||||
// You can navigate to the edit page or trigger a resubmit function
|
||||
}}
|
||||
className="ml-auto px-3 py-1 bg-[#FEF2F2] text-[#7C2320] text-sm font-medium rounded hover:bg-[#FEF2F2] transition-colors"
|
||||
>
|
||||
Resubmit
|
||||
<img src="/assets/images/arrow-right-bold 1.svg" alt="" className="w-4 h-4 ml-1 inline-block" />
|
||||
</button>
|
||||
onClick={() => {
|
||||
navigate('/survey', {
|
||||
state: {
|
||||
submission: {
|
||||
id: product.submission_id,
|
||||
quarter: product.quarter,
|
||||
year: product.year,
|
||||
establishment_name: product.establishment_name,
|
||||
permanent_factory_code: product.permanent_factory_code,
|
||||
industry_code: product.industry_code,
|
||||
license_number: product.license_number,
|
||||
isic_code: product.isic_code,
|
||||
emirate: product.emirate
|
||||
},
|
||||
isResubmit: true
|
||||
}
|
||||
});
|
||||
}}
|
||||
className="ml-auto px-3 py-1 bg-[#FEF2F2] text-[#7C2320] text-sm font-medium rounded hover:bg-[#FEF2F2] transition-colors"
|
||||
>
|
||||
Resubmit
|
||||
<img src="/assets/images/arrow-right-bold 1.svg" alt="" className="w-4 h-4 ml-1 inline-block" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -735,6 +735,7 @@ const ReviewSubmit = ({
|
||||
<div className="space-y-2">
|
||||
<textarea
|
||||
placeholder="Enter your remarks here..."
|
||||
readOnly
|
||||
value={remarks}
|
||||
onChange={(e) => setRemarks(e.target.value)}
|
||||
className="w-full min-h-[100px] p-3 border border-#CBA344 rounded-md focus:ring-2 focus:ring-[#CBA344] focus:border-transparent"
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
import React from "react";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
|
||||
const DeleteUserModal = ({ userName, onClose, onDelete }) => {
|
||||
return (
|
||||
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/20">
|
||||
<div className="bg-white rounded-lg w-[420px] p-6 shadow-lg relative">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="bg-red-100 p-2 rounded-full">
|
||||
<AlertTriangle className="text-red-500" size={20} />
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-gray-800">Delete User</h3>
|
||||
</div>
|
||||
|
||||
<p className="text-gray-600 mb-6">
|
||||
Are you sure you want to delete{" "}
|
||||
<span className="font-semibold text-gray-900">{userName}</span>?<br />
|
||||
This action will permanently delete the data and cannot be undone.
|
||||
</p>
|
||||
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="px-5 py-2 rounded-md border border-gray-300 text-gray-700 hover:bg-gray-100"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={onDelete}
|
||||
className="px-5 py-2 rounded-md bg-[#92722A] text-white font-medium"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteUserModal;
|
||||
@ -0,0 +1,102 @@
|
||||
import React from "react";
|
||||
|
||||
const EditUserModal = ({ formData, setFormData, onClose, onUpdate }) => {
|
||||
return (
|
||||
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/10">
|
||||
<div className="bg-white rounded-lg w-[480px] shadow-lg p-6 relative">
|
||||
{/* Close Button */}
|
||||
<button
|
||||
className="absolute top-3 right-3 text-gray-500 hover:text-gray-800"
|
||||
onClick={onClose}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
{/* Header */}
|
||||
<h3 className="text-xl font-semibold text-gray-800 mb-6">Edit User</h3>
|
||||
|
||||
{/* Form */}
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
onUpdate();
|
||||
}}
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
{/* Name & Email in one row */}
|
||||
<div className="flex gap-4">
|
||||
{/* Name */}
|
||||
<div className="flex-1">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Name <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter Name"
|
||||
className="w-full border border-[#D9C9A3] rounded-md px-3 py-2 focus:ring-1 focus:ring-[#B68A35]"
|
||||
value={formData.name}
|
||||
onChange={(e) =>
|
||||
setFormData((prev) => ({ ...prev, name: e.target.value }))
|
||||
}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Email */}
|
||||
<div className="flex-1">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Email <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Enter Email"
|
||||
className="w-full border border-[#D9C9A3] rounded-md px-3 py-2 focus:ring-1 focus:ring-[#B68A35]"
|
||||
value={formData.email}
|
||||
onChange={(e) =>
|
||||
setFormData((prev) => ({ ...prev, email: e.target.value }))
|
||||
}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Status
|
||||
</label>
|
||||
<select
|
||||
className="w-full border border-[#D9C9A3] rounded-md px-3 py-2 focus:ring-1 focus:ring-[#B68A35]"
|
||||
value={formData.status}
|
||||
onChange={(e) =>
|
||||
setFormData((prev) => ({ ...prev, status: e.target.value }))
|
||||
}
|
||||
>
|
||||
<option value="Active">Active</option>
|
||||
<option value="Inactive">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Buttons */}
|
||||
<div className="flex justify-end gap-3 mt-6">
|
||||
<button
|
||||
type="button"
|
||||
className="px-5 py-2 rounded-md border border-gray-300 text-gray-700 hover:bg-gray-100"
|
||||
onClick={onClose}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="px-5 py-2 rounded-md bg-[#B68A35] text-white font-medium hover:bg-[#9c6f28]"
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditUserModal;
|
||||
@ -6,11 +6,14 @@ import {
|
||||
getAdminUser,
|
||||
getAdminUserById,
|
||||
updateAdminUser,
|
||||
deleteAdminUser
|
||||
deleteAdminUser, // ✅ Added import
|
||||
} from '@/services/configuration/adminService';
|
||||
|
||||
import CustomToast from '@/components/common/CustomToast';
|
||||
import { X } from 'lucide-react';
|
||||
import { TextField, SelectField } from '@/components/common/FormControls';
|
||||
import EditUserModal from './EditUserModal';
|
||||
import DeleteUserModal from './DeleteUserModal';
|
||||
|
||||
const searchIconSrc = '/assets/images/material-symbols_search-rounded.svg';
|
||||
const exportIconSrc = '/assets/images/DownloadSimple.svg';
|
||||
@ -63,11 +66,14 @@ const AdminUsers = () => {
|
||||
const [currentUser, setCurrentUser] = useState(null);
|
||||
const [users, setUsers] = useState([]);
|
||||
const [editingRow, setEditingRow] = useState(null);
|
||||
const [deletingRow, setDeletingRow] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const pageSize = 10;
|
||||
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||
const [selectedUser, setSelectedUser] = useState(null);
|
||||
const [deletingRow, setDeletingRow] = useState(null);
|
||||
const [formData, setFormData] = useState({
|
||||
name: '',
|
||||
email: '',
|
||||
@ -202,6 +208,54 @@ const [confirmPassword, setConfirmPassword] = useState('');
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateUser = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const updatedUser = {
|
||||
name: formData.name,
|
||||
email: formData.email,
|
||||
is_active: formData.status === "Active", // ✅ status handled via is_active
|
||||
};
|
||||
|
||||
const res = await updateAdminUser(currentUser.id, updatedUser);
|
||||
|
||||
const success =
|
||||
res?.status === "success" ||
|
||||
res?.code === 200 ||
|
||||
res?.data?.status === "success" ||
|
||||
(!res.error && res);
|
||||
|
||||
if (!success) throw new Error(res?.message || "Failed to update user");
|
||||
|
||||
showToast("User updated successfully!", "success");
|
||||
setIsEditModalOpen(false);
|
||||
|
||||
// ✅ update UI
|
||||
setUsers((prev) =>
|
||||
prev.map((u) =>
|
||||
u.id === currentUser.id
|
||||
? {
|
||||
...u,
|
||||
name: formData.name,
|
||||
email: formData.email,
|
||||
status: formData.status,
|
||||
is_active: formData.status === "Active",
|
||||
}
|
||||
: u
|
||||
)
|
||||
);
|
||||
|
||||
setCurrentUser(null);
|
||||
} catch (error) {
|
||||
console.error("Error updating user:", error);
|
||||
showToast(error?.response?.data?.message || "Failed to update user", "error");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const validateForm = () => {
|
||||
const newErrors = {};
|
||||
if (!formData.name || !formData.name.trim()) newErrors.name = 'Name is required';
|
||||
@ -209,49 +263,70 @@ const [confirmPassword, setConfirmPassword] = useState('');
|
||||
return newErrors;
|
||||
};
|
||||
|
||||
const handleEdit = async (index) => {
|
||||
const user = users[index];
|
||||
if (!user || !user.id) {
|
||||
showToast('Invalid user selected', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
setEditingRow(index);
|
||||
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');
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
setFormData({
|
||||
name,
|
||||
email,
|
||||
status: is_active ? 'Active' : 'Inactive',
|
||||
});
|
||||
|
||||
setErrors({});
|
||||
setIsEditModalOpen(true);
|
||||
} catch (error) {
|
||||
console.error('Error fetching user data:', error);
|
||||
showToast(error?.response?.data?.message || 'Failed to load user data', 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
const handleDeleteClick = (user) => {
|
||||
setSelectedUser(user);
|
||||
setShowDeleteModal(true);
|
||||
};
|
||||
const handleConfirmDelete = async () => {
|
||||
try {
|
||||
if (!selectedUser) return;
|
||||
setDeletingRow(selectedUser.id);
|
||||
await deleteAdminUser(selectedUser.id); // 🔥 API call
|
||||
|
||||
showToast("User deleted successfully!", "success"); // ✅ use showToast()
|
||||
|
||||
setUsers((prev) => prev.filter((u) => u.id !== selectedUser.id));
|
||||
} catch (error) {
|
||||
showToast("Failed to delete user!", "error"); // ✅ same toast handler for error
|
||||
} finally {
|
||||
setDeletingRow(null);
|
||||
setShowDeleteModal(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEdit = async (user) => {
|
||||
if (!user || !user.id) {
|
||||
showToast('Invalid user selected', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
setEditingRow(user); // store which row is being edited
|
||||
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');
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
setFormData({
|
||||
name,
|
||||
email,
|
||||
status: is_active ? 'Active' : 'Inactive',
|
||||
});
|
||||
|
||||
setErrors({});
|
||||
setIsEditModalOpen(true); // ✅ opens your modal
|
||||
} catch (error) {
|
||||
console.error('Error fetching user data:', error);
|
||||
showToast(error?.response?.data?.message || 'Failed to load user data', 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleOpenResetModal = (user) => {
|
||||
setResetUser(user);
|
||||
@ -266,40 +341,12 @@ const handleCloseResetModal = () => {
|
||||
};
|
||||
|
||||
// ✅ DELETE FUNCTIONALITY IMPLEMENTED HERE
|
||||
const handleDelete = async (index) => {
|
||||
const user = users[index];
|
||||
if (!user || !user.id) {
|
||||
showToast('Invalid user selected for delete', 'error');
|
||||
return;
|
||||
}
|
||||
const handleDelete = (rowIndex) => {
|
||||
const user = users[rowIndex];
|
||||
setSelectedUser(user);
|
||||
setShowDeleteModal(true);
|
||||
};
|
||||
|
||||
const confirmDelete = window.confirm(`Are you sure you want to delete "${user.name}"?`);
|
||||
if (!confirmDelete) return;
|
||||
|
||||
setDeletingRow(index);
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const res = await deleteAdminUser(user.id);
|
||||
|
||||
const success =
|
||||
res?.status === 'success' ||
|
||||
res?.code === 200 ||
|
||||
res?.data?.status === 'success' ||
|
||||
res?.message?.toLowerCase().includes('deleted');
|
||||
|
||||
if (!success) throw new Error(res?.message || 'Failed to delete user');
|
||||
|
||||
setUsers((prev) => prev.filter((u) => u.id !== user.id));
|
||||
showToast('User deleted successfully', 'success');
|
||||
} catch (error) {
|
||||
console.error('Error deleting user:', error);
|
||||
showToast(error?.response?.data?.message || error.message || 'Delete failed', 'error');
|
||||
} finally {
|
||||
setDeletingRow(null);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
// ✅ END DELETE FUNCTIONALITY
|
||||
|
||||
const handleEditSubmit = async (e) => {
|
||||
@ -376,10 +423,49 @@ const handleCloseResetModal = () => {
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 sm:justify-end">
|
||||
<button className="h-9 px-3 rounded-md bg-[#F7F7F7] border border-[#C3C6CB] text-sm inline-flex items-center gap-2 cursor-pointer">
|
||||
<img src={exportIconSrc} alt="Export" className="h-4 w-4" />
|
||||
<span>Export CSV</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (!users.length) return;
|
||||
|
||||
// Define CSV headers (excluding date/time column logic)
|
||||
const csvHeader = ['Name', 'Email', 'Status', 'Last Login'].join(',');
|
||||
|
||||
// Map user data into CSV rows
|
||||
const csvRows = users.map((user) =>
|
||||
[user.name, user.email, user.status, user.lastLogin]
|
||||
.map((value) => `"${String(value ?? '').replace(/"/g, '""')}"`)
|
||||
.join(',')
|
||||
);
|
||||
|
||||
// Create the CSV file content
|
||||
const blob = new Blob([csvHeader + '\n' + csvRows.join('\n')], {
|
||||
type: 'text/csv;charset=utf-8;',
|
||||
});
|
||||
|
||||
// Create download link
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.setAttribute('download', 'admin-users.csv'); // 👈 No date in filename
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// Cleanup
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
}}
|
||||
className={`h-9 px-3 rounded-md border text-sm inline-flex items-center gap-2 ${
|
||||
users.length
|
||||
? 'bg-[#F7F7F7] border-[#C3C6CB] text-[#232528]'
|
||||
: 'bg-[#F3F4F6] border-[#E5E7EB] text-[#9CA3AF] cursor-not-allowed'
|
||||
}`}
|
||||
disabled={!users.length}
|
||||
>
|
||||
<img src={exportIconSrc} alt="Export" className="h-4 w-4" />
|
||||
<span>Export CSV</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setIsAddUserModalOpen(true)}
|
||||
className="h-9 px-3 rounded-md bg-[#B68A35] text-white text-sm inline-flex items-center gap-2 cursor-pointer"
|
||||
@ -422,29 +508,31 @@ const handleCloseResetModal = () => {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
|
||||
title="Edit"
|
||||
onClick={() => handleEdit(rowIndex)}
|
||||
>
|
||||
<img
|
||||
src={editingRow === rowIndex ? pencilActiveSrc : pencilInactiveSrc}
|
||||
alt="Edit"
|
||||
className="h-4 w-4"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
|
||||
title="Delete"
|
||||
onClick={() => handleDelete(rowIndex)}
|
||||
>
|
||||
<img
|
||||
src={deletingRow === rowIndex ? trashActiveSrc : trashInactiveSrc}
|
||||
alt="Delete"
|
||||
className="h-4 w-4"
|
||||
/>
|
||||
</button>
|
||||
type="button"
|
||||
className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
|
||||
title="Edit"
|
||||
onClick={() => handleEdit(user)} // pass user directly instead of rowIndex
|
||||
>
|
||||
<img
|
||||
src={editingRow?.id === user.id ? pencilActiveSrc : pencilInactiveSrc}
|
||||
alt="Edit"
|
||||
className="h-4 w-4"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="h-8 w-8 grid place-items-center rounded hover:bg-gray-50 cursor-pointer"
|
||||
title="Delete"
|
||||
onClick={() => handleDelete(rowIndex)}
|
||||
>
|
||||
<img
|
||||
src={deletingRow === rowIndex ? trashActiveSrc : trashInactiveSrc}
|
||||
alt="Delete"
|
||||
className="h-4 w-4"
|
||||
/>
|
||||
</button>
|
||||
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@ -523,6 +611,26 @@ const handleCloseResetModal = () => {
|
||||
</div>
|
||||
|
||||
)}
|
||||
{/* Edit Modal */}
|
||||
{isEditModalOpen && (
|
||||
<EditUserModal
|
||||
formData={formData}
|
||||
setFormData={setFormData}
|
||||
onClose={() => setIsEditModalOpen(false)}
|
||||
onUpdate={handleUpdateUser}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Delete Modal */}
|
||||
{showDeleteModal && (
|
||||
<DeleteUserModal
|
||||
userName={selectedUser?.name}
|
||||
onClose={() => setShowDeleteModal(false)}
|
||||
onDelete={handleConfirmDelete}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -559,9 +559,17 @@ const CompanyProfile = () => {
|
||||
<TextField
|
||||
label="Postal Code"
|
||||
value={form.contactPostalCode}
|
||||
onChange={handleFormChange('contactPostalCode')}
|
||||
onChange={(e) => {
|
||||
// Only allow numeric input
|
||||
if (e.target.value === '' || /^[0-9\b]+$/.test(e.target.value)) {
|
||||
handleFormChange('contactPostalCode')(e);
|
||||
}
|
||||
}}
|
||||
placeholder="Enter postal code"
|
||||
width="100%"
|
||||
type="tel"
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
/>
|
||||
<TextField
|
||||
label="PO Box"
|
||||
@ -704,9 +712,17 @@ const CompanyProfile = () => {
|
||||
<TextField
|
||||
label="Postal Code"
|
||||
value={form.corporatePostalCode}
|
||||
onChange={handleFormChange('corporatePostalCode')}
|
||||
onChange={(e) => {
|
||||
// Only allow numeric input
|
||||
if (e.target.value === '' || /^[0-9\b]+$/.test(e.target.value)) {
|
||||
handleFormChange('corporatePostalCode')(e);
|
||||
}
|
||||
}}
|
||||
placeholder="Enter postal code"
|
||||
width="100%"
|
||||
type="tel"
|
||||
inputMode="numeric"
|
||||
pattern="[0-9]*"
|
||||
/>
|
||||
<TextField
|
||||
label="PO Box"
|
||||
|
||||
@ -311,8 +311,10 @@ const filteredRows = useMemo(() => {
|
||||
: hscodeFilter.trim();
|
||||
return entry.product_name?.toLowerCase().includes(productName.toLowerCase());
|
||||
})();
|
||||
const matchesStatus = statusFilter === 'all' ||
|
||||
entry.status?.toLowerCase() === statusFilter.toLowerCase();
|
||||
|
||||
return matchesSearch && matchesYear && matchesQuarter && matchesHscode;
|
||||
return matchesSearch && matchesYear && matchesQuarter && matchesHscode && matchesStatus;
|
||||
});
|
||||
|
||||
setPagination((prev) => ({
|
||||
@ -322,7 +324,7 @@ const filteredRows = useMemo(() => {
|
||||
}));
|
||||
|
||||
return filtered;
|
||||
}, [auditHistory, searchTerm, yearFilter, quarterFilter, hscodeFilter]);
|
||||
}, [auditHistory, searchTerm, yearFilter, quarterFilter, hscodeFilter,statusFilter]);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -42,12 +42,40 @@ export const getAdminUserById = async (id) => {
|
||||
}
|
||||
};
|
||||
|
||||
// export const deleteAdminUser = async (id) => {
|
||||
// try {
|
||||
// const response = await deleteRequest(`${admin}/${id}`);
|
||||
// return response.data;
|
||||
// } catch (error) {
|
||||
// console.error('Error deleting admin user:', error);
|
||||
// throw error;
|
||||
// }
|
||||
// };
|
||||
|
||||
export const deleteAdminUser = async (id) => {
|
||||
try {
|
||||
if (!id) throw new Error("Invalid user ID");
|
||||
|
||||
const response = await deleteRequest(`${admin}/${id}`);
|
||||
return response.data;
|
||||
|
||||
// Log for debugging
|
||||
|
||||
// Safely check success from API
|
||||
const resData = response?.data || response;
|
||||
|
||||
const success =
|
||||
resData?.status === "success" ||
|
||||
resData?.success === true ||
|
||||
resData?.code === 200 ||
|
||||
resData?.message?.toLowerCase()?.includes("deleted");
|
||||
|
||||
if (!success) {
|
||||
throw new Error("Delete API did not return success");
|
||||
}
|
||||
|
||||
return resData;
|
||||
} catch (error) {
|
||||
console.error('Error deleting admin user:', error);
|
||||
console.error("Error deleting admin user:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@ -1,5 +1,6 @@
|
||||
import { getRequest, postRequest } from '@/services/api/CommonService';
|
||||
import resolveEstablishmentId from '@/services/utils/establishment';
|
||||
import { putRequest } from '../api/CommonService';
|
||||
|
||||
const endpoint = '/submissions';
|
||||
const QUARTER_PERIODS_ENDPOINT = '/getQuarterPeriods';
|
||||
@ -32,6 +33,23 @@ export const submitSurvey = async (payload = {}, config = {}) => {
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const resubmitSurvey = async (submissionId, payload = {}, config = {}) => {
|
||||
if (!submissionId) {
|
||||
throw new Error('Submission ID is required for resubmission');
|
||||
}
|
||||
|
||||
const establishmentId = resolveEstablishmentId(payload.establishment_id);
|
||||
const requestBody = {
|
||||
...payload,
|
||||
...(establishmentId !== undefined ? { establishment_id: establishmentId } : {}),
|
||||
};
|
||||
|
||||
const url = `${endpoint}/${submissionId}`;
|
||||
// Use putRequest instead of postRequest with method override
|
||||
const response = await putRequest(url, requestBody, config);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const fetchSubmissionHistory = async (establishmentId, config = {}) => {
|
||||
const resolvedId = resolveEstablishmentId(establishmentId);
|
||||
if (resolvedId === undefined) {
|
||||
@ -126,6 +144,7 @@ export const getSubmissionAuditHistory = async (establishmentId, params = {}) =>
|
||||
export default {
|
||||
getSubmissions,
|
||||
submitSurvey,
|
||||
resubmitSurvey,
|
||||
fetchSubmissionHistory,
|
||||
fetchSubmissionDetail,
|
||||
getQuarterPeriods,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user