feat: F025 button & action logic audit — global toast, confirm dialog, wired mutations
- Add ToastProvider (global MUI Snackbar stack) + toastStore (Zustand) - Add ConfirmDialog reusable component for destructive actions - Wire toast feedback to all async mutations: review status, AI output status, match approval, shortlist add/remove/title/finalize, signal review actions - Fix dead UserMenu buttons (Profil, Einstellungen) — show info toast - Migrate local Snackbar instances in AddToShortlistDialog and FutureSignalDetailPanel to global toast store Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
AIMonitoringEmptyState,
|
||||
} from '../../components/ai-monitoring'
|
||||
import { useAIOutputs, useUpdateAIOutputReviewStatus } from '../../hooks/useAIMonitoring'
|
||||
import { useToastStore } from '../../stores/toastStore'
|
||||
import type { AIOutput, AIOutputType } from '../../domain/aiOutput'
|
||||
import type { ReviewStatus } from '../../domain/enums'
|
||||
|
||||
@@ -58,6 +59,7 @@ export default function AIMonitoring() {
|
||||
const [filters, setFilters] = useState<Filters>({ type: '', reviewStatus: '', hasError: null })
|
||||
const [selectedOutput, setSelectedOutput] = useState<AIOutput | null>(null)
|
||||
|
||||
const showToast = useToastStore((s) => s.showToast)
|
||||
const { data: allOutputs = [], isLoading } = useAIOutputs()
|
||||
const updateStatus = useUpdateAIOutputReviewStatus()
|
||||
|
||||
@@ -66,11 +68,25 @@ export default function AIMonitoring() {
|
||||
const failedCount = allOutputs.filter(o => !!o.error).length
|
||||
const pendingCount = allOutputs.filter(o => o.reviewStatus === 'UNREVIEWED' || o.reviewStatus === 'FLAGGED').length
|
||||
|
||||
const STATUS_TOAST: Record<ReviewStatus, string> = {
|
||||
UNREVIEWED: 'Status zurückgesetzt.',
|
||||
IN_REVIEW: 'Output zur Prüfung markiert.',
|
||||
APPROVED: 'Output genehmigt.',
|
||||
REJECTED: 'Output abgelehnt.',
|
||||
FLAGGED: 'Output markiert.',
|
||||
}
|
||||
|
||||
const handleUpdateStatus = (status: ReviewStatus) => {
|
||||
if (!selectedOutput) return
|
||||
updateStatus.mutate(
|
||||
{ id: selectedOutput.id, status },
|
||||
{ onSuccess: (res) => setSelectedOutput(res.data) }
|
||||
{
|
||||
onSuccess: (res) => {
|
||||
setSelectedOutput(res.data)
|
||||
showToast(STATUS_TOAST[status] ?? 'Status aktualisiert.')
|
||||
},
|
||||
onError: () => showToast('Statusänderung fehlgeschlagen.', 'error'),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from '../../components/review'
|
||||
import { useReviewQueue, useUpdateReviewStatus, useAddReviewNote } from '../../hooks/useReviewQueue'
|
||||
import { useSessionStore } from '../../stores/sessionStore'
|
||||
import { useToastStore } from '../../stores/toastStore'
|
||||
import type { ReviewTask, ReviewTaskStatus } from '../../domain/review'
|
||||
import type { ReviewFilters } from '../../provider/IReviewProvider'
|
||||
|
||||
@@ -24,6 +25,7 @@ function filterTasks(tasks: ReviewTask[], filters: ReviewFilters): ReviewTask[]
|
||||
|
||||
export default function ReviewQueue() {
|
||||
const { currentUser } = useSessionStore()
|
||||
const showToast = useToastStore((s) => s.showToast)
|
||||
const userRole = currentUser?.role ?? 'REVIEWER'
|
||||
|
||||
const [filters, setFilters] = useState<ReviewFilters>({})
|
||||
@@ -40,6 +42,15 @@ export default function ReviewQueue() {
|
||||
const escalatedCount = allTasks.filter(t => t.status === 'ESCALATED').length
|
||||
const criticalCount = allTasks.filter(t => t.priority === 'CRITICAL' && (t.status === 'PENDING' || t.status === 'IN_REVIEW')).length
|
||||
|
||||
const STATUS_TOAST: Record<ReviewTaskStatus, string> = {
|
||||
PENDING: 'Status auf "Ausstehend" gesetzt.',
|
||||
IN_REVIEW: 'Aufgabe zur Prüfung übernommen.',
|
||||
APPROVED: 'Aufgabe genehmigt.',
|
||||
REJECTED: 'Aufgabe abgelehnt.',
|
||||
ESCALATED: 'Aufgabe eskaliert.',
|
||||
NEEDS_MORE_DATA: 'Weitere Daten angefordert.',
|
||||
}
|
||||
|
||||
const handleAction = (status: ReviewTaskStatus) => {
|
||||
if (!selectedTask) return
|
||||
updateStatus.mutate(
|
||||
@@ -47,7 +58,9 @@ export default function ReviewQueue() {
|
||||
{
|
||||
onSuccess: (res) => {
|
||||
setSelectedTask(res.data)
|
||||
showToast(STATUS_TOAST[status] ?? 'Status aktualisiert.')
|
||||
},
|
||||
onError: () => showToast('Statusänderung fehlgeschlagen.', 'error'),
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -59,7 +72,9 @@ export default function ReviewQueue() {
|
||||
{
|
||||
onSuccess: (res) => {
|
||||
setSelectedTask(res.data)
|
||||
showToast('Notiz hinzugefügt.')
|
||||
},
|
||||
onError: () => showToast('Notiz konnte nicht gespeichert werden.', 'error'),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useMatches, useApproveMatch } from '../../hooks/useMatches'
|
||||
import { useProperties } from '../../hooks/useProperties'
|
||||
import { useNeeds } from '../../hooks/useNeeds'
|
||||
import { useMatchCenterStore } from '../../stores/matchCenterStore'
|
||||
import { useToastStore } from '../../stores/toastStore'
|
||||
import { MatchListCard, MatchBriefingPanel, MatchCenterSkeleton } from '../../components/match-center'
|
||||
import type { Match } from '../../domain/match'
|
||||
|
||||
@@ -36,6 +37,7 @@ export default function MatchCenter() {
|
||||
const { data: needs = [] } = useNeeds()
|
||||
const { setSelectedProperty, setSelectedNeed } = useMatchCenterStore()
|
||||
const approveMatch = useApproveMatch()
|
||||
const showToast = useToastStore((s) => s.showToast)
|
||||
|
||||
const [selectedMatchId, setSelectedMatchId] = useState<string | null>(null)
|
||||
const [filterStrength, setFilterStrength] = useState('')
|
||||
@@ -152,7 +154,10 @@ export default function MatchCenter() {
|
||||
property={propMap.get(match.propertyId)}
|
||||
need={needMap.get(match.needId)}
|
||||
onSelect={() => handleSelectMatch(match)}
|
||||
onApprove={() => approveMatch.mutate(match.id)}
|
||||
onApprove={() => approveMatch.mutate(match.id, {
|
||||
onSuccess: () => showToast('Match genehmigt.'),
|
||||
onError: () => showToast('Genehmigung fehlgeschlagen.', 'error'),
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user