diff --git a/backend/igny8_core/auth/views.py b/backend/igny8_core/auth/views.py index b6782836..4fb13e44 100644 --- a/backend/igny8_core/auth/views.py +++ b/backend/igny8_core/auth/views.py @@ -873,6 +873,66 @@ class SeedKeywordViewSet(viewsets.ReadOnlyModelViewSet): return queryset + @action(detail=False, methods=['get'], url_path='stats', url_name='stats') + def stats(self, request): + """ + Get aggregated keyword statistics by industry and country. + Returns top industries and countries with keyword counts and total volume. + """ + from django.db.models import Count, Sum, Q + + try: + # Top industries by keyword count + industries = Industry.objects.annotate( + keyword_count=Count('seed_keywords', filter=Q(seed_keywords__is_active=True)), + total_volume=Sum('seed_keywords__volume', filter=Q(seed_keywords__is_active=True)) + ).filter( + keyword_count__gt=0 + ).order_by('-keyword_count')[:10] + + industries_data = [{ + 'name': ind.name, + 'slug': ind.slug, + 'keyword_count': ind.keyword_count or 0, + 'total_volume': ind.total_volume or 0, + } for ind in industries] + + # Keywords by country + countries = SeedKeyword.objects.filter( + is_active=True + ).values('country').annotate( + keyword_count=Count('id'), + total_volume=Sum('volume') + ).order_by('-keyword_count') + + countries_data = [{ + 'country': c['country'], + 'country_display': dict(SeedKeyword.COUNTRY_CHOICES).get(c['country'], c['country']), + 'keyword_count': c['keyword_count'], + 'total_volume': c['total_volume'] or 0, + } for c in countries] + + # Total stats + total_stats = SeedKeyword.objects.filter(is_active=True).aggregate( + total_keywords=Count('id'), + total_volume=Sum('volume') + ) + + data = { + 'industries': industries_data, + 'countries': countries_data, + 'total_keywords': total_stats['total_keywords'] or 0, + 'total_volume': total_stats['total_volume'] or 0, + } + + return success_response(data=data, request=request) + except Exception as e: + return error_response( + error=f'Failed to fetch keyword stats: {str(e)}', + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + request=request + ) + @action(detail=False, methods=['post'], url_path='import_seed_keywords', url_name='import_seed_keywords') def import_seed_keywords(self, request): """ diff --git a/frontend/src/components/dashboard/KeywordLibraryStatsWidget.tsx b/frontend/src/components/dashboard/KeywordLibraryStatsWidget.tsx new file mode 100644 index 00000000..a80e969e --- /dev/null +++ b/frontend/src/components/dashboard/KeywordLibraryStatsWidget.tsx @@ -0,0 +1,160 @@ +/** + * Keyword Library Stats Widget + * Shows global seed keyword statistics: industries, countries, and totals + */ + +import { Card } from '../ui/card'; +import Badge from '../ui/badge/Badge'; +import { Spinner } from '../ui/spinner/Spinner'; +import { DocsIcon, GridIcon, GlobeIcon } from '../../icons'; +import { KeywordStats } from '../../services/api'; + +interface KeywordLibraryStatsWidgetProps { + stats: KeywordStats | null; + loading: boolean; +} + +export default function KeywordLibraryStatsWidget({ stats, loading }: KeywordLibraryStatsWidgetProps) { + if (loading) { + return ( +
+ By Industry +
++ {industry.name} +
++ Vol: {industry.total_volume.toLocaleString()} +
++ +{stats.industries.length - 7} more industries +
++ Geographic coverage +
++ {country.country_display} +
++ Vol: {country.total_volume.toLocaleString()} +
++ Global library +
+Total Keywords
++ {stats.total_keywords.toLocaleString()} +
+Total Search Volume
++ {stats.total_volume.toLocaleString()} +
++ Monthly searches +
+Industries Covered
++ {stats.industries.length} +
++ Ready-to-use, pre-vetted keywords to jumpstart your content creation — no research needed +
+{addedCount} keywords added to your workflow @@ -982,11 +982,11 @@ export default function IndustriesSectorsKeywords() {
- Add top keywords for each of your sectors. Keywords will be added to your planner workflow. + Ready-to-use keywords to jumpstart your content — no research needed. Simply add to your workflow and start creating.
- 💡 Recommended: Start by adding High Opportunity Keywords from the section above. - They're curated for your sectors and ready to use. Once you've added those, you can browse our full keyword library below for additional targeted keywords. + 💡 Recommended: Start with the complimentary Quick-Start Keywords above to accelerate your workflow. + They're pre-vetted and ready to use immediately. Once added, you can browse our full library below for additional targeted keywords.