Add common loading component
This has no specific issue associated, but reduces boilerplate in most page components
This commit is contained in:
parent
7f7eb191fb
commit
a6fd891cc5
|
@ -6,46 +6,39 @@
|
||||||
|
|
||||||
<h3>Welcome, @state.User!.Name!</h3>
|
<h3>Welcome, @state.User!.Name!</h3>
|
||||||
|
|
||||||
@if (RetrievingData)
|
<Loading OnLoad=@LoadProfile Message=@(new MarkupString("Retrieving your employment profile…"))>
|
||||||
{
|
@if (Profile != null)
|
||||||
<p>Retrieving your employment profile...</p>
|
{
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<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>
|
|
||||||
<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 “Edit Profile” in the menu to get
|
|
||||||
started!
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
<hr>
|
|
||||||
<p>
|
<p>
|
||||||
There @(ProfileCount == 1 ? "is" : "are") @(ProfileCount == 0 ? "no" : ProfileCount) employment
|
Your employment profile was last updated <FullDateTime TheDate=@Profile.LastUpdatedOn />. Your profile currently
|
||||||
profile@(ProfileCount != 1 ? "s" : "") from citizens of Gitmo Nation.
|
lists @Profile.Skills.Length skill@(Profile.Skills.Length != 1 ? "s" : "").
|
||||||
@if (ProfileCount > 0)
|
|
||||||
{
|
|
||||||
<text>Take a look around and see if you can help them find work!</text>
|
|
||||||
}
|
|
||||||
</p>
|
</p>
|
||||||
</ErrorList>
|
<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 “Edit Profile” 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>
|
<hr>
|
||||||
<h4>
|
<h4>
|
||||||
<a href="https://github.com/bit-badger/jobs-jobs-jobs/issues/3" target="_blank">Phase 3</a> – What Works
|
<a href="https://github.com/bit-badger/jobs-jobs-jobs/issues/3" target="_blank">Phase 3</a> – What Works
|
||||||
|
|
|
@ -11,11 +11,6 @@ namespace JobsJobsJobs.Client.Pages.Citizen
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class Dashboard : ComponentBase
|
public partial class Dashboard : ComponentBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Whether the data is being retrieved
|
|
||||||
/// </summary>
|
|
||||||
private bool RetrievingData { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The user's profile
|
/// The user's profile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -27,11 +22,10 @@ namespace JobsJobsJobs.Client.Pages.Citizen
|
||||||
private int ProfileCount { get; set; }
|
private int ProfileCount { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error messages from data access
|
/// Load the user's profile information
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IList<string> ErrorMessages { get; } = new List<string>();
|
/// <param name="errors">A collection to report errors that may be encountered</param>
|
||||||
|
public async Task LoadProfile(ICollection<string> errors)
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
{
|
||||||
if (state.User != null)
|
if (state.User != null)
|
||||||
{
|
{
|
||||||
|
@ -47,7 +41,7 @@ namespace JobsJobsJobs.Client.Pages.Citizen
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ErrorMessages.Add(profileTask.Result.Error);
|
errors.Add(profileTask.Result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profileCountTask.Result.IsOk)
|
if (profileCountTask.Result.IsOk)
|
||||||
|
@ -56,10 +50,8 @@ namespace JobsJobsJobs.Client.Pages.Citizen
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ErrorMessages.Add(profileCountTask.Result.Error);
|
errors.Add(profileCountTask.Result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
RetrievingData = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,118 +8,111 @@
|
||||||
|
|
||||||
<h3>Employment Profile</h3>
|
<h3>Employment Profile</h3>
|
||||||
|
|
||||||
@if (AllLoaded)
|
<Loading OnLoad=@SetUpProfile Message=@(new MarkupString("Loading Your Profile…"))>
|
||||||
{
|
<EditForm Model=@ProfileForm OnValidSubmit=@SaveProfile>
|
||||||
<ErrorList Errors=@ErrorMessages>
|
<DataAnnotationsValidator />
|
||||||
<EditForm Model=@ProfileForm OnValidSubmit=@SaveProfile>
|
<div class="form-row">
|
||||||
<DataAnnotationsValidator />
|
<div class="col">
|
||||||
<div class="form-row">
|
<div class="form-check">
|
||||||
<div class="col">
|
<InputCheckbox id="seeking" class="form-check-input" @bind-Value=@ProfileForm.IsSeekingEmployment />
|
||||||
<div class="form-check">
|
<label for="seeking" class="form-check-label">I am currently seeking employment</label>
|
||||||
<InputCheckbox id="seeking" class="form-check-input" @bind-Value=@ProfileForm.IsSeekingEmployment />
|
@if (IsSeeking)
|
||||||
<label for="seeking" class="form-check-label">I am currently seeking employment</label>
|
{
|
||||||
@if (IsSeeking)
|
<em> 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>– Select –</option>
|
||||||
|
@foreach (var (id, name) in Continents)
|
||||||
{
|
{
|
||||||
<em> If you have found employment, consider
|
<option value="@id">@name</option>
|
||||||
<a href="/success-story/add">telling your fellow citizens about it</a>
|
|
||||||
</em>
|
|
||||||
}
|
}
|
||||||
</div>
|
</InputSelect>
|
||||||
|
<ValidationMessage For=@(() => ProfileForm.ContinentId) />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="col col-xs-12 col-sm-6 col-md-8">
|
||||||
<div class="col col-xs-12 col-sm-6 col-md-4">
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label for="region" class="jjj-required">Region</label>
|
||||||
<label for="continentId" class="jjj-required">Continent</label>
|
<InputText id="region" @bind-Value=@ProfileForm.Region class="form-control"
|
||||||
<InputSelect id="continentId" @bind-Value=@ProfileForm.ContinentId class="form-control">
|
placeholder="Country, state, geographic area, etc." />
|
||||||
<option>– Select –</option>
|
<ValidationMessage For=@(() => ProfileForm.Region) />
|
||||||
@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>
|
</div>
|
||||||
<div class="form-row">
|
</div>
|
||||||
<div class="col">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="col">
|
||||||
<label for="bio" class="jjj-required">Professional Biography</label>
|
<div class="form-group">
|
||||||
<MarkdownEditor Id="bio" @bind-Text=@ProfileForm.Biography />
|
<label for="bio" class="jjj-required">Professional Biography</label>
|
||||||
<ValidationMessage For=@(() => ProfileForm.Biography) />
|
<MarkdownEditor Id="bio" @bind-Text=@ProfileForm.Biography />
|
||||||
</div>
|
<ValidationMessage For=@(() => ProfileForm.Biography) />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
</div>
|
||||||
<div class="col col-xs-12 col-sm-12 offset-md-2 col-md-4">
|
<div class="form-row">
|
||||||
<div class="form-check">
|
<div class="col col-xs-12 col-sm-12 offset-md-2 col-md-4">
|
||||||
<InputCheckbox id="isRemote" class="form-check-input" @bind-Value=@ProfileForm.RemoteWork />
|
<div class="form-check">
|
||||||
<label for="isRemote" class="form-check-label">I am looking for remote work</label>
|
<InputCheckbox id="isRemote" class="form-check-input" @bind-Value=@ProfileForm.RemoteWork />
|
||||||
</div>
|
<label for="isRemote" class="form-check-label">I am looking for remote work</label>
|
||||||
</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>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<div class="col col-xs-12 col-sm-12 col-md-4">
|
||||||
<h4>
|
<div class="form-check">
|
||||||
Skills
|
<InputCheckbox id="isFull" class="form-check-input" @bind-Value=@ProfileForm.FullTime />
|
||||||
<button type="button" class="btn btn-outline-primary" @onclick=@AddNewSkill>Add a Skill</button>
|
<label for="isFull" class="form-check-label">I am looking for full-time work</label>
|
||||||
</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’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>
|
</div>
|
||||||
<div class="form-row">
|
</div>
|
||||||
<div class="col">
|
<hr>
|
||||||
<div class="form-check">
|
<h4>
|
||||||
<InputCheckbox id="isPublic" class="form-check-input" @bind-Value=@ProfileForm.IsPublic />
|
Skills
|
||||||
<label for="isPublic" class="form-check-label">
|
<button type="button" class="btn btn-outline-primary" @onclick=@AddNewSkill>Add a Skill</button>
|
||||||
Allow my profile to be searched publicly (outside NA Social)
|
</h4>
|
||||||
</label>
|
@foreach (var skill in ProfileForm.Skills)
|
||||||
</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>
|
<SkillEdit Skill=@skill OnRemove=@RemoveSkill />
|
||||||
<br><a href="/profile/view/@state.User!.Id"><span class="oi oi-file"></span> View Your User Profile</a>
|
|
||||||
</p>
|
|
||||||
}
|
}
|
||||||
</ErrorList>
|
<hr>
|
||||||
}
|
<h4>Experience</h4>
|
||||||
else
|
<p>
|
||||||
{
|
This application does not have a place to individually list your chronological job history; however, you can
|
||||||
<p>Loading your profile...</p>
|
use this area to list prior jobs, their dates, and anything else you want to include that’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>
|
||||||
|
}
|
||||||
|
</Loading>
|
||||||
|
|
|
@ -18,11 +18,6 @@ namespace JobsJobsJobs.Client.Pages.Citizen
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int _newSkillCounter = 0;
|
private int _newSkillCounter = 0;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A flag that indicates all the required API calls have completed, and the form is ready to be displayed
|
|
||||||
/// </summary>
|
|
||||||
private bool AllLoaded { get; set; } = false;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the citizen is seeking employment at the time the profile is loaded (used to show success story
|
/// Whether the citizen is seeking employment at the time the profile is loaded (used to show success story
|
||||||
/// link)
|
/// link)
|
||||||
|
@ -45,11 +40,10 @@ namespace JobsJobsJobs.Client.Pages.Citizen
|
||||||
private bool IsNew { get; set; } = false;
|
private bool IsNew { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error messages from API access
|
/// Set up the data needed to add or edit the user's profile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IList<string> ErrorMessages { get; } = new List<string>();
|
/// <param name="errors">The collection where errors can be reported</param>
|
||||||
|
public async Task SetUpProfile(ICollection<string> errors)
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
{
|
||||||
ServerApi.SetJwt(http, state);
|
ServerApi.SetJwt(http, state);
|
||||||
var continentTask = state.GetContinents(http);
|
var continentTask = state.GetContinents(http);
|
||||||
|
@ -75,10 +69,8 @@ namespace JobsJobsJobs.Client.Pages.Citizen
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ErrorMessages.Add(profileTask.Result.Error);
|
errors.Add(profileTask.Result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
AllLoaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -118,6 +110,5 @@ namespace JobsJobsJobs.Client.Pages.Citizen
|
||||||
toast.ShowError($"{(int)res.StatusCode} {error}");
|
toast.ShowError($"{(int)res.StatusCode} {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,51 +2,44 @@
|
||||||
@inject HttpClient http
|
@inject HttpClient http
|
||||||
@inject AppState state
|
@inject AppState state
|
||||||
|
|
||||||
@if (IsLoading)
|
<Loading OnLoad=@RetrieveProfile>
|
||||||
{
|
|
||||||
<p>Loading profile...</p>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<PageTitle Title=@($"Employment Profile for {Citizen.DisplayName}") />
|
<PageTitle Title=@($"Employment Profile for {Citizen.DisplayName}") />
|
||||||
<ErrorList Errors=@ErrorMessages>
|
<h2><a href="@Citizen.ProfileUrl" target="_blank">@Citizen.DisplayName</a></h2>
|
||||||
<h2><a href="@Citizen.ProfileUrl" target="_blank">@Citizen.DisplayName</a></h2>
|
<h4>@Profile.Continent!.Name, @Profile.Region</h4>
|
||||||
<h4>@Profile.Continent!.Name, @Profile.Region</h4>
|
<p>@WorkTypes</p>
|
||||||
<p>@WorkTypes</p>
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@(new MarkupString(Profile.Biography.ToHtml()))
|
@(new MarkupString(Profile.Biography.ToHtml()))
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@if (Profile.Skills.Length > 0)
|
@if (Profile.Skills.Length > 0)
|
||||||
{
|
{
|
||||||
<hr>
|
<hr>
|
||||||
<h4>Skills</h4>
|
<h4>Skills</h4>
|
||||||
<ul>
|
<ul>
|
||||||
@foreach (var skill in Profile.Skills)
|
@foreach (var skill in Profile.Skills)
|
||||||
{
|
{
|
||||||
var notes = skill.Notes == null ? "" : $" ({skill.Notes})";
|
var notes = skill.Notes == null ? "" : $" ({skill.Notes})";
|
||||||
<li>@skill.Description@notes</li>
|
<li>@skill.Description@notes</li>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Profile.Experience != null)
|
@if (Profile.Experience != null)
|
||||||
{
|
{
|
||||||
<hr>
|
<hr>
|
||||||
<h4>Experience / Employment History</h4>
|
<h4>Experience / Employment History</h4>
|
||||||
<div>
|
<div>
|
||||||
@(new MarkupString(Profile.Experience.ToHtml()))
|
@(new MarkupString(Profile.Experience.ToHtml()))
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Id == state.User!.Id.ToString())
|
@if (Id == state.User!.Id.ToString())
|
||||||
{
|
{
|
||||||
<hr>
|
<hr>
|
||||||
<p><a href="/citizen/profile"><span class="oi oi-pencil"></span> Edit Your Profile</a></p>
|
<p><a href="/citizen/profile"><span class="oi oi-pencil"></span> Edit Your Profile</a></p>
|
||||||
}
|
}
|
||||||
</ErrorList>
|
</Loading>
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Domain = JobsJobsJobs.Shared;
|
using Domain = JobsJobsJobs.Shared;
|
||||||
|
|
||||||
|
@ -8,11 +7,6 @@ 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;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The citizen whose profile is being displayed
|
/// The citizen whose profile is being displayed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -48,18 +42,17 @@ namespace JobsJobsJobs.Client.Pages.Profile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Error messages from data retrieval
|
|
||||||
/// </summary>
|
|
||||||
private IList<string> ErrorMessages { get; } = new List<string>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ID of the citizen whose profile should be displayed
|
/// The ID of the citizen whose profile should be displayed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Id { get; set; } = default!;
|
public string Id { get; set; } = default!;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
/// <summary>
|
||||||
|
/// Retrieve the requested profile
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="errors">A collection to report errors that may occur</param>
|
||||||
|
public async Task RetrieveProfile(ICollection<string> errors)
|
||||||
{
|
{
|
||||||
ServerApi.SetJwt(http, state);
|
ServerApi.SetJwt(http, state);
|
||||||
var citizenTask = ServerApi.RetrieveOne<Domain.Citizen>(http, $"citizen/get/{Id}");
|
var citizenTask = ServerApi.RetrieveOne<Domain.Citizen>(http, $"citizen/get/{Id}");
|
||||||
|
@ -73,11 +66,11 @@ namespace JobsJobsJobs.Client.Pages.Profile
|
||||||
}
|
}
|
||||||
else if (citizenTask.Result.IsOk)
|
else if (citizenTask.Result.IsOk)
|
||||||
{
|
{
|
||||||
ErrorMessages.Add("Citizen not found");
|
errors.Add("Citizen not found");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ErrorMessages.Add(citizenTask.Result.Error);
|
errors.Add(citizenTask.Result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profileTask.Result.IsOk && profileTask.Result.Ok != null)
|
if (profileTask.Result.IsOk && profileTask.Result.Ok != null)
|
||||||
|
@ -86,14 +79,12 @@ namespace JobsJobsJobs.Client.Pages.Profile
|
||||||
}
|
}
|
||||||
else if (profileTask.Result.IsOk)
|
else if (profileTask.Result.IsOk)
|
||||||
{
|
{
|
||||||
ErrorMessages.Add("Profile not found");
|
errors.Add("Profile not found");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ErrorMessages.Add(profileTask.Result.Error);
|
errors.Add(profileTask.Result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
IsLoading = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,52 +6,44 @@
|
||||||
@inject IToastService toast
|
@inject IToastService toast
|
||||||
|
|
||||||
<PageTitle Title=@Title />
|
<PageTitle Title=@Title />
|
||||||
|
|
||||||
<h3>@Title</h3>
|
<h3>@Title</h3>
|
||||||
|
|
||||||
<ErrorList Errors=@ErrorMessages>
|
<Loading OnLoad=@RetrieveStory>
|
||||||
@if (Loading)
|
@if (IsNew)
|
||||||
{
|
{
|
||||||
<p>Loading...</p>
|
<p>
|
||||||
|
Congratulations on your employment! Your fellow citizens would enjoy hearing how it all came about; tell us
|
||||||
|
about it below! <em>(These will be visible to other users, but not to the general public.)</em>
|
||||||
|
</p>
|
||||||
}
|
}
|
||||||
else
|
<EditForm Model=@Form OnValidSubmit=@SaveStory>
|
||||||
{
|
<div class="form-row">
|
||||||
@if (IsNew)
|
<div class="col">
|
||||||
{
|
<div class="form-check">
|
||||||
<p>
|
<InputCheckbox id="fromHere" class="form-check-input" @bind-Value=@Form.FromHere />
|
||||||
Congratulations on your employment! Your fellow citizens would enjoy hearing how it all came about; tell us
|
<label for="fromHere" class="form-check-label">I found my employment here</label>
|
||||||
about it below! <em>(These will be visible to other users, but not to the general public.)</em>
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
<EditForm Model=@Form OnValidSubmit=@SaveStory>
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="form-check">
|
|
||||||
<InputCheckbox id="fromHere" class="form-check-input" @bind-Value=@Form.FromHere />
|
|
||||||
<label for="fromHere" class="form-check-label">I found my employment here</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
</div>
|
||||||
<div class="col">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="col">
|
||||||
<label for="story" class="jjj-label">The Success Story</label>
|
<div class="form-group">
|
||||||
<MarkdownEditor Id="story" @bind-Text=@Form.Story />
|
<label for="story" class="jjj-label">The Success Story</label>
|
||||||
</div>
|
<MarkdownEditor Id="story" @bind-Text=@Form.Story />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
</div>
|
||||||
<div class="col">
|
<div class="form-row">
|
||||||
<br>
|
<div class="col">
|
||||||
<button type="submit" class="btn btn-outline-primary">Save</button>
|
<br>
|
||||||
@if (IsNew)
|
<button type="submit" class="btn btn-outline-primary">Save</button>
|
||||||
{
|
@if (IsNew)
|
||||||
<p>
|
{
|
||||||
<em>(Saving this will set “Seeking Employment” to “No” on your profile.)</em>
|
<p>
|
||||||
</p>
|
<em>(Saving this will set “Seeking Employment” to “No” on your profile.)</em>
|
||||||
}
|
</p>
|
||||||
</div>
|
}
|
||||||
</div>
|
</div>
|
||||||
</EditForm>
|
</div>
|
||||||
}
|
</EditForm>
|
||||||
</ErrorList>
|
</Loading>
|
||||||
|
|
|
@ -16,11 +16,6 @@ namespace JobsJobsJobs.Client.Pages.SuccessStory
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string? Id { get; set; }
|
public string? Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether we are loading information
|
|
||||||
/// </summary>
|
|
||||||
private bool Loading { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The page title / header
|
/// The page title / header
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -37,11 +32,10 @@ namespace JobsJobsJobs.Client.Pages.SuccessStory
|
||||||
private bool IsNew => Form.Id == "new";
|
private bool IsNew => Form.Id == "new";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error messages from API access
|
/// Retrieve the story
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IList<string> ErrorMessages { get; } = new List<string>();
|
/// <param name="errors">A collection to use in reporting errors that may occur</param>
|
||||||
|
public async Task RetrieveStory(ICollection<string> errors)
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
{
|
||||||
if (Id != null)
|
if (Id != null)
|
||||||
{
|
{
|
||||||
|
@ -58,14 +52,13 @@ namespace JobsJobsJobs.Client.Pages.SuccessStory
|
||||||
}
|
}
|
||||||
else if (story.IsOk)
|
else if (story.IsOk)
|
||||||
{
|
{
|
||||||
ErrorMessages.Add($"The success story {Id} does not exist");
|
errors.Add($"The success story {Id} does not exist");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ErrorMessages.Add(story.Error);
|
errors.Add(story.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -3,15 +3,10 @@
|
||||||
@inject AppState state
|
@inject AppState state
|
||||||
|
|
||||||
<PageTitle Title="Success Stories" />
|
<PageTitle Title="Success Stories" />
|
||||||
|
|
||||||
<h3>Success Stories</h3>
|
<h3>Success Stories</h3>
|
||||||
|
|
||||||
<ErrorList Errors=@ErrorMessages>
|
<Loading OnLoad=@LoadStories>
|
||||||
@if (Loading)
|
@if (Stories.Any())
|
||||||
{
|
|
||||||
<p>Loading...</p>
|
|
||||||
}
|
|
||||||
else if (Stories.Any())
|
|
||||||
{
|
{
|
||||||
<table class="table table-sm table-hover">
|
<table class="table table-sm table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -43,4 +38,4 @@
|
||||||
{
|
{
|
||||||
<p>There are no success stories recorded <em>(yet)</em></p>
|
<p>There are no success stories recorded <em>(yet)</em></p>
|
||||||
}
|
}
|
||||||
</ErrorList>
|
</Loading>
|
||||||
|
|
|
@ -1,30 +1,22 @@
|
||||||
using JobsJobsJobs.Shared.Api;
|
using JobsJobsJobs.Shared.Api;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace JobsJobsJobs.Client.Pages.SuccessStory
|
namespace JobsJobsJobs.Client.Pages.SuccessStory
|
||||||
{
|
{
|
||||||
public partial class ListStories : ComponentBase
|
public partial class ListStories : ComponentBase
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Whether we are still loading data
|
|
||||||
/// </summary>
|
|
||||||
private bool Loading { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The story entries
|
/// The story entries
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IEnumerable<StoryEntry> Stories { get; set; } = default!;
|
private IEnumerable<StoryEntry> Stories { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error messages encountered
|
/// Load all success stories
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IList<string> ErrorMessages { get; set; } = new List<string>();
|
/// <param name="errors">The collection into which errors can be reported</param>
|
||||||
|
public async Task LoadStories(ICollection<string> errors)
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
{
|
||||||
ServerApi.SetJwt(http, state);
|
ServerApi.SetJwt(http, state);
|
||||||
var stories = await ServerApi.RetrieveMany<StoryEntry>(http, "success/list");
|
var stories = await ServerApi.RetrieveMany<StoryEntry>(http, "success/list");
|
||||||
|
@ -35,10 +27,8 @@ namespace JobsJobsJobs.Client.Pages.SuccessStory
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ErrorMessages.Add(stories.Error);
|
errors.Add(stories.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Loading = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/JobsJobsJobs/Client/Shared/Loading.razor
Normal file
18
src/JobsJobsJobs/Client/Shared/Loading.razor
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
@if (IsLoading)
|
||||||
|
{
|
||||||
|
<p>@Message</p>
|
||||||
|
}
|
||||||
|
else if (ErrorMessages.Count > 0)
|
||||||
|
{
|
||||||
|
<p>The following error@(ErrorMessages.Count == 1 ? "" : "s") occurred:</p>
|
||||||
|
<ul>
|
||||||
|
@foreach (var msg in ErrorMessages)
|
||||||
|
{
|
||||||
|
<li><pre>@msg</pre></li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@ChildContent
|
||||||
|
}
|
58
src/JobsJobsJobs/Client/Shared/Loading.razor.cs
Normal file
58
src/JobsJobsJobs/Client/Shared/Loading.razor.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace JobsJobsJobs.Client.Shared
|
||||||
|
{
|
||||||
|
public partial class Loading : ComponentBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The delegate to call to load the data for this page
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<ICollection<string>> OnLoad { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The message to display when the page is loading (optional)
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public MarkupString Message { get; set; } = new MarkupString("Loading…");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The content to be displayed once the data has been loaded
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public RenderFragment ChildContent { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error messages that may arise from the data loading delegate
|
||||||
|
/// </summary>
|
||||||
|
private ICollection<string> ErrorMessages { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether we are currently loading data
|
||||||
|
/// </summary>
|
||||||
|
private bool IsLoading { get; set; } = true;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (OnLoad.HasDelegate)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await OnLoad.InvokeAsync(ErrorMessages);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,10 +9,10 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
|
<div class="@NavMenuCssClass" @onclick=@ToggleNavMenu>
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item px-3">
|
<li class="nav-item px-3">
|
||||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
<NavLink class="nav-link" href="" Match=@NavLinkMatch.All>
|
||||||
<span class="oi oi-home" aria-hidden="true"></span> Home
|
<span class="oi oi-home" aria-hidden="true"></span> Home
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user