Spaces:
Paused
Paused
| import React, { useState } from 'react'; | |
| import { | |
| Briefcase, FileText, Download, Loader2, CheckCircle, | |
| ArrowRight, Sparkles, Building2 | |
| } from 'lucide-react'; | |
| import { Button } from '@/components/ui/button'; | |
| import { Input } from '@/components/ui/input'; | |
| import { Textarea } from '@/components/ui/textarea'; | |
| import { API_URL } from '@/config/api'; | |
| import { cn } from '@/lib/utils'; | |
| interface GeneratedPresentation { | |
| filename: string; | |
| url: string; | |
| } | |
| export default function TDCSolutionWidget() { | |
| const [customerName, setCustomerName] = useState(''); | |
| const [need, setNeed] = useState(''); | |
| const [isGenerating, setIsGenerating] = useState(false); | |
| const [result, setResult] = useState<GeneratedPresentation | null>(null); | |
| const [error, setError] = useState<string | null>(null); | |
| const handleGenerate = async () => { | |
| if (!customerName.trim() || !need.trim()) return; | |
| setIsGenerating(true); | |
| setError(null); | |
| setResult(null); | |
| try { | |
| // Call the TDC Generator Tool via MCP route | |
| const response = await fetch(`${API_URL}/api/mcp/route`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| tool: 'tdc.generate_presentation', | |
| params: { | |
| customerName, | |
| need | |
| } | |
| }) | |
| }); | |
| const data = await response.json(); | |
| if (data.result && data.result.success) { | |
| setResult(data.result.data); | |
| } else { | |
| throw new Error(data.result?.error || 'Generation failed'); | |
| } | |
| } catch (err: any) { | |
| console.error('Generation error:', err); | |
| setError(err.message || 'Failed to generate presentation'); | |
| } finally { | |
| setIsGenerating(false); | |
| } | |
| }; | |
| const handleReset = () => { | |
| setResult(null); | |
| setError(null); | |
| setCustomerName(''); | |
| setNeed(''); | |
| }; | |
| return ( | |
| <div className="h-full flex flex-col bg-white text-slate-900 rounded-lg overflow-hidden border border-slate-200 shadow-sm relative"> | |
| {/* TDC Brand Header Bar */} | |
| <div className="h-1.5 w-full bg-[#0000BF]" /> | |
| {/* Header */} | |
| <div className="p-4 flex items-center justify-between border-b border-slate-100"> | |
| <div className="flex items-center gap-2"> | |
| <div className="bg-[#0000BF] p-1.5 rounded text-white"> | |
| <Building2 className="w-4 h-4" /> | |
| </div> | |
| <div> | |
| <h2 className="font-bold text-sm text-[#0000BF]">TDC Erhverv</h2> | |
| <p className="text-[10px] text-slate-500 font-medium">LØSNINGSDESIGNER</p> | |
| </div> | |
| </div> | |
| {result && ( | |
| <button onClick={handleReset} className="text-xs text-slate-400 hover:text-[#0000BF]"> | |
| Ny løsning | |
| </button> | |
| )} | |
| </div> | |
| {/* Content */} | |
| <div className="flex-1 p-4 overflow-y-auto"> | |
| {!result ? ( | |
| <div className="space-y-4"> | |
| <div className="space-y-1.5"> | |
| <label className="text-xs font-semibold text-slate-600 uppercase">Kunde</label> | |
| <Input | |
| value={customerName} | |
| onChange={e => setCustomerName(e.target.value)} | |
| placeholder="Virksomhedens navn..." | |
| className="bg-slate-50 border-slate-200 focus:ring-[#0000BF] text-slate-900 placeholder:text-slate-400" | |
| /> | |
| </div> | |
| <div className="space-y-1.5"> | |
| <label className="text-xs font-semibold text-slate-600 uppercase">Behov & Udfordringer</label> | |
| <Textarea | |
| value={need} | |
| onChange={e => setNeed(e.target.value)} | |
| placeholder="Beskriv kundens behov (f.eks. 'Vi har brug for sikker hjemmearbejde til 50 ansatte og bedre mobildækning')..." | |
| className="bg-slate-50 border-slate-200 focus:ring-[#0000BF] text-slate-900 placeholder:text-slate-400 min-h-[100px] resize-none" | |
| /> | |
| </div> | |
| <div className="pt-2"> | |
| <Button | |
| onClick={handleGenerate} | |
| disabled={isGenerating || !customerName || !need} | |
| className={cn( | |
| "w-full bg-[#0000BF] hover:bg-[#000090] text-white font-medium shadow-md transition-all", | |
| isGenerating && "opacity-80" | |
| )} | |
| > | |
| {isGenerating ? ( | |
| <> | |
| <Loader2 className="w-4 h-4 mr-2 animate-spin" /> | |
| Designer Løsning... | |
| </> | |
| ) : ( | |
| <> | |
| <Sparkles className="w-4 h-4 mr-2" /> | |
| Generer Præsentation | |
| </> | |
| )} | |
| </Button> | |
| </div> | |
| {error && ( | |
| <div className="p-3 bg-red-50 text-red-600 text-xs rounded-md border border-red-100 flex items-start gap-2"> | |
| <div className="mt-0.5">⚠️</div> | |
| <div>{error}</div> | |
| </div> | |
| )} | |
| <div className="mt-4 p-3 bg-slate-50 rounded border border-slate-100 text-[10px] text-slate-500"> | |
| <p className="font-semibold mb-1">PRODUKTKATALOG INKLUDERET:</p> | |
| <div className="flex flex-wrap gap-1"> | |
| {['One+', '5G+', 'Sikker Fiber', 'Managed Cloud', 'Teams'].map(p => ( | |
| <span key={p} className="bg-white border border-slate-200 px-1.5 py-0.5 rounded text-slate-600">{p}</span> | |
| ))} | |
| </div> | |
| </div> | |
| </div> | |
| ) : ( | |
| <div className="h-full flex flex-col items-center justify-center text-center space-y-4 animate-in fade-in zoom-in-95 duration-300"> | |
| <div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-2"> | |
| <CheckCircle className="w-8 h-8 text-green-600" /> | |
| </div> | |
| <div> | |
| <h3 className="text-lg font-bold text-slate-900">Løsning Designet!</h3> | |
| <p className="text-xs text-slate-500 mt-1 max-w-[200px] mx-auto"> | |
| En skræddersyet præsentation til <span className="font-semibold text-[#0000BF]">{customerName}</span> er klar. | |
| </p> | |
| </div> | |
| <div className="w-full max-w-[240px] bg-slate-50 p-3 rounded-lg border border-slate-200 flex items-center gap-3 text-left hover:border-[#0000BF]/30 transition-colors"> | |
| <div className="bg-[#0000BF]/10 p-2 rounded"> | |
| <FileText className="w-5 h-5 text-[#0000BF]" /> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <div className="text-xs font-medium text-slate-900 truncate"> | |
| {result.filename} | |
| </div> | |
| <div className="text-[10px] text-slate-500">PowerPoint (.pptx)</div> | |
| </div> | |
| </div> | |
| <a | |
| href={`${API_URL}${result.url}`} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="w-full max-w-[240px]" | |
| > | |
| <Button className="w-full bg-green-600 hover:bg-green-700 text-white shadow-md"> | |
| <Download className="w-4 h-4 mr-2" /> | |
| Download PPT | |
| </Button> | |
| </a> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |