@hed-hog/operations 0.0.3 → 0.0.285

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 (108) hide show
  1. package/README.md +122 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/operations-data.controller.d.ts +139 -0
  7. package/dist/operations-data.controller.d.ts.map +1 -0
  8. package/dist/operations-data.controller.js +113 -0
  9. package/dist/operations-data.controller.js.map +1 -0
  10. package/dist/operations-growth.controller.d.ts +48 -0
  11. package/dist/operations-growth.controller.d.ts.map +1 -0
  12. package/dist/operations-growth.controller.js +90 -0
  13. package/dist/operations-growth.controller.js.map +1 -0
  14. package/dist/operations.module.d.ts.map +1 -1
  15. package/dist/operations.module.js +10 -4
  16. package/dist/operations.module.js.map +1 -1
  17. package/dist/operations.service.d.ts +178 -0
  18. package/dist/operations.service.d.ts.map +1 -0
  19. package/dist/operations.service.js +134 -0
  20. package/dist/operations.service.js.map +1 -0
  21. package/hedhog/data/menu.yaml +251 -132
  22. package/hedhog/data/operations_career_level.yaml +102 -0
  23. package/hedhog/data/operations_career_track.yaml +8 -0
  24. package/hedhog/data/operations_certification.yaml +38 -0
  25. package/hedhog/data/operations_evaluation_cycle.yaml +18 -0
  26. package/hedhog/data/operations_performance_criterion.yaml +48 -0
  27. package/hedhog/data/role.yaml +14 -7
  28. package/hedhog/data/route.yaml +143 -80
  29. package/hedhog/frontend/app/_components/allocation-calendar.tsx.ejs +56 -56
  30. package/hedhog/frontend/app/_components/kanban-board.tsx.ejs +83 -83
  31. package/hedhog/frontend/app/_components/operations-header.tsx.ejs +29 -29
  32. package/hedhog/frontend/app/_components/section-card.tsx.ejs +32 -32
  33. package/hedhog/frontend/app/_components/status-badge.tsx.ejs +15 -15
  34. package/hedhog/frontend/app/_components/timesheet-entry-dialog.tsx.ejs +142 -142
  35. package/hedhog/frontend/app/_lib/hooks/use-operations-data.ts.ejs +41 -41
  36. package/hedhog/frontend/app/_lib/hooks/use-operations-growth-data.ts.ejs +63 -0
  37. package/hedhog/frontend/app/_lib/mocks/allocations.mock.ts.ejs +74 -74
  38. package/hedhog/frontend/app/_lib/mocks/contracts.mock.ts.ejs +74 -74
  39. package/hedhog/frontend/app/_lib/mocks/operations-growth.mock.ts.ejs +824 -0
  40. package/hedhog/frontend/app/_lib/mocks/projects.mock.ts.ejs +60 -60
  41. package/hedhog/frontend/app/_lib/mocks/tasks.mock.ts.ejs +88 -88
  42. package/hedhog/frontend/app/_lib/mocks/timesheets.mock.ts.ejs +84 -84
  43. package/hedhog/frontend/app/_lib/mocks/users.mock.ts.ejs +67 -67
  44. package/hedhog/frontend/app/_lib/services/contracts.service.ts.ejs +10 -10
  45. package/hedhog/frontend/app/_lib/services/operations-growth.service.ts.ejs +31 -0
  46. package/hedhog/frontend/app/_lib/services/projects.service.ts.ejs +10 -10
  47. package/hedhog/frontend/app/_lib/services/tasks.service.ts.ejs +10 -10
  48. package/hedhog/frontend/app/_lib/services/timesheets.service.ts.ejs +10 -10
  49. package/hedhog/frontend/app/_lib/types/operations-growth.ts.ejs +209 -0
  50. package/hedhog/frontend/app/_lib/types/operations.ts.ejs +95 -95
  51. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +25 -25
  52. package/hedhog/frontend/app/_lib/utils/growth.ts.ejs +62 -0
  53. package/hedhog/frontend/app/_lib/utils/metrics.ts.ejs +103 -103
  54. package/hedhog/frontend/app/_lib/utils/status.ts.ejs +80 -80
  55. package/hedhog/frontend/app/allocations/page.tsx.ejs +154 -99
  56. package/hedhog/frontend/app/approvals/page.tsx.ejs +147 -147
  57. package/hedhog/frontend/app/career/page.tsx.ejs +143 -0
  58. package/hedhog/frontend/app/certifications/page.tsx.ejs +201 -0
  59. package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +108 -108
  60. package/hedhog/frontend/app/contracts/page.tsx.ejs +180 -124
  61. package/hedhog/frontend/app/evaluations/page.tsx.ejs +277 -0
  62. package/hedhog/frontend/app/goals/page.tsx.ejs +170 -0
  63. package/hedhog/frontend/app/growth/page.tsx.ejs +288 -0
  64. package/hedhog/frontend/app/layout.tsx.ejs +9 -9
  65. package/hedhog/frontend/app/manager/page.tsx.ejs +175 -0
  66. package/hedhog/frontend/app/page.tsx.ejs +177 -177
  67. package/hedhog/frontend/app/projects/[id]/page.tsx.ejs +186 -186
  68. package/hedhog/frontend/app/projects/page.tsx.ejs +111 -111
  69. package/hedhog/frontend/app/rewards/page.tsx.ejs +195 -0
  70. package/hedhog/frontend/app/tasks/page.tsx.ejs +47 -47
  71. package/hedhog/frontend/app/timesheets/page.tsx.ejs +126 -126
  72. package/hedhog/frontend/messages/en.json +152 -142
  73. package/hedhog/frontend/messages/pt.json +152 -142
  74. package/hedhog/table/operations_allocation.yaml +52 -0
  75. package/hedhog/table/operations_calibration_item.yaml +61 -0
  76. package/hedhog/table/operations_calibration_session.yaml +25 -0
  77. package/hedhog/table/operations_career_level.yaml +75 -0
  78. package/hedhog/table/operations_career_track.yaml +21 -0
  79. package/hedhog/table/operations_certification.yaml +48 -0
  80. package/hedhog/table/operations_contract.yaml +57 -0
  81. package/hedhog/table/operations_employee.yaml +64 -0
  82. package/hedhog/table/operations_employee_certification.yaml +43 -0
  83. package/hedhog/table/operations_employee_connect.yaml +61 -0
  84. package/hedhog/table/operations_employee_evaluation.yaml +113 -0
  85. package/hedhog/table/operations_employee_evaluation_item.yaml +39 -0
  86. package/hedhog/table/operations_employee_profile.yaml +80 -0
  87. package/hedhog/table/operations_employee_skill_matrix.yaml +30 -0
  88. package/hedhog/table/operations_evaluation_cycle.yaml +31 -0
  89. package/hedhog/table/operations_goal.yaml +67 -0
  90. package/hedhog/table/operations_goal_progress.yaml +31 -0
  91. package/hedhog/table/operations_performance_criterion.yaml +29 -0
  92. package/hedhog/table/operations_project.yaml +66 -0
  93. package/hedhog/table/operations_promotion_readiness.yaml +49 -0
  94. package/hedhog/table/operations_promotion_recommendation.yaml +63 -0
  95. package/hedhog/table/operations_public_recognition.yaml +46 -0
  96. package/hedhog/table/operations_reward.yaml +100 -0
  97. package/hedhog/table/operations_score_event.yaml +81 -0
  98. package/hedhog/table/operations_task.yaml +60 -0
  99. package/hedhog/table/operations_timesheet.yaml +49 -0
  100. package/hedhog/table/operations_timesheet_entry.yaml +51 -0
  101. package/package.json +4 -4
  102. package/src/index.ts +2 -1
  103. package/src/language/en.json +8 -8
  104. package/src/language/pt.json +8 -8
  105. package/src/operations-data.controller.ts +54 -0
  106. package/src/operations-growth.controller.ts +44 -0
  107. package/src/operations.module.ts +21 -15
  108. package/src/operations.service.ts +137 -0
