This commit is contained in:
2026-01-21 08:21:19 +01:00
parent 4733e1a1cc
commit fd6e7c44e1
46 changed files with 3165 additions and 456 deletions

View File

@@ -1,5 +1,6 @@
'use client'
import { useState } from 'react'
import { useRouter, useParams } from 'next/navigation'
import { useQuery } from '@tanstack/react-query'
import { monitorAPI } from '@/lib/api'
@@ -7,13 +8,17 @@ import { DashboardLayout } from '@/components/layout/dashboard-layout'
import { Button } from '@/components/ui/button'
import { Card, CardContent } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { SEORankingCard } from '@/components/seo-ranking-card'
import { toast } from 'sonner'
export default function MonitorHistoryPage() {
const router = useRouter()
const params = useParams()
const id = params?.id as string
const [isChecking, setIsChecking] = useState(false)
const [isCheckingSeo, setIsCheckingSeo] = useState(false)
const { data: monitorData } = useQuery({
const { data: monitorData, refetch: refetchMonitor } = useQuery({
queryKey: ['monitor', id],
queryFn: async () => {
const response = await monitorAPI.get(id)
@@ -21,7 +26,7 @@ export default function MonitorHistoryPage() {
},
})
const { data: historyData, isLoading } = useQuery({
const { data: historyData, isLoading, refetch: refetchHistory } = useQuery({
queryKey: ['history', id],
queryFn: async () => {
const response = await monitorAPI.history(id)
@@ -29,6 +34,41 @@ export default function MonitorHistoryPage() {
},
})
const handleCheckNow = async (type: 'content' | 'seo' = 'content') => {
if (type === 'seo') {
if (isCheckingSeo) return
setIsCheckingSeo(true)
} else {
if (isChecking) return
setIsChecking(true)
}
try {
const result = await monitorAPI.check(id, type)
if (type === 'seo') {
toast.success('SEO Ranking check completed')
} else {
if (result.snapshot?.errorMessage) {
toast.error(`Check failed: ${result.snapshot.errorMessage}`)
} else {
toast.success(result.snapshot?.changed ? 'Changes detected!' : 'No changes detected')
}
}
refetchMonitor()
refetchHistory()
} catch (err: any) {
console.error('Failed to trigger check:', err)
toast.error(`Failed to check ${type === 'seo' ? 'SEO' : 'monitor'}`)
} finally {
if (type === 'seo') {
setIsCheckingSeo(false)
} else {
setIsChecking(false)
}
}
}
if (isLoading) {
return (
<DashboardLayout>
@@ -66,6 +106,40 @@ export default function MonitorHistoryPage() {
</div>
{monitor && (
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={() => handleCheckNow('content')}
disabled={isChecking || isCheckingSeo}
className="gap-2"
>
{isChecking ? (
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
) : (
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
)}
Check Now
</Button>
{monitor.seoKeywords && monitor.seoKeywords.length > 0 && (
<Button
variant="outline"
size="sm"
onClick={() => handleCheckNow('seo')}
disabled={isChecking || isCheckingSeo}
className="gap-2 border-purple-200 text-purple-700 hover:bg-purple-50"
>
{isCheckingSeo ? (
<div className="h-4 w-4 animate-spin rounded-full border-2 border-purple-600 border-t-transparent" />
) : (
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
</svg>
)}
SEO Check
</Button>
)}
<Button
variant="outline"
size="sm"
@@ -105,6 +179,19 @@ export default function MonitorHistoryPage() {
</div>
</div>
{/* SEO Rankings */}
{monitor && monitor.seoKeywords && monitor.seoKeywords.length > 0 && (
<div className="mb-8">
<div className="flex items-center gap-2 mb-4 text-purple-700">
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
</svg>
<h2 className="text-lg font-semibold">SEO Keyword Performance</h2>
</div>
<SEORankingCard monitorId={id} keywords={monitor.seoKeywords} />
</div>
)}
{/* History List */}
<div>
<h2 className="mb-4 text-lg font-semibold">Check History</h2>
@@ -181,7 +268,7 @@ export default function MonitorHistoryPage() {
{snapshot.summary && (
<div className="mt-3 p-3 bg-muted/50 rounded-md text-sm">
<p className="font-medium text-foreground mb-1">Summary</p>
<p>{snapshot.summary}</p>
<p className="whitespace-pre-wrap break-words leading-relaxed mt-2">{snapshot.summary}</p>
</div>
)}
</div>

View File

@@ -158,7 +158,7 @@ export default function SnapshotDetailsPage() {
{snapshot.summary && (
<div className="mt-6 rounded-lg bg-blue-50 border border-blue-200 p-4">
<p className="text-sm font-medium text-blue-900">Change Summary</p>
<p className="text-sm text-blue-700 mt-1">{snapshot.summary}</p>
<p className="text-sm text-blue-700 mt-2 whitespace-pre-wrap break-words leading-relaxed">{snapshot.summary}</p>
</div>
)}
</CardContent>