@hed-hog/tag 0.0.186 → 0.0.191
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.
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
PageHeader,
|
|
5
|
+
PaginationFooter,
|
|
6
|
+
SearchBar,
|
|
7
|
+
} from '@/components/entity-list';
|
|
8
|
+
import {
|
|
9
|
+
AlertDialog,
|
|
10
|
+
AlertDialogAction,
|
|
11
|
+
AlertDialogCancel,
|
|
12
|
+
AlertDialogContent,
|
|
13
|
+
AlertDialogDescription,
|
|
14
|
+
AlertDialogFooter,
|
|
15
|
+
AlertDialogHeader,
|
|
16
|
+
AlertDialogTitle,
|
|
17
|
+
AlertDialogTrigger,
|
|
18
|
+
} from '@/components/ui/alert-dialog';
|
|
19
|
+
import { Badge } from '@/components/ui/badge';
|
|
20
|
+
import { Button } from '@/components/ui/button';
|
|
21
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
22
|
+
import {
|
|
23
|
+
Dialog,
|
|
24
|
+
DialogContent,
|
|
25
|
+
DialogDescription,
|
|
26
|
+
DialogFooter,
|
|
27
|
+
DialogHeader,
|
|
28
|
+
DialogTitle,
|
|
29
|
+
} from '@/components/ui/dialog';
|
|
30
|
+
import { Input } from '@/components/ui/input';
|
|
31
|
+
import { Label } from '@/components/ui/label';
|
|
32
|
+
import {
|
|
33
|
+
Select,
|
|
34
|
+
SelectContent,
|
|
35
|
+
SelectItem,
|
|
36
|
+
SelectTrigger,
|
|
37
|
+
SelectValue,
|
|
38
|
+
} from '@/components/ui/select';
|
|
39
|
+
import { useDebounce } from '@/hooks/use-debounce';
|
|
40
|
+
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
41
|
+
import { Edit, Save, Tag as TagIcon, Trash2, X } from 'lucide-react';
|
|
42
|
+
import { useTranslations } from 'next-intl';
|
|
43
|
+
import { useEffect, useState } from 'react';
|
|
44
|
+
import { toast } from 'sonner';
|
|
45
|
+
|
|
46
|
+
type PaginationResult<T> = {
|
|
47
|
+
data: T[];
|
|
48
|
+
total: number;
|
|
49
|
+
page: number;
|
|
50
|
+
pageSize: number;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
type Tag = {
|
|
54
|
+
id: number;
|
|
55
|
+
slug: string;
|
|
56
|
+
color: string;
|
|
57
|
+
status: 'active' | 'inactive';
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default function TagPage() {
|
|
61
|
+
const t = useTranslations('tag.Tag');
|
|
62
|
+
const [tags, setTags] = useState<Tag[]>([]);
|
|
63
|
+
const [selectedTag, setSelectedTag] = useState<Partial<Tag> | null>(null);
|
|
64
|
+
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
|
65
|
+
const [isNewTag, setIsNewTag] = useState(false);
|
|
66
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
67
|
+
const debouncedSearch = useDebounce(searchTerm);
|
|
68
|
+
const [page, setPage] = useState(1);
|
|
69
|
+
const [pageSize, setPageSize] = useState(10);
|
|
70
|
+
const { request } = useApp();
|
|
71
|
+
|
|
72
|
+
const {
|
|
73
|
+
data: { data, total },
|
|
74
|
+
refetch: refetchTag,
|
|
75
|
+
} = useQuery<PaginationResult<Tag>>({
|
|
76
|
+
queryKey: ['tag', debouncedSearch, page, pageSize],
|
|
77
|
+
queryFn: async () => {
|
|
78
|
+
const response = await request({
|
|
79
|
+
url: '/tag',
|
|
80
|
+
params: {
|
|
81
|
+
search: debouncedSearch,
|
|
82
|
+
page,
|
|
83
|
+
pageSize,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
return response.data as PaginationResult<Tag>;
|
|
87
|
+
},
|
|
88
|
+
initialData: {
|
|
89
|
+
data: [],
|
|
90
|
+
total: 0,
|
|
91
|
+
page: 1,
|
|
92
|
+
pageSize: 10,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const { data: statsData, refetch: refetchStats } = useQuery<any>({
|
|
97
|
+
queryKey: ['tag-stats'],
|
|
98
|
+
queryFn: async () => {
|
|
99
|
+
const response = await request({
|
|
100
|
+
url: '/tag/stats',
|
|
101
|
+
});
|
|
102
|
+
return response.data;
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (data) {
|
|
108
|
+
setTags(data);
|
|
109
|
+
}
|
|
110
|
+
}, [data]);
|
|
111
|
+
|
|
112
|
+
const handleNewTag = (): void => {
|
|
113
|
+
setSelectedTag({
|
|
114
|
+
slug: '',
|
|
115
|
+
color: '#000000',
|
|
116
|
+
status: 'active',
|
|
117
|
+
});
|
|
118
|
+
setIsNewTag(true);
|
|
119
|
+
setIsEditDialogOpen(true);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const handleEditTag = async (tag: Tag): Promise<void> => {
|
|
123
|
+
try {
|
|
124
|
+
const response = await request({
|
|
125
|
+
url: `/tag/${tag.id}`,
|
|
126
|
+
method: 'GET',
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
setSelectedTag(response.data);
|
|
130
|
+
setIsNewTag(false);
|
|
131
|
+
setIsEditDialogOpen(true);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error(error);
|
|
134
|
+
toast.error(t('errorLoading'));
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const handleSaveTag = async () => {
|
|
139
|
+
if (!selectedTag) return;
|
|
140
|
+
|
|
141
|
+
const payload = {
|
|
142
|
+
slug: selectedTag.slug,
|
|
143
|
+
color: selectedTag.color,
|
|
144
|
+
status: selectedTag.status,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
if (selectedTag.id) {
|
|
149
|
+
await request({
|
|
150
|
+
url: `/tag/${selectedTag.id}`,
|
|
151
|
+
method: 'PATCH',
|
|
152
|
+
data: payload,
|
|
153
|
+
});
|
|
154
|
+
toast.success(t('successUpdate'));
|
|
155
|
+
} else {
|
|
156
|
+
await request({
|
|
157
|
+
url: `/tag`,
|
|
158
|
+
method: 'POST',
|
|
159
|
+
data: payload,
|
|
160
|
+
});
|
|
161
|
+
toast.success(t('successCreate'));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
setIsEditDialogOpen(false);
|
|
165
|
+
await refetchTag();
|
|
166
|
+
await refetchStats();
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error(error);
|
|
169
|
+
toast.error(t('errorSave'));
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const handleDeleteTag = async (tagId: number): Promise<void> => {
|
|
174
|
+
try {
|
|
175
|
+
await request({
|
|
176
|
+
url: `/tag/${tagId}`,
|
|
177
|
+
method: 'DELETE',
|
|
178
|
+
});
|
|
179
|
+
toast.success(t('successDelete'));
|
|
180
|
+
await refetchTag();
|
|
181
|
+
await refetchStats();
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error(error);
|
|
184
|
+
toast.error(t('errorDelete'));
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const handleSearchChange = (value: string): void => {
|
|
189
|
+
setSearchTerm(value);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
refetchTag();
|
|
194
|
+
refetchStats();
|
|
195
|
+
}, [isEditDialogOpen, debouncedSearch, page, pageSize]);
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<div className="flex flex-col h-screen px-4">
|
|
199
|
+
<PageHeader
|
|
200
|
+
breadcrumbs={[
|
|
201
|
+
{ label: 'Home', href: '/' },
|
|
202
|
+
{ label: t('description') },
|
|
203
|
+
]}
|
|
204
|
+
actions={[
|
|
205
|
+
{
|
|
206
|
+
label: t('newTag'),
|
|
207
|
+
onClick: () => handleNewTag(),
|
|
208
|
+
variant: 'default',
|
|
209
|
+
},
|
|
210
|
+
]}
|
|
211
|
+
title={t('title')}
|
|
212
|
+
description={t('description')}
|
|
213
|
+
/>
|
|
214
|
+
|
|
215
|
+
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
|
|
216
|
+
<Card className="transition-shadow hover:shadow-md p-0">
|
|
217
|
+
<CardContent className="p-4">
|
|
218
|
+
<div className="flex items-center space-x-3">
|
|
219
|
+
<div className="rounded-full bg-blue-100 p-2 dark:bg-blue-900">
|
|
220
|
+
<TagIcon className="h-6 w-6 text-blue-600 dark:text-blue-400" />
|
|
221
|
+
</div>
|
|
222
|
+
<div>
|
|
223
|
+
<p className="text-sm font-medium text-muted-foreground">
|
|
224
|
+
{t('totalTags')}
|
|
225
|
+
</p>
|
|
226
|
+
<p className="text-2xl font-bold">{statsData?.total || 0}</p>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
</CardContent>
|
|
230
|
+
</Card>
|
|
231
|
+
|
|
232
|
+
<Card className="transition-shadow hover:shadow-md p-0">
|
|
233
|
+
<CardContent className="p-4">
|
|
234
|
+
<div className="flex items-center space-x-3">
|
|
235
|
+
<div className="rounded-full bg-green-100 p-2 dark:bg-green-900">
|
|
236
|
+
<TagIcon className="h-6 w-6 text-green-600 dark:text-green-400" />
|
|
237
|
+
</div>
|
|
238
|
+
<div>
|
|
239
|
+
<p className="text-sm font-medium text-muted-foreground">
|
|
240
|
+
{t('activeTags')}
|
|
241
|
+
</p>
|
|
242
|
+
<p className="text-2xl font-bold">{statsData?.active || 0}</p>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
</CardContent>
|
|
246
|
+
</Card>
|
|
247
|
+
|
|
248
|
+
<Card className="transition-shadow hover:shadow-md p-0">
|
|
249
|
+
<CardContent className="p-4">
|
|
250
|
+
<div className="flex items-center space-x-3">
|
|
251
|
+
<div className="rounded-full bg-gray-100 p-2 dark:bg-gray-900">
|
|
252
|
+
<TagIcon className="h-6 w-6 text-gray-600 dark:text-gray-400" />
|
|
253
|
+
</div>
|
|
254
|
+
<div>
|
|
255
|
+
<p className="text-sm font-medium text-muted-foreground">
|
|
256
|
+
{t('inactiveTags')}
|
|
257
|
+
</p>
|
|
258
|
+
<p className="text-2xl font-bold">{statsData?.inactive || 0}</p>
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
</CardContent>
|
|
262
|
+
</Card>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<div className="mb-4 flex flex-col gap-4 md:flex-row mt-4">
|
|
266
|
+
<SearchBar
|
|
267
|
+
searchQuery={searchTerm}
|
|
268
|
+
onSearchChange={handleSearchChange}
|
|
269
|
+
onSearch={() => refetchTag()}
|
|
270
|
+
placeholder={t('searchPlaceholder')}
|
|
271
|
+
/>
|
|
272
|
+
</div>
|
|
273
|
+
|
|
274
|
+
<div className="space-y-3">
|
|
275
|
+
{tags.length === 0 ? (
|
|
276
|
+
<Card>
|
|
277
|
+
<CardContent className="flex flex-col items-center justify-center p-12">
|
|
278
|
+
<TagIcon className="mb-4 h-12 w-12 text-muted-foreground" />
|
|
279
|
+
<p className="text-lg font-medium text-muted-foreground">
|
|
280
|
+
{t('noTagsFound')}
|
|
281
|
+
</p>
|
|
282
|
+
<p className="text-sm text-muted-foreground">
|
|
283
|
+
{searchTerm ? t('adjustSearch') : t('createNewTag')}
|
|
284
|
+
</p>
|
|
285
|
+
</CardContent>
|
|
286
|
+
</Card>
|
|
287
|
+
) : (
|
|
288
|
+
tags.map((tag) => (
|
|
289
|
+
<Card
|
|
290
|
+
key={tag.id}
|
|
291
|
+
onDoubleClick={() => handleEditTag(tag)}
|
|
292
|
+
className="cursor-pointer transition-shadow hover:shadow-md"
|
|
293
|
+
>
|
|
294
|
+
<CardContent className="flex items-center justify-between p-6">
|
|
295
|
+
<div className="flex items-center space-x-4">
|
|
296
|
+
<div
|
|
297
|
+
className="h-10 w-10 rounded-md"
|
|
298
|
+
style={{ backgroundColor: tag.color }}
|
|
299
|
+
/>
|
|
300
|
+
<div>
|
|
301
|
+
<div className="flex items-center gap-2">
|
|
302
|
+
<h2 className="font-semibold text-lg">#{tag.slug}</h2>
|
|
303
|
+
<Badge
|
|
304
|
+
variant={
|
|
305
|
+
tag.status === 'active' ? 'default' : 'secondary'
|
|
306
|
+
}
|
|
307
|
+
>
|
|
308
|
+
{tag.status === 'active' ? t('active') : t('inactive')}
|
|
309
|
+
</Badge>
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
</div>
|
|
313
|
+
<div className="flex space-x-2">
|
|
314
|
+
<Button
|
|
315
|
+
variant="ghost"
|
|
316
|
+
size="icon"
|
|
317
|
+
onClick={() => handleEditTag(tag)}
|
|
318
|
+
>
|
|
319
|
+
<Edit className="h-4 w-4" />
|
|
320
|
+
</Button>
|
|
321
|
+
<AlertDialog>
|
|
322
|
+
<AlertDialogTrigger asChild>
|
|
323
|
+
<Button variant="ghost" size="icon">
|
|
324
|
+
<Trash2 className="h-4 w-4 text-destructive" />
|
|
325
|
+
</Button>
|
|
326
|
+
</AlertDialogTrigger>
|
|
327
|
+
<AlertDialogContent>
|
|
328
|
+
<AlertDialogHeader>
|
|
329
|
+
<AlertDialogTitle>
|
|
330
|
+
{t('confirmDelete')}
|
|
331
|
+
</AlertDialogTitle>
|
|
332
|
+
<AlertDialogDescription>
|
|
333
|
+
{t('deleteDescription')}
|
|
334
|
+
</AlertDialogDescription>
|
|
335
|
+
</AlertDialogHeader>
|
|
336
|
+
<AlertDialogFooter>
|
|
337
|
+
<AlertDialogCancel>{t('cancel')}</AlertDialogCancel>
|
|
338
|
+
<AlertDialogAction
|
|
339
|
+
onClick={() => handleDeleteTag(tag.id)}
|
|
340
|
+
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
341
|
+
>
|
|
342
|
+
{t('delete')}
|
|
343
|
+
</AlertDialogAction>
|
|
344
|
+
</AlertDialogFooter>
|
|
345
|
+
</AlertDialogContent>
|
|
346
|
+
</AlertDialog>
|
|
347
|
+
</div>
|
|
348
|
+
</CardContent>
|
|
349
|
+
</Card>
|
|
350
|
+
))
|
|
351
|
+
)}
|
|
352
|
+
</div>
|
|
353
|
+
|
|
354
|
+
<PaginationFooter
|
|
355
|
+
currentPage={page}
|
|
356
|
+
pageSize={pageSize}
|
|
357
|
+
totalItems={total}
|
|
358
|
+
onPageChange={setPage}
|
|
359
|
+
onPageSizeChange={setPageSize}
|
|
360
|
+
pageSizeOptions={[10, 20, 30, 40, 50]}
|
|
361
|
+
/>
|
|
362
|
+
|
|
363
|
+
<Dialog open={isEditDialogOpen} onOpenChange={setIsEditDialogOpen}>
|
|
364
|
+
<DialogContent className="max-h-[90vh] max-w-2xl overflow-y-auto">
|
|
365
|
+
<DialogHeader>
|
|
366
|
+
<DialogTitle>
|
|
367
|
+
{isNewTag ? t('createTag') : t('editTag')}
|
|
368
|
+
</DialogTitle>
|
|
369
|
+
<DialogDescription>
|
|
370
|
+
{isNewTag ? t('createDescription') : t('editDescription')}
|
|
371
|
+
</DialogDescription>
|
|
372
|
+
</DialogHeader>
|
|
373
|
+
|
|
374
|
+
<div className="space-y-4">
|
|
375
|
+
<div className="space-y-2">
|
|
376
|
+
<Label htmlFor="slug">{t('slug')}</Label>
|
|
377
|
+
<Input
|
|
378
|
+
id="slug"
|
|
379
|
+
value={selectedTag?.slug || ''}
|
|
380
|
+
onChange={(e) =>
|
|
381
|
+
setSelectedTag({ ...selectedTag, slug: e.target.value })
|
|
382
|
+
}
|
|
383
|
+
placeholder={t('slugPlaceholder')}
|
|
384
|
+
/>
|
|
385
|
+
</div>
|
|
386
|
+
|
|
387
|
+
<div className="space-y-2">
|
|
388
|
+
<Label htmlFor="color">{t('color')}</Label>
|
|
389
|
+
<div className="flex gap-2">
|
|
390
|
+
<Input
|
|
391
|
+
id="color"
|
|
392
|
+
type="color"
|
|
393
|
+
value={selectedTag?.color || '#000000'}
|
|
394
|
+
onChange={(e) =>
|
|
395
|
+
setSelectedTag({ ...selectedTag, color: e.target.value })
|
|
396
|
+
}
|
|
397
|
+
className="h-10 w-20"
|
|
398
|
+
/>
|
|
399
|
+
<Input
|
|
400
|
+
value={selectedTag?.color || '#000000'}
|
|
401
|
+
onChange={(e) =>
|
|
402
|
+
setSelectedTag({ ...selectedTag, color: e.target.value })
|
|
403
|
+
}
|
|
404
|
+
placeholder={t('colorPlaceholder')}
|
|
405
|
+
/>
|
|
406
|
+
</div>
|
|
407
|
+
</div>
|
|
408
|
+
|
|
409
|
+
<div className="space-y-2">
|
|
410
|
+
<Label htmlFor="status">{t('status')}</Label>
|
|
411
|
+
<Select
|
|
412
|
+
value={selectedTag?.status || 'active'}
|
|
413
|
+
onValueChange={(value: 'active' | 'inactive') =>
|
|
414
|
+
setSelectedTag({ ...selectedTag, status: value })
|
|
415
|
+
}
|
|
416
|
+
>
|
|
417
|
+
<SelectTrigger className="w-full" id="status">
|
|
418
|
+
<SelectValue />
|
|
419
|
+
</SelectTrigger>
|
|
420
|
+
<SelectContent>
|
|
421
|
+
<SelectItem value="active">{t('active')}</SelectItem>
|
|
422
|
+
<SelectItem value="inactive">{t('inactive')}</SelectItem>
|
|
423
|
+
</SelectContent>
|
|
424
|
+
</Select>
|
|
425
|
+
</div>
|
|
426
|
+
</div>
|
|
427
|
+
|
|
428
|
+
<DialogFooter>
|
|
429
|
+
<Button
|
|
430
|
+
variant="outline"
|
|
431
|
+
onClick={() => setIsEditDialogOpen(false)}
|
|
432
|
+
>
|
|
433
|
+
<X className="mr-2 h-4 w-4" />
|
|
434
|
+
{t('cancel')}
|
|
435
|
+
</Button>
|
|
436
|
+
<Button onClick={handleSaveTag}>
|
|
437
|
+
<Save className="mr-2 h-4 w-4" />
|
|
438
|
+
{t('save')}
|
|
439
|
+
</Button>
|
|
440
|
+
</DialogFooter>
|
|
441
|
+
</DialogContent>
|
|
442
|
+
</Dialog>
|
|
443
|
+
</div>
|
|
444
|
+
);
|
|
445
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Tag": {
|
|
3
|
+
"title": "Tags",
|
|
4
|
+
"description": "Manage all system tags",
|
|
5
|
+
"newTag": "New Tag",
|
|
6
|
+
"totalTags": "Total Tags",
|
|
7
|
+
"activeTags": "Active Tags",
|
|
8
|
+
"inactiveTags": "Inactive Tags",
|
|
9
|
+
"searchPlaceholder": "Search tags...",
|
|
10
|
+
"noTagsFound": "No tags found",
|
|
11
|
+
"adjustSearch": "Try adjusting your search",
|
|
12
|
+
"createNewTag": "Start by creating a new tag",
|
|
13
|
+
"active": "Active",
|
|
14
|
+
"inactive": "Inactive",
|
|
15
|
+
"confirmDelete": "Confirm deletion",
|
|
16
|
+
"deleteDescription": "Are you sure you want to delete this tag? This action cannot be undone.",
|
|
17
|
+
"cancel": "Cancel",
|
|
18
|
+
"delete": "Delete",
|
|
19
|
+
"editTag": "Edit Tag",
|
|
20
|
+
"createTag": "Create Tag",
|
|
21
|
+
"editDescription": "Edit the fields below to update the tag.",
|
|
22
|
+
"createDescription": "Fill in the fields below to create a new tag.",
|
|
23
|
+
"slug": "Slug",
|
|
24
|
+
"slugPlaceholder": "tag-slug",
|
|
25
|
+
"color": "Color",
|
|
26
|
+
"colorPlaceholder": "#000000",
|
|
27
|
+
"status": "Status",
|
|
28
|
+
"save": "Save",
|
|
29
|
+
"errorLoading": "Error loading tag data.",
|
|
30
|
+
"successUpdate": "Tag updated successfully!",
|
|
31
|
+
"successCreate": "Tag created successfully!",
|
|
32
|
+
"errorSave": "Error saving tag.",
|
|
33
|
+
"successDelete": "Tag deleted successfully!",
|
|
34
|
+
"errorDelete": "Error deleting tag."
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Tag": {
|
|
3
|
+
"title": "Tags",
|
|
4
|
+
"description": "Gerencie todas as tags do sistema",
|
|
5
|
+
"newTag": "Nova Tag",
|
|
6
|
+
"totalTags": "Total de Tags",
|
|
7
|
+
"activeTags": "Tags Ativas",
|
|
8
|
+
"inactiveTags": "Tags Inativas",
|
|
9
|
+
"searchPlaceholder": "Buscar tags...",
|
|
10
|
+
"noTagsFound": "Nenhuma tag encontrada",
|
|
11
|
+
"adjustSearch": "Tente ajustar sua busca",
|
|
12
|
+
"createNewTag": "Comece criando uma nova tag",
|
|
13
|
+
"active": "Ativa",
|
|
14
|
+
"inactive": "Inativa",
|
|
15
|
+
"confirmDelete": "Confirmar exclusão",
|
|
16
|
+
"deleteDescription": "Tem certeza que deseja excluir esta tag? Esta ação não pode ser desfeita.",
|
|
17
|
+
"cancel": "Cancelar",
|
|
18
|
+
"delete": "Excluir",
|
|
19
|
+
"editTag": "Editar Tag",
|
|
20
|
+
"createTag": "Nova Tag",
|
|
21
|
+
"editDescription": "Edite os campos abaixo para atualizar a tag.",
|
|
22
|
+
"createDescription": "Preencha os campos abaixo para criar uma nova tag.",
|
|
23
|
+
"slug": "Slug",
|
|
24
|
+
"slugPlaceholder": "slug-da-tag",
|
|
25
|
+
"color": "Cor",
|
|
26
|
+
"colorPlaceholder": "#000000",
|
|
27
|
+
"status": "Status",
|
|
28
|
+
"save": "Salvar",
|
|
29
|
+
"errorLoading": "Erro ao carregar os dados da tag.",
|
|
30
|
+
"successUpdate": "Tag atualizada com sucesso!",
|
|
31
|
+
"successCreate": "Tag criada com sucesso!",
|
|
32
|
+
"errorSave": "Erro ao salvar a tag.",
|
|
33
|
+
"successDelete": "Tag excluída com sucesso!",
|
|
34
|
+
"errorDelete": "Erro ao excluir a tag."
|
|
35
|
+
}
|
|
36
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hed-hog/tag",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.191",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"@nestjs/core": "^11",
|
|
10
10
|
"@nestjs/jwt": "^11",
|
|
11
11
|
"@nestjs/mapped-types": "*",
|
|
12
|
+
"@hed-hog/core": "0.0.191",
|
|
13
|
+
"@hed-hog/api-pagination": "0.0.5",
|
|
12
14
|
"@hed-hog/api-prisma": "0.0.4",
|
|
13
15
|
"@hed-hog/api": "0.0.3",
|
|
14
|
-
"@hed-hog/core": "0.0.186",
|
|
15
|
-
"@hed-hog/api-pagination": "0.0.5",
|
|
16
16
|
"@hed-hog/api-locale": "0.0.11"
|
|
17
17
|
},
|
|
18
18
|
"exports": {
|