Add UserActionLog and enhance registry features
Build and Push Docker Image / build-and-push (push) Successful in 1m59s
Build and Push Docker Image / build-and-push (push) Successful in 1m59s
- Introduced `UserActionLog` entity to track user actions. - Replaced `CanBeSecondHand` with `PreferSecondHand` property. - Added `ShowBankAccountName` to `RegistrySettings`. - Updated models and migrations for new properties. - Enhanced `RegistryService` with user action logging and item details. - Redesigned `Home.razor` with a grid layout and modal for registries. - Added `RegistryActionLog.razor` for admin action logs. - Improved `RegistryPublic.razor` with purchaser/contributor details. - Replaced sidebar with `TopBar.razor` for responsive navigation. - Updated CSS for new components and improved responsiveness.
This commit is contained in:
@@ -1,86 +1,172 @@
|
||||
@page "/"
|
||||
|
||||
@using BirthList.Web.Features.Registries
|
||||
|
||||
<PageTitle>Birth Registry</PageTitle>
|
||||
|
||||
<h1>Birth Registry</h1>
|
||||
<h1>Welcome to Gift List</h1>
|
||||
|
||||
<AuthorizeView>
|
||||
<Authorized Context="authState">
|
||||
<div class="mb-4">
|
||||
<h2>Create your registry</h2>
|
||||
<EditForm Model="Model" OnValidSubmit="CreateRegistryAsync" Context="formContext" FormName="create-registry-form">
|
||||
<DataAnnotationsValidator />
|
||||
<div class="row g-3">
|
||||
<div class="col-md-5">
|
||||
<label class="form-label">Title</label>
|
||||
<InputText class="form-control" @bind-Value="Model.Title" />
|
||||
<div class="registry-sections">
|
||||
<div class="mb-4">
|
||||
<div class="section-header">
|
||||
<h2>Registries you manage</h2>
|
||||
<button class="btn btn-primary btn-sm" @onclick="() => ShowCreateForm = !ShowCreateForm">
|
||||
<span class="bi bi-plus"></span> Create new
|
||||
</button>
|
||||
</div>
|
||||
@if (MyRegistries.Count == 0)
|
||||
{
|
||||
<p class="text-muted">No registries yet.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="registry-grid">
|
||||
@foreach (var registry in MyRegistries)
|
||||
{
|
||||
<div class="registry-card">
|
||||
<h3>@registry.Title</h3>
|
||||
<div class="registry-actions">
|
||||
<a href="/registry/@registry.PublicLinkCode" class="btn btn-outline-primary btn-sm">View</a>
|
||||
<a href="/registry/@registry.Id/admin" class="btn btn-outline-secondary btn-sm">Manage</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Type</label>
|
||||
<InputSelect class="form-select" @bind-Value="Model.RegistryType">
|
||||
<option value="@BirthList.Domain.Entities.RegistryType.Birth">Birth</option>
|
||||
<option value="@BirthList.Domain.Entities.RegistryType.Wedding">Wedding</option>
|
||||
<option value="@BirthList.Domain.Entities.RegistryType.Birthday">Birthday</option>
|
||||
</InputSelect>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h2>Visited registries</h2>
|
||||
@if (VisitedRegistries.Count == 0)
|
||||
{
|
||||
<p class="text-muted">No visited registries yet.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="registry-grid">
|
||||
@foreach (var registry in VisitedRegistries)
|
||||
{
|
||||
<div class="registry-card">
|
||||
<h3>@registry.Title</h3>
|
||||
<div class="registry-actions">
|
||||
<a href="/registry/@registry.PublicLinkCode" class="btn btn-outline-primary btn-sm">View</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">Theme</label>
|
||||
<InputSelect class="form-select" @bind-Value="Model.ThemeKey">
|
||||
<option value="default">Default</option>
|
||||
<option value="soft">Soft</option>
|
||||
<option value="modern">Modern</option>
|
||||
</InputSelect>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (ShowCreateForm)
|
||||
{
|
||||
<div class="create-registry-modal-overlay" @onclick="() => ShowCreateForm = false">
|
||||
<div class="create-registry-modal" @onclick:stopPropagation="true">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Create new registry</h3>
|
||||
<button type="button" class="btn-close" @onclick="() => ShowCreateForm = false"></button>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<button class="btn btn-primary w-100" type="submit">Create</button>
|
||||
<div class="modal-body">
|
||||
<EditForm Model="Model" OnValidSubmit="CreateRegistryAsync" Context="formContext" FormName="create-registry-form">
|
||||
<DataAnnotationsValidator />
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Title</label>
|
||||
<InputText class="form-control" @bind-Value="Model.Title" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Type</label>
|
||||
<InputSelect class="form-select" @bind-Value="Model.RegistryType">
|
||||
<option value="@BirthList.Domain.Entities.RegistryType.Birth">Birth</option>
|
||||
<option value="@BirthList.Domain.Entities.RegistryType.Wedding">Wedding</option>
|
||||
<option value="@BirthList.Domain.Entities.RegistryType.Birthday">Birthday</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Theme</label>
|
||||
<InputSelect class="form-select" @bind-Value="Model.ThemeKey">
|
||||
<option value="default">Default</option>
|
||||
<option value="soft">Soft</option>
|
||||
<option value="modern">Modern</option>
|
||||
</InputSelect>
|
||||
</div>
|
||||
@if (!string.IsNullOrWhiteSpace(ErrorMessage))
|
||||
{
|
||||
<div class="alert alert-danger mb-3">@ErrorMessage</div>
|
||||
}
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" @onclick="() => ShowCreateForm = false">Cancel</button>
|
||||
<button class="btn btn-primary" type="submit">Create</button>
|
||||
</div>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
</EditForm>
|
||||
@if (!string.IsNullOrWhiteSpace(ErrorMessage))
|
||||
{
|
||||
<div class="alert alert-danger mt-3">@ErrorMessage</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h2>Registries you manage</h2>
|
||||
@if (MyRegistries.Count == 0)
|
||||
{
|
||||
<p>No registries yet.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul>
|
||||
@foreach (var registry in MyRegistries)
|
||||
{
|
||||
<li>
|
||||
<a href="/registry/@registry.PublicLinkCode">@registry.Title</a>
|
||||
|
|
||||
<a href="/registry/@registry.Id/admin">Admin</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Visited registries</h2>
|
||||
@if (VisitedRegistries.Count == 0)
|
||||
{
|
||||
<p>No visited registries yet.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul>
|
||||
@foreach (var registry in VisitedRegistries)
|
||||
{
|
||||
<li><a href="/registry/@registry.PublicLinkCode">@registry.Title</a></li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
<p>Please <a href="Account/Login">log in</a> to create and manage registries.</p>
|
||||
<div class="alert alert-info mt-4">
|
||||
<p>Please <a href="Account/Login">log in</a> to create and manage registries.</p>
|
||||
</div>
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
|
||||
@code {
|
||||
[SupplyParameterFromForm(FormName = "create-registry-form")]
|
||||
protected RegistryCreateModel Model { get; set; } = new();
|
||||
|
||||
protected IReadOnlyList<RegistrySummaryViewModel> MyRegistries { get; private set; } = [];
|
||||
protected IReadOnlyList<RegistrySummaryViewModel> VisitedRegistries { get; private set; } = [];
|
||||
protected string? ErrorMessage { get; private set; }
|
||||
protected bool ShowCreateForm { get; private set; }
|
||||
|
||||
[Inject] private RegistryService RegistryService { get; set; } = null!;
|
||||
[Inject] private RegistryUserContext RegistryUserContext { get; set; } = null!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected async Task CreateRegistryAsync()
|
||||
{
|
||||
ErrorMessage = null;
|
||||
|
||||
var userId = await RegistryUserContext.GetUserIdAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
ErrorMessage = "You must be logged in to create a registry.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Model.Title))
|
||||
{
|
||||
ErrorMessage = "Title is required.";
|
||||
return;
|
||||
}
|
||||
|
||||
await RegistryService.CreateRegistryAsync(userId, Model, CancellationToken.None).ConfigureAwait(false);
|
||||
Model = new RegistryCreateModel
|
||||
{
|
||||
RegistryType = Model.RegistryType,
|
||||
ThemeKey = Model.ThemeKey
|
||||
};
|
||||
ShowCreateForm = false;
|
||||
await LoadAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task LoadAsync()
|
||||
{
|
||||
var userId = await RegistryUserContext.GetUserIdAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
MyRegistries = [];
|
||||
VisitedRegistries = [];
|
||||
return;
|
||||
}
|
||||
|
||||
MyRegistries = await RegistryService.GetAdminRegistriesAsync(userId, CancellationToken.None).ConfigureAwait(false);
|
||||
VisitedRegistries = await RegistryService.GetVisitedRegistriesAsync(userId, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user