@page "/issues/add" @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using TaskTrackingSystem.Shared @using TaskTrackingSystem.Shared.Enums @using TaskTrackingSystem.Shared.Models.Issue @using TaskTrackingSystem.Shared.Models.Project @using TaskTrackingSystem.Shared.Models.Task @using TaskTrackingSystem.Shared.Models.User @rendermode @(new InteractiveServerRenderMode(prerender: false)) @attribute [Authorize] @inject ApiClientService ApiClient @inject IJSRuntime JS @inject AuthenticationStateProvider AuthStateProvider @inject MenuAuthorizationService MenuAuthorization @inject NavigationManager Navigation @AppLocalization.PageTitle("addIssue", "Add Issue")

@AppLocalization.Text("common.addIssue", "Add Issue")

@AppLocalization.Text("issue.addIssueDescription", "Create a one-day work issue for a task and record the hours you spent.")

@if (isLoading) { } else {
@if (isTaskError) {

@taskErrorMessage

}
@if (isTitleError) {

@titleErrorMessage

}

@AppLocalization.Text("issue.actualHoursHint", "Use the total hours you spent today. For your standard day, this is usually 7 hours.")

@if (isAssigneeDropdownOpen) {
@if (isLoadingProjectMembers) {
@AppLocalization.Text("common.loadingProjectMembers", "Loading project members...")
} else {
@foreach (var user in FilteredProjectMembers) { var isSelected = formAssignedTo == user.Id; } @if (!FilteredProjectMembers.Any()) {
@AppLocalization.Text("common.noMembersMatchSearch", "No members match the current search.")
}
}
}
@if (!string.IsNullOrWhiteSpace(errorMessage)) {

@errorMessage

}
}
@code { private bool isLoading = true; private bool isSaving; private bool showConfirmDialog; private bool isTaskError; private bool isTitleError; private string taskErrorMessage = ""; private string titleErrorMessage = ""; private string? errorMessage; private string? successMessage; private List tasks = new(); private List projects = new(); private List projectMembers = new(); private long currentUserId; private long formTaskId; private string formTitle = ""; private string? formDescription; private long? formAssignedTo; private decimal? formEstimatedHours; private decimal? formActualHours = 7m; private DateTime formStartDate = DateTime.Today; private DateTime formDueDate = DateTime.Today; private AppTaskStatus formStatusId = AppTaskStatus.Todo; private TaskPriority formPriorityId = TaskPriority.Medium; private string? formDelayReason; private bool formIsBlocked; private string? formBlockedBy; private int formEscalationLevel; private string assigneeSearchInput = ""; private bool isAssigneeDropdownOpen; private bool isLoadingProjectMembers; private TaskDto? SelectedTask => tasks.FirstOrDefault(t => t.Id == formTaskId); private string SelectedTaskLabel => SelectedTask == null ? "No task selected" : SelectedTask.Title; private string SelectedProjectLabel => SelectedTask == null ? "No project" : (projects.FirstOrDefault(p => p.Id == SelectedTask.ProjectId)?.Name ?? $"Project #{SelectedTask.ProjectId}"); private string SelectedAssigneeLabel => formAssignedTo.HasValue ? (projectMembers.FirstOrDefault(u => u.Id == formAssignedTo.Value) is { } user ? $"{user.FirstName} {user.LastName}" : "Selected member") : "Unassigned"; private IEnumerable FilteredProjectMembers { get { var result = projectMembers.Where(u => u.IsActive); if (!string.IsNullOrWhiteSpace(assigneeSearchInput)) { var search = assigneeSearchInput.Trim(); result = result.Where(u => $"{u.FirstName} {u.LastName}".Contains(search, StringComparison.OrdinalIgnoreCase) || u.Username.Contains(search, StringComparison.OrdinalIgnoreCase)); } return result.OrderBy(u => u.FirstName).ThenBy(u => u.LastName); } } protected override async Task OnInitializedAsync() { var authState = await AuthStateProvider.GetAuthenticationStateAsync(); var user = authState.User; var idStr = user.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value; if (idStr != null) { long.TryParse(idStr, out currentUserId); } await LoadDataAsync(user); } protected override async Task OnAfterRenderAsync(bool firstRender) { await JS.InvokeVoidAsync("initIcons"); } private async Task LoadDataAsync(System.Security.Claims.ClaimsPrincipal user) { var client = ApiClient.CreateClient(); try { var tasksTask = client.GetFromJsonAsync>("Task", Serialization.CaseInsensitive); var projectsTask = client.GetFromJsonAsync>("Project", Serialization.CaseInsensitive); var usersTask = client.GetFromJsonAsync>("User", Serialization.CaseInsensitive); await Task.WhenAll(tasksTask, projectsTask, usersTask); tasks = tasksTask.Result ?? new(); projects = projectsTask.Result ?? new(); var allUsers = usersTask.Result ?? new(); projectMembers = allUsers.Where(u => u.IsActive).ToList(); formTaskId = tasks.FirstOrDefault()?.Id ?? 0; await LoadProjectMembersForTaskAsync(formTaskId); } catch (Exception ex) { errorMessage = ex.Message; } finally { isLoading = false; } } private async Task OnTaskChanged(ChangeEventArgs e) { if (long.TryParse(e.Value?.ToString(), out var taskId)) { formTaskId = taskId; await LoadProjectMembersForTaskAsync(formTaskId); if (formTaskId > 0) { formAssignedTo = currentUserId; } } } private async Task LoadProjectMembersForTaskAsync(long taskId) { isLoadingProjectMembers = true; projectMembers.Clear(); var task = tasks.FirstOrDefault(t => t.Id == taskId); if (task == null) { formAssignedTo = null; isLoadingProjectMembers = false; return; } var client = ApiClient.CreateClient(); try { var membersResult = await client.GetFromJsonAsync>>($"Project/{task.ProjectId}/members", Serialization.CaseInsensitive); if (membersResult?.IsSuccess == true && membersResult.Value != null) { projectMembers = membersResult.Value.Where(u => u.IsActive).OrderBy(u => u.FirstName).ThenBy(u => u.LastName).ToList(); if (projectMembers.Any(u => u.Id == currentUserId)) { formAssignedTo = currentUserId; } else if (formAssignedTo.HasValue && !projectMembers.Any(u => u.Id == formAssignedTo.Value)) { formAssignedTo = projectMembers.FirstOrDefault()?.Id; } } } catch (Exception ex) { Console.WriteLine($"Failed to load project members: {ex.Message}"); } finally { isLoadingProjectMembers = false; } } private void ToggleAssigneeDropdown() { isAssigneeDropdownOpen = !isAssigneeDropdownOpen; if (isAssigneeDropdownOpen) { assigneeSearchInput = ""; } } private void CloseAssigneeDropdown() { isAssigneeDropdownOpen = false; } private void EnsureAssigneeDropdownOpen() { isAssigneeDropdownOpen = true; } private void SetFormAssignee(long? userId) { formAssignedTo = userId; isAssigneeDropdownOpen = false; assigneeSearchInput = ""; } private void RequestSaveConfirmation() { isTaskError = false; isTitleError = false; taskErrorMessage = ""; titleErrorMessage = ""; if (formTaskId <= 0) { isTaskError = true; taskErrorMessage = "Please select a task."; return; } if (string.IsNullOrWhiteSpace(formTitle)) { isTitleError = true; titleErrorMessage = "Issue title is required."; return; } showConfirmDialog = true; } private void CloseConfirmDialog() { showConfirmDialog = false; } private async Task ConfirmSave() { showConfirmDialog = false; await SaveIssueAsync(); } private async Task SaveIssueAsync() { if (formTaskId <= 0) { errorMessage = "Please select a task."; return; } if (string.IsNullOrWhiteSpace(formTitle)) { errorMessage = "Issue title is required."; return; } isSaving = true; errorMessage = null; try { var client = ApiClient.CreateClient(); var dto = new CreateIssueDto { TaskId = formTaskId, Title = formTitle.Trim(), Description = formDescription, AssignedTo = formAssignedTo, EstimatedHours = formEstimatedHours, ActualHours = formActualHours, DelayReason = formDelayReason, IsBlocked = formIsBlocked, BlockedBy = formBlockedBy, EscalationLevel = formEscalationLevel, StartDate = formStartDate, DueDate = formDueDate, StatusId = formStatusId, PriorityId = formPriorityId }; var response = await client.PostAsJsonAsync("Issue", dto); var result = await response.Content.ReadFromJsonAsync>(Serialization.CaseInsensitive); if (result?.IsSuccess == true) { successMessage = "Issue created successfully!"; ResetForm(); } else { errorMessage = result?.ErrorMessage ?? "Failed to create issue."; } } catch (Exception ex) { errorMessage = ex.Message; } finally { isSaving = false; } } private void ResetForm() { formTaskId = tasks.FirstOrDefault()?.Id ?? 0; formTitle = ""; formDescription = null; formAssignedTo = currentUserId; formEstimatedHours = null; formActualHours = 7m; formStartDate = DateTime.Today; formDueDate = DateTime.Today; formStatusId = AppTaskStatus.Todo; formPriorityId = TaskPriority.Medium; formDelayReason = null; formIsBlocked = false; formBlockedBy = null; formEscalationLevel = 0; taskErrorMessage = ""; titleErrorMessage = ""; isTaskError = false; isTitleError = false; assigneeSearchInput = ""; isAssigneeDropdownOpen = false; _ = LoadProjectMembersForTaskAsync(formTaskId); } }