Convert db to EF Core; start on view page

Also returning skills with profile inquiries now, though that particular query is failing (current WIP) #2
This commit is contained in:
2021-01-06 23:18:54 -05:00
parent 97b3de1cea
commit ef12da01dc
26 changed files with 515 additions and 508 deletions

View File

@@ -3,34 +3,4 @@
@inject NavigationManager nav
@inject AppState state
<p>@message</p>
@code {
string message = "Logging you on with No Agenda Social...";
protected override async Task OnInitializedAsync()
{
// Exchange authorization code for a JWT
var query = QueryHelpers.ParseQuery(nav.ToAbsoluteUri(nav.Uri).Query);
if (query.TryGetValue("code", out var authCode))
{
var logOnResult = await ServerApi.LogOn(http, authCode);
if (logOnResult.IsOk)
{
var logOn = logOnResult.Ok;
state.User = new UserInfo(logOn.CitizenId, logOn.Name);
state.Jwt = logOn.Jwt;
nav.NavigateTo("/citizen/dashboard");
}
else
{
message = logOnResult.Error;
}
}
else
{
message = "Did not receive a token from No Agenda Social (perhaps you clicked \"Cancel\"?)";
}
}
}
<p>@Message</p>

View File

@@ -0,0 +1,40 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.WebUtilities;
using System.Threading.Tasks;
namespace JobsJobsJobs.Client.Pages.Citizen
{
public partial class Authorized : ComponentBase
{
/// <summary>
/// The message to be displayed on this page
/// </summary>
private string Message { get; set; } = "Logging you on with No Agenda Social...";
protected override async Task OnInitializedAsync()
{
// Exchange authorization code for a JWT
var query = QueryHelpers.ParseQuery(nav.ToAbsoluteUri(nav.Uri).Query);
if (query.TryGetValue("code", out var authCode))
{
var logOnResult = await ServerApi.LogOn(http, authCode);
if (logOnResult.IsOk)
{
var logOn = logOnResult.Ok;
state.User = new UserInfo(logOn.CitizenId, logOn.Name);
state.Jwt = logOn.Jwt;
nav.NavigateTo("/citizen/dashboard");
}
else
{
Message = logOnResult.Error;
}
}
else
{
Message = "Did not receive a token from No Agenda Social (perhaps you clicked \"Cancel\"?)";
}
}
}
}

View File

@@ -1,6 +1,8 @@
@page "/citizen/dashboard"
@inject HttpClient http
@inject AppState state
<h3>Welcome, @State.User!.Name!</h3>
<h3>Welcome, @state.User!.Name!</h3>
@if (RetrievingData)
{
@@ -8,34 +10,25 @@
}
else
{
if (Profile != null)
{
<ErrorList Errors=@ErrorMessages>
@if (Profile != null)
{
<p>
Your employment profile was last updated <FullDateTime TheDate=@Profile.LastUpdatedOn />. Your profile currently
lists @Profile.Skills.Length skill@(Profile.Skills.Length != 1 ? "s" : "").
</p>
}
else
{
<p>You do not have an employment profile established; click &ldquo;Profile&rdquo;* in the menu to get started!</p>
}
<p>
Your employment profile was last updated <FullDateTime TheDate="@Profile.LastUpdatedOn" />. Your profile currently
lists @SkillCount skill@(SkillCount != 1 ? "s" : "").
There @(ProfileCount == 1 ? "is" : "are") @(ProfileCount == 0 ? "no" : ProfileCount) employment
profile@(ProfileCount != 1 ? "s" : "") from citizens of Gitmo Nation.
@if (ProfileCount > 0)
{
<text>Take a look around and see if you can help them find work!</text>
}
</p>
}
else
{
<p>You do not have an employment profile established; click &ldquo;Profile&rdquo;* in the menu to get started!</p>
}
<p>
There @(ProfileCount == 1 ? "is" : "are") @(ProfileCount == 0 ? "no" : ProfileCount) employment
profile@(ProfileCount != 1 ? "s" : "") from citizens of Gitmo Nation.
@if (ProfileCount > 0)
{
<text>Take a look around and see if you can help them find work!</text>
}
</p>
}
@if (ErrorMessages.Count > 0)
{
<p><strong>The following error(s) occurred:</strong></p>
<p>
@foreach (var msg in ErrorMessages)
{
@msg<br>
}
</p>
</ErrorList>
}

View File

