Display profile now works

wrapping up #2
This commit is contained in:
Daniel J. Summers 2021-01-07 22:49:10 -05:00
parent ef12da01dc
commit 4f1c7b782a
18 changed files with 192 additions and 31 deletions

View File

@ -3,4 +3,6 @@
@inject NavigationManager nav @inject NavigationManager nav
@inject AppState state @inject AppState state
<PageTitle Title="Logging in..." />
<p>@Message</p> <p>@Message</p>

View File

@ -2,6 +2,8 @@
@inject HttpClient http @inject HttpClient http
@inject AppState state @inject AppState state
<PageTitle Title="Dashboard" />
<h3>Welcome, @state.User!.Name!</h3> <h3>Welcome, @state.User!.Name!</h3>
@if (RetrievingData) @if (RetrievingData)
@ -17,17 +19,19 @@ else
Your employment profile was last updated <FullDateTime TheDate=@Profile.LastUpdatedOn />. Your profile currently Your employment profile was last updated <FullDateTime TheDate=@Profile.LastUpdatedOn />. Your profile currently
lists @Profile.Skills.Length skill@(Profile.Skills.Length != 1 ? "s" : ""). lists @Profile.Skills.Length skill@(Profile.Skills.Length != 1 ? "s" : "").
</p> </p>
<p><a href="/profile/view/@state.User.Id">View Your Employment Profile</a></p>
} }
else else
{ {
<p>You do not have an employment profile established; click &ldquo;Profile&rdquo;* in the menu to get started!</p> <p>You do not have an employment profile established; click &ldquo;Profile&rdquo;* in the menu to get started!</p>
} }
<hr>
<p> <p>
There @(ProfileCount == 1 ? "is" : "are") @(ProfileCount == 0 ? "no" : ProfileCount) employment There @(ProfileCount == 1 ? "is" : "are") @(ProfileCount == 0 ? "no" : ProfileCount) employment
profile@(ProfileCount != 1 ? "s" : "") from citizens of Gitmo Nation. profile@(ProfileCount != 1 ? "s" : "") from citizens of Gitmo Nation.
@if (ProfileCount > 0) @if (ProfileCount > 0)
{ {
<text>Take a look around and see if you can help them find work!</text> <text>Take a look around and see if you can help them find work!</text> <em>(coming soon)</em>
} }
</p> </p>
</ErrorList> </ErrorList>

View File

