File size: 4,136 Bytes
ce8f04a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import React, { useState } from 'react';
import { AlertTriangle, CheckCircle } from 'lucide-react';
import toast from 'react-hot-toast';
import { resolveGsdHitl } from '../../api/client';

interface GsdHitlBannerProps {
    projectId: string;
    hitl: {
        id: string;
        title: string;
        question: string;
        options?: string[];
        risk_level?: string;
    };
    onResolved: () => void;
}

export const GsdHitlBanner: React.FC<GsdHitlBannerProps> = ({ projectId, hitl, onResolved }) => {
    const [isSubmitting, setIsSubmitting] = useState(false);
    const options = hitl.options?.length ? hitl.options : ['Tak, kontynuuj', 'Nie, wymaga poprawy'];

    const handleDecision = async (decision: string) => {
        try {
            setIsSubmitting(true);
            toast.loading('Zapisuję odpowiedź...', { id: 'gsd-hitl' });
            const res = await resolveGsdHitl(projectId, hitl.id || '', decision);
            if (res?.status === 'error') {
                throw new Error(res.message || 'Błąd zapisu HITL');
            }
            const msg =
                res?.approved === false
                    ? res.message || 'Zapisano prośbę o korektę.'
                    : res?.message || 'Odpowiedź zapisana — kontynuujemy przygotowanie wniosku.';
            toast.success(msg, { id: 'gsd-hitl' });
            onResolved();
            // Force project + sections refresh in parent trees
            try {
                window.dispatchEvent(new Event('refresh-sections'));
            } catch {
                /* ignore */
            }
        } catch (err: any) {
            const detail = err?.response?.data?.detail || err?.message;
            toast.error(typeof detail === 'string' ? detail : 'Nie udało się zapisać odpowiedzi.', { id: 'gsd-hitl' });
        } finally {
            setIsSubmitting(false);
        }
    };

    return (
        <div style={{
            margin: '0 0 1rem 0',
            padding: '1rem 1.25rem',
            borderRadius: '12px',
            background: 'rgba(245, 158, 11, 0.08)',
            border: '1px solid rgba(245, 158, 11, 0.35)',
            display: 'flex',
            flexDirection: 'column',
            gap: '0.75rem',
        }}>
            <div style={{ display: 'flex', alignItems: 'flex-start', gap: '0.75rem' }}>
                <AlertTriangle size={22} color="#f59e0b" style={{ flexShrink: 0, marginTop: 2 }} />
                <div>
                    <div style={{ fontWeight: 700, color: '#fde68a', marginBottom: '0.35rem' }}>
                        Wymagane potwierdzenie: {hitl.title}
                    </div>
                    <div style={{ color: 'var(--text-secondary)', fontSize: '0.9rem', whiteSpace: 'pre-wrap' }}>
                        {hitl.question}
                    </div>
                    {hitl.risk_level && (
                        <div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', marginTop: '0.35rem' }}>
                            Poziom ryzyka: {hitl.risk_level}
                        </div>
                    )}
                </div>
            </div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem', paddingLeft: '2rem' }}>
                {options.map((opt) => (
                    <button
                        key={opt}
                        type="button"
                        disabled={isSubmitting}
                        onClick={() => handleDecision(opt)}
                        className="btn"
                        style={{
                            background: opt.toLowerCase().startsWith('tak') ? 'var(--accent-green)' : 'rgba(255,255,255,0.08)',
                            color: opt.toLowerCase().startsWith('tak') ? '#000' : '#fff',
                            fontSize: '0.85rem',
                            opacity: isSubmitting ? 0.6 : 1,
                        }}
                    >
                        <CheckCircle size={14} style={{ marginRight: 4 }} />
                        {opt}
                    </button>
                ))}
            </div>
        </div>
    );
};