User commited on
Commit
d594ffb
·
1 Parent(s): ecb51fa

update: issue form

Browse files
TaskTrackingSystem.WebApp/Components/Pages/Features/Issues/AddIssue.razor CHANGED
@@ -33,205 +33,183 @@
33
  }
34
  else
35
  {
36
- <div class="grid grid-cols-1 xl:grid-cols-3 gap-6 items-start">
37
- <div class="xl:col-span-2 rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
38
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
39
- <div class="md:col-span-2">
40
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Task <span class="text-red-500">*</span></label>
41
- <select value="@formTaskId" @onchange="OnTaskChanged" class="w-full rounded-lg border @(isTaskError ? "border-red-500 focus:ring-red-500" : "border-slate-200 focus:ring-violet-600") px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:border-transparent transition-all">
42
- <option value="0">Select task...</option>
43
- @foreach (var task in tasks)
44
- {
45
- <option value="@task.Id">@task.Title</option>
46
- }
47
- </select>
48
- @if (isTaskError)
49
  {
50
- <p class="mt-1 text-xs text-red-500">@taskErrorMessage</p>
51
  }
52
- </div>
53
-
54
- <div class="md:col-span-2">
55
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Issue Title <span class="text-red-500">*</span></label>
56
- <input @bind="formTitle" type="text" placeholder="What did you work on?"
57
- class="w-full rounded-lg border @(isTitleError ? "border-red-500 focus:ring-red-500" : "border-slate-200 focus:ring-violet-600") px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:border-transparent transition-all" />
58
- @if (isTitleError)
59
- {
60
- <p class="mt-1 text-xs text-red-500">@titleErrorMessage</p>
61
- }
62
- </div>
63
-
64
- <div class="md:col-span-2">
65
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Description</label>
66
- <textarea @bind="formDescription" rows="4" placeholder="Add a short note about the work you did..."
67
- class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all"></textarea>
68
- </div>
69
-
70
- <div>
71
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Project</label>
72
- <input value="@SelectedProjectLabel" readonly
73
- class="w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-700 focus:outline-none" />
74
- </div>
75
-
76
- <div>
77
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Assignee</label>
78
- <div class="relative">
79
- <button type="button"
80
- @onclick="ToggleAssigneeDropdown"
81
- class="flex h-11 w-full items-center justify-between rounded-lg border border-slate-200 bg-white px-3 text-left text-sm text-slate-900 shadow-sm transition-colors hover:border-violet-300 hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-violet-600">
82
- <span class="truncate @(formAssignedTo.HasValue ? "font-medium text-slate-900" : "text-slate-400")">@SelectedAssigneeLabel</span>
83
- <i data-lucide="chevron-down" class="ml-3 h-4 w-4 shrink-0 text-slate-400"></i>
84
- </button>
85
-
86
- @if (isAssigneeDropdownOpen)
87
- {
88
- <div class="absolute bottom-full left-0 z-30 mb-2 w-full rounded-2xl border border-slate-200 bg-white p-3 shadow-[0_18px_40px_rgba(15,23,42,0.16)]">
89
- <div class="flex items-center justify-end">
90
- <button type="button"
91
- @onclick="CloseAssigneeDropdown"
92
- class="inline-flex h-7 w-7 items-center justify-center rounded-lg text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-600"
93
- aria-label="Close assignee dropdown">
94
- <i data-lucide="x" class="h-4 w-4"></i>
95
- </button>
96
- </div>
97
- <div class="relative">
98
- <input @bind="assigneeSearchInput"
99
- @onfocus="EnsureAssigneeDropdownOpen"
100
- type="text"
101
- placeholder="Search project members..."
102
- class="w-full rounded-xl border border-slate-200 bg-white py-2 pl-9 pr-3 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent" />
103
- <i data-lucide="search" class="absolute left-3 top-2.5 h-4 w-4 text-slate-400"></i>
104
- </div>
105
-
106
- @if (isLoadingProjectMembers)
107
- {
108
- <div class="mt-3 rounded-xl border border-dashed border-slate-200 bg-slate-50 px-3 py-4 text-center text-xs text-slate-500">
109
- Loading project members...
110
- </div>
111
- }
112
- else
113
- {
114
- <div class="mt-3 max-h-56 overflow-y-auto space-y-2 pr-1">
115
- <button type="button"
116
- @onclick="() => SetFormAssignee(null)"
117
- class="flex w-full items-center gap-3 rounded-xl border px-3 py-3 text-left transition-colors @(formAssignedTo.HasValue ? "border-slate-200 bg-white hover:bg-slate-50" : "border-violet-600 bg-violet-50/40")">
118
- <span class="flex h-9 w-9 items-center justify-center rounded-full bg-slate-100 text-slate-500 text-xs font-bold shrink-0">
119
- <i data-lucide="user-minus" class="h-4 w-4"></i>
120
- </span>
121
- <div class="min-w-0 flex-1">
122
- <p class="text-sm font-semibold text-slate-900">Unassigned</p>
123
- </div>
124
- </button>
125
 
126
- @foreach (var user in FilteredProjectMembers)
127
- {
128
- var isSelected = formAssignedTo == user.Id;
129
- <button type="button"
130
- @onclick="() => SetFormAssignee(user.Id)"
131
- class="flex w-full items-center gap-3 rounded-xl border px-3 py-3 text-left transition-colors @(isSelected ? "border-violet-600 bg-violet-50/40" : "border-slate-100 bg-white hover:border-slate-200 hover:bg-slate-50")">
132
- <span class="flex h-9 w-9 items-center justify-center rounded-full bg-violet-100 text-violet-700 text-xs font-bold shrink-0">
133
- @(user.FirstName.Length > 0 ? user.FirstName[0].ToString().ToUpper() : "")@(user.LastName.Length > 0 ? user.LastName[0].ToString().ToUpper() : "")
134
- </span>
135
- <div class="min-w-0 flex-1">
136
- <p class="truncate text-sm font-semibold text-slate-900">@user.FirstName @user.LastName</p>
137
- <p class="truncate text-xs text-slate-500">@@@user.Username</p>
138
- </div>
139
- </button>
140
- }
141
-
142
- @if (!FilteredProjectMembers.Any())
143
- {
144
- <div class="rounded-xl border border-dashed border-slate-200 bg-slate-50 px-3 py-4 text-center text-xs text-slate-500">
145
- No members match the current search.
146
- </div>
147
- }
148
- </div>
149
- }
150
- </div>
151
- }
152
- </div>
153
- </div>
154
 
155
- <div>
156
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Start Date</label>
157
- <input @bind="formStartDate" type="date"
158
- class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all" />
159
- </div>
160
 
161
- <div>
162
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Due Date</label>
163
- <input @bind="formDueDate" type="date"
164
- class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all" />
165
- </div>
 
166
 
167
- <div>
168
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Actual Hours</label>
169
- <input @bind="formActualHours" type="number" step="0.25" min="0" max="7"
170
- class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all"
171
- placeholder="e.g. 7" />
172
- <p class="mt-1 text-xs text-slate-500">Use the total hours you spent today. For your standard day, this is usually 7 hours.</p>
173
- </div>
174
 
175
- <div>
176
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Status</label>
177
- <select @bind="formStatusId" class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all">
178
- <option value="@AppTaskStatus.Todo">To Do</option>
179
- <option value="@AppTaskStatus.InProgress">In Progress</option>
180
- <option value="@AppTaskStatus.Done">Done</option>
181
- </select>
182
- </div>
183
 
184
- <div>
185
- <label class="block text-sm font-medium text-slate-700 mb-1.5">Priority</label>
186
- <select @bind="formPriorityId" class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all">
187
- <option value="@TaskPriority.Low">Low</option>
188
- <option value="@TaskPriority.Medium">Medium</option>
189
- <option value="@TaskPriority.High">High</option>
190
- </select>
191
- </div>
192
  </div>
193
 
194
- <div class="mt-6 flex items-center justify-end gap-3">
195
- <button @onclick="ResetForm" class="inline-flex items-center rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50 transition-colors shadow-sm">
196
- Reset
197
- </button>
198
- <button @onclick="RequestSaveConfirmation" disabled="@isSaving" class="inline-flex items-center rounded-lg bg-violet-600 px-5 py-2 text-sm font-semibold text-white hover:bg-violet-700 disabled:opacity-50 transition-colors shadow-sm">
199
- @(isSaving ? "Saving..." : "Add Issue")
200
- </button>
201
  </div>
202
 
203
- @if (!string.IsNullOrWhiteSpace(errorMessage))
204
- {
205
- <p class="mt-4 text-sm text-red-600">@errorMessage</p>
206
- }
207
- </div>
 
 
 
208
 
209
- <div class="rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
210
- <div class="flex items-center justify-between">
211
- <h3 class="text-sm font-bold uppercase tracking-wider text-slate-400">Today Summary</h3>
212
- <span class="text-xs text-slate-500">@DateTime.Today.ToString("dd MMM yyyy")</span>
213
  </div>
214
 
215
- <div class="mt-4 space-y-4">
216
- <div class="rounded-xl bg-slate-50 p-4 border border-slate-100">
217
- <p class="text-xs font-semibold text-slate-400 uppercase tracking-wider">Selected Task</p>
218
- <p class="mt-1 text-sm font-semibold text-slate-900">@SelectedTaskLabel</p>
219
- <p class="mt-1 text-xs text-slate-500">@SelectedProjectLabel</p>
220
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
 
222
- <div class="rounded-xl bg-violet-50 p-4 border border-violet-100">
223
- <p class="text-xs font-semibold text-violet-600 uppercase tracking-wider">Work Hours</p>
224
- <p class="mt-1 text-2xl font-bold text-violet-700">@((formActualHours.HasValue ? formActualHours.Value : 0m).ToString("0.##")) hr</p>
225
- <p class="mt-1 text-xs text-violet-700/80">Your daily target is 7 hours.</p>
226
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
- <div class="rounded-xl bg-emerald-50 p-4 border border-emerald-100">
229
- <p class="text-xs font-semibold text-emerald-600 uppercase tracking-wider">Date Range</p>
230
- <p class="mt-1 text-sm font-semibold text-emerald-900">@formStartDate.ToString("dd MMM yyyy") - @formDueDate.ToString("dd MMM yyyy")</p>
231
- <p class="mt-1 text-xs text-emerald-700/80">Kept simple for same-day work tracking.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  </div>
233
  </div>
234
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  </div>
236
  }
