File size: 4,436 Bytes
212c959 | 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 101 102 103 104 105 106 107 108 | import { useState } from 'react'
const STAR_HINTS = ['', 'Poor π', 'Fair π', 'Good π', 'Great π', 'Excellent π€©']
export default function FeedbackModal({ onSubmit, onClose }) {
const [rating, setRating] = useState(0)
const [hover, setHover] = useState(0)
const [cat, setCat] = useState('general')
const [text, setText] = useState('')
const [err, setErr] = useState('')
const [done, setDone] = useState(false)
const [loading, setLoading] = useState(false)
const handleSubmit = async () => {
if (!rating) return setErr('Please select a star rating.')
if (!text.trim()) return setErr('Please write a short message.')
setLoading(true)
try {
await onSubmit({ rating, category: cat, message: text.trim() })
setDone(true)
} catch (e) {
setErr(e.message || 'Failed to submit feedback')
} finally {
setLoading(false)
}
}
if (done) {
return (
<div className="modal-overlay" onClick={e => e.target === e.currentTarget && onClose()}>
<div className="modal-card" style={{ maxWidth: 440 }}>
<div className="modal-header">
<span className="modal-title">Send Feedback</span>
<button className="modal-close" onClick={onClose}>
<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div className="feedback-success">
<div className="feedback-success-icon">π</div>
<div className="feedback-success-title">Thank you!</div>
<div className="feedback-success-sub">Your feedback has been saved. We read every single one.</div>
<button className="btn btn-primary" onClick={onClose} style={{ marginTop: 10 }}>Close</button>
</div>
</div>
</div>
)
}
return (
<div className="modal-overlay" onClick={e => e.target === e.currentTarget && onClose()}>
<div className="modal-card" style={{ maxWidth: 460 }}>
<div className="modal-header">
<span className="modal-title">Send Feedback</span>
<button className="modal-close" onClick={onClose}>
<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div className="modal-body">
<div className="field-label">How would you rate OwnGPT?</div>
<div className="star-row">
{[1,2,3,4,5].map(v => (
<button
key={v}
className={`star-btn ${rating >= v ? 'lit' : ''} ${hover >= v ? 'hover' : ''}`}
onMouseEnter={() => setHover(v)}
onMouseLeave={() => setHover(0)}
onClick={() => setRating(v)}
>
β
</button>
))}
</div>
<div className="star-hint">{STAR_HINTS[hover || rating]}</div>
<div className="field-label" style={{ marginTop: 16 }}>Category</div>
<div className="fcat-row">
<button className={`fcat-btn ${cat === 'general' ? 'active' : ''}`} onClick={() => setCat('general')}>π¬ General</button>
<button className={`fcat-btn ${cat === 'bug' ? 'active' : ''}`} onClick={() => setCat('bug')}>π Bug</button>
<button className={`fcat-btn ${cat === 'feature' ? 'active' : ''}`} onClick={() => setCat('feature')}>β¨ Feature</button>
<button className={`fcat-btn ${cat === 'other' ? 'active' : ''}`} onClick={() => setCat('other')}>π Other</button>
</div>
<div className="field-label">Your message</div>
<textarea
className="field-textarea"
placeholder="Tell us what you think..."
value={text}
onChange={e => setText(e.target.value)}
maxLength={2000}
/>
<div className="char-count">{text.length} / 2000</div>
{err && <div className="field-error" style={{ marginTop: 8 }}>{err}</div>}
</div>
<div className="modal-footer">
<button className="btn" onClick={onClose}>Cancel</button>
<button className="btn btn-primary" onClick={handleSubmit} disabled={loading}>
{loading ? 'Sending...' : 'Submit Feedback'}
</button>
</div>
</div>
</div>
)
}
|