@hed-hog/operations 0.0.325 → 0.0.326
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/controllers/operations-collaborators.controller.d.ts +5 -0
- package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
- package/dist/operations.service.d.ts +9 -1
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +140 -26
- package/dist/operations.service.js.map +1 -1
- package/hedhog/data/integration_event_catalog.yaml +313 -0
- package/hedhog/data/setting_group.yaml +21 -0
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +410 -23
- package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +504 -375
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +258 -230
- package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +225 -162
- package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +484 -230
- package/hedhog/frontend/app/_lib/api.ts.ejs +13 -4
- package/hedhog/frontend/app/_lib/hooks/use-mention-items.ts.ejs +28 -0
- package/hedhog/frontend/app/_lib/types.ts.ejs +30 -29
- package/hedhog/frontend/app/my-tasks/page.tsx.ejs +347 -236
- package/hedhog/frontend/app/reports/projects/page.tsx.ejs +31 -7
- package/hedhog/frontend/messages/en.json +38 -55
- package/hedhog/frontend/messages/en.json.ejs +21 -4
- package/hedhog/frontend/messages/pt.json +36 -55
- package/hedhog/frontend/messages/pt.json.ejs +14 -3
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts +1 -0
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts.map +1 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.ts +1 -0
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts +1 -0
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts.map +1 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.ts +1 -0
- package/hedhog/table/operations_collaborator.yaml +5 -0
- package/hedhog/table/operations_collaborator_compensation_history.yaml +4 -0
- package/package.json +5 -5
- package/src/operations.service.ts +202 -26
|
@@ -123,6 +123,7 @@ import {
|
|
|
123
123
|
YAxis,
|
|
124
124
|
} from 'recharts';
|
|
125
125
|
import { fetchOperations, mutateOperations } from '../_lib/api';
|
|
126
|
+
import { useMentionItems } from '../_lib/hooks/use-mention-items';
|
|
126
127
|
import { useOperationsAccess } from '../_lib/hooks/use-operations-access';
|
|
127
128
|
import type {
|
|
128
129
|
OperationsProjectDetails,
|
|
@@ -142,7 +143,11 @@ import { ProjectCostsSection } from './project-costs-section';
|
|
|
142
143
|
import { ProjectFormScreen } from './project-form-screen';
|
|
143
144
|
import { SectionCard } from './section-card';
|
|
144
145
|
import { StatusBadge } from './status-badge';
|
|
145
|
-
import {
|
|
146
|
+
import {
|
|
147
|
+
TaskCommentsSection,
|
|
148
|
+
TaskDetailSheet,
|
|
149
|
+
type TaskDetailSheetData,
|
|
150
|
+
} from './task-detail-sheet';
|
|
146
151
|
import { TaskFileAttachments } from './task-file-attachments';
|
|
147
152
|
|
|
148
153
|
type BoardColumnId = 'todo' | 'doing' | 'review' | 'done';
|
|
@@ -873,7 +878,7 @@ function ProjectDetailsSkeleton() {
|
|
|
873
878
|
<Skeleton className="h-8 w-72" />
|
|
874
879
|
<Skeleton className="h-4 w-full max-w-md" />
|
|
875
880
|
</div>
|
|
876
|
-
<div className="hidden
|
|
881
|
+
<div className="hidden shrink-0 gap-2 lg:flex">
|
|
877
882
|
<Skeleton className="h-9 w-20 rounded-lg" />
|
|
878
883
|
<Skeleton className="h-9 w-28 rounded-lg" />
|
|
879
884
|
<Skeleton className="h-9 w-9 rounded-lg" />
|
|
@@ -1093,6 +1098,7 @@ export function ProjectDetailsScreen({ projectId }: { projectId: number }) {
|
|
|
1093
1098
|
const contractT = useTranslations('operations.ContractFormPage');
|
|
1094
1099
|
const { request, currentLocaleCode, getSettingValue } = useApp();
|
|
1095
1100
|
const access = useOperationsAccess();
|
|
1101
|
+
const mentionItems = useMentionItems(request);
|
|
1096
1102
|
const isLimitedView = !access.isDirector && !access.isSupervisor;
|
|
1097
1103
|
const router = useRouter();
|
|
1098
1104
|
const pathname = usePathname();
|
|
@@ -3028,7 +3034,7 @@ export function ProjectDetailsScreen({ projectId }: { projectId: number }) {
|
|
|
3028
3034
|
{(isOver) => (
|
|
3029
3035
|
<div
|
|
3030
3036
|
className={[
|
|
3031
|
-
'flex min-h-
|
|
3037
|
+
'flex min-h-128 flex-col overflow-hidden rounded-3xl border bg-linear-to-b p-3 transition-all',
|
|
3032
3038
|
getColumnClassName(column.id),
|
|
3033
3039
|
isOver
|
|
3034
3040
|
? 'border-primary shadow-lg ring-2 ring-primary/15'
|
|
@@ -3103,11 +3109,7 @@ export function ProjectDetailsScreen({ projectId }: { projectId: number }) {
|
|
|
3103
3109
|
: 'hover:border-primary/40 hover:shadow-lg',
|
|
3104
3110
|
].join(' ')}
|
|
3105
3111
|
onClick={() =>
|
|
3106
|
-
|
|
3107
|
-
...task,
|
|
3108
|
-
projectName: project?.name,
|
|
3109
|
-
projectCode: project?.code,
|
|
3110
|
-
})
|
|
3112
|
+
!isDragging && openEditTaskForm(task)
|
|
3111
3113
|
}
|
|
3112
3114
|
onKeyDown={(event) => {
|
|
3113
3115
|
if (
|
|
@@ -3115,11 +3117,7 @@ export function ProjectDetailsScreen({ projectId }: { projectId: number }) {
|
|
|
3115
3117
|
event.key === ' '
|
|
3116
3118
|
) {
|
|
3117
3119
|
event.preventDefault();
|
|
3118
|
-
|
|
3119
|
-
...task,
|
|
3120
|
-
projectName: project?.name,
|
|
3121
|
-
projectCode: project?.code,
|
|
3122
|
-
});
|
|
3120
|
+
openEditTaskForm(task);
|
|
3123
3121
|
}
|
|
3124
3122
|
}}
|
|
3125
3123
|
>
|
|
@@ -4131,6 +4129,7 @@ export function ProjectDetailsScreen({ projectId }: { projectId: number }) {
|
|
|
4131
4129
|
<TaskDetailSheet
|
|
4132
4130
|
task={selectedTask}
|
|
4133
4131
|
open={selectedTask !== null}
|
|
4132
|
+
defaultTab="comments"
|
|
4134
4133
|
onOpenChange={(open) => {
|
|
4135
4134
|
if (!open) {
|
|
4136
4135
|
setSelectedTask(null);
|
|
@@ -4228,7 +4227,7 @@ export function ProjectDetailsScreen({ projectId }: { projectId: number }) {
|
|
|
4228
4227
|
}}
|
|
4229
4228
|
>
|
|
4230
4229
|
<SheetContent className="flex w-full flex-col overflow-hidden sm:max-w-xl">
|
|
4231
|
-
<SheetHeader>
|
|
4230
|
+
<SheetHeader className="shrink-0">
|
|
4232
4231
|
<SheetTitle>
|
|
4233
4232
|
{editingTaskId
|
|
4234
4233
|
? t('taskForm.titleEdit')
|
|
@@ -4236,234 +4235,263 @@ export function ProjectDetailsScreen({ projectId }: { projectId: number }) {
|
|
|
4236
4235
|
</SheetTitle>
|
|
4237
4236
|
</SheetHeader>
|
|
4238
4237
|
|
|
4239
|
-
<
|
|
4240
|
-
<
|
|
4241
|
-
<
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4238
|
+
<Tabs defaultValue="info" className="flex min-h-0 flex-1 flex-col">
|
|
4239
|
+
<TabsList className="mx-4 grid w-[calc(100%-2rem)] shrink-0 grid-cols-2">
|
|
4240
|
+
<TabsTrigger value="info">{t('taskForm.tabInfo')}</TabsTrigger>
|
|
4241
|
+
{editingTaskId ? (
|
|
4242
|
+
<TabsTrigger value="comments">
|
|
4243
|
+
{t('taskForm.tabComments')}
|
|
4244
|
+
</TabsTrigger>
|
|
4245
|
+
) : null}
|
|
4246
|
+
</TabsList>
|
|
4247
|
+
<TabsContent
|
|
4248
|
+
value="info"
|
|
4249
|
+
className="flex min-h-0 flex-1 flex-col data-[state=inactive]:hidden"
|
|
4250
|
+
>
|
|
4251
|
+
<div className="flex-1 space-y-4 overflow-y-auto px-4 py-2">
|
|
4252
|
+
<div className="space-y-1.5">
|
|
4253
|
+
<Label htmlFor="task-name">
|
|
4254
|
+
{t('taskForm.nameLabel')} *
|
|
4255
|
+
</Label>
|
|
4256
|
+
<Input
|
|
4257
|
+
id="task-name"
|
|
4258
|
+
placeholder={t('taskForm.namePlaceholder')}
|
|
4259
|
+
value={taskFormData.name}
|
|
4260
|
+
onChange={(e) =>
|
|
4261
|
+
setTaskFormData((prev) => ({
|
|
4262
|
+
...prev,
|
|
4263
|
+
name: e.target.value,
|
|
4264
|
+
}))
|
|
4265
|
+
}
|
|
4266
|
+
/>
|
|
4267
|
+
</div>
|
|
4254
4268
|
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
+
<div className="space-y-1.5">
|
|
4270
|
+
<Label htmlFor="task-description">
|
|
4271
|
+
{t('taskForm.descriptionLabel')}
|
|
4272
|
+
</Label>
|
|
4273
|
+
<RichTextEditor
|
|
4274
|
+
value={taskFormData.description}
|
|
4275
|
+
onChange={(val) =>
|
|
4276
|
+
setTaskFormData((prev) => ({
|
|
4277
|
+
...prev,
|
|
4278
|
+
description: val,
|
|
4279
|
+
}))
|
|
4280
|
+
}
|
|
4281
|
+
mentions={mentionItems}
|
|
4282
|
+
/>
|
|
4283
|
+
</div>
|
|
4269
4284
|
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4285
|
+
<div className="grid grid-cols-2 gap-3">
|
|
4286
|
+
<div className="space-y-1.5">
|
|
4287
|
+
<Label>{t('taskForm.priorityLabel')}</Label>
|
|
4288
|
+
<Select
|
|
4289
|
+
value={taskFormData.priority}
|
|
4290
|
+
onValueChange={(v) =>
|
|
4291
|
+
setTaskFormData((prev) => ({
|
|
4292
|
+
...prev,
|
|
4293
|
+
priority: v as TaskFormState['priority'],
|
|
4294
|
+
}))
|
|
4295
|
+
}
|
|
4296
|
+
>
|
|
4297
|
+
<SelectTrigger className="w-full">
|
|
4298
|
+
<SelectValue />
|
|
4299
|
+
</SelectTrigger>
|
|
4300
|
+
<SelectContent>
|
|
4301
|
+
<SelectItem value="low">
|
|
4302
|
+
{getTaskPriorityLabel('low')}
|
|
4303
|
+
</SelectItem>
|
|
4304
|
+
<SelectItem value="medium">
|
|
4305
|
+
{getTaskPriorityLabel('medium')}
|
|
4306
|
+
</SelectItem>
|
|
4307
|
+
<SelectItem value="high">
|
|
4308
|
+
{getTaskPriorityLabel('high')}
|
|
4309
|
+
</SelectItem>
|
|
4310
|
+
</SelectContent>
|
|
4311
|
+
</Select>
|
|
4312
|
+
</div>
|
|
4298
4313
|
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4314
|
+
<div className="space-y-1.5">
|
|
4315
|
+
<Label>{t('taskForm.columnLabel')}</Label>
|
|
4316
|
+
<Select
|
|
4317
|
+
value={taskFormData.status}
|
|
4318
|
+
onValueChange={(v) =>
|
|
4319
|
+
setTaskFormData((prev) => ({
|
|
4320
|
+
...prev,
|
|
4321
|
+
status: v as BoardColumnId,
|
|
4322
|
+
}))
|
|
4323
|
+
}
|
|
4324
|
+
>
|
|
4325
|
+
<SelectTrigger className="w-full">
|
|
4326
|
+
<SelectValue />
|
|
4327
|
+
</SelectTrigger>
|
|
4328
|
+
<SelectContent>
|
|
4329
|
+
{KANBAN_COLUMNS.map((col) => (
|
|
4330
|
+
<SelectItem key={col.id} value={col.id}>
|
|
4331
|
+
{col.label}
|
|
4332
|
+
</SelectItem>
|
|
4333
|
+
))}
|
|
4334
|
+
</SelectContent>
|
|
4335
|
+
</Select>
|
|
4336
|
+
</div>
|
|
4337
|
+
</div>
|
|
4338
|
+
|
|
4339
|
+
<div className="space-y-1.5">
|
|
4340
|
+
<Label>Responsável</Label>
|
|
4341
|
+
<Select
|
|
4342
|
+
value={taskFormData.assigneeCollaboratorId}
|
|
4343
|
+
onValueChange={(value) =>
|
|
4344
|
+
setTaskFormData((prev) => ({
|
|
4345
|
+
...prev,
|
|
4346
|
+
assigneeCollaboratorId: value,
|
|
4347
|
+
}))
|
|
4348
|
+
}
|
|
4349
|
+
>
|
|
4350
|
+
<SelectTrigger className="w-full">
|
|
4351
|
+
<SelectValue
|
|
4352
|
+
placeholder={commonT('labels.notAssigned')}
|
|
4353
|
+
/>
|
|
4354
|
+
</SelectTrigger>
|
|
4355
|
+
<SelectContent>
|
|
4356
|
+
<SelectItem value="none">
|
|
4357
|
+
{commonT('labels.notAssigned')}
|
|
4317
4358
|
</SelectItem>
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4359
|
+
{taskAssigneeOptions.map((option) => (
|
|
4360
|
+
<SelectItem key={option.id} value={option.id}>
|
|
4361
|
+
{option.label}
|
|
4362
|
+
</SelectItem>
|
|
4363
|
+
))}
|
|
4364
|
+
</SelectContent>
|
|
4365
|
+
</Select>
|
|
4366
|
+
</div>
|
|
4323
4367
|
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
</SelectItem>
|
|
4342
|
-
{taskAssigneeOptions.map((option) => (
|
|
4343
|
-
<SelectItem key={option.id} value={option.id}>
|
|
4344
|
-
{option.label}
|
|
4345
|
-
</SelectItem>
|
|
4346
|
-
))}
|
|
4347
|
-
</SelectContent>
|
|
4348
|
-
</Select>
|
|
4349
|
-
</div>
|
|
4368
|
+
<div className="grid grid-cols-2 gap-3">
|
|
4369
|
+
<div className="space-y-1.5">
|
|
4370
|
+
<Label htmlFor="task-due-date">
|
|
4371
|
+
{t('taskForm.deadlineLabel')}
|
|
4372
|
+
</Label>
|
|
4373
|
+
<Input
|
|
4374
|
+
id="task-due-date"
|
|
4375
|
+
type="date"
|
|
4376
|
+
value={taskFormData.dueDate}
|
|
4377
|
+
onChange={(e) =>
|
|
4378
|
+
setTaskFormData((prev) => ({
|
|
4379
|
+
...prev,
|
|
4380
|
+
dueDate: e.target.value,
|
|
4381
|
+
}))
|
|
4382
|
+
}
|
|
4383
|
+
/>
|
|
4384
|
+
</div>
|
|
4350
4385
|
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4386
|
+
<div className="space-y-1.5">
|
|
4387
|
+
<Label htmlFor="task-estimate">
|
|
4388
|
+
{t('taskForm.estimateLabel')}
|
|
4389
|
+
</Label>
|
|
4390
|
+
<Input
|
|
4391
|
+
id="task-estimate"
|
|
4392
|
+
type="number"
|
|
4393
|
+
min="0"
|
|
4394
|
+
step="0.5"
|
|
4395
|
+
placeholder="0"
|
|
4396
|
+
value={taskFormData.estimateHours}
|
|
4397
|
+
onChange={(e) =>
|
|
4398
|
+
setTaskFormData((prev) => ({
|
|
4399
|
+
...prev,
|
|
4400
|
+
estimateHours: e.target.value,
|
|
4401
|
+
}))
|
|
4402
|
+
}
|
|
4403
|
+
/>
|
|
4404
|
+
</div>
|
|
4405
|
+
</div>
|
|
4368
4406
|
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
estimateHours: e.target.value,
|
|
4384
|
-
}))
|
|
4385
|
-
}
|
|
4386
|
-
/>
|
|
4387
|
-
</div>
|
|
4388
|
-
</div>
|
|
4407
|
+
<div className="space-y-1.5">
|
|
4408
|
+
<Label htmlFor="task-tags">{t('taskForm.tagsLabel')}</Label>
|
|
4409
|
+
<Input
|
|
4410
|
+
id="task-tags"
|
|
4411
|
+
placeholder={t('taskForm.tagsPlaceholder')}
|
|
4412
|
+
value={taskFormData.tags}
|
|
4413
|
+
onChange={(e) =>
|
|
4414
|
+
setTaskFormData((prev) => ({
|
|
4415
|
+
...prev,
|
|
4416
|
+
tags: e.target.value,
|
|
4417
|
+
}))
|
|
4418
|
+
}
|
|
4419
|
+
/>
|
|
4420
|
+
</div>
|
|
4389
4421
|
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
}))
|
|
4401
|
-
}
|
|
4402
|
-
/>
|
|
4403
|
-
</div>
|
|
4422
|
+
{editingTaskId ? (
|
|
4423
|
+
<div className="space-y-1.5">
|
|
4424
|
+
<Label className="flex items-center gap-1.5">
|
|
4425
|
+
<Paperclip className="size-3.5" />
|
|
4426
|
+
{t('taskForm.attachmentsLabel')}
|
|
4427
|
+
</Label>
|
|
4428
|
+
<TaskFileAttachments taskId={editingTaskId} />
|
|
4429
|
+
</div>
|
|
4430
|
+
) : null}
|
|
4431
|
+
</div>
|
|
4404
4432
|
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4433
|
+
<div className="mt-4 flex flex-wrap items-center justify-between gap-2 border-t px-4 pb-4 pt-4">
|
|
4434
|
+
<div className="flex gap-2">
|
|
4435
|
+
{editingTaskId ? (
|
|
4436
|
+
<Button
|
|
4437
|
+
type="button"
|
|
4438
|
+
variant="outline"
|
|
4439
|
+
disabled={
|
|
4440
|
+
taskFormLoading || archivingTaskId === editingTaskId
|
|
4441
|
+
}
|
|
4442
|
+
onClick={() => {
|
|
4443
|
+
if (!editingTaskId) return;
|
|
4444
|
+
const id = editingTaskId;
|
|
4445
|
+
setTaskFormOpen(false);
|
|
4446
|
+
setEditingTaskId(null);
|
|
4447
|
+
setTaskFormData(EMPTY_TASK_FORM);
|
|
4448
|
+
void handleArchiveTask(id);
|
|
4449
|
+
}}
|
|
4450
|
+
>
|
|
4451
|
+
{archivingTaskId === editingTaskId ? (
|
|
4452
|
+
<Loader2 className="mr-2 size-4 animate-spin" />
|
|
4453
|
+
) : (
|
|
4454
|
+
<Archive className="mr-2 size-4" />
|
|
4455
|
+
)}
|
|
4456
|
+
{commonT('actions.archive')}
|
|
4457
|
+
</Button>
|
|
4458
|
+
) : null}
|
|
4459
|
+
</div>
|
|
4460
|
+
<div className="flex gap-2">
|
|
4461
|
+
<Button
|
|
4462
|
+
variant="outline"
|
|
4463
|
+
onClick={() => {
|
|
4464
|
+
setTaskFormOpen(false);
|
|
4465
|
+
setEditingTaskId(null);
|
|
4466
|
+
setTaskFormData(EMPTY_TASK_FORM);
|
|
4467
|
+
}}
|
|
4468
|
+
disabled={taskFormLoading}
|
|
4469
|
+
>
|
|
4470
|
+
{commonT('actions.cancel')}
|
|
4471
|
+
</Button>
|
|
4472
|
+
<Button
|
|
4473
|
+
onClick={() => void handleTaskFormSubmit()}
|
|
4474
|
+
disabled={taskFormLoading || !taskFormData.name.trim()}
|
|
4475
|
+
>
|
|
4476
|
+
{taskFormLoading
|
|
4477
|
+
? t('taskForm.saving')
|
|
4478
|
+
: editingTaskId
|
|
4479
|
+
? commonT('actions.save')
|
|
4480
|
+
: commonT('actions.create')}
|
|
4481
|
+
</Button>
|
|
4482
|
+
</div>
|
|
4412
4483
|
</div>
|
|
4413
|
-
|
|
4414
|
-
</div>
|
|
4484
|
+
</TabsContent>
|
|
4415
4485
|
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
type="button"
|
|
4421
|
-
variant="outline"
|
|
4422
|
-
disabled={
|
|
4423
|
-
taskFormLoading || archivingTaskId === editingTaskId
|
|
4424
|
-
}
|
|
4425
|
-
onClick={() => {
|
|
4426
|
-
if (!editingTaskId) return;
|
|
4427
|
-
const id = editingTaskId;
|
|
4428
|
-
setTaskFormOpen(false);
|
|
4429
|
-
setEditingTaskId(null);
|
|
4430
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
4431
|
-
void handleArchiveTask(id);
|
|
4432
|
-
}}
|
|
4433
|
-
>
|
|
4434
|
-
{archivingTaskId === editingTaskId ? (
|
|
4435
|
-
<Loader2 className="mr-2 size-4 animate-spin" />
|
|
4436
|
-
) : (
|
|
4437
|
-
<Archive className="mr-2 size-4" />
|
|
4438
|
-
)}
|
|
4439
|
-
{commonT('actions.archive')}
|
|
4440
|
-
</Button>
|
|
4441
|
-
) : null}
|
|
4442
|
-
</div>
|
|
4443
|
-
<div className="flex gap-2">
|
|
4444
|
-
<Button
|
|
4445
|
-
variant="outline"
|
|
4446
|
-
onClick={() => {
|
|
4447
|
-
setTaskFormOpen(false);
|
|
4448
|
-
setEditingTaskId(null);
|
|
4449
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
4450
|
-
}}
|
|
4451
|
-
disabled={taskFormLoading}
|
|
4452
|
-
>
|
|
4453
|
-
{commonT('actions.cancel')}
|
|
4454
|
-
</Button>
|
|
4455
|
-
<Button
|
|
4456
|
-
onClick={() => void handleTaskFormSubmit()}
|
|
4457
|
-
disabled={taskFormLoading || !taskFormData.name.trim()}
|
|
4486
|
+
{editingTaskId ? (
|
|
4487
|
+
<TabsContent
|
|
4488
|
+
value="comments"
|
|
4489
|
+
className="min-h-0 flex-1 overflow-y-auto px-4 py-2 data-[state=inactive]:hidden"
|
|
4458
4490
|
>
|
|
4459
|
-
{
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
: commonT('actions.create')}
|
|
4464
|
-
</Button>
|
|
4465
|
-
</div>
|
|
4466
|
-
</div>
|
|
4491
|
+
<TaskCommentsSection taskId={editingTaskId} />
|
|
4492
|
+
</TabsContent>
|
|
4493
|
+
) : null}
|
|
4494
|
+
</Tabs>
|
|
4467
4495
|
</SheetContent>
|
|
4468
4496
|
</Sheet>
|
|
4469
4497
|
) : null}
|