@namespace OpenArchival.Blazor.AdminPages.Shared @using Microsoft.AspNetCore.Components.Web @using OpenArchival.DataAccess @using System.ComponentModel.DataAnnotations @using OpenArchival.Blazor.CustomComponents @using MudBlazor @inject ArtifactEntrySharedHelpers Helpers; @inject IArtifactDefectProvider DefectsProvider; @inject IArtifactStorageLocationProvider StorageLocationProvider; @inject IArchiveEntryTagProvider TagsProvider; @inject IArtifactTypeProvider TypesProvider; @inject IListedNameProvider ListedNameProvider; @if (Model.Files.Count > 0) { @(Model.Files[0].OriginalName) } Delete @foreach (var error in ValidationResults) { @error.ErrorMessage } Archive Item Title Archive Item Numbering Enter a unique ID for this entry Item Description Item Quantity Storage Location Artifact Type @* Tags entry *@ Tags Listed Names Enter any names of the people associated with this entry. Associated Dates + Defects Related Artifacts Tag this entry with the identifier of any other entry to link them. Artifact Text Contents Input the text transcription of the words on the artifact if applicable to aid the search engine. Additional files @code { [Parameter] public required FilePathListing MainFilePath { get; set; } [Parameter] public EventCallback ModelChanged { get; set; } [Parameter] public EventCallback InputsChanged { get; set; } [Parameter] public required ArtifactEntryValidationModel Model { get; set; } = new() { StorageLocation = "hello", Title = "Hello" }; [Parameter] public required int ArtifactEntryIndex {get; set;} [Parameter] public EventCallback<(int index, string filename)> OnEntryDeletedClicked { get; set; } private ChipContainer _tagsChipContainer; private string _tagsInputValue { get; set; } = ""; private ChipContainer _assocaitedDatesChipContainer; private DateTime? _associatedDateInputValue { get; set; } = default; private ChipContainer _listedNamesChipContainer; private string _listedNamesInputValue { get; set; } = ""; private ChipContainer _defectsChipContainer; private string _defectsInputValue = ""; private ChipContainer _assocaitedArtifactsChipContainer; private ArtifactEntry? _associatedArtifactValue = null; private string _artifactTextContent = ""; public bool IsValid { get; set; } public List ValidationResults { get; private set; } = []; public UploadDropBox _uploadDropBox = default!; protected override Task OnParametersSetAsync() { if (_uploadDropBox is not null && Model is not null && Model.Files is not null) { _uploadDropBox.ExistingFiles = Model.Files.GetRange(1, Model.Files.Count - 1); } if (Model.Files is not null && Model.Files.Any()) { MainFilePath = Model.Files[0]; } return base.OnParametersSetAsync(); } public async Task OnInputsChanged() { // 1. Clear previous validation errors ValidationResults.Clear(); var validationContext = new ValidationContext(Model); // 2. Run the validator IsValid = Validator.TryValidateObject(Model, validationContext, ValidationResults, validateAllProperties: true); // 3. REMOVE this line. Let the parent's update trigger the re-render. // StateHasChanged(); await InputsChanged.InvokeAsync(); } private async Task OnFilesUploaded(List filePathListings) { if (MainFilePath is not null) { var oldFiles = Model.Files.GetRange(1, Model.Files.Count - 1); Model.Files = [MainFilePath]; Model.Files.AddRange(oldFiles); Model.Files.AddRange(filePathListings); } else { Model.Files = []; } Model.Files.AddRange(filePathListings); StateHasChanged(); } private async Task OnFilesCleared() { if (MainFilePath is not null) { Model.Files = [MainFilePath]; } else { Model.Files = []; } } private Task OnDefectsValueChanged(string text) { _defectsInputValue = text; return ModelChanged.InvokeAsync(Model); } private Task OnTagsInputTextChanged(string text) { _tagsInputValue = text; return ModelChanged.InvokeAsync(Model); } private Task OnListedNamesTextChanged(string text) { _listedNamesInputValue = text; return ModelChanged.InvokeAsync(Model); } private Task OnAssociatedArtifactChanged(ArtifactEntry grouping) { if (grouping is not null) { _associatedArtifactValue = grouping; return ModelChanged.InvokeAsync(Model); } return ModelChanged.InvokeAsync(Model); } private Task OnArtifactTextContentChanged(string value) { Model.FileTextContent = value; return ModelChanged.InvokeAsync(Model); } public async Task HandleChipContainerEnter(KeyboardEventArgs args, ChipContainer container, Type value, Action resetInputAction) { if (args.Key == "Enter") { await container.AddItem(value); resetInputAction?.Invoke(); StateHasChanged(); await ModelChanged.InvokeAsync(Model); } } public async Task HandleAssociatedDateChipContainerAdd(MouseEventArgs args) { if (_associatedDateInputValue is not null) { DateTime unspecifiedDate = (DateTime)_associatedDateInputValue; DateTime utcDate = DateTime.SpecifyKind(unspecifiedDate, DateTimeKind.Utc); await _assocaitedDatesChipContainer.AddItem(utcDate); _associatedDateInputValue = default; } } private async Task OnDeleteEntryClicked(MouseEventArgs args) { await OnEntryDeletedClicked.InvokeAsync((ArtifactEntryIndex, MainFilePath.OriginalName)); } }