@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 List tasks = new(); private List projects = new(); private List projectMembers = new(); private long currentUserId; private long formTaskId; private string formTitle = ""; private string? formTitleMy; private string? formDescription; private string? formDescriptionMy; private bool burmeseGenerated; private bool englishGenerated; private bool burmeseNeedsReview; private bool englishNeedsReview; 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 string? formDelayReasonMy; private bool formIsBlocked; private string? formBlockedBy; private string? formBlockedByMy; private int formEscalationLevel; private string assigneeSearchInput = ""; private bool isAssigneeDropdownOpen; private bool isLoadingProjectMembers; private void MoveIssueTitleToEnglish() { formTitle = formTitleMy ?? string.Empty; } private void MoveIssueTitleToBurmese() { formTitleMy = formTitle; } private void MoveIssueDescriptionToEnglish() { formDescription = formDescriptionMy; } private void MoveIssueDescriptionToBurmese() { formDescriptionMy = formDescription; } private void MoveIssueDelayToEnglish() { formDelayReason = formDelayReasonMy; } private void MoveIssueDelayToBurmese() { formDelayReasonMy = formDelayReason; } private void MoveIssueBlockedByToEnglish() { formBlockedBy = formBlockedByMy; } private void MoveIssueBlockedByToBurmese() { formBlockedByMy = formBlockedBy; } private void MarkGenerated(bool english) { if (english) { englishGenerated = true; englishNeedsReview = true; } else { burmeseGenerated = true; burmeseNeedsReview = true; } } private Task GenerateIssueEnglishTitle(TranslationResult result) { formTitle = result.TranslatedText ?? string.Empty; MarkGenerated(true); return Task.CompletedTask; } private Task GenerateIssueBurmeseTitle(TranslationResult result) { formTitleMy = result.TranslatedText; MarkGenerated(false); return Task.CompletedTask; } private Task GenerateIssueEnglishDescription(TranslationResult result) { formDescription = result.TranslatedText ?? string.Empty; MarkGenerated(true); return Task.CompletedTask; } private Task GenerateIssueBurmeseDescription(TranslationResult result) { formDescriptionMy = result.TranslatedText; MarkGenerated(false); return Task.CompletedTask; } private Task GenerateIssueEnglishDelay(TranslationResult result) { formDelayReason = result.TranslatedText; MarkGenerated(true); return Task.CompletedTask; } private Task GenerateIssueBurmeseDelay(TranslationResult result) { formDelayReasonMy = result.TranslatedText; MarkGenerated(false); return Task.CompletedTask; } private Task GenerateIssueEnglishBlockedBy(TranslationResult result) { formBlockedBy = result.TranslatedText; MarkGenerated(true); return Task.CompletedTask; } private Task GenerateIssueBurmeseBlockedBy(TranslationResult result) { formBlockedByMy = result.TranslatedText; MarkGenerated(false); return Task.CompletedTask; } private TaskDto? SelectedTask => tasks.FirstOrDefault(t => t.Id == formTaskId); private string SelectedTaskLabel => SelectedTask == null ? AppLocalization.Text("common.noTaskSelectedForIssue", "No task selected") : Content.GetTaskTitle(SelectedTask); private string SelectedProjectLabel => SelectedTask == null ? AppLocalization.Text("common.noProject", "No project") : (projects.FirstOrDefault(p => p.Id == SelectedTask.ProjectId) is { } project ? Content.GetProjectName(project) : $"{AppLocalization.Text("common.project", "Project")} #{AppLocalization.Number(SelectedTask.ProjectId)}"); private string SelectedAssigneeLabel => formAssignedTo.HasValue ? (projectMembers.FirstOrDefault(u => u.Id == formAssignedTo.Value) is { } user ? Content.GetUserFullName(user) : AppLocalization.Text("common.selectedMember", "Selected member")) : AppLocalization.Text("common.unassigned", "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} {u.FirstNameMy} {u.LastNameMy}".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) { Console.WriteLine($"Load issue data error: {ex.Message}"); errorMessage = AppLocalization.Text("common.loadFailed", "Unable to load the requested data. Please try again."); } 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 = AppLocalization.Text("validation.selectTaskRequired", "Please select a task."); return; } if (string.IsNullOrWhiteSpace(formTitle) && string.IsNullOrWhiteSpace(formTitleMy)) { isTitleError = true; titleErrorMessage = AppLocalization.Text("validation.issueTitleRequired", "Issue title is required."); return; } if (formDueDate.Date < formStartDate.Date) { errorMessage = AppLocalization.Text("issue.dateRangeInvalid", "The due date cannot be earlier than the start date."); return; } showConfirmDialog = true; } private void CloseConfirmDialog() { showConfirmDialog = false; } private async Task ConfirmSave() { showConfirmDialog = false; await SaveIssueAsync(); } private async Task SaveIssueAsync() { if (isSaving) { return; } if (formTaskId <= 0) { errorMessage = AppLocalization.Text("validation.selectTaskRequired", "Please select a task."); return; } if (string.IsNullOrWhiteSpace(formTitle) && string.IsNullOrWhiteSpace(formTitleMy)) { errorMessage = AppLocalization.Text("validation.issueTitleRequired", "Issue title is required."); return; } if (formDueDate.Date < formStartDate.Date) { errorMessage = AppLocalization.Text("issue.dateRangeInvalid", "The due date cannot be earlier than the start date."); return; } isSaving = true; errorMessage = null; try { var client = ApiClient.CreateClient(); var dto = new CreateIssueDto { TaskId = formTaskId, Title = formTitle.Trim(), TitleMy = formTitleMy, Description = formDescription, DescriptionMy = formDescriptionMy, AssignedTo = formAssignedTo, EstimatedHours = formEstimatedHours, ActualHours = formActualHours, DelayReason = formDelayReason, DelayReasonMy = formDelayReasonMy, IsBlocked = formIsBlocked, BlockedBy = formBlockedBy, BlockedByMy = formBlockedByMy, 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 (response.IsSuccessStatusCode && result?.IsSuccess == true) { Navigation.NavigateTo("/issues/all?created=true"); } else { errorMessage = AppLocalization.Text("issue.failedCreate", "Failed to create issue. Please try again."); Console.WriteLine($"Create issue rejected: {result?.ErrorMessage ?? response.ReasonPhrase}"); } } catch (Exception ex) { errorMessage = AppLocalization.Text("issue.failedCreate", "Failed to create issue. Please try again."); Console.WriteLine($"Create issue error: {ex.Message}"); } finally { isSaving = false; } } private void ResetForm() { formTaskId = tasks.FirstOrDefault()?.Id ?? 0; formTitle = ""; formTitleMy = null; formDescription = null; formDescriptionMy = null; burmeseGenerated = englishGenerated = burmeseNeedsReview = englishNeedsReview = false; formAssignedTo = currentUserId; formEstimatedHours = null; formActualHours = 7m; formStartDate = DateTime.Today; formDueDate = DateTime.Today; formStatusId = AppTaskStatus.Todo; formPriorityId = TaskPriority.Medium; formDelayReason = null; formDelayReasonMy = null; formIsBlocked = false; formBlockedBy = null; formBlockedByMy = null; formEscalationLevel = 0; taskErrorMessage = ""; titleErrorMessage = ""; isTaskError = false; isTitleError = false; assigneeSearchInput = ""; isAssigneeDropdownOpen = false; _ = LoadProjectMembersForTaskAsync(formTaskId); } }