Add visual save confirmation to User Management page
Role and agency changes now show an inline green checkmark + "Saved" indicator on the affected row that auto-clears after 2 seconds. Agency creation shows a green success banner that auto-dismisses after 3 seconds. Successful actions also clear any stale error banners. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8220955cd4
commit
51c4909ee7
1 changed files with 32 additions and 1 deletions
|
|
@ -22,6 +22,8 @@ export const UserManagement: React.FC = () => {
|
|||
const [agencies, setAgencies] = useState<AgencyResponse[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [savedUserId, setSavedUserId] = useState<string | null>(null);
|
||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||||
|
||||
// New agency form
|
||||
const [newAgencyName, setNewAgencyName] = useState('');
|
||||
|
|
@ -48,10 +50,17 @@ export const UserManagement: React.FC = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const showSavedIndicator = (userId: string) => {
|
||||
setSavedUserId(userId);
|
||||
setError(null);
|
||||
setTimeout(() => setSavedUserId(prev => prev === userId ? null : prev), 2000);
|
||||
};
|
||||
|
||||
const handleRoleChange = async (userId: string, newRole: string) => {
|
||||
try {
|
||||
const updated = await apiService.updateUser(userId, { role: newRole });
|
||||
setUsers(prev => prev.map(u => u.id === userId ? updated : u));
|
||||
showSavedIndicator(userId);
|
||||
} catch (err) {
|
||||
console.error('Failed to update user role:', err);
|
||||
setError('Failed to update user role.');
|
||||
|
|
@ -62,6 +71,7 @@ export const UserManagement: React.FC = () => {
|
|||
try {
|
||||
const updated = await apiService.updateUser(userId, { agency_id: agencyId });
|
||||
setUsers(prev => prev.map(u => u.id === userId ? updated : u));
|
||||
showSavedIndicator(userId);
|
||||
} catch (err) {
|
||||
console.error('Failed to update user agency:', err);
|
||||
setError('Failed to update user agency.');
|
||||
|
|
@ -77,6 +87,9 @@ export const UserManagement: React.FC = () => {
|
|||
const newAgency = await apiService.createAgency(newAgencyName.trim());
|
||||
setAgencies(prev => [...prev, newAgency].sort((a, b) => a.name.localeCompare(b.name)));
|
||||
setNewAgencyName('');
|
||||
setError(null);
|
||||
setSuccessMessage('Agency created successfully');
|
||||
setTimeout(() => setSuccessMessage(prev => prev === 'Agency created successfully' ? null : prev), 3000);
|
||||
} catch (err) {
|
||||
console.error('Failed to create agency:', err);
|
||||
setError('Failed to create agency.');
|
||||
|
|
@ -115,6 +128,13 @@ export const UserManagement: React.FC = () => {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{successMessage && (
|
||||
<div className="mb-4 p-3 bg-green-50 border border-green-200 rounded-[10px] text-green-700 text-sm">
|
||||
{successMessage}
|
||||
<button onClick={() => setSuccessMessage(null)} className="ml-2 font-semibold hover:underline">Dismiss</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Users Table */}
|
||||
<section className="mb-10">
|
||||
<h2 className="text-xl font-semibold text-primary-blue mb-4">Users ({users.length})</h2>
|
||||
|
|
@ -128,6 +148,7 @@ export const UserManagement: React.FC = () => {
|
|||
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Role</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Agency</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider">Created</th>
|
||||
<th className="px-6 py-3 text-left text-xs font-bold text-black-title uppercase tracking-wider w-20"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-grey-300">
|
||||
|
|
@ -178,11 +199,21 @@ export const UserManagement: React.FC = () => {
|
|||
<td className="px-6 py-4 whitespace-nowrap text-sm text-grey-700">
|
||||
{formatDate(user.created_at)}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm">
|
||||
{savedUserId === user.id && (
|
||||
<span className="inline-flex items-center gap-1 text-green-700 font-medium">
|
||||
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
Saved
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{users.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={5} className="px-6 py-8 text-center text-grey-700">
|
||||
<td colSpan={6} className="px-6 py-8 text-center text-grey-700">
|
||||
No users found.
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue