@hed-hog/operations 0.0.301 → 0.0.303
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.
- package/dist/operations.service.d.ts +1 -0
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +77 -37
- package/dist/operations.service.js.map +1 -1
- package/hedhog/data/menu.yaml +1 -22
- package/hedhog/frontend/app/contracts/page.tsx.ejs +99 -102
- package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +87 -93
- package/hedhog/frontend/app/departments/page.tsx.ejs +95 -74
- package/hedhog/frontend/app/page.tsx.ejs +3 -341
- package/hedhog/frontend/app/projects/page.tsx.ejs +133 -127
- package/package.json +6 -6
- package/src/operations.service.ts +70 -7
package/hedhog/data/menu.yaml
CHANGED
|
@@ -16,27 +16,6 @@
|
|
|
16
16
|
- where:
|
|
17
17
|
slug: admin-operations-director
|
|
18
18
|
|
|
19
|
-
- menu_id:
|
|
20
|
-
where:
|
|
21
|
-
slug: /operations
|
|
22
|
-
icon: layout-dashboard
|
|
23
|
-
url: /operations
|
|
24
|
-
name:
|
|
25
|
-
en: Dashboard
|
|
26
|
-
pt: Dashboard
|
|
27
|
-
slug: /operations/dashboard
|
|
28
|
-
order: 111
|
|
29
|
-
relations:
|
|
30
|
-
role:
|
|
31
|
-
- where:
|
|
32
|
-
slug: admin
|
|
33
|
-
- where:
|
|
34
|
-
slug: admin-operations-collaborator
|
|
35
|
-
- where:
|
|
36
|
-
slug: admin-operations-supervisor
|
|
37
|
-
- where:
|
|
38
|
-
slug: admin-operations-director
|
|
39
|
-
|
|
40
19
|
- menu_id:
|
|
41
20
|
where:
|
|
42
21
|
slug: /operations
|
|
@@ -156,7 +135,7 @@
|
|
|
156
135
|
- menu_id:
|
|
157
136
|
where:
|
|
158
137
|
slug: /operations
|
|
159
|
-
icon:
|
|
138
|
+
icon: calendar-time
|
|
160
139
|
url: /operations/time-off
|
|
161
140
|
name:
|
|
162
141
|
en: Time Off
|
|
@@ -722,111 +722,108 @@ export default function OperationsContractsPage() {
|
|
|
722
722
|
})}
|
|
723
723
|
</div>
|
|
724
724
|
) : (
|
|
725
|
-
<
|
|
726
|
-
<
|
|
727
|
-
<
|
|
728
|
-
<
|
|
729
|
-
<
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
{contract.name ||
|
|
763
|
-
contract.code ||
|
|
764
|
-
commonT('labels.notAvailable')}
|
|
765
|
-
</div>
|
|
766
|
-
<div className="truncate text-xs text-muted-foreground">
|
|
767
|
-
{[
|
|
768
|
-
contract.code,
|
|
769
|
-
contract.contractTemplateName,
|
|
770
|
-
contract.mainRelatedPartyName,
|
|
771
|
-
getContractOptionLabel(
|
|
772
|
-
'originTypes',
|
|
773
|
-
contract.originType
|
|
774
|
-
),
|
|
775
|
-
]
|
|
776
|
-
.filter(Boolean)
|
|
777
|
-
.join(' • ') || commonT('labels.notAvailable')}
|
|
778
|
-
</div>
|
|
779
|
-
</div>
|
|
780
|
-
</TableCell>
|
|
781
|
-
<TableCell>
|
|
782
|
-
<StatusBadge
|
|
783
|
-
label={getContractOptionLabel(
|
|
784
|
-
'statuses',
|
|
785
|
-
contract.status
|
|
786
|
-
)}
|
|
787
|
-
className={getStatusBadgeClass(contract.status)}
|
|
788
|
-
/>
|
|
789
|
-
</TableCell>
|
|
790
|
-
<TableCell className="hidden md:table-cell">
|
|
791
|
-
<StatusBadge
|
|
792
|
-
label={getContractOptionLabel(
|
|
793
|
-
'signatureStatuses',
|
|
794
|
-
contract.signatureStatus
|
|
795
|
-
)}
|
|
796
|
-
className={getStatusBadgeClass(
|
|
797
|
-
contract.signatureStatus
|
|
798
|
-
)}
|
|
799
|
-
/>
|
|
800
|
-
</TableCell>
|
|
801
|
-
<TableCell className="hidden lg:table-cell">
|
|
802
|
-
<div className="truncate">
|
|
803
|
-
{getContractOptionLabel(
|
|
804
|
-
'contractTypes',
|
|
805
|
-
contract.contractType
|
|
806
|
-
)}
|
|
807
|
-
</div>
|
|
808
|
-
</TableCell>
|
|
809
|
-
<TableCell className="hidden xl:table-cell">
|
|
810
|
-
<div className="truncate">
|
|
811
|
-
{contract.clientName ||
|
|
725
|
+
<div className="overflow-x-auto rounded-md border">
|
|
726
|
+
<Table className="table-fixed">
|
|
727
|
+
<TableHeader>
|
|
728
|
+
<TableRow>
|
|
729
|
+
<TableHead className="w-[34%]">
|
|
730
|
+
{t('columns.title')}
|
|
731
|
+
</TableHead>
|
|
732
|
+
<TableHead>{commonT('labels.status')}</TableHead>
|
|
733
|
+
<TableHead className="hidden md:table-cell">
|
|
734
|
+
{t('columns.signatureStatus')}
|
|
735
|
+
</TableHead>
|
|
736
|
+
<TableHead className="hidden lg:table-cell">
|
|
737
|
+
{t('columns.type')}
|
|
738
|
+
</TableHead>
|
|
739
|
+
<TableHead className="hidden xl:table-cell">
|
|
740
|
+
{commonT('labels.client')}
|
|
741
|
+
</TableHead>
|
|
742
|
+
<TableHead className="hidden 2xl:table-cell">
|
|
743
|
+
{t('columns.financials')}
|
|
744
|
+
</TableHead>
|
|
745
|
+
<TableHead className="w-30 text-right sm:w-42.5">
|
|
746
|
+
{commonT('labels.actions')}
|
|
747
|
+
</TableHead>
|
|
748
|
+
</TableRow>
|
|
749
|
+
</TableHeader>
|
|
750
|
+
<TableBody>
|
|
751
|
+
{filteredRows.map((contract) => {
|
|
752
|
+
const financialTotal =
|
|
753
|
+
(contract.valueAmount ?? 0) + (contract.revenueAmount ?? 0);
|
|
754
|
+
|
|
755
|
+
return (
|
|
756
|
+
<TableRow key={contract.id} className="hover:bg-muted/30">
|
|
757
|
+
<TableCell>
|
|
758
|
+
<div className="min-w-0">
|
|
759
|
+
<div className="truncate font-medium">
|
|
760
|
+
{contract.name ||
|
|
761
|
+
contract.code ||
|
|
812
762
|
commonT('labels.notAvailable')}
|
|
813
763
|
</div>
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
764
|
+
<div className="truncate text-xs text-muted-foreground">
|
|
765
|
+
{[
|
|
766
|
+
contract.code,
|
|
767
|
+
contract.contractTemplateName,
|
|
768
|
+
contract.mainRelatedPartyName,
|
|
769
|
+
getContractOptionLabel(
|
|
770
|
+
'originTypes',
|
|
771
|
+
contract.originType
|
|
772
|
+
),
|
|
773
|
+
]
|
|
774
|
+
.filter(Boolean)
|
|
775
|
+
.join(' • ') || commonT('labels.notAvailable')}
|
|
821
776
|
</div>
|
|
822
|
-
</
|
|
823
|
-
</
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
777
|
+
</div>
|
|
778
|
+
</TableCell>
|
|
779
|
+
<TableCell>
|
|
780
|
+
<StatusBadge
|
|
781
|
+
label={getContractOptionLabel(
|
|
782
|
+
'statuses',
|
|
783
|
+
contract.status
|
|
784
|
+
)}
|
|
785
|
+
className={getStatusBadgeClass(contract.status)}
|
|
786
|
+
/>
|
|
787
|
+
</TableCell>
|
|
788
|
+
<TableCell className="hidden md:table-cell">
|
|
789
|
+
<StatusBadge
|
|
790
|
+
label={getContractOptionLabel(
|
|
791
|
+
'signatureStatuses',
|
|
792
|
+
contract.signatureStatus
|
|
793
|
+
)}
|
|
794
|
+
className={getStatusBadgeClass(
|
|
795
|
+
contract.signatureStatus
|
|
796
|
+
)}
|
|
797
|
+
/>
|
|
798
|
+
</TableCell>
|
|
799
|
+
<TableCell className="hidden lg:table-cell">
|
|
800
|
+
<div className="truncate">
|
|
801
|
+
{getContractOptionLabel(
|
|
802
|
+
'contractTypes',
|
|
803
|
+
contract.contractType
|
|
804
|
+
)}
|
|
805
|
+
</div>
|
|
806
|
+
</TableCell>
|
|
807
|
+
<TableCell className="hidden xl:table-cell">
|
|
808
|
+
<div className="truncate">
|
|
809
|
+
{contract.clientName ||
|
|
810
|
+
commonT('labels.notAvailable')}
|
|
811
|
+
</div>
|
|
812
|
+
</TableCell>
|
|
813
|
+
<TableCell className="hidden 2xl:table-cell">
|
|
814
|
+
{formatCurrency(financialTotal)}
|
|
815
|
+
</TableCell>
|
|
816
|
+
<TableCell>
|
|
817
|
+
<div className="flex justify-end">
|
|
818
|
+
{renderContractActions(contract, 'end')}
|
|
819
|
+
</div>
|
|
820
|
+
</TableCell>
|
|
821
|
+
</TableRow>
|
|
822
|
+
);
|
|
823
|
+
})}
|
|
824
|
+
</TableBody>
|
|
825
|
+
</Table>
|
|
826
|
+
</div>
|
|
830
827
|
)
|
|
831
828
|
) : (
|
|
832
829
|
<EmptyState
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { EmptyState, Page, SearchBar } from '@/components/entity-list';
|
|
4
4
|
import { Button } from '@/components/ui/button';
|
|
5
|
-
import { Card, CardContent } from '@/components/ui/card';
|
|
6
5
|
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
7
6
|
import {
|
|
8
7
|
Sheet,
|
|
@@ -256,99 +255,94 @@ export default function OperationsContractTemplatesPage() {
|
|
|
256
255
|
/>
|
|
257
256
|
|
|
258
257
|
{isLoading ? (
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
</CardContent>
|
|
263
|
-
</Card>
|
|
258
|
+
<div className="rounded-md border px-4 py-6 text-sm text-muted-foreground">
|
|
259
|
+
{commonT('actions.refresh')}...
|
|
260
|
+
</div>
|
|
264
261
|
) : filteredTemplates.length ? (
|
|
265
|
-
<
|
|
266
|
-
<
|
|
267
|
-
<
|
|
268
|
-
<
|
|
269
|
-
<
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
<
|
|
284
|
-
|
|
285
|
-
<
|
|
286
|
-
<
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
</div>
|
|
350
|
-
</CardContent>
|
|
351
|
-
</Card>
|
|
262
|
+
<div className="overflow-x-auto rounded-md border">
|
|
263
|
+
<Table>
|
|
264
|
+
<TableHeader>
|
|
265
|
+
<TableRow>
|
|
266
|
+
<TableHead>{t('columns.name')}</TableHead>
|
|
267
|
+
<TableHead>{t('columns.code')}</TableHead>
|
|
268
|
+
<TableHead>{t('columns.type')}</TableHead>
|
|
269
|
+
<TableHead>{t('columns.usageCount')}</TableHead>
|
|
270
|
+
<TableHead>{commonT('labels.billingModel')}</TableHead>
|
|
271
|
+
<TableHead>{t('columns.updatedAt')}</TableHead>
|
|
272
|
+
<TableHead>{commonT('labels.status')}</TableHead>
|
|
273
|
+
<TableHead className="text-right">
|
|
274
|
+
{commonT('labels.actions')}
|
|
275
|
+
</TableHead>
|
|
276
|
+
</TableRow>
|
|
277
|
+
</TableHeader>
|
|
278
|
+
<TableBody>
|
|
279
|
+
{filteredTemplates.map((template) => (
|
|
280
|
+
<TableRow key={template.id}>
|
|
281
|
+
<TableCell>
|
|
282
|
+
<div className="space-y-1">
|
|
283
|
+
<div className="font-medium">{template.name}</div>
|
|
284
|
+
<div className="max-w-md text-xs text-muted-foreground">
|
|
285
|
+
{template.description || commonT('labels.notAvailable')}
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
</TableCell>
|
|
289
|
+
<TableCell>{template.code || '—'}</TableCell>
|
|
290
|
+
<TableCell>
|
|
291
|
+
{formatEnumLabel(template.contractType)}
|
|
292
|
+
</TableCell>
|
|
293
|
+
<TableCell>{template.usageCount ?? 0}</TableCell>
|
|
294
|
+
<TableCell>
|
|
295
|
+
{formatEnumLabel(template.billingModel)}
|
|
296
|
+
</TableCell>
|
|
297
|
+
<TableCell>{formatDate(template.updatedAt)}</TableCell>
|
|
298
|
+
<TableCell>
|
|
299
|
+
<StatusBadge
|
|
300
|
+
label={formatEnumLabel(template.status)}
|
|
301
|
+
className={getStatusBadgeClass(template.status)}
|
|
302
|
+
/>
|
|
303
|
+
</TableCell>
|
|
304
|
+
<TableCell>
|
|
305
|
+
<div className="flex justify-end gap-2">
|
|
306
|
+
<Button
|
|
307
|
+
type="button"
|
|
308
|
+
variant="outline"
|
|
309
|
+
size="sm"
|
|
310
|
+
className="cursor-pointer"
|
|
311
|
+
asChild
|
|
312
|
+
>
|
|
313
|
+
<Link
|
|
314
|
+
href={`/operations/contracts?template=${template.id}`}
|
|
315
|
+
>
|
|
316
|
+
{commonT('actions.useTemplate')}
|
|
317
|
+
</Link>
|
|
318
|
+
</Button>
|
|
319
|
+
<Button
|
|
320
|
+
type="button"
|
|
321
|
+
variant="outline"
|
|
322
|
+
size="icon"
|
|
323
|
+
className="cursor-pointer"
|
|
324
|
+
onClick={() => openEditSheet(template)}
|
|
325
|
+
>
|
|
326
|
+
<Pencil className="size-4" />
|
|
327
|
+
</Button>
|
|
328
|
+
<Button
|
|
329
|
+
type="button"
|
|
330
|
+
variant="outline"
|
|
331
|
+
size="sm"
|
|
332
|
+
className="cursor-pointer"
|
|
333
|
+
onClick={() => void toggleTemplateStatus(template)}
|
|
334
|
+
>
|
|
335
|
+
{template.status === 'active'
|
|
336
|
+
? commonT('actions.deactivate')
|
|
337
|
+
: commonT('actions.activate')}
|
|
338
|
+
</Button>
|
|
339
|
+
</div>
|
|
340
|
+
</TableCell>
|
|
341
|
+
</TableRow>
|
|
342
|
+
))}
|
|
343
|
+
</TableBody>
|
|
344
|
+
</Table>
|
|
345
|
+
</div>
|
|
352
346
|
) : (
|
|
353
347
|
<EmptyState
|
|
354
348
|
icon={<FileStack className="size-12" />}
|