@ -1,22 +1,16 @@
@page "/citizen/profile" @page "/citizen/profile"
@inject HttpClient http @inject HttpClient http
@inject AppState state @inject AppState state
@inject NavigationManager nav
@inject IToastService toast @inject IToastService toast
<PageTitle Title="Edit Profile" />
<h3>Employment Profile</h3> <h3>Employment Profile</h3>
@if (AllLoaded) @if (AllLoaded)
{ {
@if (ErrorMessages.Count > 0) <ErrorList Errors=@ErrorMessages>
{
<p><strong>Error</strong></p>
@foreach (var msg in ErrorMessages)
{
<p>@msg</p>
}
}
else
{
<EditForm Model=@ProfileForm OnValidSubmit=@SaveProfile> <EditForm Model=@ProfileForm OnValidSubmit=@SaveProfile>
<DataAnnotationsValidator /> <DataAnnotationsValidator />
<div class="form-row"> <div class="form-row">
@ -111,7 +105,13 @@
</div> </div>
</div> </div>
</EditForm> </EditForm>
@if (!IsNew)
{
<p>
<br><a href="/profile/view/@state.User!.Id"><span class="oi oi-file"></span> View Your User Profile</a>
</p>
} }
</ErrorList>
} }
else else
{ {

View File

@ -33,6 +33,11 @@ namespace JobsJobsJobs.Client.Pages.Citizen
/// </summary> /// </summary>
private IEnumerable<Continent> Continents { get; set; } = Enumerable.Empty<Continent>(); private IEnumerable<Continent> Continents { get; set; } = Enumerable.Empty<Continent>();
/// <summary>
/// Whether this is a new profile or not
/// </summary>
private bool IsNew { get; set; } = false;
/// <summary> /// <summary>
/// Error messages from API access /// Error messages from API access
/// </summary> /// </summary>
@ -57,9 +62,15 @@ namespace JobsJobsJobs.Client.Pages.Citizen
if (profileTask.Result.IsOk) if (profileTask.Result.IsOk)
{ {
ProfileForm = (profileTask.Result.Ok == null) if (profileTask.Result.Ok == null)
? new ProfileForm() {
: ProfileForm.FromProfile(profileTask.Result.Ok); ProfileForm = new ProfileForm();
IsNew = true;
}
else
{
ProfileForm = ProfileForm.FromProfile(profileTask.Result.Ok);
}
if (ProfileForm.Skills.Count == 0) AddNewSkill(); if (ProfileForm.Skills.Count == 0) AddNewSkill();
} }
else else
@ -98,6 +109,7 @@ namespace JobsJobsJobs.Client.Pages.Citizen
if (res.IsSuccessStatusCode) if (res.IsSuccessStatusCode)
{ {
toast.ShowSuccess("Profile Saved Successfully"); toast.ShowSuccess("Profile Saved Successfully");
nav.NavigateTo($"/profile/view/{state.User!.Id}");
} }
else else
{ {

View File

@ -1,6 +1,8 @@
@page "/" @page "/"
@inject IJSRuntime js @inject IJSRuntime js
<PageTitle Title="Welcome!" />
<p> <p>
Future home of No Agenda Jobs, where citizens of Gitmo Nation can assist one another in finding or enhancing their Future home of No Agenda Jobs, where citizens of Gitmo Nation can assist one another in finding or enhancing their
employment. This will enable them to continue providing value for value to Adam and John, as they continue their work employment. This will enable them to continue providing value for value to Adam and John, as they continue their work
@ -10,12 +12,12 @@
Do you not understand the terms in the paragraph above? No worries; just head over to Do you not understand the terms in the paragraph above? No worries; just head over to
<a href="https://noagendashow.net"> <a href="https://noagendashow.net">
The Best Podcast in the Universe The Best Podcast in the Universe
</a> <em><a class="audio" @onclick=@PlayTrue>(it&rsquo;s true!)</a></em> and find out what you&rsquo;re missing. </a> <em><a class="audio" @onclick=@PlayTrue>(that&rsquo;s true!)</a></em> and find out what you&rsquo;re missing.
</p> </p>
<audio id="itstrue"> <audio id="thatstrue">
<source src="/audio/thats-true.mp3"> <source src="/audio/thats-true.mp3">
</audio> </audio>
@code { @code {
async void PlayTrue() => await js.InvokeVoidAsync("Audio.play", "itstrue"); async void PlayTrue() => await js.InvokeVoidAsync("Audio.play", "thatstrue");
} }

View File

@ -8,8 +8,45 @@
} }
else else
{ {
<PageTitle Title=@($"Employment Profile for {Citizen.DisplayName}") />
<ErrorList Errors=@ErrorMessages> <ErrorList Errors=@ErrorMessages>
<h3>View Profile</h3> <h2><a href="@Citizen.ProfileUrl" target="_blank">@Citizen.DisplayName</a></h2>
<h4>@Profile.Continent!.Name, @Profile.Region</h4>
<p>@WorkTypes</p>
<hr>
<div>
@(new MarkupString(Profile.Biography.ToHtml()))
</div>
@if (Profile.Skills.Length > 0)
{
<hr>
<h4>Skills</h4>
<ul>
@foreach (var skill in Profile.Skills)
{
var notes = skill.Notes == null ? "" : $" ({skill.Notes})";
<li>@skill.Description@notes</li>
}
</ul>
}
@if (Profile.Experience != null)
{
<hr>
<h4>Experience / Employment History</h4>
<div>
@(new MarkupString(Profile.Experience.ToHtml()))
</div>
}
@if (Id == state.User!.Id.ToString())
{
<hr>
<p><a href="/citizen/profile"><span class="oi oi-pencil"></span> Edit Your Profile</a></p>
}
</ErrorList> </ErrorList>
} }

View File

@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -9,22 +8,62 @@ namespace JobsJobsJobs.Client.Pages.Profile
{ {
public partial class View : ComponentBase public partial class View : ComponentBase
{ {
/// <summary>
/// Whether data for this component is loading
/// </summary>
private bool IsLoading { get; set; } = true; private bool IsLoading { get; set; } = true;
private Domain.Citizen? Citizen { get; set; } /// <summary>
/// The citizen whose profile is being displayed
/// </summary>
private Domain.Citizen Citizen { get; set; } = default!;
private Domain.Profile? Profile { get; set; } /// <summary>
/// The profile to display
/// </summary>
private Domain.Profile Profile { get; set; } = default!;
/// <summary>
/// The work types for the top of the page
/// </summary>
private MarkupString WorkTypes
{
get
{
IEnumerable<string> parts()
{
if (Profile.SeekingEmployment)
{
yield return "<strong><em>CURRENTLY SEEKING EMPLOYMENT</em></strong>";
}
else
{
yield return "Not actively seeking employment";
}
yield return $"{(Profile.FullTime ? "I" : "Not i")}nterested in full-time employment";
yield return $"{(Profile.RemoteWork ? "I" : "Not i")}nterested in remote opportunities";
}
return new MarkupString(string.Join(" &bull; ", parts()));
}
}
/// <summary>
/// Error messages from data retrieval
/// </summary>
private IList<string> ErrorMessages { get; } = new List<string>(); private IList<string> ErrorMessages { get; } = new List<string>();
/// <summary>
/// The ID of the citizen whose profile should be displayed
/// </summary>
[Parameter] [Parameter]
public string Id { get; set; } = default!; public string Id { get; set; } = default!;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
ServerApi.SetJwt(http, state); ServerApi.SetJwt(http, state);
var citizenTask = ServerApi.RetrieveOne<Domain.Citizen>(http, $"/api/citizen/{Id}"); var citizenTask = ServerApi.RetrieveOne<Domain.Citizen>(http, $"citizen/get/{Id}");
var profileTask = ServerApi.RetrieveOne<Domain.Profile>(http, $"/api/profile/get/{Id}"); var profileTask = ServerApi.RetrieveOne<Domain.Profile>(http, $"profile/get/{Id}");
await Task.WhenAll(citizenTask, profileTask); await Task.WhenAll(citizenTask, profileTask);
@ -53,6 +92,8 @@ namespace JobsJobsJobs.Client.Pages.Profile
{ {
ErrorMessages.Add(profileTask.Result.Error); ErrorMessages.Add(profileTask.Result.Error);
} }
IsLoading = false;
} }
} }
} }

