@hed-hog/core 0.0.296 → 0.0.298

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/auth/auth.controller.d.ts +14 -14
  2. package/dist/auth/auth.service.d.ts +14 -14
  3. package/dist/challenge/challenge.service.d.ts +2 -2
  4. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts +15 -1
  5. package/dist/dashboard/dashboard-core/dashboard-core.controller.d.ts.map +1 -1
  6. package/dist/dashboard/dashboard-core/dashboard-core.controller.js +9 -0
  7. package/dist/dashboard/dashboard-core/dashboard-core.controller.js.map +1 -1
  8. package/dist/dashboard/dashboard-core/dashboard-core.module.d.ts.map +1 -1
  9. package/dist/dashboard/dashboard-core/dashboard-core.module.js +6 -1
  10. package/dist/dashboard/dashboard-core/dashboard-core.module.js.map +1 -1
  11. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts +175 -3
  12. package/dist/dashboard/dashboard-core/dashboard-core.service.d.ts.map +1 -1
  13. package/dist/dashboard/dashboard-core/dashboard-core.service.js +531 -5
  14. package/dist/dashboard/dashboard-core/dashboard-core.service.js.map +1 -1
  15. package/dist/file/file.controller.d.ts.map +1 -1
  16. package/dist/file/file.controller.js +16 -0
  17. package/dist/file/file.controller.js.map +1 -1
  18. package/dist/file/file.service.d.ts +7 -1
  19. package/dist/file/file.service.d.ts.map +1 -1
  20. package/dist/file/file.service.js +38 -1
  21. package/dist/file/file.service.js.map +1 -1
  22. package/dist/file/provider/s3.provider.d.ts +1 -0
  23. package/dist/file/provider/s3.provider.d.ts.map +1 -1
  24. package/dist/file/provider/s3.provider.js +38 -29
  25. package/dist/file/provider/s3.provider.js.map +1 -1
  26. package/dist/oauth/oauth.service.d.ts.map +1 -1
  27. package/dist/oauth/oauth.service.js +2 -1
  28. package/dist/oauth/oauth.service.js.map +1 -1
  29. package/dist/profile/profile.controller.d.ts +6 -6
  30. package/dist/profile/profile.service.d.ts +6 -6
  31. package/dist/session/session.controller.d.ts +2 -2
  32. package/dist/session/session.service.d.ts +3 -3
  33. package/dist/setting/setting.controller.d.ts +9 -9
  34. package/dist/setting/setting.service.d.ts +10 -10
  35. package/dist/user/constants/user.constants.d.ts +1 -0
  36. package/dist/user/constants/user.constants.d.ts.map +1 -1
  37. package/dist/user/constants/user.constants.js +2 -1
  38. package/dist/user/constants/user.constants.js.map +1 -1
  39. package/dist/user/user.controller.d.ts +15 -15
  40. package/dist/user/user.service.d.ts +39 -39
  41. package/dist/user/user.service.d.ts.map +1 -1
  42. package/dist/user/user.service.js +2 -1
  43. package/dist/user/user.service.js.map +1 -1
  44. package/hedhog/data/dashboard_item.yaml +11 -11
  45. package/hedhog/data/route.yaml +8 -0
  46. package/hedhog/frontend/app/dashboard/[slug]/dashboard-content.tsx.ejs +76 -15
  47. package/hedhog/frontend/app/dashboard/components/widgets/email-notifications.tsx.ejs +85 -61
  48. package/hedhog/frontend/app/dashboard/components/widgets/locale-config.tsx.ejs +139 -280
  49. package/hedhog/frontend/app/dashboard/components/widgets/mail-config.tsx.ejs +161 -407
  50. package/hedhog/frontend/app/dashboard/components/widgets/oauth-config.tsx.ejs +150 -271
  51. package/hedhog/frontend/app/dashboard/components/widgets/profile-card.tsx.ejs +3 -3
  52. package/hedhog/frontend/app/dashboard/components/widgets/storage-config.tsx.ejs +161 -305
  53. package/hedhog/frontend/app/dashboard/components/widgets/theme-config.tsx.ejs +184 -246
  54. package/hedhog/frontend/app/dashboard/components/widgets/user-roles.tsx.ejs +12 -14
  55. package/hedhog/frontend/messages/en.json +90 -0
  56. package/hedhog/frontend/messages/pt.json +90 -0
  57. package/hedhog/table/mail_sent_user.yaml +75 -0
  58. package/package.json +4 -4
  59. package/src/dashboard/dashboard-core/dashboard-core.controller.ts +5 -0
  60. package/src/dashboard/dashboard-core/dashboard-core.module.ts +6 -1
  61. package/src/dashboard/dashboard-core/dashboard-core.service.ts +766 -3
  62. package/src/file/file.controller.ts +37 -13
  63. package/src/file/file.service.ts +47 -5
  64. package/src/file/provider/s3.provider.ts +39 -29
  65. package/src/oauth/oauth.service.ts +8 -7
  66. package/src/user/constants/user.constants.ts +1 -0
  67. package/src/user/user.service.ts +2 -1
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
 
