Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 30 additions & 16 deletions src/components/CoinDetail/CoinChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const customStyles = {
upBorderColor: '#4073FF',
downBorderColor: '#FF4D66',
upWickColor: '#4073FF',
downWickColor: '#FF4D66',
downWickColor: '#FF4D66',
},
priceMark: {
last: {
Expand All @@ -24,7 +24,21 @@ const customStyles = {
color: '#FF4D66',
}
}
}
},
grid: {
horizontal: { color: '#233554' },
vertical: { color: '#233554' },
},
xAxis: {
tickText: { color: '#8892B0' },
},
yAxis: {
tickText: { color: '#8892B0' },
},
crosshair: {
horizontal: { line: { color: '#8892B0' } },
vertical: { line: { color: '#8892B0' } },
},
}

const CoinChart = ({ ticker }) => {
Expand Down Expand Up @@ -111,35 +125,35 @@ const CoinChart = ({ ticker }) => {
return (
<div className="mt-10">
<div className="flex flex-row gap-4">
<div className="font-semibold text-[20px]">
<div className="font-semibold text-[20px] text-[#CCD6F6]">
{ticker}
</div>
<div
className="bg-[#1F78F2] px-2 py-1 rounded-sm text-white text-[12px] cursor-pointer flex items-center"
onClick={onClickMinute}
<div
className="border border-[#233554] hover:border-[#64FFDA] hover:text-[#64FFDA] px-2 py-1 rounded-sm text-[#8892B0] text-[12px] cursor-pointer flex items-center transition-colors"
onClick={onClickMinute}
>
1분
</div>
<div
className="bg-[#1F78F2] px-2 py-1 rounded-sm text-white text-[12px] cursor-pointer flex items-center"
<div
className="border border-[#233554] hover:border-[#64FFDA] hover:text-[#64FFDA] px-2 py-1 rounded-sm text-[#8892B0] text-[12px] cursor-pointer flex items-center transition-colors"
onClick={onClickHour}
>
1시간
</div>
<div
className="bg-[#1F78F2] px-2 py-1 rounded-sm text-white text-[12px] cursor-pointer flex items-center"
onClick={onClickFourHour}
<div
className="border border-[#233554] hover:border-[#64FFDA] hover:text-[#64FFDA] px-2 py-1 rounded-sm text-[#8892B0] text-[12px] cursor-pointer flex items-center transition-colors"
onClick={onClickFourHour}
>
4시간
</div>
<div className="bg-[#1F78F2] px-2 py-1 rounded-sm text-white text-[12px] cursor-pointer flex items-center">
<div className="border border-[#233554] hover:border-[#64FFDA] hover:text-[#64FFDA] px-2 py-1 rounded-sm text-[#8892B0] text-[12px] cursor-pointer flex items-center transition-colors">
6시간
</div>
<div className="bg-[#1F78F2] px-2 py-1 rounded-sm text-white text-[12px] cursor-pointer flex items-center">
<div className="border border-[#233554] hover:border-[#64FFDA] hover:text-[#64FFDA] px-2 py-1 rounded-sm text-[#8892B0] text-[12px] cursor-pointer flex items-center transition-colors">
12시간
</div>
<div
className="bg-[#1F78F2] px-2 py-1 rounded-sm text-white text-[12px] cursor-pointer flex items-center"
<div
className="border border-[#233554] hover:border-[#64FFDA] hover:text-[#64FFDA] px-2 py-1 rounded-sm text-[#8892B0] text-[12px] cursor-pointer flex items-center transition-colors"
onClick={onClickDay}
>
1일
Expand All @@ -158,7 +172,7 @@ const CoinChart = ({ ticker }) => {
</div>
)}
{isLoading && <div className="absolute inset-0 z-10 bg-gray-100 animate-pulse"/>}
<div id="chart" className="w-full h-150"/>
<div id="chart" className="w-full h-150 bg-[#112240]"/>
</div>
</div>
)
Expand Down
16 changes: 7 additions & 9 deletions src/components/CoinDetail/DailyNews.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ const DailyNews = ({ticker}) => {

useEffect(() => {
const fetchCoinNews = async () => {
try {
try {
setIsLoading(true);
setIsError(null);
const res = await getCoinNews(ticker, 0, 20);
//console.log(res.data);
setNewsData(res.data?.content || []);
} catch (error) {
console.log("백엔드 불러오기 실패 : ", error);
Expand All @@ -28,7 +27,7 @@ const DailyNews = ({ticker}) => {
const renderContent = () => {
if (isLoading) {
return (
<div className="py-8 text-center text-[16px] text-[#9E9E9E]">
<div className="py-8 text-center text-[16px] text-[#8892B0]">
뉴스를 불러오는 중입니다.
</div>
)
Expand All @@ -42,14 +41,14 @@ const DailyNews = ({ticker}) => {
}
if (newsData.length === 0) {
return (
<div className="py-8 text-center text-[16px] text-[#9E9E9E]">
<div className="py-8 text-center text-[16px] text-[#8892B0]">
등록된 뉴스가 없습니다.
</div>
)
}

return newsData.map((news) => (
<DailyNewsCard
<DailyNewsCard
key={news.newsId}
status={news.sentimentLabel}
title={news.title}
Expand All @@ -59,11 +58,10 @@ const DailyNews = ({ticker}) => {
/>
))
}


return (
<div className="h-150 mt-6 border border-[#E0E0E0] bg-[#FFFFFF] p-8 rounded-sm flex flex-col gap-4">
<h1 className="text-[20px] font-bold">
<div className="h-150 mt-6 border border-[#233554] bg-[#112240] p-8 rounded-sm flex flex-col gap-4">
<h1 className="text-[20px] font-bold text-[#CCD6F6]">
최근 24시간 호재/악재 뉴스
</h1>

Expand All @@ -74,4 +72,4 @@ const DailyNews = ({ticker}) => {
)
}

export default DailyNews;
export default DailyNews;
10 changes: 5 additions & 5 deletions src/components/CoinDetail/DailyNewsCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const DailyNewsCard = ({status, title, publisher, reliability, time}) => {
NEGATIVE : "악재",
POSITIVE : "호재"
}

const CalculateTime = (t) => {
const getTime = new Date(t);
const milliSeconds = new Date() - getTime;
Expand All @@ -31,15 +31,15 @@ const DailyNewsCard = ({status, title, publisher, reliability, time}) => {
}

return (
<div className="flex flex-col bg-[#FAFAFA] px-4 py-4 gap-2 cursor-pointer hover:bg-[#f4f4f4] transition-colors">
<div className="flex flex-col bg-[#0A192F] px-4 py-4 gap-2 cursor-pointer hover:bg-[#1E3A5F] transition-colors">
<div className="flex flex-row items-center gap-3">
<RoundButton status={labelType[status]} content={contentType[status]}/>
<div className="text-[16px] font-semibold">
<div className="text-[16px] font-semibold text-[#CCD6F6]">
{title}
</div>
</div>

<div className="flex flex-row gap-1 items-center text-[#7A7A7A] text-[14px]">
<div className="flex flex-row gap-1 items-center text-[#8892B0] text-[14px]">
<div>{CalculateTime(time)}</div>
|
<div>신뢰도: 약 {RoundReliability(reliability)}%</div>
Expand All @@ -50,4 +50,4 @@ const DailyNewsCard = ({status, title, publisher, reliability, time}) => {
)
}

export default DailyNewsCard;
export default DailyNewsCard;
29 changes: 11 additions & 18 deletions src/components/CoinDetail/History.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ import HistoryCard from "./HistoryCard";
import { getAiPredictions } from "../../apis/CoinDetail/aihistory";

const History = ({ticker, currentPrice}) => {
//mock data
// const mockData= [
// {id: 1, date: "2026.02.08", time: "16:00", prediction: "호재", result: "53", isSuccess: true},
// {id: 2, date: "2026.02.08", time: "16:30", prediction: "호재", result: "54", isSuccess: true},
// {id: 3, date: "2026.02.08", time: "17:00", prediction: "악재", result: "42", isSuccess: false},
// ]
const timeMapping = {
"1시간": "HOUR_1",
"3시간": "HOUR_3",
Expand All @@ -26,7 +20,6 @@ const History = ({ticker, currentPrice}) => {
setIsLoading(true);
setIsError(null);
const res = await getAiPredictions(ticker);
//console.log(res);
setPredictionList(res.data?.content || []);

} catch (error) {
Expand All @@ -44,7 +37,7 @@ const History = ({ticker, currentPrice}) => {
const renderContent = () => {
if (isLoading) {
return (
<div className="py-8 text-center text-[16px] text-[#9E9E9E]">
<div className="py-8 text-center text-[16px] text-[#8892B0]">
AI 예측 히스토리를 불러오는 중입니다.
</div>
)
Expand All @@ -58,20 +51,20 @@ const History = ({ticker, currentPrice}) => {
}
if (predictionList.length === 0) {
return (
<div className="py-8 text-center text-[16px] text-[#9E9E9E]">
<div className="py-8 text-center text-[16px] text-[#8892B0]">
AI 히스토리가 없습니다.
</div>
)
}

return (
predictionList.map((item) => {
const targetInterval = timeMapping[selectedTime]; //HOUR_1
const targetInterval = timeMapping[selectedTime];
const verification = item.verifications?.find(v => v.intervalType === targetInterval);
if (!verification) return null;

return (
<HistoryCard
<HistoryCard
key={item.predictionId}
date={item.predictionDate}
time={item.predictionTime}
Expand All @@ -89,19 +82,19 @@ const History = ({ticker, currentPrice}) => {

const time_type = ["1시간", "3시간", "12시간", "24시간"];
return (
<div className="mt-8 border border-[#E0E0E0] bg-[#FFFFFF] p-8 rounded-sm flex flex-col">
<div className="mt-8 border border-[#233554] bg-[#112240] p-8 rounded-sm flex flex-col">
<div className="flex flex-row justify-between items-center">
<div className="text-[20px] font-bold">
<div className="text-[20px] font-bold text-[#CCD6F6]">
AI 예측 히스토리
</div>

<div className="flex flex-row gap-3">
{time_type.map((time) => (
<div
<div
key={time}
onClick={() => setSelectedTime(time)}
className={`border border-[#E0E0E0] px-4 py-2 rounded-sm text-[14px] cursor-pointer flex items-center
${selectedTime === time ? "text-white bg-[#1F78F2] border-none" : "border-[#E0E0E0] text-[#616161]"}`}
className={`border px-4 py-2 rounded-sm text-[14px] cursor-pointer flex items-center
${selectedTime === time ? "text-[#0A192F] bg-[#64FFDA] border-transparent" : "border-[#233554] text-[#8892B0]"}`}
>
{time}
</div>
Expand All @@ -116,4 +109,4 @@ const History = ({ticker, currentPrice}) => {
)
}

export default History;
export default History;
38 changes: 19 additions & 19 deletions src/components/CoinDetail/HistoryCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const HistoryCard = ({date, time, ai_prediction, actual_price, current_price, pr
const StatusConfig = {
positive: { color: 'text-[#FF4D66]', icon: "mingcute:arrow-up-fill" },
negative: { color: 'text-[#4073FF]', icon: "mingcute:arrow-down-fill" },
neutral: { color: 'text-[#9E9E9E]', icon: null }
neutral: { color: 'text-[#8892B0]', icon: null }
};

const {rate, status} = useMemo(() => {
Expand All @@ -32,20 +32,20 @@ const HistoryCard = ({date, time, ai_prediction, actual_price, current_price, pr
}, [actual_price, current_price]);

return (
<div className="w-full bg-[#FAFAFA] flex flex-col">
<div className="w-full bg-[#0A192F] flex flex-col">
<div className='w-full flex justify-between items-center px-6 py-5'>
<div className="flex flex-col gap-2">
<div className="font-medium">{time.split("T")[1].split(":")[0]}:{time.split("T")[1].split(":")[1]}</div>
<div className="text-[#787878] text-[14px]">{date}</div>
<div className="font-medium text-[#CCD6F6]">{time.split("T")[1].split(":")[0]}:{time.split("T")[1].split(":")[1]}</div>
<div className="text-[#8892B0] text-[14px]">{date}</div>
</div>

<div className="flex flex-col justify-center items-center gap-2">
<div>AI 예측</div>
<div className="text-[#CCD6F6]">AI 예측</div>
<RoundButton content={LabelToContent[ai_prediction]} status={LabelToStatus[ai_status]}/>
</div>

<div className="flex flex-col justify-center items-center gap-2">
<div>실제 결과</div>
<div className="text-[#CCD6F6]">실제 결과</div>
<div className={`flex flex-row gap-1 items-center font-bold ${StatusConfig[status].color}`}>
{rate}%
{StatusConfig[status].icon && (
Expand All @@ -55,42 +55,42 @@ const HistoryCard = ({date, time, ai_prediction, actual_price, current_price, pr
</div>

<div className="flex flex-col justify-center items-center gap-2">
<div>예측 결과</div>
<div className="text-[#CCD6F6]">예측 결과</div>
<RoundButton content={prediction_result} status={prediction_status}/>
</div>

<div
className="w-46 h-9 border border-[#E0E0E0] items-center flex flex-row justify-center rounded-sm text-[#787878] cursor-pointer gap-2"
onClick={() => setIsOpen(!isOpen)}
<div
className="w-46 h-9 border border-[#233554] items-center flex flex-row justify-center rounded-sm text-[#8892B0] cursor-pointer gap-2 hover:border-[#64FFDA] hover:text-[#64FFDA] transition-colors"
onClick={() => setIsOpen(!isOpen)}
>
<p>사용된 기사 보기</p>
{isOpen ?
(<iconify-icon icon="mingcute:up-line" className="text-[#787878]"></iconify-icon>) :
(<iconify-icon icon="mingcute:down-line" className="text-[#787878]"></iconify-icon>)
{isOpen ?
(<iconify-icon icon="mingcute:up-line"></iconify-icon>) :
(<iconify-icon icon="mingcute:down-line"></iconify-icon>)
}
</div>
</div>

{isOpen && (
<div className='flex flex-col border border-[#EDEDED] shadow-sm rounded-md gap-2 px-6 py-5'>
<p className='font-semibold text-[16px]'>
<div className='flex flex-col border border-[#233554] rounded-md gap-2 px-6 py-5'>
<p className='font-semibold text-[16px] text-[#CCD6F6]'>
이 예측에 사용된 기사
</p>

<div className='flex flex-col gap-2'>
<PredictionNewsCard
<PredictionNewsCard
status={"NEGATIVE"}
title={"비트코인 사상 최고가 경신, 10만 달러 돌파"}
publisher={"코인데스크"}
time={"2025-01-15T09:30:00"}
/>
<PredictionNewsCard
<PredictionNewsCard
status={"NEGATIVE"}
title={"비트코인 사상 최고가 경신, 10만 달러 돌파"}
publisher={"코인데스크"}
time={"2025-01-15T09:30:00"}
/>
<PredictionNewsCard
<PredictionNewsCard
status={"NEGATIVE"}
title={"비트코인 사상 최고가 경신, 10만 달러 돌파"}
publisher={"코인데스크"}
Expand All @@ -103,4 +103,4 @@ const HistoryCard = ({date, time, ai_prediction, actual_price, current_price, pr
)
}

export default HistoryCard;
export default HistoryCard;
8 changes: 4 additions & 4 deletions src/components/CoinDetail/PredictionNewsCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ const PredictionNewsCard = ({status, title, publisher, time}) => {


return (
<div className="flex flex-row items-center bg-white border border-[#EDEDED] px-4 py-2.5 gap-3">
<div className="flex flex-row items-center bg-[#112240] border border-[#233554] px-4 py-2.5 gap-3">
<div>
<RoundButton status={labelType[status]} content={contentType[status]}/>
</div>
<div className="text-[#212121] text-[14px] font-medium">
<div className="text-[#CCD6F6] text-[14px] font-medium">
{title}
</div>
<div className="text-[#787878] text-[12px] flex items-center">
<div className="text-[#8892B0] text-[12px] flex items-center">
{publisher} | {formatTime(time)}
</div>
</div>
)
}

export default PredictionNewsCard;
export default PredictionNewsCard;
Loading
Loading