Files
WorkManagementTool/WorkManagementTool/Components/ProjectTask/ProjectTaskCreation.razor
Namu 0cd4cd37fc
Some checks failed
build / build (push) Failing after 27s
SonarQube Scan / SonarQube Trigger (push) Successful in 33s
Feat: Adds project task creation
2026-01-26 16:13:31 +01:00

187 lines
5.9 KiB
Plaintext

@page "/projects/tasks/creation/{ProjectId:int}"
@using Microsoft.AspNetCore.Authorization
@using Services;
@using Data.Entities;
@using Microsoft.AspNetCore.Components.Forms
@attribute [Authorize]
@rendermode InteractiveServer
@inject ProjectService ProjectService
@inject ProjectTaskService ProjectTaskService
@inject NavigationManager NavigationManager
@inject ILogger<ProjectTaskCreation> Logger
<h3>Project Task Creation</h3>
@if (Project is null)
{
<p class="alert alert-warning">Project not found</p>
}
else
{
<h5>@Project.Name task creation</h5>
<EditForm EditContext="@editContext" OnValidSubmit="Submit" class="mb-3" FormName="project-task-creation">
<ValidationSummary />
<div class="form-group mb-2">
<label for="title" class="form-label">Title</label>
<InputText id="title" class="form-control" @bind-Value="Model!.Title" />
<ValidationMessage For="@(() => Model!.Title)" />
</div>
<div class="form-group mb-2">
<label for="description" class="form-label">Description</label>
<InputTextArea id="description" class="form-control" @bind-Value="Model!.Description" />
<ValidationMessage For="@(() => Model!.Description)" />
</div>
<div class="form-group mb-2">
<label for="due-date" class="form-label">Due date</label>
<InputDate id="due-date" class="form-control" @bind-Value="Model!.DueDate" />
<ValidationMessage For="@(() => Model!.DueDate)" />
</div>
@if (Project.Tasks != null && Project.Tasks.Any())
{
<div class="form-group mb-3">
<label class="form-label">Previous tasks (0..N)</label>
<div class="border rounded p-2" style="max-height:220px; overflow:auto;">
@foreach (var t in Project.Tasks)
{
<div class="form-check">
<input class="form-check-input"
type="checkbox"
id="prev-@t.Id"
checked="@selectedPreviousTaskIds.Contains(t.Id)"
@onchange="e => TogglePreviousTask((ChangeEventArgs)e, t.Id)" />
<label class="form-check-label" for="prev-@t.Id">
@t.Title (@t.DueDate.ToShortDateString())
</label>
</div>
}
</div>
@if (previousTasksError is not null)
{
<div class="text-danger mt-1">@previousTasksError</div>
}
</div>
}
<button type="submit" class="btn btn-primary">+</button>
</EditForm>
}
@code {
[Parameter]
public int ProjectId { get; set; }
public Project? Project { get; set; }
public ProjectTask? Model { get; set; }
private EditContext? editContext;
private ValidationMessageStore? messageStore;
// contient les ids sélectionnés via les checkboxes
private HashSet<int> selectedPreviousTaskIds = new();
private string? previousTasksError;
protected async override Task OnInitializedAsync()
{
Project = await ProjectService.GetProjectByIdAsync(ProjectId);
Model = new()
{
DueDate = DateTime.Now.AddDays(1)
};
editContext = new EditContext(Model!);
messageStore = new ValidationMessageStore(editContext);
editContext.OnFieldChanged += (_, args) =>
{
if (args.FieldIdentifier.FieldName == nameof(ProjectTask.DueDate))
{
ValidatePreviousDates();
}
};
}
private void TogglePreviousTask(ChangeEventArgs e, int id)
{
var isChecked = e?.Value is bool b && b;
if (!isChecked && e?.Value is string s)
isChecked = s == "true" || s == "on" || s == "checked";
if (isChecked)
selectedPreviousTaskIds.Add(id);
else
selectedPreviousTaskIds.Remove(id);
ValidatePreviousDates();
}
private void ValidatePreviousDates()
{
if (messageStore is null || editContext is null || Model is null)
return;
messageStore.Clear();
if (selectedPreviousTaskIds.Count > 0)
{
var invalids = new List<string>();
foreach (var id in selectedPreviousTaskIds)
{
var prev = Project?.Tasks?.FirstOrDefault(t => t.Id == id);
if (prev != null)
{
if (prev.DueDate >= Model.DueDate)
{
invalids.Add($"« {prev.Title} » due {prev.DueDate.ToShortDateString()} must be before the new task due date.");
}
}
}
if (invalids.Any())
{
messageStore.Add(new FieldIdentifier(Model, nameof(Model.DueDate)), invalids);
previousTasksError = "Certaines tâches précédentes ont une date d'échéance non cohérente.";
}
else
{
previousTasksError = null;
}
}
else
{
previousTasksError = null;
}
editContext.NotifyValidationStateChanged();
}
private async Task Submit()
{
if (Model is null || Project is null || editContext is null)
return;
ValidatePreviousDates();
var valid = editContext.Validate();
if (!valid)
{
Logger.LogWarning("Project task form invalid.");
return;
}
// On passe uniquement les ids au service (solution simple et sans conflit de tracking)
Model.Project = Project;
await ProjectTaskService.AddTaskAsync(Model, selectedPreviousTaskIds);
NavigationManager.NavigateTo($"/projects/tasks/{ProjectId}");
}
}