feat: add frontend/src/components/Compose.tsx

This commit is contained in:
zio 2026-06-01 22:12:59 +09:00
parent e4f634f3fb
commit cc8ea14bf6

View File

@ -0,0 +1,83 @@
import { useState } from 'react'
import { mailApi } from '../api/mailApi'
import { useMailStore } from '../store/mailStore'
export default function Compose() {
const { replyTo, closeCompose, username } = useMailStore()
const [to, setTo] = useState(replyTo?.sender_addr || '')
const [cc, setCc] = useState('')
const [subject, setSubject] = useState(
replyTo ? (replyTo.subject.startsWith('Re:') ? replyTo.subject : `Re: ${replyTo.subject}`) : ''
)
const [body, setBody] = useState(
replyTo
? `\n\n---\n${replyTo.date}${replyTo.sender} (${replyTo.sender_addr}) 님이 작성:\n${replyTo.body_text || '(HTML 메일)'}\n`
: ''
)
const [sending, setSending] = useState(false)
const [error, setError] = useState('')
const [success, setSuccess] = useState(false)
const [showCc, setShowCc] = useState(false)
const send = async () => {
if (!to.trim() || !subject.trim()) { setError('받는사람과 제목은 필수입니다'); return }
setSending(true); setError('')
try {
await mailApi.send({ to, cc: cc || undefined, subject, body })
setSuccess(true)
setTimeout(closeCompose, 1500)
} catch (e: any) {
setError(e.response?.data?.detail || '발송에 실패했습니다')
} finally { setSending(false) }
}
return (
<div className="compose-overlay" onClick={e => e.target === e.currentTarget && closeCompose()}>
<div className="compose-box">
<div className="compose-header">
<span> {replyTo ? '답장' : '새 메일'}</span>
<button className="compose-close" onClick={closeCompose}></button>
</div>
<div className="compose-fields">
<div className="compose-field">
<label> </label>
<span className="compose-from">{username}</span>
</div>
<div className="compose-field">
<label> </label>
<input value={to} onChange={e => setTo(e.target.value)} placeholder="수신자 이메일" />
<button className="btn-cc-toggle" onClick={() => setShowCc(v => !v)}></button>
</div>
{showCc && (
<div className="compose-field">
<label></label>
<input value={cc} onChange={e => setCc(e.target.value)} placeholder="참조 이메일" />
</div>
)}
<div className="compose-field">
<label></label>
<input value={subject} onChange={e => setSubject(e.target.value)} placeholder="제목 입력" />
</div>
</div>
<textarea
className="compose-body"
value={body}
onChange={e => setBody(e.target.value)}
placeholder="내용을 입력하세요..."
/>
{error && <div className="compose-error"> {error}</div>}
{success && <div className="compose-success"> !</div>}
<div className="compose-footer">
<button className="btn-send" onClick={send} disabled={sending}>
{sending ? '발송 중...' : '📨 보내기'}
</button>
<button className="btn-cancel" onClick={closeCompose}></button>
</div>
</div>
</div>
)
}