@@ -1,9 +1,8 @@
using JobsJobsJobs.Shared;
using JobsJobsJobs.Shared.Api;
using JobsJobsJobs.Shared.Api;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Domain = JobsJobsJobs.Shared;
namespace JobsJobsJobs.Client.Pages.Citizen
{
@@ -20,46 +19,27 @@ namespace JobsJobsJobs.Client.Pages.Citizen
/// <summary>
/// The user's profile
/// </summary>
private Profile? Profile { get; set; } = null;
/// <summary>
/// The number of skills in the user's profile
/// </summary>
private long SkillCount { get; set; } = 0L;
private Domain.Profile? Profile { get; set; } = null;
/// <summary>
/// The number of profiles
/// </summary>
private long ProfileCount { get; set; } = 0L;
private int ProfileCount { get; set; }
/// <summary>
/// Error messages from data access
/// </summary>
private IList<string> ErrorMessages { get; } = new List<string>();
/// <summary>
/// The HTTP client to use for API access
/// </summary>
[Inject]
public HttpClient Http { get; set; } = default!;
/// <summary>
/// The current application state
/// </summary>
[Inject]
public AppState State { get; set; } = default!;
protected override async Task OnInitializedAsync()
{
if (State.User != null)
if (state.User != null)
{
ServerApi.SetJwt(Http, State);
var profileTask = ServerApi.RetrieveProfile(Http, State);
var profileCountTask = ServerApi.RetrieveOne<Count>(Http, "profile/count");
var skillCountTask = ServerApi.RetrieveOne<Count>(Http, "profile/skill-count");
ServerApi.SetJwt(http, state);
var profileTask = ServerApi.RetrieveProfile(http, state);
var profileCountTask = ServerApi.RetrieveOne<Count>(http, "profile/count");
await Task.WhenAll(profileTask, profileCountTask, skillCountTask);
await Task.WhenAll(profileTask, profileCountTask);
if (profileTask.Result.IsOk)
{
@@ -79,18 +59,8 @@ namespace JobsJobsJobs.Client.Pages.Citizen
ErrorMessages.Add(profileCountTask.Result.Error);
}
if (skillCountTask.Result.IsOk)
{
SkillCount = skillCountTask.Result.Ok?.Value ?? 0;
}
else
{
ErrorMessages.Add(skillCountTask.Result.Error);
}
RetrievingData = false;
}
}
}
}

View File

