Files
igny8/frontend/src/components/common/SiteCard.tsx
IGNY8 VPS (Salman) e8360a6703 fix fix fi x fix
2026-01-12 15:30:15 +00:00

149 lines
4.7 KiB
TypeScript

import { ReactNode } from 'react';
import Switch from '../form/switch/Switch';
import Button from '../ui/button/Button';
import Badge from '../ui/badge/Badge';
import SiteSetupChecklist from '../sites/SiteSetupChecklist';
import SiteTypeBadge from '../sites/SiteTypeBadge';
import { Site } from '../../services/api';
import { BoxCubeIcon as SettingsIcon, EyeIcon, FileIcon, TrashBinIcon } from '../../icons';
interface SiteCardProps {
site: Site;
icon: ReactNode;
onToggle: (siteId: number, enabled: boolean) => void;
onSettings: (site: Site) => void;
onDetails: (site: Site) => void;
onDelete?: (site: Site) => void;
isToggling?: boolean;
}
export default function SiteCard({
site,
icon,
onToggle,
onSettings,
onDetails,
onDelete,
isToggling = false,
}: SiteCardProps) {
const handleToggle = (enabled: boolean) => {
onToggle(site.id, enabled);
};
// Setup checklist state derived from site data
const hasIndustry = !!site.industry || !!site.industry_name;
const hasSectors = site.active_sectors_count > 0;
const hasWordPressIntegration = site.has_integration ?? false;
const hasKeywords = (site.keywords_count ?? 0) > 0;
return (
<article className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/3">
<div className="relative p-3">
<div className="flex items-center gap-2 mb-1">
<div className="inline-flex items-center justify-center text-lg">
{icon}
</div>
<div className="flex-1 min-w-0">
<h3 className="text-lg font-semibold text-gray-800 dark:text-white/90">
{site.name}
</h3>
{site.domain && (
<p className="text-xs text-gray-400 dark:text-gray-500 truncate">
{site.domain}
</p>
)}
</div>
</div>
{site.description && (
<p className="max-w-xs text-sm text-gray-500 dark:text-gray-400 mb-2 ml-8">
{site.description}
</p>
)}
<div className="flex items-center gap-1.5 mt-2 mb-2 flex-wrap">
<SiteTypeBadge hostingType={site.hosting_type} size="xs" />
{site.industry_name && (
<Badge variant="soft" color="warning" size="xs">
{site.industry_name}
</Badge>
)}
<Badge variant="soft" color="neutral" size="xs">
{site.active_sectors_count} / 5 Sectors
</Badge>
</div>
{/* Setup Checklist - Compact View */}
<div className="mt-2">
<SiteSetupChecklist
siteId={site.id}
siteName={site.name}
hasIndustry={hasIndustry}
hasSectors={hasSectors}
hasWordPressIntegration={hasWordPressIntegration}
hasKeywords={hasKeywords}
compact={true}
/>
</div>
{/* Status badge and toggle in top right */}
<div className="absolute top-3 right-3 flex items-center gap-2">
<Switch
label=""
checked={site.is_active}
disabled={isToggling}
onChange={handleToggle}
/>
<div className="flex flex-col items-center gap-1">
<Badge
variant="solid"
color={site.is_active ? "success" : "error"}
size="xs"
>
{site.is_active ? 'Active' : 'Inactive'}
</Badge>
<span className="text-xs text-gray-500">Button</span>
</div>
</div>
</div>
<div className="flex items-center justify-center border-t border-gray-200 p-2 dark:border-gray-800">
<div className="flex gap-1.5">
<Button
variant="primary"
tone="brand"
size="sm"
onClick={() => onDetails(site)}
startIcon={<EyeIcon className="w-4 h-4" />}
>
Dashboard
</Button>
<Button
variant="secondary"
tone="neutral"
size="sm"
onClick={() => onDetails(site)}
startIcon={<FileIcon className="w-4 h-4" />}
>
Content
</Button>
<Button
variant="outline"
tone="neutral"
size="sm"
onClick={() => onSettings(site)}
startIcon={<SettingsIcon className="w-4 h-4" />}
>
Settings
</Button>
<Button
variant="primary"
tone="danger"
size="sm"
onClick={() => onDelete && onDelete(site)}
startIcon={<TrashBinIcon className="w-4 h-4" />}
>
Delete
</Button>
</div>
</div>
</article>
);
}