feature/syasya/testlayout #7
@ -1,46 +1,187 @@
 | 
			
		||||
'use client';
 | 
			
		||||
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import React, { useEffect, useMemo, useState } from 'react';
 | 
			
		||||
import DashboardLayout from '../adminDashboard/dashlayout';
 | 
			
		||||
import SiteCard from '@/components/dashboards/SiteCard'; // Import the new SiteCard component
 | 
			
		||||
import { mockSiteData, SiteName } from '@/types/SiteData'; // Import your mock data and SiteName type
 | 
			
		||||
import SiteCard from '@/components/dashboards/SiteCard';
 | 
			
		||||
 | 
			
		||||
type CrmProject = {
 | 
			
		||||
  name: string;                 // e.g. PROJ-0008 (siteId)
 | 
			
		||||
  project_name: string;
 | 
			
		||||
  status?: string | null;
 | 
			
		||||
  modified?: string | null;
 | 
			
		||||
  customer?: string | null;
 | 
			
		||||
  project_type?: string | null;
 | 
			
		||||
  custom_address?: string | null;
 | 
			
		||||
  custom_email?: string | null;
 | 
			
		||||
  custom_mobile_phone_no?: string | null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const API = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:8000';
 | 
			
		||||
 | 
			
		||||
const SitesPage = () => {
 | 
			
		||||
    // Helper function to determine status (can be externalized if used elsewhere)
 | 
			
		||||
    const getSiteStatus = (siteName: SiteName): string => {
 | 
			
		||||
        const statusMap: Record<SiteName, string> = {
 | 
			
		||||
            'Site A': 'Active',
 | 
			
		||||
            'Site B': 'Inactive',
 | 
			
		||||
            'Site C': 'Faulty',
 | 
			
		||||
        };
 | 
			
		||||
        return statusMap[siteName];
 | 
			
		||||
  const [projects, setProjects] = useState<CrmProject[]>([]);
 | 
			
		||||
  const [loading, setLoading] = useState(true);
 | 
			
		||||
  const [err, setErr] = useState<string | null>(null);
 | 
			
		||||
  const [q, setQ] = useState('');             // search filter
 | 
			
		||||
 | 
			
		||||
  // pagination
 | 
			
		||||
  const [page, setPage] = useState(1);
 | 
			
		||||
  const [pageSize, setPageSize] = useState(6); // tweak as you like
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    let cancelled = false;
 | 
			
		||||
    const run = async () => {
 | 
			
		||||
      setLoading(true);
 | 
			
		||||
      setErr(null);
 | 
			
		||||
      try {
 | 
			
		||||
        const res = await fetch(`${API}/crm/projects?limit=0`);
 | 
			
		||||
        if (!res.ok) throw new Error(await res.text());
 | 
			
		||||
        const json = await res.json();
 | 
			
		||||
        const data: CrmProject[] = json?.data ?? [];
 | 
			
		||||
        if (!cancelled) setProjects(data);
 | 
			
		||||
      } catch (e: any) {
 | 
			
		||||
        if (!cancelled) setErr(e?.message ?? 'Failed to load CRM projects');
 | 
			
		||||
      } finally {
 | 
			
		||||
        if (!cancelled) setLoading(false);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    run();
 | 
			
		||||
    return () => { cancelled = true; };
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <DashboardLayout>
 | 
			
		||||
            <div className="p-6 space-y-6">
 | 
			
		||||
                <h1 className="text-2xl font-bold mb-6 dark:text-white-light">All Sites Overview</h1>
 | 
			
		||||
  // Reset to first page whenever search or pageSize changes
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setPage(1);
 | 
			
		||||
  }, [q, pageSize]);
 | 
			
		||||
 | 
			
		||||
                <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
 | 
			
		||||
                    {/* Iterate over the keys of mockSiteData (which are your SiteNames) */}
 | 
			
		||||
                    {Object.keys(mockSiteData).map((siteNameKey) => {
 | 
			
		||||
                        const siteName = siteNameKey as SiteName; // Cast to SiteName type
 | 
			
		||||
                        const siteDetails = mockSiteData[siteName];
 | 
			
		||||
                        const siteStatus = getSiteStatus(siteName);
 | 
			
		||||
 | 
			
		||||
                        return (
 | 
			
		||||
                            <SiteCard
 | 
			
		||||
                                key={siteName} // Important for React list rendering
 | 
			
		||||
                                siteName={siteName}
 | 
			
		||||
                                details={siteDetails}
 | 
			
		||||
                                status={siteStatus}
 | 
			
		||||
                            />
 | 
			
		||||
                        );
 | 
			
		||||
                    })}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </DashboardLayout>
 | 
			
		||||
  const filtered = useMemo(() => {
 | 
			
		||||
    if (!q.trim()) return projects;
 | 
			
		||||
    const needle = q.toLowerCase();
 | 
			
		||||
    return projects.filter(p =>
 | 
			
		||||
      (p.project_name || '').toLowerCase().includes(needle) ||
 | 
			
		||||
      (p.name || '').toLowerCase().includes(needle) ||
 | 
			
		||||
      (p.customer || '').toLowerCase().includes(needle)
 | 
			
		||||
    );
 | 
			
		||||
  }, [projects, q]);
 | 
			
		||||
 | 
			
		||||
  const total = filtered.length;
 | 
			
		||||
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
 | 
			
		||||
  const safePage = Math.min(page, totalPages);
 | 
			
		||||
  const startIdx = (safePage - 1) * pageSize;
 | 
			
		||||
  const endIdx = Math.min(startIdx + pageSize, total);
 | 
			
		||||
  const pageItems = filtered.slice(startIdx, endIdx);
 | 
			
		||||
 | 
			
		||||
  const goPrev = () => setPage(p => Math.max(1, p - 1));
 | 
			
		||||
  const goNext = () => setPage(p => Math.min(totalPages, p + 1));
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <DashboardLayout>
 | 
			
		||||
      <div className="p-6 space-y-6">
 | 
			
		||||
        <div className="flex flex-col md:flex-row md:items-center md:justify-between gap-3">
 | 
			
		||||
          <h1 className="text-2xl font-bold dark:text-white-light">All Sites Overview</h1>
 | 
			
		||||
 | 
			
		||||
          <div className="flex items-center gap-3">
 | 
			
		||||
            <input
 | 
			
		||||
              value={q}
 | 
			
		||||
              onChange={e => setQ(e.target.value)}
 | 
			
		||||
              placeholder="Search by name / ID / customer"
 | 
			
		||||
              className="w-64 max-w-full px-3 py-2 rounded-md border dark:border-gray-700 bg-white dark:bg-gray-900 dark:text-white"
 | 
			
		||||
            />
 | 
			
		||||
            <select
 | 
			
		||||
              value={pageSize}
 | 
			
		||||
              onChange={e => setPageSize(Number(e.target.value))}
 | 
			
		||||
              className="px-3 py-2 rounded-md border dark:border-gray-700 bg-white dark:bg-gray-900 dark:text-white"
 | 
			
		||||
              aria-label="Items per page"
 | 
			
		||||
            >
 | 
			
		||||
              <option value={6}>6 / page</option>
 | 
			
		||||
              <option value={9}>9 / page</option>
 | 
			
		||||
              <option value={12}>12 / page</option>
 | 
			
		||||
            </select>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        {loading && (
 | 
			
		||||
          <div className="text-gray-600 dark:text-gray-400">Loading CRM projects…</div>
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
        {err && (
 | 
			
		||||
          <div className="text-red-600">Error: {err}</div>
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
        {!loading && !err && total === 0 && (
 | 
			
		||||
          <div className="text-amber-600">No sites found.</div>
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
        {!loading && !err && total > 0 && (
 | 
			
		||||
          <>
 | 
			
		||||
            {/* Pagination header */}
 | 
			
		||||
            <div className="flex items-center justify-between">
 | 
			
		||||
              <div className="text-sm text-gray-600 dark:text-gray-400">
 | 
			
		||||
                Showing <span className="font-semibold">{startIdx + 1}</span>–<span className="font-semibold">{endIdx}</span> of <span className="font-semibold">{total}</span>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div className="flex items-center gap-2 dark:text-white">
 | 
			
		||||
                <button
 | 
			
		||||
                  onClick={goPrev}
 | 
			
		||||
                  disabled={safePage <= 1}
 | 
			
		||||
                  className={`px-3 py-1.5 rounded-md border dark:border-gray-700 ${safePage <= 1 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50 dark:hover:bg-gray-800'}`}
 | 
			
		||||
                >
 | 
			
		||||
                  Previous
 | 
			
		||||
                </button>
 | 
			
		||||
                <span className="text-sm text-gray-600 dark:text-gray-400">
 | 
			
		||||
                  Page <span className="font-semibold">{safePage}</span> / {totalPages}
 | 
			
		||||
                </span>
 | 
			
		||||
                <button
 | 
			
		||||
                  onClick={goNext}
 | 
			
		||||
                  disabled={safePage >= totalPages}
 | 
			
		||||
                  className={`px-3 py-1.5 rounded-md border dark:border-gray-700 ${safePage >= totalPages ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50 dark:hover:bg-gray-800 '}`}
 | 
			
		||||
                >
 | 
			
		||||
                  Next
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {/* Cards */}
 | 
			
		||||
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
 | 
			
		||||
              {pageItems.map(p => (
 | 
			
		||||
                <SiteCard
 | 
			
		||||
                  key={p.name}
 | 
			
		||||
                  siteId={p.name}          // SiteCard self-fetches details
 | 
			
		||||
                  fallbackStatus={p.status ?? undefined}
 | 
			
		||||
                />
 | 
			
		||||
              ))}
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            {/* Pagination footer mirrors header for convenience */}
 | 
			
		||||
            <div className="flex items-center justify-between">
 | 
			
		||||
              <div className="text-sm text-gray-600 dark:text-gray-400">
 | 
			
		||||
                Showing <span className="font-semibold">{startIdx + 1}</span>–<span className="font-semibold">{endIdx}</span> of <span className="font-semibold">{total}</span>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div className="flex items-center gap-2 dark:text-white">
 | 
			
		||||
                <button
 | 
			
		||||
                  onClick={goPrev}
 | 
			
		||||
                  disabled={safePage <= 1}
 | 
			
		||||
                  className={`px-3 py-1.5 rounded-md border dark:border-gray-700 ${safePage <= 1 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50 dark:hover:bg-gray-800'}`}
 | 
			
		||||
                >
 | 
			
		||||
                  Previous
 | 
			
		||||
                </button>
 | 
			
		||||
                <span className="text-sm text-gray-600 dark:text-gray-400">
 | 
			
		||||
                  Page <span className="font-semibold">{safePage}</span> / {totalPages}
 | 
			
		||||
                </span>
 | 
			
		||||
                <button
 | 
			
		||||
                  onClick={goNext}
 | 
			
		||||
                  disabled={safePage >= totalPages}
 | 
			
		||||
                  className={`px-3 py-1.5 rounded-md border dark:border-gray-700 ${safePage >= totalPages ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50 dark:hover:bg-gray-800'}`}
 | 
			
		||||
                >
 | 
			
		||||
                  Next
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
      </div>
 | 
			
		||||
    </DashboardLayout>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default SitesPage;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,63 +1,146 @@
 | 
			
		||||
// components/dashboards/SiteCard.tsx
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import Link from 'next/link'; // Import Link from Next.js
 | 
			
		||||
import { SiteName, SiteDetails } from '@/types/SiteData'; // Adjust path as necessary
 | 
			
		||||
'use client';
 | 
			
		||||
 | 
			
		||||
import React, { useEffect, useMemo, useState } from 'react';
 | 
			
		||||
import Link from 'next/link';
 | 
			
		||||
import { formatAddress } from '@/app/utils/formatAddress';
 | 
			
		||||
import { formatCrmTimestamp } from '@/app/utils/datetime';
 | 
			
		||||
 | 
			
		||||
type CrmProject = {
 | 
			
		||||
  name: string;                  // e.g. PROJ-0008 (siteId)
 | 
			
		||||
  project_name: string;
 | 
			
		||||
  status?: string;
 | 
			
		||||
  percent_complete?: number | null;
 | 
			
		||||
  owner?: string | null;
 | 
			
		||||
  modified?: string | null;
 | 
			
		||||
  customer?: string | null;
 | 
			
		||||
  project_type?: string | null;
 | 
			
		||||
  custom_address?: string | null;
 | 
			
		||||
  custom_email?: string | null;
 | 
			
		||||
  custom_mobile_phone_no?: string | null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
interface SiteCardProps {
 | 
			
		||||
    siteName: SiteName;
 | 
			
		||||
    details: SiteDetails;
 | 
			
		||||
    status: string;
 | 
			
		||||
  siteId: string;                // CRM Project "name" (canonical id)
 | 
			
		||||
  className?: string;            // optional styling hook
 | 
			
		||||
  fallbackStatus?: string;       // optional backup status if CRM is missing it
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const SiteCard: React.FC<SiteCardProps> = ({ siteName, details, status }) => {
 | 
			
		||||
    const statusColorClass =
 | 
			
		||||
        status === 'Active' ? 'text-green-500' :
 | 
			
		||||
        status === 'Inactive' ? 'text-orange-500' :
 | 
			
		||||
        'text-red-500';
 | 
			
		||||
const API = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:8000';
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <div className="bg-white p-4 rounded-lg shadow-md dark:bg-gray-800 dark:text-white-light flex flex-col space-y-2">
 | 
			
		||||
            <h3 className="text-xl font-bold text-primary-600 dark:text-primary-400 border-b pb-2 mb-2">
 | 
			
		||||
                {siteName}
 | 
			
		||||
            </h3>
 | 
			
		||||
const SiteCard: React.FC<SiteCardProps> = ({ siteId, className = '', fallbackStatus }) => {
 | 
			
		||||
  const [project, setProject] = useState<CrmProject | null>(null);
 | 
			
		||||
  const [loading, setLoading] = useState(true);
 | 
			
		||||
  const [err, setErr] = useState<string | null>(null);
 | 
			
		||||
 | 
			
		||||
            <div className="flex justify-between items-center">
 | 
			
		||||
                <p className="text-gray-600 dark:text-gray-400 font-medium">Status:</p>
 | 
			
		||||
                <p className={`font-semibold ${statusColorClass}`}>{status}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    let cancelled = false;
 | 
			
		||||
 | 
			
		||||
            <div className="flex justify-between items-center">
 | 
			
		||||
                <p className="text-gray-600 dark:text-gray-400 font-medium">Location:</p>
 | 
			
		||||
                <p className="font-semibold">{details.location}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
    const fetchProject = async () => {
 | 
			
		||||
      setLoading(true);
 | 
			
		||||
      setErr(null);
 | 
			
		||||
      try {
 | 
			
		||||
        // ---- Try a single-project endpoint first (best) ----
 | 
			
		||||
        // e.g. GET /crm/projects/PROJ-0008
 | 
			
		||||
        const single = await fetch(`${API}/crm/projects/${encodeURIComponent(siteId)}`);
 | 
			
		||||
        if (single.ok) {
 | 
			
		||||
          const pj = await single.json();
 | 
			
		||||
          if (!cancelled) setProject(pj?.data ?? pj ?? null);
 | 
			
		||||
        } else {
 | 
			
		||||
          // ---- Fallback: fetch all and find by name (works with your existing API) ----
 | 
			
		||||
          const list = await fetch(`${API}/crm/projects?limit=0`);
 | 
			
		||||
          if (!list.ok) throw new Error(await list.text());
 | 
			
		||||
          const json = await list.json();
 | 
			
		||||
          const found = (json?.data ?? []).find((p: CrmProject) => p.name === siteId) ?? null;
 | 
			
		||||
          if (!cancelled) setProject(found);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (e: any) {
 | 
			
		||||
        if (!cancelled) setErr(e?.message ?? 'Failed to load CRM project');
 | 
			
		||||
      } finally {
 | 
			
		||||
        if (!cancelled) setLoading(false);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
            <div className="flex justify-between items-center">
 | 
			
		||||
                <p className="text-gray-600 dark:text-gray-400 font-medium">Inverter Provider:</p>
 | 
			
		||||
                <p className="font-semibold">{details.inverterProvider}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
    fetchProject();
 | 
			
		||||
    return () => { cancelled = true; };
 | 
			
		||||
  }, [siteId]);
 | 
			
		||||
 | 
			
		||||
            <div className="flex justify-between items-center">
 | 
			
		||||
                <p className="text-gray-600 dark:text-gray-400 font-medium">Emergency Contact:</p>
 | 
			
		||||
                <p className="font-semibold">{details.emergencyContact}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
  const status = project?.status || fallbackStatus || 'Unknown';
 | 
			
		||||
  const statusColorClass =
 | 
			
		||||
    status === 'Active' ? 'text-green-500' :
 | 
			
		||||
    status === 'Inactive' ? 'text-orange-500' :
 | 
			
		||||
    'text-red-500';
 | 
			
		||||
 | 
			
		||||
            <div className="flex justify-between items-center">
 | 
			
		||||
                <p className="text-gray-600 dark:text-gray-400 font-medium">Last Sync:</p>
 | 
			
		||||
                <p className="font-semibold">{details.lastSyncTimestamp}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
  const niceAddress = useMemo(() => {
 | 
			
		||||
    if (!project?.custom_address) return 'N/A';
 | 
			
		||||
    return formatAddress(project.custom_address).multiLine;
 | 
			
		||||
  }, [project?.custom_address]);
 | 
			
		||||
 | 
			
		||||
            {/* New: View Dashboard Button */}
 | 
			
		||||
            <Link
 | 
			
		||||
                href={{
 | 
			
		||||
                    pathname: '/adminDashboard', // Path to your AdminDashboard page
 | 
			
		||||
                    query: { site: siteName }, // Pass the siteName as a query parameter
 | 
			
		||||
                }}
 | 
			
		||||
                className="mt-4 w-full text-center text-sm btn-primary" // Tailwind classes for basic button styling
 | 
			
		||||
            >
 | 
			
		||||
                View Dashboard
 | 
			
		||||
            </Link>
 | 
			
		||||
  const lastSync = useMemo(() => {
 | 
			
		||||
    return formatCrmTimestamp(project?.modified, { includeSeconds: true }) || 'N/A';
 | 
			
		||||
  }, [project?.modified]);
 | 
			
		||||
 | 
			
		||||
  const inverterProvider = project?.project_type || 'N/A';
 | 
			
		||||
  const emergencyContact =
 | 
			
		||||
    project?.custom_mobile_phone_no ||
 | 
			
		||||
    project?.custom_email ||
 | 
			
		||||
    project?.customer ||
 | 
			
		||||
    'N/A';
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={`bg-white p-4 rounded-lg shadow-md dark:bg-gray-800 dark:text-white-light flex flex-col space-y-2 ${className}`}>
 | 
			
		||||
      <h3 className="text-xl font-bold text-primary-600 dark:text-primary-400 border-b pb-2 mb-2">
 | 
			
		||||
        {project?.project_name || siteId}
 | 
			
		||||
      </h3>
 | 
			
		||||
 | 
			
		||||
      {loading ? (
 | 
			
		||||
        <div className="animate-pulse space-y-2">
 | 
			
		||||
          <div className="h-4 w-24 bg-gray-200 dark:bg-gray-700 rounded" />
 | 
			
		||||
          <div className="h-4 w-48 bg-gray-200 dark:bg-gray-700 rounded" />
 | 
			
		||||
          <div className="h-4 w-40 bg-gray-200 dark:bg-gray-700 rounded" />
 | 
			
		||||
          <div className="h-4 w-36 bg-gray-200 dark:bg-gray-700 rounded" />
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
      ) : err ? (
 | 
			
		||||
        <div className="text-red-500 text-sm">Failed to load CRM: {err}</div>
 | 
			
		||||
      ) : !project ? (
 | 
			
		||||
        <div className="text-amber-500 text-sm">No CRM project found for <span className="font-semibold">{siteId}</span>.</div>
 | 
			
		||||
      ) : (
 | 
			
		||||
        <>
 | 
			
		||||
          <div className="flex justify-between items-center">
 | 
			
		||||
            <p className="text-gray-600 dark:text-gray-400 font-medium">Status:</p>
 | 
			
		||||
            <p className={`font-semibold ${statusColorClass}`}>{status}</p>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className="flex justify-between items-center">
 | 
			
		||||
            <p className="text-gray-600 dark:text-gray-400 font-medium">Location:</p>
 | 
			
		||||
            <p className="font-medium whitespace-pre-line text-right">{niceAddress}</p>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className="flex justify-between items-center">
 | 
			
		||||
            <p className="text-gray-600 dark:text-gray-400 font-medium">Inverter Provider:</p>
 | 
			
		||||
            <p className="font-medium">{inverterProvider}</p>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className="flex justify-between items-center">
 | 
			
		||||
            <p className="text-gray-600 dark:text-gray-400 font-medium">Emergency Contact:</p>
 | 
			
		||||
            <p className="font-medium text-right">{emergencyContact}</p>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className="flex justify-between items-center">
 | 
			
		||||
            <p className="text-gray-600 dark:text-gray-400 font-medium">Last Sync:</p>
 | 
			
		||||
            <p className="font-medium">{lastSync}</p>
 | 
			
		||||
          </div>
 | 
			
		||||
        </>
 | 
			
		||||
      )}
 | 
			
		||||
 | 
			
		||||
      <Link
 | 
			
		||||
        href={{ pathname: '/adminDashboard', query: { site: siteId } }}
 | 
			
		||||
        className="mt-4 w-full text-center text-sm btn-primary"
 | 
			
		||||
      >
 | 
			
		||||
        View Dashboard
 | 
			
		||||
      </Link>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default SiteCard;
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user