feat: add frontend/src/pages/Mail.tsx

This commit is contained in:
zio 2026-06-01 22:13:01 +09:00
parent 13c6258cbc
commit 1716c52354

View File

@ -0,0 +1,91 @@
import { useEffect, useCallback } from 'react'
import { mailApi } from '../api/mailApi'
import { useMailStore } from '../store/mailStore'
import FolderTree from '../components/FolderTree'
import MailList from '../components/MailList'
import MailView from '../components/MailView'
import Compose from '../components/Compose'
export default function Mail() {
const { username, displayName, currentFolder, searchQuery,
setFolders, setMessages, setLoading, composeOpen, openCompose, logout } = useMailStore()
const loadFolders = useCallback(async () => {
try {
const data = await mailApi.folders()
setFolders(Array.isArray(data) ? data : [])
} catch { /* 폴더 오류 무시 */ }
}, [setFolders])
const loadMessages = useCallback(async (page = 1) => {
setLoading(true)
try {
const data = await mailApi.messages(currentFolder, page, searchQuery || undefined)
setMessages(data.messages || [], data.total || 0, page)
} catch { setMessages([], 0, 1) }
finally { setLoading(false) }
}, [currentFolder, searchQuery, setMessages, setLoading])
useEffect(() => { loadFolders() }, [loadFolders])
useEffect(() => { loadMessages(1) }, [currentFolder, searchQuery])
// 30초 폴링
useEffect(() => {
const id = setInterval(() => { loadFolders(); loadMessages(1) }, 30000)
return () => clearInterval(id)
}, [loadFolders, loadMessages])
return (
<div className="mail-app">
{/* Header */}
<header className="mail-header">
<div className="header-brand">
<span className="header-icon"></span>
<span className="header-title"> </span>
</div>
<div className="header-center">
<SearchBar />
</div>
<div className="header-actions">
<button className="btn-compose" onClick={() => openCompose()}> </button>
<button className="btn-refresh" onClick={() => loadMessages(1)} title="새로고침">🔄</button>
<span className="header-user">{displayName || username}</span>
<button className="btn-logout" onClick={logout}></button>
</div>
</header>
{/* Body */}
<div className="mail-body">
<aside className="mail-sidebar">
<FolderTree />
</aside>
<section className="mail-list-pane">
<MailList onRefresh={() => loadMessages(1)} />
</section>
<section className="mail-view-pane">
<MailView />
</section>
</div>
{composeOpen && <Compose />}
</div>
)
}
function SearchBar() {
const { searchQuery, setSearchQuery } = useMailStore()
return (
<div className="search-bar">
<span className="search-icon">🔍</span>
<input
type="text" placeholder="메일 검색..."
value={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
onKeyDown={e => { if (e.key === 'Escape') setSearchQuery('') }}
/>
{searchQuery && (
<button className="search-clear" onClick={() => setSearchQuery('')}></button>
)}
</div>
)
}