Files
NewStrcuture_Backup/src/components/settings/facebook-accounts-dialog.tsx
T
Ace ff56cea4b8 feat: add Facebook account tracking and management
- Introduced new migration for `facebook_accounts` and `facebook_scrape_logs` tables.
- Updated the scraping logic to handle Facebook accounts, including success and failure tracking.
- Implemented API endpoints for managing Facebook accounts and their scrape logs.
- Enhanced user permissions to restrict access to Facebook account management to admins and super admins.
- Added a dialog component for displaying and managing Facebook accounts in the UI.
- Updated lead fetching logic to include user role checks for assignment and access.
2026-06-23 14:18:18 +02:00

103 lines
3.6 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog"
import { Badge } from "@/components/ui/badge"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { ShieldAlert, RefreshCw } from "lucide-react"
import { Button } from "@/components/ui/button"
interface Account {
id: string
label: string
is_active: boolean
last_scrape_at: string | null
last_success_at: string | null
last_error_at: string | null
consecutive_failures: number
flagged: boolean
flagged_reason: string | null
last_leads_found: number
last_success: boolean | null
}
export function FacebookAccountsDialog({ open, onOpenChange }: { open: boolean; onOpenChange: (v: boolean) => void }) {
const [accounts, setAccounts] = useState<Account[]>([])
const [loading, setLoading] = useState(false)
useEffect(() => {
if (open) load()
}, [open])
async function load() {
setLoading(true)
try {
const res = await fetch("/api/settings/facebook/accounts")
if (res.ok) {
setAccounts(await res.json())
}
} catch {}
setLoading(false)
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl">
<DialogHeader className="flex flex-row items-center justify-between">
<div>
<DialogTitle>Facebook Accounts</DialogTitle>
<DialogDescription>
Status of Facebook profiles used for lead scraping
</DialogDescription>
</div>
<Button variant="ghost" size="icon" onClick={load} disabled={loading}>
<RefreshCw className={`h-4 w-4 ${loading ? "animate-spin" : ""}`} />
</Button>
</DialogHeader>
{loading ? (
<div className="text-center py-8 text-muted-foreground">Loading...</div>
) : accounts.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">No accounts configured</div>
) : (
<Table>
<TableHeader>
<TableRow>
<TableHead>Label</TableHead>
<TableHead>Status</TableHead>
<TableHead>Last Scrape</TableHead>
<TableHead>Leads</TableHead>
<TableHead>Failures</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{accounts.map((a) => (
<TableRow key={a.id}>
<TableCell className="font-medium">{a.label}</TableCell>
<TableCell>
{a.flagged ? (
<Badge variant="destructive" className="gap-1">
<ShieldAlert className="h-3 w-3" />
{a.flagged_reason || "Flagged"}
</Badge>
) : a.is_active ? (
<Badge variant="default" className="bg-green-600">Active</Badge>
) : (
<Badge variant="secondary">Disabled</Badge>
)}
</TableCell>
<TableCell className="text-sm text-muted-foreground">
{a.last_scrape_at ? new Date(a.last_scrape_at).toLocaleString() : "Never"}
</TableCell>
<TableCell>{a.last_leads_found}</TableCell>
<TableCell>{a.consecutive_failures}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
)}
</DialogContent>
</Dialog>
)
}