Files
igny8/frontend/src/pages/Reference/SeedKeywords.tsx
2026-01-05 03:40:39 +00:00

121 lines
4.9 KiB
TypeScript

import { useState, useEffect } from 'react';
import PageMeta from '../../components/common/PageMeta';
import { useToast } from '../../components/ui/toast/ToastContainer';
import { fetchSeedKeywords, SeedKeyword, fetchIndustries, Industry } from '../../services/api';
import { Card } from '../../components/ui/card';
import Badge from '../../components/ui/badge/Badge';
import { usePageLoading } from '../../context/PageLoadingContext';
export default function SeedKeywords() {
const toast = useToast();
const { startLoading, stopLoading } = usePageLoading();
const [keywords, setKeywords] = useState<SeedKeyword[]>([]);
const [industries, setIndustries] = useState<Industry[]>([]);
const [selectedIndustry, setSelectedIndustry] = useState<number | null>(null);
const [searchTerm, setSearchTerm] = useState('');
useEffect(() => {
loadIndustries();
loadKeywords();
}, [selectedIndustry, searchTerm]);
const loadIndustries = async () => {
try {
const response = await fetchIndustries();
setIndustries(response.industries || []);
} catch (error: any) {
toast.error(`Failed to load industries: ${error.message}`);
}
};
const loadKeywords = async () => {
try {
startLoading('Loading seed keywords...');
const response = await fetchSeedKeywords({
industry: selectedIndustry || undefined,
search: searchTerm || undefined,
});
setKeywords(response.results || []);
} catch (error: any) {
toast.error(`Failed to load seed keywords: ${error.message}`);
} finally {
stopLoading();
}
};
return (
<>
<PageMeta title="Seed Keywords" />
<div className="mb-6">
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">Seed Keywords</h1>
<p className="text-gray-600 dark:text-gray-400 mt-1">Global keyword library for reference</p>
</div>
<div className="mb-6 flex gap-4">
<select
className="px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800"
value={selectedIndustry || ''}
onChange={(e) => setSelectedIndustry(e.target.value ? parseInt(e.target.value) : null)}
>
<option value="">All Industries</option>
{industries.map((industry) => (
<option key={industry.id} value={industry.id}>
{industry.name}
</option>
))}
</select>
<input
type="text"
placeholder="Search keywords..."
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
<Card className="p-6">
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="border-b border-gray-200 dark:border-gray-700">
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">Keyword</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">Industry</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">Sector</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">Volume</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">Difficulty</th>
<th className="text-left py-3 px-4 text-sm font-medium text-gray-700 dark:text-gray-300">Country</th>
</tr>
</thead>
<tbody>
{keywords.map((keyword) => (
<tr key={keyword.id} className="border-b border-gray-100 dark:border-gray-800">
<td className="py-3 px-4 text-sm font-medium text-gray-900 dark:text-white">
{keyword.keyword}
</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">
{keyword.industry_name}
</td>
<td className="py-3 px-4 text-sm text-gray-600 dark:text-gray-400">
{keyword.sector_name}
</td>
<td className="py-3 px-4 text-sm text-gray-900 dark:text-white">
{keyword.volume.toLocaleString()}
</td>
<td className="py-3 px-4 text-sm text-gray-900 dark:text-white">
{keyword.difficulty}
</td>
<td className="py-3 px-4">
<Badge variant="light" color="info">{keyword.country_display}</Badge>
</td>
</tr>
))}
</tbody>
</table>
</div>
</Card>
)}
</>
);
}