Updated the proostekrant to work properly again.

This commit is contained in:
douwe
2026-10-09 10:33:21 +02:00
parent 56d143b74b
commit 256a81a770
133 changed files with 10491 additions and 837 deletions
@@ -0,0 +1,190 @@
@page "/artikelen/nieuw"
@attribute [Authorize(Policy = "Editor")]
@using System.ComponentModel.DataAnnotations
@inject ArticleService Artikelen
@inject SeasonService Seizoenen
@inject UserService Gebruikers
@inject UploadService Uploads
<PageTitle>Nieuw artikel — ProostenKrant</PageTitle>
<section class="card">
<h1 class="headline">Nieuw artikel</h1>
<p class="muted">Artikel voor de redactie aanmaken en eventueel direct publiceren.</p>
@if (_fout is not null)
{
<p class="alert alert-error">@_fout</p>
}
<EditForm FormName="artikel-nieuw" Method="post" Model="Input" OnValidSubmit="Opslaan"
class="krant-form" enctype="multipart/form-data">
<div class="form-group">
<label for="title">Titel</label>
<InputText @bind-Value="Input.Title" id="title" class="form-control" placeholder="De kop boven het artikel" />
<ValidationMessage For="() => Input.Title" />
</div>
<div class="form-group">
<label for="content">Tekst</label>
<InputTextArea @bind-Value="Input.Content" id="content" rows="10" class="form-control" placeholder="Schrijf hier de inhoud van je artikel…" />
<ValidationMessage For="() => Input.Content" />
</div>
<div class="form-row">
<div class="form-group">
<label for="writer">Schrijver</label>
<InputSelect @bind-Value="Input.WriterId" id="writer" class="form-control">
<option value="0">— Kies schrijver —</option>
@foreach (var gebruiker in _gebruikers)
{
<option value="@gebruiker.Id">@gebruiker.DisplayName</option>
}
</InputSelect>
<ValidationMessage For="() => Input.WriterId" />
</div>
<div class="form-group">
<label for="eventdate">Datum van de gebeurtenis</label>
<InputDate @bind-Value="Input.EventDate" id="eventdate" class="form-control" />
<ValidationMessage For="() => Input.EventDate" />
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="season">Seizoen</label>
<InputSelect @bind-Value="Input.SeasonId" id="season" class="form-control">
<option value="0">— Kies seizoen —</option>
@foreach (var seizoen in _seizoenen)
{
<option value="@seizoen.Id">@seizoen.Name</option>
}
</InputSelect>
<ValidationMessage For="() => Input.SeasonId" />
</div>
<div class="form-group">
<label for="status">Status</label>
<InputSelect @bind-Value="Input.Status" id="status" class="form-control">
<option value="draft">Klad</option>
<option value="published">Gepubliceerd</option>
</InputSelect>
</div>
</div>
<div class="form-group">
<label>Deelnemers</label>
<div class="checkbox-group">
@foreach (var gebruiker in _gebruikers)
{
<label class="checkbox-label">
<input type="checkbox" name="Participants" value="@gebruiker.Id"
checked="@(_geselecteerd.Contains(gebruiker.Id))" />
<span>@gebruiker.DisplayName</span>
</label>
}
</div>
@if (_participantsFout is not null)
{
<span class="error-message">@_participantsFout</span>
}
</div>
<div class="form-group">
<label for="image">Afbeelding (optioneel)</label>
<input type="file" name="Afbeelding" id="image" class="form-control" accept="image/*" />
<span class="help-text">JPG, PNG, GIF of WEBP, maximaal 25 MB.</span>
@if (_afbeeldingFout is not null)
{
<span class="error-message">@_afbeeldingFout</span>
}
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Artikel opslaan</button>
<a class="btn" href="/artikelen">Annuleren</a>
</div>
</EditForm>
</section>
@code {
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
[SupplyParameterFromForm(FormName = "artikel-nieuw")]
private ArtikelInput Input { get; set; } = new();
private List<User> _gebruikers = new();
private List<Season> _seizoenen = new();
private List<int> _geselecteerd = new();
private string? _fout;
private string? _participantsFout;
private string? _afbeeldingFout;
protected override async Task OnInitializedAsync()
{
Input ??= new();
_gebruikers = await Gebruikers.GetAllAsync();
_seizoenen = await Seizoenen.GetAllAsync();
var huidig = await Seizoenen.GetCurrentAsync();
Input.SeasonId ??= huidig?.Id ?? (_seizoenen.FirstOrDefault()?.Id ?? 0);
Input.EventDate ??= DateTime.Today;
Input.Status ??= "published";
}
private async Task Opslaan()
{
Input ??= new();
var form = HttpContext.Request.Form;
_geselecteerd = form["Participants"].SelectMany(v => (v ?? "").Split(','))
.Select(s => int.TryParse(s, out var id) ? id : 0).Where(id => id > 0).ToList();
if (Input.WriterId <= 0)
{
_fout = "Kies een schrijver.";
return;
}
if (!_geselecteerd.Contains(Input.WriterId))
{
_geselecteerd.Insert(0, Input.WriterId);
}
if (_geselecteerd.Count == 0)
{
_participantsFout = "Selecteer minstens één deelnemer.";
return;
}
var (webPad, fout) = await Uploads.SaveArticleImageAsync(HttpContext.Request.Form.Files["Afbeelding"]);
if (fout is not null)
{
_afbeeldingFout = fout;
return;
}
var artikel = new Article
{
Title = Input.Title,
Content = Input.Content,
AuthorId = Input.WriterId,
Participants = string.Join(",", _geselecteerd),
EventDate = Input.EventDate,
SeasonId = Input.SeasonId,
ArticleImage = webPad,
Status = Input.Status == "published" ? "published" : "draft",
};
await Artikelen.CreateAsync(artikel);
Nav.NavigateTo("/artikelen?melding=" + Uri.EscapeDataString("Artikel succesvol opgeslagen."), forceLoad: true);
}
private sealed class ArtikelInput
{
[Required(ErrorMessage = "Geef het artikel een titel (minstens 5 tekens).")]
[MinLength(5, ErrorMessage = "De titel moet minstens 5 tekens bevatten.")]
[MaxLength(255)]
public string Title { get; set; } = "";
[Required(ErrorMessage = "Schrijf de tekst van het artikel (minstens 10 tekens).")]
[MinLength(10, ErrorMessage = "De tekst moet minstens 10 tekens bevatten.")]
public string Content { get; set; } = "";
public int WriterId { get; set; }
public DateTime? EventDate { get; set; }
public int? SeasonId { get; set; }
public string? Status { get; set; }
}
}