@@ -1,4 +1,7 @@
@page "/citizen/profile"
@inject HttpClient http
@inject AppState state
@inject IToastService toast
<h3>Employment Profile</h3>
@@ -14,12 +17,12 @@
}
else
{
<EditForm Model="@ProfileForm" OnValidSubmit="@SaveProfile">
<EditForm Model=@ProfileForm OnValidSubmit=@SaveProfile>
<DataAnnotationsValidator />
<div class="form-row">
<div class="col">
<div class="form-check">
<InputCheckbox id="seeking" class="form-check-input" @bind-Value="@ProfileForm.IsSeekingEmployment" />
<InputCheckbox id="seeking" class="form-check-input" @bind-Value=@ProfileForm.IsSeekingEmployment />
<label for="seeking" class="form-check-label">I am currently seeking employment</label>
</div>
</div>
@@ -28,22 +31,22 @@
<div class="col col-xs-12 col-sm-6 col-md-4">
<div class="form-group">
<label for="continentId" class="jjj-required">Continent</label>
<InputSelect id="continentId" @bind-Value="@ProfileForm.ContinentId" class="form-control">
<InputSelect id="continentId" @bind-Value=@ProfileForm.ContinentId class="form-control">
<option>&ndash; Select &ndash;</option>
@foreach (var (id, name) in Continents)
{
<option value="@id">@name</option>
}
</InputSelect>
<ValidationMessage For="@(() => ProfileForm.ContinentId)" />
<ValidationMessage For=@(() => ProfileForm.ContinentId) />
</div>
</div>
<div class="col col-xs-12 col-sm-6 col-md-8">
<div class="form-group">
<label for="region" class="jjj-required">Region</label>
<InputText id="region" @bind-Value="@ProfileForm.Region" class="form-control"
<InputText id="region" @bind-Value=@ProfileForm.Region class="form-control"
placeholder="Country, state, geographic area, etc." />
<ValidationMessage For="@(() => ProfileForm.Region)" />
<ValidationMessage For=@(() => ProfileForm.Region) />
</div>
</div>
</div>
@@ -51,21 +54,21 @@
<div class="col">
<div class="form-group">
<label for="bio" class="jjj-required">Professional Biography</label>
<MarkdownEditor Id="bio" @bind-Text="@ProfileForm.Biography" />
<ValidationMessage For="@(() => ProfileForm.Biography)" />
<MarkdownEditor Id="bio" @bind-Text=@ProfileForm.Biography />
<ValidationMessage For=@(() => ProfileForm.Biography) />
</div>
</div>
</div>
<div class="form-row">
<div class="col col-xs-12 col-sm-12 offset-md-2 col-md-4">
<div class="form-check">
<InputCheckbox id="isRemote" class="form-check-input" @bind-Value="@ProfileForm.RemoteWork" />
<InputCheckbox id="isRemote" class="form-check-input" @bind-Value=@ProfileForm.RemoteWork />
<label for="isRemote" class="form-check-label">I am looking for remote work</label>
</div>
</div>
<div class="col col-xs-12 col-sm-12 col-md-4">
<div class="form-check">
<InputCheckbox id="isFull" class="form-check-input" @bind-Value="@ProfileForm.FullTime" />
<InputCheckbox id="isFull" class="form-check-input" @bind-Value=@ProfileForm.FullTime />
<label for="isFull" class="form-check-label">I am looking for full-time work</label>
</div>
</div>
@@ -73,11 +76,11 @@
<hr>
<h4>
Skills &nbsp;
<button type="button" class="btn btn-outline-primary" @onclick="@AddNewSkill">Add a Skill</button>
<button type="button" class="btn btn-outline-primary" @onclick=@AddNewSkill>Add a Skill</button>
</h4>
@foreach (var skill in ProfileForm.Skills)
{
<SkillEdit Skill="@skill" OnRemove="@RemoveSkill" />
<SkillEdit Skill=@skill OnRemove=@RemoveSkill />
}
<hr>
<h4>Experience</h4>
@@ -88,13 +91,13 @@
</p>
<div class="form-row">
<div class="col">
<MarkdownEditor Id="experience" @bind-Text="@ProfileForm.Experience" />
<MarkdownEditor Id="experience" @bind-Text=@ProfileForm.Experience />
</div>
</div>
<div class="form-row">
<div class="col">
<div class="form-check">
<InputCheckbox id="isPublic" class="form-check-input" @bind-Value="@ProfileForm.IsPublic" />
<InputCheckbox id="isPublic" class="form-check-input" @bind-Value=@ProfileForm.IsPublic />
<label for="isPublic" class="form-check-label">
Allow my profile to be searched publicly (outside NA Social)
</label>

View File

@@ -1,10 +1,8 @@
using Blazored.Toast.Services;
using JobsJobsJobs.Shared;
using JobsJobsJobs.Shared;
using JobsJobsJobs.Shared.Api;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
@@ -40,32 +38,13 @@ namespace JobsJobsJobs.Client.Pages.Citizen
/// </summary>
private IList<string> ErrorMessages { get; } = new List<string>();
/// <summary>
/// HTTP client instance to use for API access
/// </summary>
[Inject]
private HttpClient Http { get; set; } = default!;
/// <summary>
/// Application state
/// </summary>
[Inject]
private AppState State { get; set; } = default!;
/// <summary>
/// Toast service
/// </summary>
[Inject]
private IToastService Toasts { get; set; } = default!;
protected override async Task OnInitializedAsync()
{
ServerApi.SetJwt(Http, State);
var continentTask = ServerApi.RetrieveMany<Continent>(Http, "continent/all");
var profileTask = ServerApi.RetrieveProfile(Http, State);
var skillTask = ServerApi.RetrieveMany<Skill>(Http, "profile/skills");
ServerApi.SetJwt(http, state);
var continentTask = ServerApi.RetrieveMany<Continent>(http, "continent/all");
var profileTask = ServerApi.RetrieveProfile(http, state);
await Task.WhenAll(continentTask, profileTask, skillTask);
await Task.WhenAll(continentTask, profileTask);
if (continentTask.Result.IsOk)
{
@@ -81,28 +60,11 @@ namespace JobsJobsJobs.Client.Pages.Citizen
ProfileForm = (profileTask.Result.Ok == null)
? new ProfileForm()
: ProfileForm.FromProfile(profileTask.Result.Ok);
}
else
{
ErrorMessages.Add(profileTask.Result.Error);
}
if (skillTask.Result.IsOk)
{
foreach (var skill in skillTask.Result.Ok)
{
ProfileForm.Skills.Add(new SkillForm
{
Id = skill.Id.ToString(),
Description = skill.Description,
Notes = skill.Notes ?? ""
});
}
if (ProfileForm.Skills.Count == 0) AddNewSkill();
}
else
{
ErrorMessages.Add(skillTask.Result.Error);
ErrorMessages.Add(profileTask.Result.Error);
}
AllLoaded = true;
@@ -132,16 +94,16 @@ namespace JobsJobsJobs.Client.Pages.Citizen
.ToList();
foreach (var blankSkill in blankSkills) ProfileForm.Skills.Remove(blankSkill);
var res = await Http.PostAsJsonAsync("/api/profile/save", ProfileForm);
var res = await http.PostAsJsonAsync("/api/profile/save", ProfileForm);
if (res.IsSuccessStatusCode)
{
Toasts.ShowSuccess("Profile Saved Successfully");
toast.ShowSuccess("Profile Saved Successfully");
}
else
{
var error = await res.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(error)) error = $"- {error}";
Toasts.ShowError($"{(int)res.StatusCode} {error}");
toast.ShowError($"{(int)res.StatusCode} {error}");
}
}