You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
6.2 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import dynamic from 'next/dynamic';
import { stockApi } from '@/lib/api';
import { List, Database as DBIcon, Layers, Calendar } from 'lucide-react';
import Layout from '@/components/Layout';
const DatabaseStats = dynamic(() => import('@/components/DatabaseStats'), {
ssr: false,
loading: () => (
<div className="animate-pulse space-y-4">
<div className="h-6 bg-gray-200 rounded w-1/3"></div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="h-32 bg-gray-200 rounded"></div>
<div className="h-32 bg-gray-200 rounded"></div>
<div className="h-32 bg-gray-200 rounded"></div>
</div>
</div>
),
});
const DatabasePage: React.FC = () => {
const [tab, setTab] = useState<'stats' | 'etf' | 'financial'>('stats');
const [etf, setEtf] = useState<{loading:boolean; items:any[]; total:number}>({loading:false, items:[], total:0});
const [fin, setFin] = useState<{loading:boolean; items:any[]; total:number}>({loading:false, items:[], total:0});
const loadEtf = async () => {
setEtf(s => ({...s, loading:true}));
try {
const res = await stockApi.getEtfSnapshots({ limit: 25 });
setEtf({loading:false, items:res.results, total:res.count});
} catch {
setEtf({loading:false, items:[], total:0});
}
};
const loadFin = async () => {
setFin(s => ({...s, loading:true}));
try {
const res = await stockApi.getFinancialRecords({ limit: 50 });
setFin({loading:false, items:res.results, total:res.count});
} catch {
setFin({loading:false, items:[], total:0});
}
};
useEffect(() => {
if (tab === 'etf') loadEtf();
if (tab === 'financial') loadFin();
}, [tab]);
return (
<Layout title="Database - Stock Oracle">
<div className="mb-6 flex items-center space-x-2">
<button onClick={() => setTab('stats')} className={`px-3 py-2 rounded-md text-sm ${tab==='stats'?'bg-blue-600 text-white':'bg-gray-100 text-gray-700'}`}>
</button>
<button onClick={() => setTab('etf')} className={`px-3 py-2 rounded-md text-sm ${tab==='etf'?'bg-blue-600 text-white':'bg-gray-100 text-gray-700'}`}>
ETF
</button>
<button onClick={() => setTab('financial')} className={`px-3 py-2 rounded-md text-sm ${tab==='financial'?'bg-blue-600 text-white':'bg-gray-100 text-gray-700'}`}>
</button>
</div>
{tab==='stats' && <DatabaseStats />}
{tab==='etf' && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center"><Layers className="h-5 w-5 mr-2"/> ETF </h3>
{etf.loading ? (
<p className="text-gray-500"> ...</p>
) : etf.items.length===0 ? (
<p className="text-gray-500"> .</p>
) : (
<div className="overflow-x-auto">
<table className="min-w-full text-sm text-gray-900">
<thead>
<tr className="text-left text-gray-800 border-b">
<th className="py-2 pr-4">Snapshot ID</th>
<th className="py-2 pr-4">Ticker</th>
<th className="py-2 pr-4">Date</th>
<th className="py-2 pr-4">Source</th>
<th className="py-2 pr-4">Holdings</th>
</tr>
</thead>
<tbody>
{etf.items.map((s:any) => (
<tr key={s.id} className="border-b hover:bg-gray-50 text-gray-900">
<td className="py-2 pr-4 font-mono text-xs break-all">{s.id}</td>
<td className="py-2 pr-4">{s.ticker}</td>
<td className="py-2 pr-4 flex items-center"><Calendar className="h-4 w-4 mr-1"/>{new Date(s.snapshot_date).toLocaleDateString('ko-KR')}</td>
<td className="py-2 pr-4">{s.source || '-'}</td>
<td className="py-2 pr-4">{s.holdings_count}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
)}
{tab==='financial' && (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center"><DBIcon className="h-5 w-5 mr-2"/> </h3>
{fin.loading ? (
<p className="text-gray-500"> ...</p>
) : fin.items.length===0 ? (
<p className="text-gray-500"> .</p>
) : (
<div className="overflow-x-auto">
<table className="min-w-full text-sm text-gray-900">
<thead>
<tr className="text-left text-gray-800 border-b">
<th className="py-2 pr-4">Ticker</th>
<th className="py-2 pr-4">Period</th>
<th className="py-2 pr-4">Type</th>
<th className="py-2 pr-4">Revenue</th>
<th className="py-2 pr-4">Net Income</th>
<th className="py-2 pr-4">Source</th>
</tr>
</thead>
<tbody>
{fin.items.map((r:any) => (
<tr key={`${r.ticker}-${r.period_date}-${r.period_type}`} className="border-b hover:bg-gray-50 text-gray-900">
<td className="py-2 pr-4">{r.ticker}</td>
<td className="py-2 pr-4">{new Date(r.period_date).toLocaleDateString('ko-KR')}</td>
<td className="py-2 pr-4">{r.period_type}</td>
<td className="py-2 pr-4">{r.revenue?.toLocaleString() ?? '-'}</td>
<td className="py-2 pr-4">{r.net_income?.toLocaleString() ?? '-'}</td>
<td className="py-2 pr-4">{r.data_source}</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
)}
</Layout>
);
};
export default DatabasePage;