Deconflict namespaces

Pluralize namespaces in client to keep from having to qualify domain namespace
This commit is contained in:
2021-02-07 16:53:36 -05:00
parent 8350d0bddf
commit e63a12b774
12 changed files with 20 additions and 20 deletions

View File

@@ -0,0 +1,8 @@
@page "/citizen/authorized"
@inject HttpClient http
@inject NavigationManager nav
@inject AppState state
<PageTitle Title="Logging on..." />
<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.Citizens
{
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

@@ -0,0 +1,47 @@
@page "/citizen/dashboard"
@inject HttpClient http
@inject AppState state
<PageTitle Title="Dashboard" />
<h3>Welcome, @state.User!.Name!</h3>
<Loading OnLoad=@LoadProfile Message=@(new MarkupString("Retrieving your employment profile&hellip;"))>
@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>
<p><a href="/profile/view/@state.User.Id">View Your Employment Profile</a></p>
@if (Profile.SeekingEmployment)
{
<p>
Your profile indicates that you are seeking employment. Once you find it,
<a href="/success-story/add">tell your fellow citizens about it!</a>
</p>
}
}
else
{
<p>
You do not have an employment profile established; click &ldquo;Edit Profile&rdquo; in the menu to get
started!
</p>
}
<hr>
<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>
</Loading>
<hr>
<p>
To see what is currently done, and how this application works, check out &ldquo;How It Works&rdquo; in the sidebar.
The application now has 4 of 5 phases complete towards version 1.0; the documentation was last updated January
31<sup>st</sup>, 2021.
</p>

View File

@@ -0,0 +1,58 @@
using JobsJobsJobs.Shared;
using JobsJobsJobs.Shared.Api;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace JobsJobsJobs.Client.Pages.Citizens
{
/// <summary>
/// The first page a user sees after signing in
/// </summary>
public partial class Dashboard : ComponentBase
{
/// <summary>
/// The user's profile
/// </summary>
private Profile? Profile { get; set; } = null;
/// <summary>
/// The number of profiles
/// </summary>
private int ProfileCount { get; set; }
/// <summary>
/// Load the user's profile information
/// </summary>
/// <param name="errors">A collection to report errors that may be encountered</param>
public async Task LoadProfile(ICollection<string> errors)
{
if (state.User != null)
{
ServerApi.SetJwt(http, state);
var profileTask = ServerApi.RetrieveProfile(http, state);
var profileCountTask = ServerApi.RetrieveOne<Count>(http, "profile/count");
await Task.WhenAll(profileTask, profileCountTask);
if (profileTask.Result.IsOk)
{
Profile = profileTask.Result.Ok;
}
else
{
errors.Add(profileTask.Result.Error);
}
if (profileCountTask.Result.IsOk)
{
ProfileCount = profileCountTask.Result.Ok?.Value ?? 0;
}
else
{
errors.Add(profileCountTask.Result.Error);
}
}
}
}
}

View File

@@ -0,0 +1,132 @@
@page "/citizen/profile"
@inject HttpClient http
@inject AppState state
@inject NavigationManager nav
@inject IToastService toast
<PageTitle Title="Edit Profile" />
<h3>Employment Profile</h3>
<Loading OnLoad=@SetUpProfile Message=@(new MarkupString("Loading Your Profile&hellip;"))>
<EditForm Model=@ProfileForm OnValidSubmit=@SaveProfile>
<DataAnnotationsValidator />
<div class="form-row">
<div class="col col-xs-12 col-sm-10 col-md-8 col-lg-6">
<div class="form-group">
<label for="realName" class="jjj-label">Real Name</label>
<InputText id="realName" @bind-Value=@ProfileForm.RealName class="form-control"
placeholder="Leave blank to use your NAS display name" />
<ValidationMessage For=@(() => ProfileForm.RealName) />
</div>
</div>
</div>
<div class="form-row">
<div class="col">
<div class="form-check">
<InputCheckbox id="seeking" class="form-check-input" @bind-Value=@ProfileForm.IsSeekingEmployment />
<label for="seeking" class="form-check-label">I am currently seeking employment</label>
@if (IsSeeking)
{
<em>&nbsp; &nbsp; If you have found employment, consider
<a href="/success-story/add">telling your fellow citizens about it</a>
</em>
}
</div>
</div>
</div>
<div class="form-row">
<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">
<option>&ndash; Select &ndash;</option>
@foreach (var (id, name) in Continents)
{
<option value="@id">@name</option>
}
</InputSelect>
<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"
placeholder="Country, state, geographic area, etc." />
<ValidationMessage For=@(() => ProfileForm.Region) />
</div>
</div>
</div>
<div class="form-row">
<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) />
</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 />
<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 />
<label for="isFull" class="form-check-label">I am looking for full-time work</label>
</div>
</div>
</div>
<hr>
<h4>
Skills &nbsp;
<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 />
}
<hr>
<h4>Experience</h4>
<p>
This application does not have a place to individually list your chronological job history; however, you can
use this area to list prior jobs, their dates, and anything else you want to include that&rsquo;s not already a
part of your Professional Biography above.
</p>
<div class="form-row">
<div class="col">
<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 />
<label for="isPublic" class="form-check-label">
Allow my profile to be searched publicly (outside NA Social)
</label>
</div>
</div>
</div>
<div class="form-row">
<div class="col">
<br>
<button type="submit" class="btn btn-outline-primary">Save</button>
</div>
</div>
</EditForm>
@if (!IsNew)
{
<p>
<br><a href="/profile/view/@state.User!.Id"><span class="oi oi-file"></span> View Your User Profile</a>
</p>
}
<p>
<br>If you want to delete your profile, or your entire account,
<a href="/so-long/options">see your deletion options here</a>.
</p>
</Loading>

