diff --git a/frontend/src/components/pilot/ProposalBanner.tsx b/frontend/src/components/pilot/ProposalBanner.tsx
index 7a760e79..264213fa 100644
--- a/frontend/src/components/pilot/ProposalBanner.tsx
+++ b/frontend/src/components/pilot/ProposalBanner.tsx
@@ -9,7 +9,9 @@
* Visual reference: docs/FlowAssist_Migration/mockups/06-slide-up-banner.html
* + 07-verify-states.html.
*/
-import { Sparkles, Check, ChevronDown } from 'lucide-react'
+import { useState } from 'react'
+import { Sparkles, Check, ChevronDown, X, MoreHorizontal, Info } from 'lucide-react'
+import { cn } from '@/lib/utils'
import type {
SessionSuggestedFix,
FixOutcome,
@@ -103,11 +105,147 @@ function ProposedBanner({ fix, onApply, onDismiss, onToggleCollapsed }: Proposal
)
}
-// Placeholder renderers — implemented in Tasks 8 & 9.
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-function VerifyingBanner(_: ProposalBannerProps) { return null }
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-function PartialBanner(_: ProposalBannerProps) { return null }
+function VerifyingBanner({ fix, onOutcome }: ProposalBannerProps) {
+ const [showOverflow, setShowOverflow] = useState(false)
+ const appliedLabel = fix.applied_at
+ ? `Applied ${formatRelativeMinutes(fix.applied_at)}`
+ : 'Applied'
+
+ return (
+
+
+
+
+
+
+ Verifying
+
+ {appliedLabel}
+
+
+
+ Did "{fix.title}" work?
+
+
+ Mark the outcome so the AI can either close the session with this as the resolution, or propose something else.
+
+
+
+
+ {showOverflow && (
+
+
+
+ )}
+
+
+
+
+
+ )
+}
+
+function formatRelativeMinutes(iso: string): string {
+ const then = new Date(iso).getTime()
+ const mins = Math.max(0, Math.round((Date.now() - then) / 60000))
+ if (mins === 0) return 'just now'
+ if (mins === 1) return '1m ago'
+ return `${mins}m ago`
+}
+
+function PartialBanner({ fix, onOutcome, onApply }: ProposalBannerProps) {
+ return (
+
+
+
+
+
+
+
+
+ Partially applied
+
+ Parked
+
+
+
+ {fix.title}
+
+ {fix.partial_notes && (
+
+ Note
+ {fix.partial_notes}
+
+ )}
+
+
+
+
+
+
+
+
+ )
+}
+
+// Placeholder renderers — implemented in Task 9.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function AIConfirmingBanner(_: ProposalBannerProps) { return null }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
diff --git a/frontend/src/index.css b/frontend/src/index.css
index 4f148cc0..295de510 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -87,11 +87,17 @@
--animate-scale-in: scale-in 150ms ease-out both;
--animate-fade: fadeIn 300ms ease both;
--animate-slide-up: slide-up 320ms cubic-bezier(.22,.9,.28,1) both;
+ --animate-pulse-amber: pulse-amber 1.6s infinite;
@keyframes slide-up {
from { transform: translateY(14px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
+ @keyframes pulse-amber {
+ 0% { box-shadow: 0 0 0 0 rgba(251,191,36,0.45); }
+ 70% { box-shadow: 0 0 0 10px rgba(251,191,36,0); }
+ 100% { box-shadow: 0 0 0 0 rgba(251,191,36,0); }
+ }
@keyframes fade-in {
from { opacity: 0; } to { opacity: 1; }
}