"use client" import { useState, useMemo } from "react" import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query" import { useToast } from "@/components/ui/use-toast" import { Trans, useLingui } from "@lingui/react/macro" import { Button } from "@/components/ui/button" import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog" import { Card, CardContent, CardHeader, CardTitle, CardDescription, } from "@/components/ui/card" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" import { Badge } from "@/components/ui/badge" import { Input } from "@/components/ui/input" import { getDomains, deleteDomain, refreshDomain, getStatusBadgeColor, getStatusLabel, formatDate, formatDays, type Domain, } from "@/lib/domains" import { MoreHorizontal, Plus, RefreshCw, Globe, AlertTriangle, CheckCircle2, Clock, Settings2Icon, FilterIcon, LayoutGridIcon, LayoutListIcon, } from "lucide-react" import { DomainDialog } from "./domain-dialog" import { Link } from "@/components/router" import { useBrowserStorage } from "@/lib/utils" type ViewMode = "table" | "grid" type StatusFilter = "all" | "active" | "expiring" | "expired" | "unknown" | "watchlist" export default function DomainsTable() { const { t } = useLingui() const { toast } = useToast() const queryClient = useQueryClient() const [dialogOpen, setDialogOpen] = useState(false) const [editingDomain, setEditingDomain] = useState(null) const [deleteConfirmId, setDeleteConfirmId] = useState(null) const [filter, setFilter] = useState("") const [statusFilter, setStatusFilter] = useState("all") const [viewMode, setViewMode] = useBrowserStorage( "domainsViewMode", window.innerWidth < 1024 ? "grid" : "table" ) const { data: domains = [], isLoading } = useQuery({ queryKey: ["domains"], queryFn: getDomains, }) // Filter by status first const statusFilteredDomains = useMemo(() => { if (statusFilter === "all") return domains return domains.filter((d) => d.status === statusFilter) }, [domains, statusFilter]) // Then filter by search text const filteredDomains = useMemo(() => { if (!filter) return statusFilteredDomains const f = filter.toLowerCase() return statusFilteredDomains.filter( (d) => d.domain_name.toLowerCase().includes(f) || (d.registrar_name || "").toLowerCase().includes(f) ) }, [statusFilteredDomains, filter]) const statusCounts = useMemo(() => { const total = domains.length const active = domains.filter((d) => d.status === "active").length const expiring = domains.filter((d) => d.status === "expiring").length const expired = domains.filter((d) => d.status === "expired").length const unknown = domains.filter((d) => d.status === "unknown").length return { total, active, expiring, expired, unknown } }, [domains]) const deleteMutation = useMutation({ mutationFn: deleteDomain, onSuccess: () => { toast({ title: "Domain deleted successfully" }) queryClient.invalidateQueries({ queryKey: ["domains"] }) }, }) const refreshMutation = useMutation({ mutationFn: refreshDomain, onSuccess: () => { toast({ title: "Domain refresh started" }) queryClient.invalidateQueries({ queryKey: ["domains"] }) }, }) const handleEdit = (domain: Domain) => { setEditingDomain(domain) setDialogOpen(true) } const handleAdd = () => { setEditingDomain(null) setDialogOpen(true) } const handleDelete = (id: string) => { setDeleteConfirmId(id) } const handleRefresh = (id: string) => { refreshMutation.mutate(id) } const getStatusIcon = (status: string) => { switch (status) { case "active": return case "expiring": return case "expired": return default: return } } if (isLoading) { return (
Loading...
) } return ( <>
{/* Title row */}
Domain Monitoring Track domain expiry dates and watch domains for purchase ({statusCounts.active} {statusCounts.expiring > 0 && ( <> {" "} {statusCounts.expiring}{" "} )} {statusCounts.expired > 0 && ( <> {" "} {statusCounts.expired}{" "} )} / {statusCounts.total})
{/* Filter row */}
setFilter(e.target.value)} value={filter} className="w-full" />
{/* Layout */} Layout setViewMode(v as ViewMode)}> Table Grid {/* Status Filter */} Status setStatusFilter(v as StatusFilter)}> All ({statusCounts.total}) Active ({statusCounts.active}) Expiring ({statusCounts.expiring}) Expired ({statusCounts.expired}) Unknown ({statusCounts.unknown})
{filteredDomains.length === 0 ? (
{filter || statusFilter !== "all" ? ( "No domains match your filters." ) : (

No domains tracked. Add domains to monitor their expiry dates or track domains you want to buy.

)}
) : viewMode === "table" ? (
Domain Status Expiry Days Left Registrar SSL Expiry Actions {filteredDomains.map((domain) => ( {domain.favicon_url && ( (e.currentTarget.style.display = "none")} /> )} {domain.domain_name}
{getStatusIcon(domain.status)} {getStatusLabel(domain.status)}
{domain.expiry_date ? formatDate(domain.expiry_date) : "Unknown"} = 0 && domain.days_until_expiry <= 30 ? domain.days_until_expiry <= 7 ? "text-red-600 font-semibold" : "text-yellow-600" : "" }> {formatDays(domain.days_until_expiry)} {domain.registrar_name || "Unknown"} {domain.ssl_valid_to ? ( = 0 && domain.ssl_days_until <= 14 ? "text-red-600" : "" } > {formatDays(domain.ssl_days_until)} ) : ( "N/A" )} handleEdit(domain)}> Edit handleRefresh(domain.id)} disabled={refreshMutation.isPending} > Refresh Visit handleDelete(domain.id)} className="text-destructive" > Delete
))}
) : (
{filteredDomains.map((domain) => (
{domain.favicon_url && ( (e.currentTarget.style.display = "none")} /> )}
{domain.domain_name}
handleEdit(domain)}>Edit handleRefresh(domain.id)} disabled={refreshMutation.isPending}> Refresh handleDelete(domain.id)} className="text-destructive"> Delete
{getStatusIcon(domain.status)} {getStatusLabel(domain.status)}
Days Left
= 0 && domain.days_until_expiry <= 30 ? domain.days_until_expiry <= 7 ? "text-red-600 font-semibold" : "text-yellow-600" : "" }> {formatDays(domain.days_until_expiry)}
SSL
= 0 && domain.ssl_days_until <= 14 ? "text-red-600" : "" } > {formatDays(domain.ssl_days_until)}
))}
)}
setDeleteConfirmId(null)}> Delete Domain Are you sure you want to delete this domain? This action cannot be undone. Cancel { if (deleteConfirmId) { deleteMutation.mutate(deleteConfirmId) setDeleteConfirmId(null) } }} className="bg-destructive text-destructive-foreground hover:bg-destructive/90" > Delete ) }