diff --git a/Apps/Client/NotificationManager.cs b/Apps/Client/NotificationManager.cs new file mode 100644 index 0000000..91a5d91 --- /dev/null +++ b/Apps/Client/NotificationManager.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Client +{ + /// + /// Service permettant d'afficher des toasts dans l'application. + /// + public class NotificationManager + { + private Queue _messages = new Queue(); + + public IReadOnlyList Messages => _messages.ToArray(); + + public event Action OnChange; + + public void Add(string message) + { + _messages.Enqueue(message); + + Task.Run(async () => + { + await Task.Delay(3000); + _messages.Dequeue(); + OnChange?.Invoke(); + }); + + OnChange?.Invoke(); + } + } +} \ No newline at end of file diff --git a/Apps/Client/Pages/Counter.razor b/Apps/Client/Pages/Counter.razor deleted file mode 100644 index bd823e5..0000000 --- a/Apps/Client/Pages/Counter.razor +++ /dev/null @@ -1,16 +0,0 @@ -@page "/counter" - -

Counter

- -

Current count: @currentCount

- - - -@code { - private int currentCount = 0; - - private void IncrementCount() - { - currentCount++; - } -} diff --git a/Apps/Client/Pages/Detail.razor b/Apps/Client/Pages/Detail.razor new file mode 100644 index 0000000..947cec7 --- /dev/null +++ b/Apps/Client/Pages/Detail.razor @@ -0,0 +1,58 @@ +@page "/links/{id:guid}" +@inject LinksClient Links +@inject CommentsClient Comments +@inject NotificationManager Notification + +@if (_link == null) +{ + + <p>Loading link detail...</p> +} +else +{ + <Title Value="@($"Viewing link {_link.Url}")" /> + + <h1>Viewing link @_link.Url</h1> + + @if(_comments == null) + { + <p>Loading link comments...</p> + } + else if (_comments.Count == 0) + { + <p>No comments yet.</p> + } + else + { + <ul> + @foreach (var comment in _comments) + { + <li>@comment.Content</li> + } + </ul> + } + + <CommentForm OnSubmit="PublishComment" /> +} + +@code { + [Parameter] + public Guid Id { get; set; } + + private LinkDTO _link; + private ICollection<CommentDTO> _comments; + + protected override async Task OnInitializedAsync() + { + _link = await Links.GetByIdAsync(Id); + _comments = await Links.CommentsAsync(Id); + } + + private async Task PublishComment(PublishCommentCommand cmd) + { + cmd.LinkId = Id; + await Comments.CreateAsync(cmd); + Notification.Add("Your comment was published!"); + _comments = await Links.CommentsAsync(Id); + } +} \ No newline at end of file diff --git a/Apps/Client/Pages/Index.razor b/Apps/Client/Pages/Index.razor index e19a1fb..ba86004 100644 --- a/Apps/Client/Pages/Index.razor +++ b/Apps/Client/Pages/Index.razor @@ -1,6 +1,8 @@ @page "/" @inject LinksClient Links +<Title Value="Latest links" /> + <h1>Latest links</h1> @if (_links == null) { diff --git a/Apps/Client/Pages/PublishLink.razor b/Apps/Client/Pages/PublishLink.razor index b7e31fe..70074fd 100644 --- a/Apps/Client/Pages/PublishLink.razor +++ b/Apps/Client/Pages/PublishLink.razor @@ -1,6 +1,7 @@ @page "/links/new" @inject LinksClient Links @inject NavigationManager Navigation +@inject NotificationManager Notification @using System.ComponentModel.DataAnnotations <h1>Publish a new link!</h1> @@ -29,6 +30,7 @@ try { await Links.CreateAsync(_model.Command); + Notification.Add("Your link was published!"); Navigation.NavigateTo("/"); } catch(Exception ex) diff --git a/Apps/Client/Pages/Sandbox.razor b/Apps/Client/Pages/Sandbox.razor new file mode 100644 index 0000000..3f7805a --- /dev/null +++ b/Apps/Client/Pages/Sandbox.razor @@ -0,0 +1,20 @@ +@page "/sandbox" + +<p>Current count: @currentCount</p> + +<Counter @bind-Count="currentCount" /> + +@* <CascadingValue Value="45"> + <Composant1 /> +</CascadingValue> + +<Composant2 /> *@ + +@code { + private int currentCount = 0; + + /* + [CascadingParameter] + public int Valeur { get; set; } + */ +} \ No newline at end of file diff --git a/Apps/Client/Program.cs b/Apps/Client/Program.cs index 04623a0..d3054c4 100644 --- a/Apps/Client/Program.cs +++ b/Apps/Client/Program.cs @@ -19,6 +19,8 @@ namespace Client builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.Configuration["BaseUrl"]) }); builder.Services.AddScoped<LinksClient>(); + builder.Services.AddScoped<CommentsClient>(); + builder.Services.AddSingleton<NotificationManager>(); await builder.Build().RunAsync(); } diff --git a/Apps/Client/Shared/CommentForm.razor b/Apps/Client/Shared/CommentForm.razor new file mode 100644 index 0000000..b5c5a90 --- /dev/null +++ b/Apps/Client/Shared/CommentForm.razor @@ -0,0 +1,22 @@ +<EditForm Model="_model" OnValidSubmit="OnValidSubmit"> + <DataAnnotationsValidator /> + <ValidationSummary /> + + <label for="content">Your comment</label> + <InputTextArea id="content" @bind-Value="_model.Content" /> + + <button type="submit">Post your comment</button> +</EditForm> + +@code { + [Parameter] + public EventCallback<PublishCommentCommand> OnSubmit { get; set; } + + private PublishCommentCommand _model = new PublishCommentCommand(); + + private async Task OnValidSubmit() + { + await OnSubmit.InvokeAsync(_model); + _model = new PublishCommentCommand(); + } +} \ No newline at end of file diff --git a/Apps/Client/Shared/Counter.razor b/Apps/Client/Shared/Counter.razor new file mode 100644 index 0000000..461474b --- /dev/null +++ b/Apps/Client/Shared/Counter.razor @@ -0,0 +1,22 @@ +<p>Current count in component: @Count</p> + +<button @onclick="Increment">+</button> +<button @onclick="Decrement">-</button> + +@code { + [Parameter] + public int Count { get; set; } + + [Parameter] + public EventCallback<int> CountChanged { get; set; } + + private void Increment() + { + CountChanged.InvokeAsync(Count + 1); + } + + private void Decrement() + { + CountChanged.InvokeAsync(Count - 1); + } +} diff --git a/Apps/Client/Shared/LinkItem.razor b/Apps/Client/Shared/LinkItem.razor index 1b68e5c..65868dd 100644 --- a/Apps/Client/Shared/LinkItem.razor +++ b/Apps/Client/Shared/LinkItem.razor @@ -1,6 +1,7 @@ <article> <h2>@Item.Url</h2> <p> + <NavLink href="@($"/links/{Item.Id}")">Show</NavLink> - Published at @Item.CreatedAt.DateTime.ToLongDateString() - 🗨 @Item.CommentsCount - 👍 @Item.UpvotesCount / 👎 @Item.DownvotesCount diff --git a/Apps/Client/Shared/MainLayout.razor b/Apps/Client/Shared/MainLayout.razor index a76e097..31fa892 100644 --- a/Apps/Client/Shared/MainLayout.razor +++ b/Apps/Client/Shared/MainLayout.razor @@ -11,6 +11,8 @@ </div> <div class="content px-4"> + <Notifications /> + @Body </div> </div> diff --git a/Apps/Client/Shared/Notifications.razor b/Apps/Client/Shared/Notifications.razor new file mode 100644 index 0000000..c706ab7 --- /dev/null +++ b/Apps/Client/Shared/Notifications.razor @@ -0,0 +1,21 @@ +@inject NotificationManager Notification +@implements IDisposable + +<div> + @foreach (var msg in Notification.Messages) + { + <p class="alert alert-success">@msg</p> + } +</div> + +@code { + protected override void OnInitialized() + { + Notification.OnChange += StateHasChanged; + } + + public void Dispose() + { + Notification.OnChange -= StateHasChanged; + } +} diff --git a/Apps/Client/Shared/Title.razor b/Apps/Client/Shared/Title.razor new file mode 100644 index 0000000..45581ec --- /dev/null +++ b/Apps/Client/Shared/Title.razor @@ -0,0 +1,11 @@ +@inject IJSRuntime JS + +@code { + [Parameter] + public string Value { get; set; } + + protected override void OnInitialized() + { + JS.InvokeVoidAsync("setTitle", Value); + } +} \ No newline at end of file diff --git a/Apps/Client/wwwroot/index.html b/Apps/Client/wwwroot/index.html index 5e02d1b..889c804 100644 --- a/Apps/Client/wwwroot/index.html +++ b/Apps/Client/wwwroot/index.html @@ -1,25 +1,32 @@ <!DOCTYPE html> <html> - -<head> + <head> <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> + <meta + name="viewport" + content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" + /> <title>Client - + - +
Loading...
- An unhandled error has occurred. - Reload - 🗙 + An unhandled error has occurred. + Reload + 🗙
- - + + +