|
|
import React from 'react'; |
|
|
import useKeywordAnalysis from '../hooks/useKeywordAnalysis'; |
|
|
|
|
|
const KeywordTrendAnalyzer = () => { |
|
|
const { |
|
|
keyword, |
|
|
setKeyword, |
|
|
analysisData, |
|
|
patternAnalysis, |
|
|
loading, |
|
|
patternLoading, |
|
|
error, |
|
|
analyzeKeyword, |
|
|
analyzeKeywordPattern |
|
|
} = useKeywordAnalysis(); |
|
|
|
|
|
const handleAnalyzeClick = async () => { |
|
|
try { |
|
|
|
|
|
await Promise.all([ |
|
|
analyzeKeyword(), |
|
|
analyzeKeywordPattern() |
|
|
]); |
|
|
} catch (err) { |
|
|
|
|
|
console.error('Analysis error:', err); |
|
|
} |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<div className="keyword-trend-analyzer p-6 bg-white rounded-lg shadow-md"> |
|
|
<h2 className="text-xl font-bold mb-4 text-gray-900">Keyword Frequency Pattern Analysis</h2> |
|
|
|
|
|
<div className="flex gap-4 mb-6"> |
|
|
<input |
|
|
type="text" |
|
|
value={keyword} |
|
|
onChange={(e) => setKeyword(e.target.value)} |
|
|
placeholder="Enter keyword to analyze" |
|
|
className="flex-1 px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 text-gray-900" |
|
|
/> |
|
|
<button |
|
|
onClick={handleAnalyzeClick} |
|
|
disabled={loading || patternLoading} |
|
|
className="px-6 py-2 rounded-md bg-blue-600 hover:bg-blue-700 text-white focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50" |
|
|
> |
|
|
{loading || patternLoading ? 'Processing...' : 'Analyze'} |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
{error && ( |
|
|
<div className="mb-4 p-3 bg-red-100 text-red-700 rounded-md"> |
|
|
{error} |
|
|
</div> |
|
|
)} |
|
|
|
|
|
{/* Pattern Analysis Results */} |
|
|
{patternAnalysis && !patternLoading && ( |
|
|
<div className="mt-6"> |
|
|
<h3 className="text-lg font-semibold mb-4 text-gray-900">Frequency Pattern Analysis for "{keyword}"</h3> |
|
|
|
|
|
<div className="bg-gray-50 rounded-lg p-4 mb-6"> |
|
|
<div className="flex items-center justify-between mb-2"> |
|
|
<span className="text-sm font-medium text-gray-700">Pattern:</span> |
|
|
<span className={`px-3 py-1 rounded-full text-sm font-semibold ${ |
|
|
patternAnalysis.pattern === 'daily' ? 'bg-blue-100 text-blue-800' : |
|
|
patternAnalysis.pattern === 'weekly' ? 'bg-green-100 text-green-800' : |
|
|
patternAnalysis.pattern === 'monthly' ? 'bg-yellow-100 text-yellow-800' : |
|
|
'bg-red-100 text-red-800' |
|
|
}`}> |
|
|
{patternAnalysis.pattern.toUpperCase()} |
|
|
</span> |
|
|
</div> |
|
|
<p className="text-gray-600 text-sm mb-1"><strong>Explanation:</strong> {patternAnalysis.details.explanation}</p> |
|
|
<p className="text-gray-600 text-sm"><strong>Confidence:</strong> {(patternAnalysis.details.confidence * 100).toFixed(0)}%</p> |
|
|
<p className="text-gray-600 text-sm"><strong>Total Articles:</strong> {patternAnalysis.total_articles}</p> |
|
|
{patternAnalysis.date_range.start && patternAnalysis.date_range.end && ( |
|
|
<p className="text-gray-600 text-sm"> |
|
|
<strong>Date Range:</strong> {patternAnalysis.date_range.start} to {patternAnalysis.date_range.end} |
|
|
</p> |
|
|
)} |
|
|
</div> |
|
|
</div> |
|
|
)} |
|
|
|
|
|
{/* Recent Articles Table */} |
|
|
{patternAnalysis && patternAnalysis.articles && patternAnalysis.articles.length > 0 && ( |
|
|
<div className="mt-6"> |
|
|
<h3 className="text-lg font-semibold mb-4 text-gray-900">5 Most Recent Articles for "{keyword}"</h3> |
|
|
|
|
|
<div className="overflow-x-auto"> |
|
|
<table className="min-w-full border border-gray-200 rounded-md"> |
|
|
<thead> |
|
|
<tr className="bg-gray-100"> |
|
|
<th className="py-2 px-4 border-b text-left text-gray-700">Title</th> |
|
|
<th className="py-2 px-4 border-b text-left text-gray-700">Date</th> |
|
|
</tr> |
|
|
</thead> |
|
|
<tbody> |
|
|
{patternAnalysis.articles.slice(0, 5).map((article, index) => { |
|
|
// Format the date from the article |
|
|
let formattedDate = 'N/A'; |
|
|
if (article.date) { |
|
|
try { |
|
|
// Parse the date string - it could be in various formats |
|
|
const date = new Date(article.date); |
|
|
// If the date parsing failed, try to extract date from the link if it's in the format needed |
|
|
if (isNaN(date.getTime())) { |
|
|
// Handle different date formats if needed |
|
|
// Try to extract from the link or other format |
|
|
formattedDate = 'N/A'; |
|
|
} else { |
|
|
// Format date as "09/oct/25" (day/mon/yy) |
|
|
const day = date.getDate().toString().padStart(2, '0'); |
|
|
const month = date.toLocaleString('default', { month: 'short' }).toLowerCase(); |
|
|
const year = date.getFullYear().toString().slice(-2); |
|
|
formattedDate = `${day}/${month}/${year}`; |
|
|
} |
|
|
} catch (e) { |
|
|
formattedDate = 'N/A'; |
|
|
} |
|
|
} |
|
|
return ( |
|
|
<tr key={index} className={index % 2 === 0 ? 'bg-white' : 'bg-gray-50'}> |
|
|
<td className="py-2 px-4 border-b text-gray-900 text-sm"> |
|
|
<a |
|
|
href={article.link} |
|
|
target="_blank" |
|
|
rel="noopener noreferrer" |
|
|
className="text-blue-600 hover:text-blue-800 underline" |
|
|
> |
|
|
{article.title} |
|
|
</a> |
|
|
</td> |
|
|
<td className="py-2 px-4 border-b text-gray-900 text-sm">{formattedDate}</td> |
|
|
</tr> |
|
|
); |
|
|
})} |
|
|
</tbody> |
|
|
</table> |
|
|
</div> |
|
|
</div> |
|
|
)} |
|
|
</div> |
|
|
); |
|
|
}; |
|
|
|
|
|
export default KeywordTrendAnalyzer; |