237
  </div>
@@ -267,6 +245,7 @@
267
  private string formTitle = "";
268
  private string? formDescription;
269
  private long? formAssignedTo;
 
270
  private decimal? formActualHours = 7m;
271
  private DateTime formStartDate = DateTime.Today;
272
  private DateTime formDueDate = DateTime.Today;
@@ -490,6 +469,7 @@
490
  Title = formTitle.Trim(),
491
  Description = formDescription,
492
  AssignedTo = formAssignedTo,
 
493
  ActualHours = formActualHours,
494
  StartDate = formStartDate,
495
  DueDate = formDueDate,
@@ -526,6 +506,7 @@
526
  formTitle = "";
527
  formDescription = null;
528
  formAssignedTo = currentUserId;
 
529
  formActualHours = 7m;
530
  formStartDate = DateTime.Today;
531
  formDueDate = DateTime.Today;
 
33
  }
34
  else
35
  {
36
+ <div class="w-full rounded-2xl border border-slate-200 bg-white p-6 shadow-sm">
37
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
38
+ <div class="md:col-span-2">
39
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Task <span class="text-red-500">*</span></label>
40
+ <select value="@formTaskId" @onchange="OnTaskChanged" class="w-full rounded-lg border @(isTaskError ? "border-red-500 focus:ring-red-500" : "border-slate-200 focus:ring-violet-600") px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:border-transparent transition-all">
41
+ <option value="0">Select task...</option>
42
+ @foreach (var task in tasks)
 
 
 
 
 
 
43
  {
44
+ <option value="@task.Id">@task.Title</option>
45
  }
46
+ </select>
47
+ @if (isTaskError)
48
+ {
49
+ <p class="mt-1 text-xs text-red-500">@taskErrorMessage</p>
50
+ }
51
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ <div class="md:col-span-2">
54
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Issue Title <span class="text-red-500">*</span></label>
55
+ <input @bind="formTitle" type="text" placeholder="What did you work on?"
56
+ class="w-full rounded-lg border @(isTitleError ? "border-red-500 focus:ring-red-500" : "border-slate-200 focus:ring-violet-600") px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:border-transparent transition-all" />
57
+ @if (isTitleError)
58
+ {
59
+ <p class="mt-1 text-xs text-red-500">@titleErrorMessage</p>
60
+ }
61
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
+ <div class="md:col-span-2">
64
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Description</label>
65
+ <textarea @bind="formDescription" rows="4" placeholder="Add a short note about the work you did..."
66
+ class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all"></textarea>
67
+ </div>
68
 
69
+ <div>
70
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Estimated Hours</label>
71
+ <input @bind="formEstimatedHours" type="number" step="0.25" min="0"
72
+ class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all"
73
+ placeholder="e.g. 4" />
74
+ </div>
75
 
76
+ <div>
77
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Actual Hours</label>
78
+ <input @bind="formActualHours" type="number" step="0.25" min="0" max="7"
79
+ class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all"
80
+ placeholder="e.g. 7" />
81
+ <p class="mt-1 text-xs text-slate-500">Use the total hours you spent today. For your standard day, this is usually 7 hours.</p>
82
+ </div>
83
 
84
+ <div>
85
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Start Date</label>
86
+ <input @bind="formStartDate" type="date"
87
+ class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all" />
88
+ </div>
 
 
 
89
 
90
+ <div>
91
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Due Date</label>
92
+ <input @bind="formDueDate" type="date"
93
+ class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all" />
 
 
 
 
94
  </div>
95
 
96
+ <div>
97
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Status</label>
98
+ <select @bind="formStatusId" class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all">
99
+ <option value="@AppTaskStatus.Todo">To Do</option>
100
+ <option value="@AppTaskStatus.InProgress">In Progress</option>
101
+ <option value="@AppTaskStatus.Done">Done</option>
102
+ </select>
103
  </div>
104
 
105
+ <div>
106
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Priority</label>
107
+ <select @bind="formPriorityId" class="w-full rounded-lg border border-slate-200 px-3 py-2 text-sm text-slate-900 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent transition-all">
108
+ <option value="@TaskPriority.Low">Low</option>
109
+ <option value="@TaskPriority.Medium">Medium</option>
110
+ <option value="@TaskPriority.High">High</option>
111
+ </select>
112
+ </div>
113
 
114
+ <div>
115
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Project</label>
116
+ <input value="@SelectedProjectLabel" readonly
117
+ class="w-full rounded-lg border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-700 focus:outline-none" />
118
  </div>
119
 
120
+ <div>
121
+ <label class="block text-sm font-medium text-slate-700 mb-1.5">Assignee</label>
122
+ <div class="relative">
123
+ <button type="button"
124
+ @onclick="ToggleAssigneeDropdown"
125
+ class="flex h-11 w-full items-center justify-between rounded-lg border border-slate-200 bg-white px-3 text-left text-sm text-slate-900 shadow-sm transition-colors hover:border-violet-300 hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-violet-600">
126
+ <span class="truncate @(formAssignedTo.HasValue ? "font-medium text-slate-900" : "text-slate-400")">@SelectedAssigneeLabel</span>
127
+ <i data-lucide="chevron-down" class="ml-3 h-4 w-4 shrink-0 text-slate-400"></i>
128
+ </button>
129
+
130
+ @if (isAssigneeDropdownOpen)
131
+ {
132
+ <div class="absolute bottom-full left-0 z-30 mb-2 w-full rounded-2xl border border-slate-200 bg-white p-3 shadow-[0_18px_40px_rgba(15,23,42,0.16)]">
133
+ <div class="flex items-center justify-end">
134
+ <button type="button"
135
+ @onclick="CloseAssigneeDropdown"
136
+ class="inline-flex h-7 w-7 items-center justify-center rounded-lg text-slate-400 transition-colors hover:bg-slate-100 hover:text-slate-600"
137
+ aria-label="Close assignee dropdown">
138
+ <i data-lucide="x" class="h-4 w-4"></i>
139
+ </button>
140
+ </div>
141
+ <div class="relative">
142
+ <input @bind="assigneeSearchInput"
143
+ @onfocus="EnsureAssigneeDropdownOpen"
144
+ type="text"
145
+ placeholder="Search project members..."
146
+ class="w-full rounded-xl border border-slate-200 bg-white py-2 pl-9 pr-3 text-sm text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-600 focus:border-transparent" />
147
+ <i data-lucide="search" class="absolute left-3 top-2.5 h-4 w-4 text-slate-400"></i>
148
+ </div>
149
 
150
+ @if (isLoadingProjectMembers)
151
+ {
152
+ <div class="mt-3 rounded-xl border border-dashed border-slate-200 bg-slate-50 px-3 py-4 text-center text-xs text-slate-500">
153
+ Loading project members...
154
+ </div>
155
+ }
156
+ else
157
+ {
158
+ <div class="mt-3 max-h-56 overflow-y-auto space-y-2 pr-1">
159
+ <button type="button"
160
+ @onclick="() => SetFormAssignee(null)"
161
+ class="flex w-full items-center gap-3 rounded-xl border px-3 py-3 text-left transition-colors @(formAssignedTo.HasValue ? "border-slate-200 bg-white hover:bg-slate-50" : "border-violet-600 bg-violet-50/40")">
162
+ <span class="flex h-9 w-9 items-center justify-center rounded-full bg-slate-100 text-slate-500 text-xs font-bold shrink-0">
163
+ <i data-lucide="user-minus" class="h-4 w-4"></i>
164
+ </span>
165
+ <div class="min-w-0 flex-1">
166
+ <p class="text-sm font-semibold text-slate-900">Unassigned</p>
167
+ </div>
168
+ </button>
169
 
170
+ @foreach (var user in FilteredProjectMembers)
171
+ {
172
+ var isSelected = formAssignedTo == user.Id;
173
+ <button type="button"
174
+ @onclick="() => SetFormAssignee(user.Id)"
175
+ class="flex w-full items-center gap-3 rounded-xl border px-3 py-3 text-left transition-colors @(isSelected ? "border-violet-600 bg-violet-50/40" : "border-slate-100 bg-white hover:border-slate-200 hover:bg-slate-50")">
176
+ <span class="flex h-9 w-9 items-center justify-center rounded-full bg-violet-100 text-violet-700 text-xs font-bold shrink-0">
177
+ @(user.FirstName.Length > 0 ? user.FirstName[0].ToString().ToUpper() : "")@(user.LastName.Length > 0 ? user.LastName[0].ToString().ToUpper() : "")
178
+ </span>
179
+ <div class="min-w-0 flex-1">
180
+ <p class="truncate text-sm font-semibold text-slate-900">@user.FirstName @user.LastName</p>
181
+ <p class="truncate text-xs text-slate-500">@@@user.Username</p>
182
+ </div>
183
+ </button>
184
+ }
185
+
186
+ @if (!FilteredProjectMembers.Any())
187
+ {
188
+ <div class="rounded-xl border border-dashed border-slate-200 bg-slate-50 px-3 py-4 text-center text-xs text-slate-500">
189
+ No members match the current search.
190
+ </div>
191
+ }
192
+ </div>
193
+ }
194
+ </div>
195
+ }
196
  </div>
197
  </div>
198
  </div>
199
+
200
+ <div class="mt-6 flex items-center justify-end gap-3">
201
+ <button @onclick="ResetForm" class="inline-flex items-center rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50 transition-colors shadow-sm">
202
+ Reset
203
+ </button>
204
+ <button @onclick="RequestSaveConfirmation" disabled="@isSaving" class="inline-flex items-center rounded-lg bg-violet-600 px-5 py-2 text-sm font-semibold text-white hover:bg-violet-700 disabled:opacity-50 transition-colors shadow-sm">
205
+ @(isSaving ? "Saving..." : "Add Issue")
206
+ </button>
207
+ </div>
208
+
209
+ @if (!string.IsNullOrWhiteSpace(errorMessage))
210
+ {
211
+ <p class="mt-4 text-sm text-red-600">@errorMessage</p>
212
+ }
213
  </div>
214
  }
215
  </div>
 
245
  private string formTitle = "";
246
  private string? formDescription;
247
  private long? formAssignedTo;
248
+ private decimal? formEstimatedHours;
249
  private decimal? formActualHours = 7m;
250
  private DateTime formStartDate = DateTime.Today;
251
  private DateTime formDueDate = DateTime.Today;
 
469
  Title = formTitle.Trim(),
470
  Description = formDescription,
471
  AssignedTo = formAssignedTo,
472
+ EstimatedHours = formEstimatedHours,
473
  ActualHours = formActualHours,
474
  StartDate = formStartDate,
475
  DueDate = formDueDate,
 
506
  formTitle = "";
507
  formDescription = null;
508
  formAssignedTo = currentUserId;
509
+ formEstimatedHours = null;
510
  formActualHours = 7m;
511
  formStartDate = DateTime.Today;
512
  formDueDate = DateTime.Today;