대시보드 분리
This commit is contained in:
79
frontend/src/components/JournalPanel.tsx
Normal file
79
frontend/src/components/JournalPanel.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React from 'react'
|
||||
import { Activity } from 'lucide-react'
|
||||
|
||||
interface JournalPanelProps {
|
||||
journals: any[] | undefined
|
||||
onResetPending: () => void
|
||||
}
|
||||
|
||||
const JournalPanel = React.memo(({ journals, onResetPending }: JournalPanelProps) => {
|
||||
return (
|
||||
<div className="bg-gray-800/50 backdrop-blur-sm border border-gray-700/50 rounded-xl overflow-hidden flex flex-col h-1/2 shadow-lg">
|
||||
<div className="flex flex-col h-full p-3">
|
||||
<div className="flex flex-col h-full min-h-0">
|
||||
<div className="flex items-center justify-between mb-2 flex-shrink-0">
|
||||
<h3 className="font-bold flex items-center gap-2 text-green-400 text-sm">
|
||||
<Activity size={16} />
|
||||
매매일지
|
||||
</h3>
|
||||
<button
|
||||
onClick={onResetPending}
|
||||
className="px-2 py-1 text-[10px] bg-red-500/20 hover:bg-red-500/30 text-red-400 rounded border border-red-500/30 transition-colors"
|
||||
title="미체결 주문 정리"
|
||||
>
|
||||
미체결 정리
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-2 overflow-y-auto custom-scrollbar flex-1">
|
||||
{journals && journals.length > 0 ? (
|
||||
journals.map((journal: any) => {
|
||||
const journalDate = new Date(journal.journal_date || journal.created_at)
|
||||
const dateStr = journalDate.toLocaleDateString('ko-KR', { month: '2-digit', day: '2-digit', timeZone: 'Asia/Seoul' })
|
||||
const timeStr = journalDate.toLocaleTimeString('ko-KR', { hour: '2-digit', minute: '2-digit', hour12: false, timeZone: 'Asia/Seoul' })
|
||||
const isGoodMood = journal.mood === '좋음' || journal.mood === 'good' || journal.mood === 'positive'
|
||||
const isBadMood = journal.mood === '나쁨' || journal.mood === 'bad' || journal.mood === 'negative'
|
||||
const tags: string[] = Array.isArray(journal.tags) ? journal.tags : []
|
||||
const hasProfitTag = tags.some((t: string) => t.includes('익절') || t.includes('profit'))
|
||||
const hasLossTag = tags.some((t: string) => t.includes('손절') || t.includes('loss'))
|
||||
|
||||
return (
|
||||
<div key={journal.id} className="p-3 hover:bg-gray-700/30 rounded-lg transition-colors bg-gray-900/30 border border-gray-700/30">
|
||||
<div className="flex justify-between items-start mb-1.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-base">
|
||||
{isGoodMood ? '😊' : isBadMood ? '😔' : '📝'}
|
||||
</span>
|
||||
<span className="font-bold text-gray-200 text-sm">{journal.stock_name || journal.stock_code}</span>
|
||||
{hasProfitTag && <span className="px-1.5 py-0.5 text-[9px] rounded bg-green-500/20 text-green-400">익절</span>}
|
||||
{hasLossTag && <span className="px-1.5 py-0.5 text-[9px] rounded bg-red-500/20 text-red-400">손절</span>}
|
||||
</div>
|
||||
<span className="text-[10px] text-gray-500 font-mono">{dateStr} {timeStr}</span>
|
||||
</div>
|
||||
<div className="text-[11px] text-gray-300 leading-relaxed line-clamp-3 whitespace-pre-line">
|
||||
{journal.content}
|
||||
</div>
|
||||
{tags.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1 mt-1.5">
|
||||
{tags.slice(0, 4).map((tag: string, i: number) => (
|
||||
<span key={i} className="px-1.5 py-0.5 text-[9px] rounded bg-gray-700/50 text-gray-400">#{tag}</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<div className="h-full flex flex-col items-center justify-center text-gray-600 text-xs gap-1">
|
||||
<span>매매일지 없음</span>
|
||||
<span className="text-[10px] text-gray-700">매도 체결 후 자동으로 생성됩니다</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
JournalPanel.displayName = 'JournalPanel'
|
||||
export default JournalPanel
|
||||
Reference in New Issue
Block a user