PageSourceSearch

https://sistur.lovable.app/assets/CertificateStatsPanel-DKumPYH8.js

js sistur.lovable.app collected 2026-10-03 03:46:29 UTC 6,441 bytes, 170 lines download raw bytes

1const e=`import { tx } from '@/i18n/t';
2import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
3import { Badge } from '@/components/ui/badge';
4import { Skeleton } from '@/components/ui/skeleton';
5import { 
6  Award, 
7  TrendingUp, 
8  TrendingDown, 
9  CheckCircle, 
10  XCircle,
11  BarChart3
12} from 'lucide-react';
13import { useCertificateStats } from '@/hooks/useCertificates';
14
15export function CertificateStatsPanel() {
16  const { data: stats, isLoading, error } = useCertificateStats();
17
18  if (isLoading) {
19    return (
20      <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
21        {[...Array(4)].map((_, i) => (
22          <Card key={i}>
23            <CardContent className="pt-6">
24              <Skeleton className="h-8 w-16 mb-2" />
25              <Skeleton className="h-4 w-24" />
26            </CardContent>
27          </Card>
28        ))}
29      </div>
30    );
31  }
32
33  if (error || !stats) {
34    return (
35      <Card className="border-destructive/30 bg-destructive/5">
36        <CardContent className="py-6 text-center text-destructive">
37          {tx("Erro ao carregar estatísticas de certificados")}
38        </CardContent>
39      </Card>
40    );
41  }
42
43  const monthChange = stats.thisMonth - stats.lastMonth;
44  const monthChangePercent = stats.lastMonth > 0 
45    ? Math.round((monthChange / stats.lastMonth) * 100) 
46    : stats.thisMonth > 0 ? 100 : 0;
47
48  return (
49    <div className="space-y-6">
50      {/* Overview Stats */}
51      <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
52        <Card>
53          <CardContent className="pt-6">
54            <div className="flex items-center justify-between">
55              <div>
56                <p className="text-3xl font-bold">{stats.total}</p>
57                <p className="text-sm text-muted-foreground">{tx("Total de Certificados")}</p>
58              </div>
59              <div className="p-3 rounded-full bg-primary/10">
60                <Award className="h-6 w-6 text-primary" />
61              </div>
62            </div>
63          </CardContent>
64        </Card>
65
66        <Card>
67          <CardContent className="pt-6">
68            <div className="flex items-center justify-between">
69              <div>
70                <p className="text-3xl font-bold text-green-600">{stats.active}</p>
71                <p className="text-sm text-muted-foreground">{tx("Ativos")}</p>
72              </div>
73              <div className="p-3 rounded-full bg-green-500/10">
74                <CheckCircle className="h-6 w-6 text-green-600" />
75              </div>
76            </div>
77          </CardContent>
78        </Card>
79
80        <Card>
81          <CardContent className="pt-6">
82            <div className="flex items-center justify-between">
83              <div>
84                <p className="text-3xl font-bold text-red-600">{stats.revoked}</p>
85                <p className="text-sm text-muted-foreground">{tx("Revogados")}</p>
86              </div>
87              <div className="p-3 rounded-full bg-red-500/10">
88                <XCircle className="h-6 w-6 text-red-600" />
89              </div>
90            </div>
91          </CardContent>
92        </Card>
93
94        <Card>
95          <CardContent className="pt-6">
96            <div className="flex items-center justify-between">
97              <div>
98                <div className="flex items-center gap-2">
99                  <p className="text-3xl font-bold">{stats.thisMonth}</p>
100                  {monthChange !== 0 && (
101                    <Badge 
102                      variant="outline" 
103                      className={monthChange > 0 
104                        ? "bg-green-500/10 text-green-700 border-green-500/30" 
105                        : "bg-red-500/10 text-red-700 border-red-500/30"
106                      }
107                    >
108                      {monthChange > 0 ? (
109                        <TrendingUp className="h-3 w-3 mr-1" />
110                      ) : (
111                        <TrendingDown className="h-3 w-3 mr-1" />
112                      )}
113                      {monthChange > 0 ? '+' : ''}{monthChangePercent}%
114                    </Badge>
115                  )}
116                </div>
117                <p className="text-sm text-muted-foreground">{tx("Este mês")}</p>
118              </div>
119              <div className="p-3 rounded-full bg-blue-500/10">
120                <BarChart3 className="h-6 w-6 text-blue-600" />
121              </div>
122            </div>
123          </CardContent>
124        </Card>
125      </div>
126
127      {/* By Pillar */}
128      <Card>
129        <CardHeader>
130          <CardTitle className="text-base">
130{tx("Certificados por Pilar")}</CardTitle>
131          <CardDescription>{tx("Distribuição de certificados emitidos por área")}</CardDescription>
132        </CardHeader>
133        <CardContent>
134          <div className="grid gap-4 md:grid-cols-3">
135            <div className="flex items-center justify-between p-4 rounded-lg bg-blue-500/5 border border-blue-500/20">
136              <div>
137                <p className="text-2xl font-bold text-blue-700">{stats.byPillar.RA}</p>
138                <p className="text-sm text-muted-foreground">{tx("Relações Ambientais")}</p>
139              </div>
140              <Badge variant="outline" className="bg-blue-500/10 text-blue-700 border-blue-500/30">
141                RA
142              </Badge>
143            </div>
144
145            <div className="flex items-center justify-between p-4 rounded-lg bg-green-500/5 border border-green-500/20">
146              <div>
147                <p className="text-2xl font-bold text-green-700">{stats.byPillar.OE}</p>
148                <p className="text-sm text-muted-foreground">{tx("Organização Estrutural")}</p>
149              </div>
150              <Badge variant="outline" className="bg-green-500/10 text-green-700 border-green-500/30">
151                OE
152              </Badge>
153            </div>
154
155            <div className="flex items-center justify-between p-4 rounded-lg bg-purple-500/5 border border-purple-500/20">
156              <div>
157                <p className="text-2xl font-bold text-purple-700">{stats.byPillar.AO}</p>
158                <p className="text-sm text-muted-foreground">{tx("Ações Operacionais")}</p>
159              </div>
160              <Badge variant="outline" className="bg-purple-500/10 text-purple-700 border-purple-500/30">
161                AO
162              </Badge>
163            </div>
164          </div>
165        </CardContent>
166      </Card>
167    </div>
168  );
169}
170`;export{e as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.