Merges ac-helper (PHP Activation Calendar) and brief-extractor (Python AI) into a single Docker app with React/TypeScript frontend. Features: - Brief upload → AI extraction → review → Activation Calendar import - Handsontable v17 spreadsheet with dependent dropdowns (148 categories) - AI natural language commands via Gemini (YOLO mode, voice input) - Azure AD MSAL SPA PKCE authentication, user roles (user/admin) - CSV Activation Calendar export - Real-time WebSocket job progress - Admin: user management, dropdown Excel upload - Multi-stage Dockerfile, docker-compose, nginx proxy instructions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
46 lines
1.8 KiB
TypeScript
46 lines
1.8 KiB
TypeScript
import { useState } from 'react'
|
|
|
|
interface Props {
|
|
question: string
|
|
onAnswer: (answer: string) => void
|
|
onDismiss: () => void
|
|
}
|
|
|
|
export default function AIQuestionModal({ question, onAnswer, onDismiss }: Props) {
|
|
const [answer, setAnswer] = useState('')
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center" style={{ background: 'rgba(0,0,0,0.7)' }}>
|
|
<div className="rounded-lg p-6 w-full max-w-md shadow-2xl" style={{ background: 'var(--bg-card)', border: '1px solid var(--border)' }}>
|
|
<div className="mb-2 text-xs font-semibold uppercase tracking-wider" style={{ color: 'var(--accent)' }}>
|
|
AI needs clarification
|
|
</div>
|
|
<p className="mb-4 text-sm" style={{ color: 'var(--text-primary)' }}>{question}</p>
|
|
|
|
<input
|
|
autoFocus
|
|
value={answer}
|
|
onChange={e => setAnswer(e.target.value)}
|
|
onKeyDown={e => { if (e.key === 'Enter' && answer.trim()) onAnswer(answer.trim()) }}
|
|
placeholder="Your answer…"
|
|
className="w-full px-3 py-2 rounded text-sm outline-none mb-4"
|
|
style={{ background: '#1a1a1a', color: 'var(--text-primary)', border: '1px solid var(--border)' }}
|
|
/>
|
|
|
|
<div className="flex gap-2 justify-end">
|
|
<button onClick={onDismiss} className="px-3 py-2 text-sm rounded" style={{ color: 'var(--text-secondary)' }}>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
onClick={() => answer.trim() && onAnswer(answer.trim())}
|
|
disabled={!answer.trim()}
|
|
className="px-4 py-2 text-sm font-medium rounded disabled:opacity-40"
|
|
style={{ background: 'var(--accent)', color: '#000' }}
|
|
>
|
|
Send
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|