View File

@ -8,7 +8,7 @@ else
<ul> <ul>
@foreach (var msg in Errors) @foreach (var msg in Errors)
{ {
<li>@msg</li> <li><pre>@msg</pre></li>
} }
</ul> </ul>
} }

View File

@ -33,7 +33,7 @@
</li> </li>
<li class="nav-item px-3"> <li class="nav-item px-3">
<NavLink class="nav-link" href="/citizen/profile"> <NavLink class="nav-link" href="/citizen/profile">
<span class="oi oi-spreadsheet" aria-hidden="true"></span> Profile <span class="oi oi-pencil" aria-hidden="true"></span> Edit Profile
</NavLink> </NavLink>
</li> </li>
<li class="nav-item px-3"> <li class="nav-item px-3">

View File

@ -0,0 +1,11 @@
@inject IJSRuntime js
@code {
[Parameter]
public string Title { get; set; } = default!;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
await js.InvokeVoidAsync("setPageTitle", $"{Title} ~ Jobs, Jobs, Jobs");
}
}

View File

@ -35,6 +35,14 @@
document.getElementById(audio).play() document.getElementById(audio).play()
} }
} }
/**
* Set the title of the document. (called by PageTitle component)
*
* @param theTitle The title to be set
*/
function setPageTitle(theTitle) {
document.title = theTitle
}
</script> </script>
</body> </body>

View File

@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "5.0.1",
"commands": [
"dotnet-ef"
]
}
}
}

View File

@ -1,9 +1,5 @@
using JobsJobsJobs.Shared; using JobsJobsJobs.Shared;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace JobsJobsJobs.Server.Data namespace JobsJobsJobs.Server.Data
{ {

View File

@ -81,6 +81,8 @@ namespace JobsJobsJobs.Server.Data
m.Property(e => e.LastUpdatedOn).HasColumnName("last_updated_on").IsRequired(); m.Property(e => e.LastUpdatedOn).HasColumnName("last_updated_on").IsRequired();
m.Property(e => e.Experience).HasColumnName("experience") m.Property(e => e.Experience).HasColumnName("experience")
.HasConversion(Converters.OptionalMarkdownStringConverter); .HasConversion(Converters.OptionalMarkdownStringConverter);
m.Ignore(e => e.Continent);
m.Ignore(e => e.Skills);
}); });
modelBuilder.Entity<Skill>(m => modelBuilder.Entity<Skill>(m =>

View File

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<UserSecretsId>553960ef-0c79-47d4-98d8-9ca1708e558f</UserSecretsId>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -6,6 +6,7 @@
<ActiveDebugProfile>JobsJobsJobs.Server</ActiveDebugProfile> <ActiveDebugProfile>JobsJobsJobs.Server</ActiveDebugProfile>
<Controller_SelectedScaffolderID>MvcControllerEmptyScaffolder</Controller_SelectedScaffolderID> <Controller_SelectedScaffolderID>MvcControllerEmptyScaffolder</Controller_SelectedScaffolderID>
<Controller_SelectedScaffolderCategoryPath>root/Common/MVC/Controller</Controller_SelectedScaffolderCategoryPath> <Controller_SelectedScaffolderCategoryPath>root/Common/MVC/Controller</Controller_SelectedScaffolderCategoryPath>
<NameOfLastUsedPublishProfile>FolderProfile</NameOfLastUsedPublishProfile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor> <DebuggerFlavor>ProjectDebugger</DebuggerFlavor>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DeleteExistingFiles>True</DeleteExistingFiles>
<ExcludeApp_Data>False</ExcludeApp_Data>
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\net5.0\publish\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishSingleFile>True</PublishSingleFile>
<PublishTrimmed>True</PublishTrimmed>
<ProjectGuid>35aeecbf-489d-41c5-9ba3-6e43ad7a8196</ProjectGuid>
<SelfContained>true</SelfContained>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_PublishTargetUrl>C:\Users\danie\Documents\sandbox\jobs-jobs-jobs\src\JobsJobsJobs\Server\bin\Release\net5.0\publish\</_PublishTargetUrl>
</PropertyGroup>
</Project>