diff --git a/frontend/src/app/(dashboard)/staff/page.tsx b/frontend/src/app/(dashboard)/staff/page.tsx index ae4c389..958e489 100644 --- a/frontend/src/app/(dashboard)/staff/page.tsx +++ b/frontend/src/app/(dashboard)/staff/page.tsx @@ -25,7 +25,9 @@ import { Badge } from '@/components/ui/shared/Badge'; import { Input } from '@/components/ui/shared/Input'; import { Checkbox } from '@/components/ui/shared/Checkbox'; import { Table } from '@/components/ui/shared/Table'; -import type { ApiError } from '@/types/api'; +import { ToastStack } from '@/components/ui/shared/Toast'; +import { formatApiErrorMessage } from '@/components/shared/formatApiError'; +import { useToast } from '@/lib/hooks/useToast'; type StoredInviteLink = { membershipId: string; @@ -54,14 +56,6 @@ function writeStoredInviteLinks(orgId: string, links: Record(null); const [loading, setLoading] = useState(true); - const [error, setError] = useState(''); - const [success, setSuccess] = useState(''); + const toast = useToast(); const [inviteOpen, setInviteOpen] = useState(false); const [inviteEmail, setInviteEmail] = useState(''); @@ -169,14 +162,14 @@ export default function StaffPage() { }, [seats]); const load = useCallback(async () => { - setError(''); + toast.setError(''); setLoading(true); try { const res = await staffApi.list(); setMembers(res.data.members); setSeats(res.data.seats); } catch (e) { - setError(formatApiMessage(e)); + toast.showError(formatApiErrorMessage(e, 'Failed to load staff.')); } finally { setLoading(false); } @@ -221,17 +214,11 @@ export default function StaffPage() { } }, [currentOrganization, router]); - useEffect(() => { - if (!success) return; - const t = setTimeout(() => setSuccess(''), 4000); - return () => clearTimeout(t); - }, [success]); - async function copyStaffInviteLink(member: StaffMemberDto) { if (!canShareStaffInviteLink(member)) return; setCopyingInviteMembershipId(member.id); - setError(''); + toast.setError(''); try { let invitationUrl = pendingInviteLinks[member.id]?.invitationUrl; if (!invitationUrl || member.invitationStatus === 'EXPIRED') { @@ -257,7 +244,7 @@ export default function StaffPage() { await load(); } } catch (e) { - setError(formatApiMessage(e)); + toast.showError(formatApiErrorMessage(e, 'Could not copy invitation link.')); } finally { setCopyingInviteMembershipId(null); } @@ -265,7 +252,7 @@ export default function StaffPage() { async function submitInvite() { setInviteLoading(true); - setError(''); + toast.setError(''); setLastInviteInfo(null); const displayName = inviteName.trim(); const displayEmail = inviteEmail.trim(); @@ -295,14 +282,13 @@ export default function StaffPage() { setPendingInviteLinks(nextLinks); writeStoredInviteLinks(currentOrganization.id, nextLinks); } - setSuccess(''); setInviteOpen(false); setInviteEmail(''); setInviteName(''); setInvitePerms(emptyFeaturePermissionState()); await load(); } catch (e) { - setError(formatApiMessage(e)); + toast.showError(formatApiErrorMessage(e, 'Failed to send invitation.')); } finally { setInviteLoading(false); } @@ -320,17 +306,17 @@ export default function StaffPage() { async function submitEdit() { if (!editing) return; setEditLoading(true); - setError(''); + toast.setError(''); try { await staffApi.updateMember(editing.id, { name: editName.trim(), permissionNames: permissionNamesFromFeatureState(editPerms), }); - setSuccess('Member updated'); + toast.showSuccess('Member updated.'); setEditing(null); await load(); } catch (e) { - setError(formatApiMessage(e)); + toast.showError(formatApiErrorMessage(e, 'Failed to update member.')); } finally { setEditLoading(false); } @@ -343,13 +329,13 @@ export default function StaffPage() { } else { if (!confirm(`Remove ${m.name} from this organization?`)) return; } - setError(''); + toast.setError(''); try { await staffApi.removeMember(m.id); - setSuccess('Member removed'); + toast.showSuccess('Member removed.'); await load(); } catch (e) { - setError(formatApiMessage(e)); + toast.showError(formatApiErrorMessage(e, 'Failed to remove member.')); } } @@ -383,6 +369,8 @@ export default function StaffPage() { + + {seats && (

Seats:{' '} @@ -400,18 +388,6 @@ export default function StaffPage() {

)} - {error && ( -
- {error} -
- )} - - {success && ( -
- {success} -
- )} - {lastInviteInfo && (