Convert to Blazor (#6)
Convert existing progress to Blazor on client and server
This commit was merged in pull request #6.
This commit is contained in:
13
src/JobsJobsJobs/Shared/Api/LogOnSuccess.cs
Normal file
13
src/JobsJobsJobs/Shared/Api/LogOnSuccess.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace JobsJobsJobs.Shared.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// A successful log on; returns JWT, citizen ID, and display name
|
||||
/// </summary>
|
||||
public record LogOnSuccess(string Jwt, string Id, string Name)
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID return value as a citizen ID
|
||||
/// </summary>
|
||||
public CitizenId CitizenId => CitizenId.Parse(Id);
|
||||
}
|
||||
}
|
||||
15
src/JobsJobsJobs/Shared/Domain/Citizen.cs
Normal file
15
src/JobsJobsJobs/Shared/Domain/Citizen.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using NodaTime;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// A user of Jobs, Jobs, Jobs
|
||||
/// </summary>
|
||||
public record Citizen(
|
||||
CitizenId Id,
|
||||
string NaUser,
|
||||
string DisplayName,
|
||||
string ProfileUrl,
|
||||
Instant JoinedOn,
|
||||
Instant LastSeenOn);
|
||||
}
|
||||
26
src/JobsJobsJobs/Shared/Domain/CitizenId.cs
Normal file
26
src/JobsJobsJobs/Shared/Domain/CitizenId.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of a user (a citizen of Gitmo Nation)
|
||||
/// </summary>
|
||||
public record CitizenId(ShortId Id)
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new citizen ID
|
||||
/// </summary>
|
||||
/// <returns>A new citizen ID</returns>
|
||||
public static async Task<CitizenId> Create() => new CitizenId(await ShortId.Create());
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to create a citizen ID from a string
|
||||
/// </summary>
|
||||
/// <param name="id">The prospective ID</param>
|
||||
/// <returns>The citizen ID</returns>
|
||||
/// <exception cref="System.FormatException">If the string is not a valid citizen ID</exception>
|
||||
public static CitizenId Parse(string id) => new CitizenId(ShortId.Parse(id));
|
||||
|
||||
public override string ToString() => Id.ToString();
|
||||
}
|
||||
}
|
||||
7
src/JobsJobsJobs/Shared/Domain/Continent.cs
Normal file
7
src/JobsJobsJobs/Shared/Domain/Continent.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// A continent
|
||||
/// </summary>
|
||||
public record Continent(ContinentId Id, string Name);
|
||||
}
|
||||
24
src/JobsJobsJobs/Shared/Domain/ContinentId.cs
Normal file
24
src/JobsJobsJobs/Shared/Domain/ContinentId.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of a continent
|
||||
/// </summary>
|
||||
public record ContinentId(ShortId Id)
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new continent ID
|
||||
/// </summary>
|
||||
/// <returns>A new continent ID</returns>
|
||||
public static async Task<ContinentId> Create() => new ContinentId(await ShortId.Create());
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to create a continent ID from a string
|
||||
/// </summary>
|
||||
/// <param name="id">The prospective ID</param>
|
||||
/// <returns>The continent ID</returns>
|
||||
/// <exception cref="System.FormatException">If the string is not a valid continent ID</exception>
|
||||
public static ContinentId Parse(string id) => new ContinentId(ShortId.Parse(id));
|
||||
}
|
||||
}
|
||||
21
src/JobsJobsJobs/Shared/Domain/MarkdownString.cs
Normal file
21
src/JobsJobsJobs/Shared/Domain/MarkdownString.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Markdig;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// A string of Markdown text
|
||||
/// </summary>
|
||||
public record MarkdownString(string Text)
|
||||
{
|
||||
/// <summary>
|
||||
/// The Markdown conversion pipeline (enables all advanced features)
|
||||
/// </summary>
|
||||
private readonly MarkdownPipeline Pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
|
||||
|
||||
/// <summary>
|
||||
/// Convert this Markdown string to HTML
|
||||
/// </summary>
|
||||
/// <returns>This Markdown string as HTML</returns>
|
||||
public string ToHtml() => Markdown.ToHtml(Text, Pipeline);
|
||||
}
|
||||
}
|
||||
25
src/JobsJobsJobs/Shared/Domain/Profile.cs
Normal file
25
src/JobsJobsJobs/Shared/Domain/Profile.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using NodaTime;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// A job seeker profile
|
||||
/// </summary>
|
||||
public record Profile(
|
||||
CitizenId Id,
|
||||
bool SeekingEmployment,
|
||||
bool IsPublic,
|
||||
ContinentId ContinentId,
|
||||
string Region,
|
||||
bool RemoteWork,
|
||||
bool FullTime,
|
||||
MarkdownString Biography,
|
||||
Instant LastUpdatedOn,
|
||||
MarkdownString? Experience)
|
||||
{
|
||||
/// <summary>
|
||||
/// Navigation property for continent
|
||||
/// </summary>
|
||||
public Continent? Continent { get; set; }
|
||||
}
|
||||
}
|
||||
38
src/JobsJobsJobs/Shared/Domain/ShortId.cs
Normal file
38
src/JobsJobsJobs/Shared/Domain/ShortId.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// A short ID
|
||||
/// </summary>
|
||||
public record ShortId(string Id)
|
||||
{
|
||||
/// <summary>
|
||||
/// Validate the format of the short ID
|
||||
/// </summary>
|
||||
private static readonly Regex ValidShortId =
|
||||
new Regex("^[a-z0-9_-]{12}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new short ID
|
||||
/// </summary>
|
||||
/// <returns>A new short ID</returns>
|
||||
public static async Task<ShortId> Create() => new ShortId(await Nanoid.Nanoid.GenerateAsync(size: 12));
|
||||
|
||||
/// <summary>
|
||||
/// Try to parse a string of text into a short ID
|
||||
/// </summary>
|
||||
/// <param name="text">The text of the prospective short ID</param>
|
||||
/// <returns>The short ID</returns>
|
||||
/// <exception cref="FormatException">If the format is not valid</exception>
|
||||
public static ShortId Parse(string text)
|
||||
{
|
||||
if (text.Length == 12 && ValidShortId.IsMatch(text)) return new ShortId(text);
|
||||
throw new FormatException($"The string {text} is not a valid short ID");
|
||||
}
|
||||
|
||||
public override string ToString() => Id;
|
||||
}
|
||||
}
|
||||
7
src/JobsJobsJobs/Shared/Domain/Skill.cs
Normal file
7
src/JobsJobsJobs/Shared/Domain/Skill.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// A skill the job seeker possesses
|
||||
/// </summary>
|
||||
public record Skill(SkillId Id, CitizenId CitizenId, string Description, string? Notes);
|
||||
}
|
||||
16
src/JobsJobsJobs/Shared/Domain/SkillId.cs
Normal file
16
src/JobsJobsJobs/Shared/Domain/SkillId.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of a skill
|
||||
/// </summary>
|
||||
public record SkillId(ShortId Id)
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new skill ID
|
||||
/// </summary>
|
||||
/// <returns>A new skill ID</returns>
|
||||
public static async Task<SkillId> Create() => new SkillId(await ShortId.Create());
|
||||
}
|
||||
}
|
||||
14
src/JobsJobsJobs/Shared/Domain/Success.cs
Normal file
14
src/JobsJobsJobs/Shared/Domain/Success.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using NodaTime;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// A record of success finding employment
|
||||
/// </summary>
|
||||
public record Success(
|
||||
SuccessId Id,
|
||||
CitizenId CitizenId,
|
||||
Instant RecordedOn,
|
||||
bool FromHere,
|
||||
MarkdownString? Story);
|
||||
}
|
||||
16
src/JobsJobsJobs/Shared/Domain/SuccessId.cs
Normal file
16
src/JobsJobsJobs/Shared/Domain/SuccessId.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of a success report
|
||||
/// </summary>
|
||||
public record SuccessId(ShortId Id)
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new success report ID
|
||||
/// </summary>
|
||||
/// <returns>A new success report ID</returns>
|
||||
public static async Task<SuccessId> Create() => new SuccessId(await ShortId.Create());
|
||||
}
|
||||
}
|
||||
17
src/JobsJobsJobs/Shared/JobsJobsJobs.Shared.csproj
Normal file
17
src/JobsJobsJobs/Shared/JobsJobsJobs.Shared.csproj
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Markdig" Version="0.22.1" />
|
||||
<PackageReference Include="Nanoid" Version="2.1.0" />
|
||||
<PackageReference Include="NodaTime" Version="3.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SupportedPlatform Include="browser" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
64
src/JobsJobsJobs/Shared/Result.cs
Normal file
64
src/JobsJobsJobs/Shared/Result.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
namespace JobsJobsJobs.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// A result with two different possibilities
|
||||
/// </summary>
|
||||
/// <typeparam name="TOk">The type of the Ok result</typeparam>
|
||||
public struct Result<TOk>
|
||||
{
|
||||
private readonly TOk? _okValue;
|
||||
|
||||
/// <summary>
|
||||
/// Is this an Ok result?
|
||||
/// </summary>
|
||||
public bool IsOk { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this an Error result?
|
||||
/// </summary>
|
||||
public bool IsError
|
||||
{
|
||||
get => !IsOk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Ok value
|
||||
/// </summary>
|
||||
public TOk Ok
|
||||
{
|
||||
get => _okValue!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The error value
|
||||
/// </summary>
|
||||
public string Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor (inaccessible - use static creation methods)
|
||||
/// </summary>
|
||||
/// <param name="isOk">Whether this is an Ok result</param>
|
||||
/// <param name="okValue">The value of the Ok result</param>
|
||||
/// <param name="error">The error message of the Error result</param>
|
||||
private Result(bool isOk, TOk? okValue = default, string error = "")
|
||||
{
|
||||
IsOk = isOk;
|
||||
_okValue = okValue;
|
||||
Error = error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an Ok result
|
||||
/// </summary>
|
||||
/// <param name="okValue">The value of the Ok result</param>
|
||||
/// <returns>The Ok result</returns>
|
||||
public static Result<TOk> AsOk(TOk okValue) => new Result<TOk>(true, okValue);
|
||||
|
||||
/// <summary>
|
||||
/// Create an Error result
|
||||
/// </summary>
|
||||
/// <param name="error">The error message</param>
|
||||
/// <returns>The Error result</returns>
|
||||
public static Result<TOk> AsError(string error) => new Result<TOk>(false) { Error = error };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user