feat: review popup drag-drop attachments, .md styling

This commit is contained in:
Krao Hasanee
2026-06-02 14:33:50 -04:00
parent 894ec323f2
commit e912f82520
+26 -22
View File
@@ -223,6 +223,8 @@ export default function TaskDetail() {
const [reviewFiles, setReviewFiles] = useState([]);
const [reviewNotes, setReviewNotes] = useState('');
const [reviewSaving, setReviewSaving] = useState(false);
const [reviewDragging, setReviewDragging] = useState(false);
const reviewDragCounter = useRef(0);
const reviewFileRef = useRef(null);
const [comments, setComments] = useState([]);
const [commentBody, setCommentBody] = useState('');
@@ -771,42 +773,44 @@ export default function TaskDetail() {
</div>
{reviewModal && (
<div style={popupOverlayStyle} onClick={() => { if (!reviewSaving) { setReviewModal(false); setReviewFiles([]); } }}>
<div style={{ ...popupSurfaceStyle, background: 'var(--card-bg)', width: 'min(480px, 96vw)', display: 'flex', flexDirection: 'column', gap: 14 }} onClick={e => e.stopPropagation()}>
<div style={popupOverlayStyle} onClick={() => { if (!reviewSaving) { setReviewModal(false); setReviewFiles([]); setReviewNotes(''); } }}>
<div style={{ ...popupSurfaceStyle, background: 'var(--card-bg)', width: 'min(480px, 96vw)', maxHeight: 'calc(100vh - 48px)', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 14 }} onClick={e => e.stopPropagation()}>
<div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)' }}>Place in Review</div>
<div>
<div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)', marginBottom: 6 }}>Notes <span style={{ color: 'var(--text-muted)', fontWeight: 400, textTransform: 'none', letterSpacing: 0 }}>(optional)</span></div>
<textarea
rows={4}
placeholder="Add notes for this submission…"
value={reviewNotes}
onChange={e => setReviewNotes(e.target.value)}
style={{ fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', width: '100%', fontFamily: 'inherit', boxSizing: 'border-box', resize: 'vertical' }}
/>
<textarea rows={4} placeholder="Add notes for this submission…" value={reviewNotes} onChange={e => setReviewNotes(e.target.value)} style={{ fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', width: '100%', fontFamily: 'inherit', boxSizing: 'border-box', resize: 'vertical' }} />
</div>
<div>
<div style={{ fontSize: 11, fontWeight: 500, textTransform: 'uppercase', letterSpacing: 0.8, color: 'var(--text-secondary)', marginBottom: 6 }}>Attachments <span style={{ color: 'var(--text-muted)', fontWeight: 400, textTransform: 'none', letterSpacing: 0 }}>(optional)</span></div>
<input
ref={reviewFileRef}
type="file"
multiple
style={{ fontSize: 13, color: 'var(--text-primary)', background: 'var(--card-bg-2)', border: '1px solid var(--border)', borderRadius: 6, padding: '6px 10px', width: '100%', fontFamily: 'inherit', boxSizing: 'border-box' }}
onChange={e => setReviewFiles(Array.from(e.target.files || []))}
/>
<input ref={reviewFileRef} type="file" multiple id="review-file-input" style={{ display: 'none' }} onChange={e => { setReviewFiles(prev => [...prev, ...Array.from(e.target.files)]); e.target.value = ''; }} />
<div
onDragEnter={e => { e.preventDefault(); reviewDragCounter.current++; setReviewDragging(true); }}
onDragLeave={e => { e.preventDefault(); reviewDragCounter.current--; if (reviewDragCounter.current === 0) setReviewDragging(false); }}
onDragOver={e => e.preventDefault()}
onDrop={e => { e.preventDefault(); reviewDragCounter.current = 0; setReviewDragging(false); setReviewFiles(prev => [...prev, ...Array.from(e.dataTransfer.files)]); }}
onClick={() => reviewFileRef.current?.click()}
style={{ border: `2px dashed ${reviewDragging ? 'var(--accent)' : reviewFiles.length > 0 ? 'var(--accent)' : 'var(--border)'}`, borderRadius: 8, padding: '16px', textAlign: 'center', background: reviewDragging ? 'color-mix(in srgb, var(--accent) 8%, var(--bg))' : 'transparent', transition: 'all 160ms', cursor: 'pointer' }}
>
<div style={{ fontSize: 20, marginBottom: 4 }}>{reviewDragging ? '📂' : '📎'}</div>
<div style={{ fontSize: 13, color: 'var(--text-primary)' }}>
{reviewDragging ? 'Drop files here' : reviewFiles.length > 0 ? `${reviewFiles.length} file${reviewFiles.length !== 1 ? 's' : ''} attached — click or drag to add more` : 'Click or drag files here'}
</div>
<div style={{ fontSize: 12, color: 'var(--text-secondary)', marginTop: 2 }}>Any file type accepted</div>
</div>
{reviewFiles.length > 0 && (
<div style={{ marginTop: 6, display: 'flex', flexDirection: 'column', gap: 3 }}>
<div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 4 }}>
{reviewFiles.map((f, i) => (
<div key={i} style={{ fontSize: 12, color: 'var(--text-muted)', display: 'flex', alignItems: 'center', gap: 8 }}>
<span>{f.name}</span>
<button type="button" className="btn-icon btn-icon-danger" style={{ fontSize: 10 }} onClick={() => setReviewFiles(prev => prev.filter((_, j) => j !== i))}></button>
<div key={i} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '5px 10px', background: 'var(--card-bg-2)', borderRadius: 6, border: '1px solid var(--border)' }}>
<span style={{ fontSize: 12, color: 'var(--text-primary)' }}>{f.name}</span>
<button type="button" className="btn btn-danger" onClick={() => setReviewFiles(prev => prev.filter((_, j) => j !== i))}>Remove</button>
</div>
))}
</div>
)}
</div>
<div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', paddingTop: 4 }}>
<button className="btn btn-primary" disabled={reviewSaving} onClick={handleConfirmReview}>{reviewSaving ? 'Submitting…' : 'Place in Review'}</button>
<button className="btn btn-outline" disabled={reviewSaving} onClick={() => { setReviewModal(false); setReviewFiles([]); }}>Cancel</button>
<button className="btn btn-outline" disabled={reviewSaving} onClick={handleConfirmReview}>{reviewSaving ? 'Submitting…' : 'Place in Review'}</button>
<button className="btn btn-outline" disabled={reviewSaving} onClick={() => { setReviewModal(false); setReviewFiles([]); setReviewNotes(''); }}>Cancel</button>
</div>
</div>
</div>