@@ -1,83 +1,83 @@
1
- import { formatDate, formatHours } from '../_lib/utils/format';
2
- import {
3
- getTaskBadgeClasses,
4
- getTaskStatusLabel,
5
- } from '../_lib/utils/status';
6
- import type { OperationsUser, Task, TaskStatus } from '../_lib/types/operations';
7
- import { StatusBadge } from './status-badge';
8
-
9
- const columns: TaskStatus[] = [
10
- 'backlog',
11
- 'todo',
12
- 'in-progress',
13
- 'review',
14
- 'done',
15
- ];
16
-
17
- interface KanbanBoardProps {
18
- tasks: Task[];
19
- users: OperationsUser[];
20
- }
21
-
22
- export function KanbanBoard({ tasks, users }: KanbanBoardProps) {
23
- return (
24
- <div className="grid gap-4 xl:grid-cols-5">
25
- {columns.map((column) => {
26
- const columnTasks = tasks.filter((task) => task.status === column);
27
-
28
- return (
29
- <div
30
- key={column}
31
- className="rounded-xl border bg-muted/30 p-3 shadow-sm"
32
- >
33
- <div className="mb-3 flex items-center justify-between">
34
- <h3 className="text-sm font-semibold">{getTaskStatusLabel(column)}</h3>
35
- <span className="text-xs text-muted-foreground">
36
- {columnTasks.length}
37
- </span>
38
- </div>
39
- <div className="space-y-3">
40
- {columnTasks.map((task) => {
41
- const assignedUser = users.find(
42
- (user) => user.id === task.assignedUserId
43
- );
44
-
45
- return (
46
- <div
47
- key={task.id}
48
- className="rounded-lg border bg-background p-3 shadow-sm"
49
- >
50
- <div className="space-y-2">
51
- <div className="flex items-start justify-between gap-2">
52
- <p className="text-sm font-medium">{task.title}</p>
53
- <StatusBadge
54
- label={getTaskStatusLabel(task.status)}
55
- className={getTaskBadgeClasses(task.status)}
56
- />
57
- </div>
58
- <div className="flex flex-wrap gap-2">
59
- {task.labels.map((label) => (
60
- <span
61
- key={label}
62
- className="rounded-full bg-slate-100 px-2 py-0.5 text-[11px] text-slate-700"
63
- >
64
- {label}
65
- </span>
66
- ))}
67
- </div>
68
- <div className="text-xs text-muted-foreground">
69
- <p>{assignedUser?.name ?? 'Unassigned'}</p>
70
- <p>{formatDate(task.dueDate)}</p>
71
- <p>{formatHours(task.estimatedHours)}</p>
72
- </div>
73
- </div>
74
- </div>
75
- );
76
- })}
77
- </div>
78
- </div>
79
- );
80
- })}
81
- </div>
82
- );
83
- }
1
+ import { formatDate, formatHours } from '../_lib/utils/format';
2
+ import {
3
+ getTaskBadgeClasses,
4
+ getTaskStatusLabel,
5
+ } from '../_lib/utils/status';
6
+ import type { OperationsUser, Task, TaskStatus } from '../_lib/types/operations';
7
+ import { StatusBadge } from './status-badge';
8
+
9
+ const columns: TaskStatus[] = [
10
+ 'backlog',
11
+ 'todo',
12
+ 'in-progress',
13
+ 'review',
14
+ 'done',
15
+ ];
16
+
17
+ interface KanbanBoardProps {
18
+ tasks: Task[];
19
+ users: OperationsUser[];
20
+ }
21
+
22
+ export function KanbanBoard({ tasks, users }: KanbanBoardProps) {
23
+ return (
24
+ <div className="grid gap-4 xl:grid-cols-5">
25
+ {columns.map((column) => {
26
+ const columnTasks = tasks.filter((task) => task.status === column);
27
+
28
+ return (
29
+ <div
30
+ key={column}
31
+ className="rounded-xl border bg-muted/30 p-3 shadow-sm"
32
+ >
33
+ <div className="mb-3 flex items-center justify-between">
34
+ <h3 className="text-sm font-semibold">{getTaskStatusLabel(column)}</h3>
35
+ <span className="text-xs text-muted-foreground">
36
+ {columnTasks.length}
37
+ </span>
38
+ </div>
39
+ <div className="space-y-3">
40
+ {columnTasks.map((task) => {
41
+ const assignedUser = users.find(
42
+ (user) => user.id === task.assignedUserId
43
+ );
44
+
45
+ return (
46
+ <div
47
+ key={task.id}
48
+ className="rounded-lg border bg-background p-3 shadow-sm"
49
+ >
50
+ <div className="space-y-2">
51
+ <div className="flex items-start justify-between gap-2">
52
+ <p className="text-sm font-medium">{task.title}</p>
53
+ <StatusBadge
54
+ label={getTaskStatusLabel(task.status)}
55
+ className={getTaskBadgeClasses(task.status)}
56
+ />
57
+ </div>
58
+ <div className="flex flex-wrap gap-2">
59
+ {task.labels.map((label) => (
60
+ <span
61
+ key={label}
62
+ className="rounded-full bg-slate-100 px-2 py-0.5 text-[11px] text-slate-700"
63
+ >
64
+ {label}
65
+ </span>
66
+ ))}
67
+ </div>
68
+ <div className="text-xs text-muted-foreground">
69
+ <p>{assignedUser?.name ?? 'Unassigned'}</p>
70
+ <p>{formatDate(task.dueDate)}</p>
71
+ <p>{formatHours(task.estimatedHours)}</p>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ );
76
+ })}
77
+ </div>
78
+ </div>
79
+ );
80
+ })}
81
+ </div>
82
+ );
83
+ }
@@ -1,29 +1,29 @@
1
- import { PageHeader } from '@/components/entity-list';
2
- import { ReactNode } from 'react';
3
-
4
- interface OperationsHeaderProps {
5
- title: string;
6
- description: string;
7
- current: string;
8
- actions?: ReactNode;
9
- }
10
-
11
- export function OperationsHeader({
12
- title,
13
- description,
14
- current,
15
- actions,
16
- }: OperationsHeaderProps) {
17
- return (
18
- <PageHeader
19
- title={title}
20
- description={description}
21
- actions={actions}
22
- breadcrumbs={[
23
- { label: 'Home', href: '/' },
24
- { label: 'Operations', href: '/operations' },
25
- { label: current },
26
- ]}
27
- />
28
- );
29
- }
1
+ import { PageHeader } from '@/components/entity-list';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface OperationsHeaderProps {
5
+ title: string;
6
+ description: string;
7
+ current: string;
8
+ actions?: ReactNode;
9
+ }
10
+
11
+ export function OperationsHeader({
12
+ title,
13
+ description,
14
+ current,
15
+ actions,
16
+ }: OperationsHeaderProps) {
17
+ return (
18
+ <PageHeader
19
+ title={title}
20
+ description={description}
21
+ actions={actions}
22
+ breadcrumbs={[
23
+ { label: 'Home', href: '/' },
24
+ { label: 'Operations', href: '/operations' },
25
+ { label: current },
26
+ ]}
27
+ />
28
+ );
29
+ }
@@ -1,32 +1,32 @@
1
- import {
2
- Card,
3
- CardContent,
4
- CardDescription,
5
- CardHeader,
6
- CardTitle,
7
- } from '@/components/ui/card';
8
- import { ReactNode } from 'react';
9
-
10
- interface SectionCardProps {
11
- title: string;
12
- description?: string;
13
- children: ReactNode;
14
- className?: string;
15
- }
16
-
17
- export function SectionCard({
18
- title,
19
- description,
20
- children,
21
- className,
22
- }: SectionCardProps) {
23
- return (
24
- <Card className={className}>
25
- <CardHeader>
26
- <CardTitle>{title}</CardTitle>
27
- {description ? <CardDescription>{description}</CardDescription> : null}
28
- </CardHeader>
29
- <CardContent>{children}</CardContent>
30
- </Card>
31
- );
32
- }
1
+ import {
2
+ Card,
3
+ CardContent,
4
+ CardDescription,
5
+ CardHeader,
6
+ CardTitle,
7
+ } from '@/components/ui/card';
8
+ import { ReactNode } from 'react';
9
+
10
+ interface SectionCardProps {
11
+ title: string;
12
+ description?: string;
13
+ children: ReactNode;
14
+ className?: string;
15
+ }
16
+
17
+ export function SectionCard({
18
+ title,
19
+ description,
20
+ children,
21
+ className,
22
+ }: SectionCardProps) {
23
+ return (
24
+ <Card className={className}>
25
+ <CardHeader>
26
+ <CardTitle>{title}</CardTitle>
27
+ {description ? <CardDescription>{description}</CardDescription> : null}
28
+ </CardHeader>
29
+ <CardContent>{children}</CardContent>
30
+ </Card>
31
+ );
32
+ }
@@ -1,15 +1,15 @@
1
- import { Badge } from '@/components/ui/badge';
2
- import { cn } from '@/lib/utils';
3
-
4
- interface StatusBadgeProps {
5
- label: string;
6
- className?: string;
7
- }
8
-
9
- export function StatusBadge({ label, className }: StatusBadgeProps) {
10
- return (
11
- <Badge variant="outline" className={cn('border-transparent', className)}>
12
- {label}
13
- </Badge>
14
- );
15
- }
1
+ import { Badge } from '@/components/ui/badge';
2
+ import { cn } from '@/lib/utils';
3
+
4
+ interface StatusBadgeProps {
5
+ label: string;
6
+ className?: string;
7
+ }
8
+
9
+ export function StatusBadge({ label, className }: StatusBadgeProps) {
10
+ return (
11
+ <Badge variant="outline" className={cn('border-transparent', className)}>
12
+ {label}
13
+ </Badge>
14
+ );
15
+ }
@@ -1,142 +1,142 @@
1
- 'use client';
2
-
3
- import { Button } from '@/components/ui/button';
4
- import {
5
- Dialog,
6
- DialogContent,
7
- DialogDescription,
8
- DialogFooter,
9
- DialogHeader,
10
- DialogTitle,
11
- DialogTrigger,
12
- } from '@/components/ui/dialog';
13
- import { Input } from '@/components/ui/input';
14
- import { Label } from '@/components/ui/label';
15
- import {
16
- Select,
17
- SelectContent,
18
- SelectItem,
19
- SelectTrigger,
20
- SelectValue,
21
- } from '@/components/ui/select';
22
- import { Textarea } from '@/components/ui/textarea';
23
- import { Plus } from 'lucide-react';
24
- import { useState } from 'react';
25
- import type { OperationsUser, Project, Task } from '../_lib/types/operations';
26
-
27
- interface TimesheetEntryDialogProps {
28
- users: OperationsUser[];
29
- projects: Project[];
30
- tasks: Task[];
31
- }
32
-
33
- export function TimesheetEntryDialog({
34
- users,
35
- projects,
36
- tasks,
37
- }: TimesheetEntryDialogProps) {
38
- const [open, setOpen] = useState(false);
39
- const [projectId, setProjectId] = useState(projects[0]?.id ?? '');
40
-
41
- const availableTasks = tasks.filter((task) => task.projectId === projectId);
42
-
43
- return (
44
- <Dialog open={open} onOpenChange={setOpen}>
45
- <DialogTrigger asChild>
46
- <Button>
47
- <Plus className="mr-2 h-4 w-4" />
48
- Add Timesheet Entry
49
- </Button>
50
- </DialogTrigger>
51
- <DialogContent className="sm:max-w-2xl">
52
- <DialogHeader>
53
- <DialogTitle>Add Timesheet Entry</DialogTitle>
54
- <DialogDescription>
55
- Mock-only modal wired for a future API-backed create flow.
56
- </DialogDescription>
57
- </DialogHeader>
58
- <div className="grid gap-4 md:grid-cols-2">
59
- <div className="space-y-2">
60
- <Label>User</Label>
61
- <Select defaultValue={users[0]?.id}>
62
- <SelectTrigger>
63
- <SelectValue />
64
- </SelectTrigger>
65
- <SelectContent>
66
- {users.map((user) => (
67
- <SelectItem key={user.id} value={user.id}>
68
- {user.name}
69
- </SelectItem>
70
- ))}
71
- </SelectContent>
72
- </Select>
73
- </div>
74
- <div className="space-y-2">
75
- <Label>Date</Label>
76
- <Input defaultValue="2026-03-16" type="date" />
77
- </div>
78
- <div className="space-y-2">
79
- <Label>Project</Label>
80
- <Select value={projectId} onValueChange={setProjectId}>
81
- <SelectTrigger>
82
- <SelectValue />
83
- </SelectTrigger>
84
- <SelectContent>
85
- {projects.map((project) => (
86
- <SelectItem key={project.id} value={project.id}>
87
- {project.name}
88
- </SelectItem>
89
- ))}
90
- </SelectContent>
91
- </Select>
92
- </div>
93
- <div className="space-y-2">
94
- <Label>Task</Label>
95
- <Select defaultValue={availableTasks[0]?.id}>
96
- <SelectTrigger>
97
- <SelectValue />
98
- </SelectTrigger>
99
- <SelectContent>
100
- {availableTasks.map((task) => (
101
- <SelectItem key={task.id} value={task.id}>
102
- {task.title}
103
- </SelectItem>
104
- ))}
105
- </SelectContent>
106
- </Select>
107
- </div>
108
- <div className="space-y-2">
109
- <Label>Hours</Label>
110
- <Input defaultValue="6" min="0" step="0.5" type="number" />
111
- </div>
112
- <div className="space-y-2">
113
- <Label>Status</Label>
114
- <Select defaultValue="pending">
115
- <SelectTrigger>
116
- <SelectValue />
117
- </SelectTrigger>
118
- <SelectContent>
119
- <SelectItem value="pending">Pending</SelectItem>
120
- <SelectItem value="approved">Approved</SelectItem>
121
- <SelectItem value="rejected">Rejected</SelectItem>
122
- </SelectContent>
123
- </Select>
124
- </div>
125
- <div className="space-y-2 md:col-span-2">
126
- <Label>Description</Label>
127
- <Textarea
128
- defaultValue="Mock entry for sprint execution and internal review."
129
- rows={4}
130
- />
131
- </div>
132
- </div>
133
- <DialogFooter>
134
- <Button variant="outline" onClick={() => setOpen(false)}>
135
- Cancel
136
- </Button>
137
- <Button onClick={() => setOpen(false)}>Save Mock Entry</Button>
138
- </DialogFooter>
139
- </DialogContent>
140
- </Dialog>
141
- );
142
- }
1
+ 'use client';
2
+
3
+ import { Button } from '@/components/ui/button';
4
+ import {
5
+ Dialog,
6
+ DialogContent,
7
+ DialogDescription,
8
+ DialogFooter,
9
+ DialogHeader,
10
+ DialogTitle,
11
+ DialogTrigger,
12
+ } from '@/components/ui/dialog';
13
+ import { Input } from '@/components/ui/input';
14
+ import { Label } from '@/components/ui/label';
15
+ import {
16
+ Select,
17
+ SelectContent,
18
+ SelectItem,
19
+ SelectTrigger,
20
+ SelectValue,
21
+ } from '@/components/ui/select';
22
+ import { Textarea } from '@/components/ui/textarea';
23
+ import { Plus } from 'lucide-react';
24
+ import { useState } from 'react';
25
+ import type { OperationsUser, Project, Task } from '../_lib/types/operations';
26
+
27
+ interface TimesheetEntryDialogProps {
28
+ users: OperationsUser[];
29
+ projects: Project[];
30
+ tasks: Task[];
31
+ }
32
+
33
+ export function TimesheetEntryDialog({
34
+ users,
35
+ projects,
36
+ tasks,
37
+ }: TimesheetEntryDialogProps) {
38
+ const [open, setOpen] = useState(false);
39
+ const [projectId, setProjectId] = useState(projects[0]?.id ?? '');
40
+
41
+ const availableTasks = tasks.filter((task) => task.projectId === projectId);
42
+
43
+ return (
44
+ <Dialog open={open} onOpenChange={setOpen}>
45
+ <DialogTrigger asChild>
46
+ <Button>
47
+ <Plus className="mr-2 h-4 w-4" />
48
+ Add Timesheet Entry
49
+ </Button>
50
+ </DialogTrigger>
51
+ <DialogContent className="sm:max-w-2xl">
52
+ <DialogHeader>
53
+ <DialogTitle>Add Timesheet Entry</DialogTitle>
54
+ <DialogDescription>
55
+ Mock-only modal wired for a future API-backed create flow.
56
+ </DialogDescription>
57
+ </DialogHeader>
58
+ <div className="grid gap-4 md:grid-cols-2">
59
+ <div className="space-y-2">
60
+ <Label>User</Label>
61
+ <Select defaultValue={users[0]?.id}>
62
+ <SelectTrigger>
63
+ <SelectValue />
64
+ </SelectTrigger>
65
+ <SelectContent>
66
+ {users.map((user) => (
67
+ <SelectItem key={user.id} value={user.id}>
68
+ {user.name}
69
+ </SelectItem>
70
+ ))}
71
+ </SelectContent>
72
+ </Select>
73
+ </div>
74
+ <div className="space-y-2">
75
+ <Label>Date</Label>
76
+ <Input defaultValue="2026-03-16" type="date" />
77
+ </div>
78
+ <div className="space-y-2">
79
+ <Label>Project</Label>
80
+ <Select value={projectId} onValueChange={setProjectId}>
81
+ <SelectTrigger>
82
+ <SelectValue />
83
+ </SelectTrigger>
84
+ <SelectContent>
85
+ {projects.map((project) => (
86
+ <SelectItem key={project.id} value={project.id}>
87
+ {project.name}
88
+ </SelectItem>
89
+ ))}
90
+ </SelectContent>
91
+ </Select>
92
+ </div>
93
+ <div className="space-y-2">
94
+ <Label>Task</Label>
95
+ <Select defaultValue={availableTasks[0]?.id}>
96
+ <SelectTrigger>
97
+ <SelectValue />
98
+ </SelectTrigger>
99
+ <SelectContent>
100
+ {availableTasks.map((task) => (
101
+ <SelectItem key={task.id} value={task.id}>
102
+ {task.title}
103
+ </SelectItem>
104
+ ))}
105
+ </SelectContent>
106
+ </Select>
107
+ </div>
108
+ <div className="space-y-2">
109
+ <Label>Hours</Label>
110
+ <Input defaultValue="6" min="0" step="0.5" type="number" />
111
+ </div>
112
+ <div className="space-y-2">
113
+ <Label>Status</Label>
114
+ <Select defaultValue="pending">
115
+ <SelectTrigger>
116
+ <SelectValue />
117
+ </SelectTrigger>
118
+ <SelectContent>
119
+ <SelectItem value="pending">Pending</SelectItem>
120
+ <SelectItem value="approved">Approved</SelectItem>
121
+ <SelectItem value="rejected">Rejected</SelectItem>
122
+ </SelectContent>
123
+ </Select>
124
+ </div>
125
+ <div className="space-y-2 md:col-span-2">
126
+ <Label>Description</Label>
127
+ <Textarea
128
+ defaultValue="Mock entry for sprint execution and internal review."
129
+ rows={4}
130
+ />
131
+ </div>
132
+ </div>
133
+ <DialogFooter>
134
+ <Button variant="outline" onClick={() => setOpen(false)}>
135
+ Cancel
136
+ </Button>
137
+ <Button onClick={() => setOpen(false)}>Save Mock Entry</Button>
138
+ </DialogFooter>
139
+ </DialogContent>
140
+ </Dialog>
141
+ );
142
+ }