View File

@@ -0,0 +1,115 @@
using JobsJobsJobs.Shared;
using JobsJobsJobs.Shared.Api;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Json;
using System.Threading.Tasks;
namespace JobsJobsJobs.Client.Pages.Citizens
{
/// <summary>
/// Profile edit page (called EditProfile so as not to create naming conflicts)
/// </summary>
public partial class EditProfile : ComponentBase
{
/// <summary>
/// Counter for IDs when "Add a Skill" button is clicked
/// </summary>
private int _newSkillCounter = 0;
/// <summary>
/// Whether the citizen is seeking employment at the time the profile is loaded (used to show success story
/// link)
/// </summary>
private bool IsSeeking { get; set; } = false;
/// <summary>
/// The form for this page
/// </summary>
private ProfileForm ProfileForm { get; set; } = new ProfileForm();
/// <summary>
/// All continents
/// </summary>
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>
/// Set up the data needed to add or edit the user's profile
/// </summary>
/// <param name="errors">The collection where errors can be reported</param>
public async Task SetUpProfile(ICollection<string> errors)
{
ServerApi.SetJwt(http, state);
var continentTask = state.GetContinents(http);
var profileTask = ServerApi.RetrieveProfile(http, state);
//var citizenTask = ServerApi.RetrieveOne<Citizen>(http,)
await Task.WhenAll(continentTask, profileTask);
Continents = continentTask.Result;
if (profileTask.Result.IsOk)
{
if (profileTask.Result.Ok == null)
{
ProfileForm = new ProfileForm();
IsNew = true;
}
else
{
ProfileForm = ProfileForm.FromProfile(profileTask.Result.Ok);
IsSeeking = profileTask.Result.Ok.SeekingEmployment;
}
if (ProfileForm.Skills.Count == 0) AddNewSkill();
}
else
{
errors.Add(profileTask.Result.Error);
}
}
/// <summary>
/// Add a new skill to the form
/// </summary>
private void AddNewSkill() =>
ProfileForm.Skills.Add(new SkillForm { Id = $"new{_newSkillCounter++}" });
/// <summary>
/// Remove the skill for the given ID
/// </summary>
/// <param name="skillId">The ID of the skill to remove</param>
private void RemoveSkill(string skillId) =>
ProfileForm.Skills.Remove(ProfileForm.Skills.First(s => s.Id == skillId));
/// <summary>
/// Save changes to the current profile
/// </summary>
public async Task SaveProfile()
{
// Remove any skills left blank
var blankSkills = ProfileForm.Skills
.Where(s => string.IsNullOrEmpty(s.Description) && string.IsNullOrEmpty(s.Notes))
.ToList();
foreach (var blankSkill in blankSkills) ProfileForm.Skills.Remove(blankSkill);
var res = await http.PostAsJsonAsync("/api/profile/save", ProfileForm);
if (res.IsSuccessStatusCode)
{
toast.ShowSuccess("Profile Saved Successfully");
nav.NavigateTo($"/profile/view/{state.User!.Id}");
}
else
{
var error = await res.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(error)) error = $"- {error}";
toast.ShowError($"{(int)res.StatusCode} {error}");
}
}
}
}

View File

@@ -0,0 +1,13 @@
@page "/citizen/log-off"
@inject NavigationManager nav
@inject AppState state
@inject IToastService toast
@code {
protected override void OnInitialized()
{
state.Jwt = "";
state.User = null;
toast.ShowSuccess("Have a Nice Day!", "Log Off Successful");
nav.NavigateTo("/");
}
}