3
3
  import { Badge } from '@/components/ui/badge';
4
- import { Button } from '@/components/ui/button';
5
4
  import {
6
5
  Card,
7
6
  CardContent,
@@ -9,437 +8,192 @@ import {
9
8
  CardHeader,
10
9
  CardTitle,
11
10
  } from '@/components/ui/card';
12
- import { Input } from '@/components/ui/input';
13
- import { Label } from '@/components/ui/label';
14
- import {
15
- Select,
16
- SelectContent,
17
- SelectItem,
18
- SelectTrigger,
19
- SelectValue,
20
- } from '@/components/ui/select';
21
- import { Switch } from '@/components/ui/switch';
22
- import { AlertCircle, CheckCircle2, Mail, Send, Server } from 'lucide-react';
23
- import { useState } from 'react';
24
-
25
- type EmailProvider = 'smtp' | 'gmail' | 'aws_ses';
26
-
27
- interface SmtpConfig {
28
- host: string;
29
- port: string;
30
- username: string;
31
- password: string;
32
- encryption: 'tls' | 'ssl' | 'none';
33
- fromName: string;
34
- fromEmail: string;
35
- }
11
+ import { useWidgetData } from '@/hooks/use-widget-data';
12
+ import type {
13
+ DashboardCoreConfigOverviewData,
14
+ MailConfigWidgetData,
15
+ } from '@/types/widget-data';
16
+ import { CheckCircle2, Mail, Send, Server } from 'lucide-react';
17
+ import { useTranslations } from 'next-intl';
18
+ import { WidgetWrapper } from '../widget-wrapper';
36
19
 
37
- interface GmailConfig {
38
- clientId: string;
39
- clientSecret: string;
40
- refreshToken: string;
41
- fromName: string;
42
- fromEmail: string;
43
- }
20
+ const defaultMailConfigData: MailConfigWidgetData = {
21
+ status: {
22
+ isConfigured: false,
23
+ selectedProvider: null,
24
+ configuredProvider: null,
25
+ },
26
+ sender: {
27
+ from: null,
28
+ },
29
+ metrics: {
30
+ templateCount: 0,
31
+ sentCount: 0,
32
+ sentLast30Days: 0,
33
+ },
34
+ providers: [],
35
+ };
44
36
 
45
- interface AwsSesConfig {
46
- accessKeyId: string;
47
- secretAccessKey: string;
48
- region: string;
49
- fromName: string;
50
- fromEmail: string;
37
+ interface MailConfigProps {
38
+ widget?: { name?: string };
39
+ onRemove?: () => void;
51
40
  }
52
41
 
53
- const initialSmtp: SmtpConfig = {
54
- host: 'smtp.empresa.com',
55
- port: '587',
56
- username: 'noreply@empresa.com',
57
- password: '',
58
- encryption: 'tls',
59
- fromName: 'HeroAdmin',
60
- fromEmail: 'noreply@empresa.com',
42
+ const iconByProvider: Record<string, React.ElementType> = {
43
+ SMTP: Server,
44
+ GMAIL: Mail,
45
+ SES: Send,
61
46
  };
62
47
 
63
- const initialGmail: GmailConfig = {
64
- clientId: '',
65
- clientSecret: '',
66
- refreshToken: '',
67
- fromName: 'HeroAdmin',
68
- fromEmail: '',
69
- };
48
+ export default function MailConfig({ widget, onRemove }: MailConfigProps) {
49
+ const t = useTranslations('core.DashboardPage.mailConfig');
70
50
 
71
- const initialAwsSes: AwsSesConfig = {
72
- accessKeyId: '',
73
- secretAccessKey: '',
74
- region: 'us-east-1',
75
- fromName: 'HeroAdmin',
76
- fromEmail: '',
77
- };
51
+ const { data, isLoading, isError, isAccessDenied } = useWidgetData<
52
+ DashboardCoreConfigOverviewData,
53
+ MailConfigWidgetData
54
+ >({
55
+ endpoint: '/dashboard-core/config/overview',
56
+ queryKey: 'dashboard-core-config-overview',
57
+ select: (d) => d.mailConfig,
58
+ });
78
59
 
79
- const providers: {
80
- value: EmailProvider;
81
- label: string;
82
- icon: React.ReactNode;
83
- description: string;
84
- }[] = [
85
- {
86
- value: 'smtp',
87
- label: 'SMTP',
88
- icon: <Server className="h-4 w-4" />,
89
- description: 'Servidor SMTP personalizado',
90
- },
91
- {
92
- value: 'gmail',
93
- label: 'Gmail',
94
- icon: <Mail className="h-4 w-4" />,
95
- description: 'API do Google Gmail',
96
- },
97
- {
98
- value: 'aws_ses',
99
- label: 'AWS SES',
100
- icon: <Send className="h-4 w-4" />,
101
- description: 'Amazon Simple Email Service',
102
- },
103
- ];
104
-
105
- export default function EmailConfig() {
106
- const [provider, setProvider] = useState<EmailProvider>('smtp');
107
- const [smtp, setSmtp] = useState(initialSmtp);
108
- const [gmail, setGmail] = useState(initialGmail);
109
- const [awsSes, setAwsSes] = useState(initialAwsSes);
110
- const [testSent, setTestSent] = useState(false);
60
+ const mailData = data ?? defaultMailConfigData;
111
61
 
112
62
  return (
113
- <Card className="h-full">
114
- <CardHeader>
115
- <div className="flex items-center justify-between">
116
- <div className="flex items-center gap-3">
117
- <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-blue-50">
118
- <Mail className="h-5 w-5 text-blue-600" />
119
- </div>
120
- <div>
121
- <CardTitle className="text-base">Envio de E-mails</CardTitle>
122
- <CardDescription>
123
- Configure o provedor de e-mail do sistema
124
- </CardDescription>
125
- </div>
126
- </div>
127
- <Badge variant="secondary" className="bg-emerald-50 text-emerald-700">
128
- <CheckCircle2 className="mr-1 h-3 w-3" />
129
- Ativo
130
- </Badge>
131
- </div>
132
- </CardHeader>
133
- <CardContent className="space-y-6">
134
- {/* Provider Selector */}
135
- <div className="grid grid-cols-3 gap-3">
136
- {providers.map((p) => (
137
- <button
138
- key={p.value}
139
- type="button"
140
- onClick={() => setProvider(p.value)}
141
- className={`flex flex-col items-center gap-2 rounded-lg border-2 p-4 text-center transition-all ${
142
- provider === p.value
143
- ? 'border-foreground bg-foreground/3'
144
- : 'border-border hover:border-foreground/20'
145
- }`}
146
- >
147
- <div
148
- className={`flex h-9 w-9 items-center justify-center rounded-full ${
149
- provider === p.value
150
- ? 'bg-foreground text-background'
151
- : 'bg-muted text-muted-foreground'
152
- }`}
153
- >
154
- {p.icon}
155
- </div>
156
- <span className="text-sm font-medium">{p.label}</span>
157
- <span className="text-xs text-muted-foreground">
158
- {p.description}
159
- </span>
160
- </button>
161
- ))}
162
- </div>
163
-
164
- {/* SMTP Fields */}
165
- {provider === 'smtp' && (
166
- <div className="space-y-4">
167
- <div className="grid gap-4 sm:grid-cols-2">
168
- <div className="space-y-2">
169
- <Label htmlFor="smtp-host">Servidor SMTP</Label>
170
- <Input
171
- id="smtp-host"
172
- value={smtp.host}
173
- onChange={(e) => setSmtp({ ...smtp, host: e.target.value })}
174
- placeholder="smtp.exemplo.com"
175
- />
63
+ <WidgetWrapper
64
+ isLoading={isLoading}
65
+ isError={isError}
66
+ isAccessDenied={isAccessDenied}
67
+ widgetName={widget?.name ?? t('title')}
68
+ onRemove={onRemove}
69
+ >
70
+ <Card className="flex h-full min-h-0 flex-col overflow-hidden">
71
+ <CardHeader className="shrink-0">
72
+ <div className="flex items-center justify-between gap-3">
73
+ <div className="flex items-center gap-3">
74
+ <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-blue-50">
75
+ <Mail className="h-5 w-5 text-blue-600" />
176
76
  </div>
177
- <div className="space-y-2">
178
- <Label htmlFor="smtp-port">Porta</Label>
179
- <Input
180
- id="smtp-port"
181
- value={smtp.port}
182
- onChange={(e) => setSmtp({ ...smtp, port: e.target.value })}
183
- placeholder="587"
184
- />
77
+ <div>
78
+ <CardTitle className="text-base">{t('title')}</CardTitle>
79
+ <CardDescription>{t('description')}</CardDescription>
185
80
  </div>
186
81
  </div>
187
- <div className="grid gap-4 sm:grid-cols-2">
188
- <div className="space-y-2">
189
- <Label htmlFor="smtp-user">Usuario</Label>
190
- <Input
191
- id="smtp-user"
192
- value={smtp.username}
193
- onChange={(e) =>
194
- setSmtp({ ...smtp, username: e.target.value })
195
- }
196
- />
197
- </div>
198
- <div className="space-y-2">
199
- <Label htmlFor="smtp-pass">Senha</Label>
200
- <Input
201
- id="smtp-pass"
202
- type="password"
203
- value={smtp.password}
204
- onChange={(e) =>
205
- setSmtp({ ...smtp, password: e.target.value })
206
- }
207
- placeholder="********"
208
- />
209
- </div>
82
+ <Badge
83
+ variant="secondary"
84
+ className={
85
+ mailData.status.isConfigured
86
+ ? 'bg-emerald-50 text-emerald-700'
87
+ : 'bg-amber-50 text-amber-700'
88
+ }
89
+ >
90
+ {mailData.status.isConfigured ? t('configured') : t('pending')}
91
+ </Badge>
92
+ </div>
93
+ </CardHeader>
94
+ <CardContent className="flex min-h-0 flex-1 flex-col gap-4 overflow-hidden pt-0">
95
+ <div className="grid grid-cols-3 gap-2">
96
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
97
+ <p className="text-[11px] text-muted-foreground">
98
+ {t('templates')}
99
+ </p>
100
+ <p className="mt-1 text-lg font-semibold">
101
+ {mailData.metrics.templateCount}
102
+ </p>
210
103
  </div>
211
- <div className="space-y-2">
212
- <Label>Criptografia</Label>
213
- <Select
214
- value={smtp.encryption}
215
- onValueChange={(val: 'tls' | 'ssl' | 'none') =>
216
- setSmtp({ ...smtp, encryption: val })
217
- }
218
- >
219
- <SelectTrigger>
220
- <SelectValue />
221
- </SelectTrigger>
222
- <SelectContent>
223
- <SelectItem value="tls">TLS (Recomendado)</SelectItem>
224
- <SelectItem value="ssl">SSL</SelectItem>
225
- <SelectItem value="none">Nenhuma</SelectItem>
226
- </SelectContent>
227
- </Select>
104
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
105
+ <p className="text-[11px] text-muted-foreground">
106
+ {t('sentTotal')}
107
+ </p>
108
+ <p className="mt-1 text-lg font-semibold">
109
+ {mailData.metrics.sentCount}
110
+ </p>
228
111
  </div>
229
- <div className="grid gap-4 sm:grid-cols-2">
230
- <div className="space-y-2">
231
- <Label htmlFor="smtp-from-name">Nome do remetente</Label>
232
- <Input
233
- id="smtp-from-name"
234
- value={smtp.fromName}
235
- onChange={(e) =>
236
- setSmtp({ ...smtp, fromName: e.target.value })
237
- }
238
- />
239
- </div>
240
- <div className="space-y-2">
241
- <Label htmlFor="smtp-from-email">E-mail do remetente</Label>
242
- <Input
243
- id="smtp-from-email"
244
- type="email"
245
- value={smtp.fromEmail}
246
- onChange={(e) =>
247
- setSmtp({ ...smtp, fromEmail: e.target.value })
248
- }
249
- />
250
- </div>
112
+ <div className="rounded-lg border bg-muted/30 p-3 text-center">
113
+ <p className="text-[11px] text-muted-foreground">
114
+ {t('sent30Days')}
115
+ </p>
116
+ <p className="mt-1 text-lg font-semibold">
117
+ {mailData.metrics.sentLast30Days}
118
+ </p>
251
119
  </div>
252
120
  </div>
253
- )}
254
121
 
255
- {/* Gmail Fields */}
256
- {provider === 'gmail' && (
257
- <div className="space-y-4">
258
- <div className="rounded-lg border border-amber-200 bg-amber-50 p-3">
259
- <div className="flex items-start gap-2">
260
- <AlertCircle className="mt-0.5 h-4 w-4 text-amber-600" />
261
- <p className="text-xs text-amber-800">
262
- Configure as credenciais OAuth2 no Google Cloud Console.
263
- Habilite a API do Gmail e gere o Client ID e Secret.
264
- </p>
265
- </div>
266
- </div>
267
- <div className="space-y-2">
268
- <Label htmlFor="gmail-client-id">Client ID</Label>
269
- <Input
270
- id="gmail-client-id"
271
- value={gmail.clientId}
272
- onChange={(e) =>
273
- setGmail({ ...gmail, clientId: e.target.value })
274
- }
275
- placeholder="xxxxx.apps.googleusercontent.com"
276
- className="font-mono text-sm"
277
- />
278
- </div>
279
- <div className="space-y-2">
280
- <Label htmlFor="gmail-client-secret">Client Secret</Label>
281
- <Input
282
- id="gmail-client-secret"
283
- type="password"
284
- value={gmail.clientSecret}
285
- onChange={(e) =>
286
- setGmail({ ...gmail, clientSecret: e.target.value })
287
- }
288
- placeholder="GOCSPX-..."
289
- className="font-mono text-sm"
290
- />
291
- </div>
292
- <div className="space-y-2">
293
- <Label htmlFor="gmail-refresh-token">Refresh Token</Label>
294
- <Input
295
- id="gmail-refresh-token"
296
- type="password"
297
- value={gmail.refreshToken}
298
- onChange={(e) =>
299
- setGmail({ ...gmail, refreshToken: e.target.value })
300
- }
301
- className="font-mono text-sm"
302
- />
303
- </div>
304
- <div className="grid gap-4 sm:grid-cols-2">
305
- <div className="space-y-2">
306
- <Label htmlFor="gmail-from-name">Nome do remetente</Label>
307
- <Input
308
- id="gmail-from-name"
309
- value={gmail.fromName}
310
- onChange={(e) =>
311
- setGmail({ ...gmail, fromName: e.target.value })
312
- }
313
- />
314
- </div>
315
- <div className="space-y-2">
316
- <Label htmlFor="gmail-from-email">E-mail do remetente</Label>
317
- <Input
318
- id="gmail-from-email"
319
- type="email"
320
- value={gmail.fromEmail}
321
- onChange={(e) =>
322
- setGmail({ ...gmail, fromEmail: e.target.value })
323
- }
324
- placeholder="email@gmail.com"
325
- />
326
- </div>
327
- </div>
122
+ <div className="rounded-lg border p-3">
123
+ <p className="mb-2 text-xs text-muted-foreground">{t('sender')}</p>
124
+ <p className="truncate text-sm font-medium">
125
+ {mailData.sender.from || t('notSet')}
126
+ </p>
328
127
  </div>
329
- )}
330
128
 
331
- {/* AWS SES Fields */}
332
- {provider === 'aws_ses' && (
333
- <div className="space-y-4">
334
- <div className="space-y-2">
335
- <Label htmlFor="ses-access-key">Access Key ID</Label>
336
- <Input
337
- id="ses-access-key"
338
- value={awsSes.accessKeyId}
339
- onChange={(e) =>
340
- setAwsSes({ ...awsSes, accessKeyId: e.target.value })
341
- }
342
- placeholder="AKIAIOSFODNN7EXAMPLE"
343
- className="font-mono text-sm"
344
- />
345
- </div>
346
- <div className="space-y-2">
347
- <Label htmlFor="ses-secret-key">Secret Access Key</Label>
348
- <Input
349
- id="ses-secret-key"
350
- type="password"
351
- value={awsSes.secretAccessKey}
352
- onChange={(e) =>
353
- setAwsSes({ ...awsSes, secretAccessKey: e.target.value })
354
- }
355
- className="font-mono text-sm"
356
- />
129
+ <div className="min-h-0 flex-1 rounded-lg border p-3">
130
+ <div className="mb-2 flex items-center justify-between">
131
+ <p className="text-xs text-muted-foreground">{t('providers')}</p>
132
+ <Badge variant="outline" className="text-[10px]">
133
+ {t('selectedProvider', {
134
+ provider: mailData.status.selectedProvider || t('none'),
135
+ })}
136
+ </Badge>
357
137
  </div>
358
138
  <div className="space-y-2">
359
- <Label>Regiao</Label>
360
- <Select
361
- value={awsSes.region}
362
- onValueChange={(val) => setAwsSes({ ...awsSes, region: val })}
363
- >
364
- <SelectTrigger>
365
- <SelectValue />
366
- </SelectTrigger>
367
- <SelectContent>
368
- <SelectItem value="us-east-1">
369
- US East (N. Virginia)
370
- </SelectItem>
371
- <SelectItem value="us-west-2">US West (Oregon)</SelectItem>
372
- <SelectItem value="eu-west-1">EU (Ireland)</SelectItem>
373
- <SelectItem value="eu-central-1">EU (Frankfurt)</SelectItem>
374
- <SelectItem value="sa-east-1">
375
- South America (Sao Paulo)
376
- </SelectItem>
377
- <SelectItem value="ap-southeast-1">
378
- Asia Pacific (Singapore)
379
- </SelectItem>
380
- </SelectContent>
381
- </Select>
382
- </div>
383
- <div className="grid gap-4 sm:grid-cols-2">
384
- <div className="space-y-2">
385
- <Label htmlFor="ses-from-name">Nome do remetente</Label>
386
- <Input
387
- id="ses-from-name"
388
- value={awsSes.fromName}
389
- onChange={(e) =>
390
- setAwsSes({ ...awsSes, fromName: e.target.value })
391
- }
392
- />
393
- </div>
394
- <div className="space-y-2">
395
- <Label htmlFor="ses-from-email">E-mail do remetente</Label>
396
- <Input
397
- id="ses-from-email"
398
- type="email"
399
- value={awsSes.fromEmail}
400
- onChange={(e) =>
401
- setAwsSes({ ...awsSes, fromEmail: e.target.value })
402
- }
403
- placeholder="noreply@seudominio.com"
404
- />
405
- </div>
406
- </div>
407
- </div>
408
- )}
139
+ {mailData.providers.length > 0 ? (
140
+ mailData.providers.map((provider) => {
141
+ const Icon = iconByProvider[provider.id] ?? Mail;
142
+ const statusClass = provider.configured
143
+ ? 'bg-emerald-50 text-emerald-700'
144
+ : 'bg-muted text-muted-foreground';
409
145
 
410
- {/* Actions */}
411
- <div className="flex items-center justify-between border-t pt-4">
412
- <div className="flex items-center gap-2">
413
- <Switch id="email-active" defaultChecked />
414
- <Label
415
- htmlFor="email-active"
416
- className="text-sm text-muted-foreground"
417
- >
418
- Envio de e-mails ativo
419
- </Label>
420
- </div>
421
- <div className="flex gap-2">
422
- <Button
423
- variant="outline"
424
- size="sm"
425
- onClick={() => {
426
- setTestSent(true);
427
- setTimeout(() => setTestSent(false), 3000);
428
- }}
429
- >
430
- {testSent ? (
431
- <>
432
- <CheckCircle2 className="mr-1 h-3.5 w-3.5 text-emerald-600" />
433
- Enviado
434
- </>
146
+ return (
147
+ <div
148
+ key={provider.id}
149
+ className="flex items-center justify-between rounded-lg border p-2"
150
+ >
151
+ <div className="flex min-w-0 items-center gap-2">
152
+ <div className="flex h-7 w-7 items-center justify-center rounded-md bg-muted/60">
153
+ <Icon className="h-3.5 w-3.5" />
154
+ </div>
155
+ <div className="min-w-0">
156
+ <p className="truncate text-sm font-medium">
157
+ {provider.label}
158
+ </p>
159
+ <p className="truncate text-[11px] text-muted-foreground">
160
+ {provider.missingKeys.length > 0
161
+ ? t('missingKeys', {
162
+ count: provider.missingKeys.length,
163
+ })
164
+ : t('allKeysPresent')}
165
+ </p>
166
+ </div>
167
+ </div>
168
+ <div className="flex items-center gap-1.5">
169
+ {provider.selected && (
170
+ <Badge variant="outline" className="text-[10px]">
171
+ {t('selected')}
172
+ </Badge>
173
+ )}
174
+ <Badge variant="secondary" className={statusClass}>
175
+ {provider.configured ? (
176
+ <>
177
+ <CheckCircle2 className="mr-1 h-3 w-3" />
178
+ {t('configured')}
179
+ </>
180
+ ) : (
181
+ t('pending')
182
+ )}
183
+ </Badge>
184
+ </div>
185
+ </div>
186
+ );
187
+ })
435
188
  ) : (
436
- 'Enviar teste'
189
+ <p className="text-xs text-muted-foreground">
190
+ {t('noProviders')}
191
+ </p>
437
192
  )}
438
- </Button>
439
- <Button size="sm">Salvar</Button>
193
+ </div>
440
194
  </div>
441
- </div>
442
- </CardContent>
443
- </Card>
195
+ </CardContent>
196
+ </Card>
197
+ </WidgetWrapper>
444
198
  );
445
199
  }