feat(cv): redesign document editing with revision-safe letters and writing tools
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace JobTrackerApi.Models;
|
||||
|
||||
// A reviewed snapshot, never a live link to profile or CV settings.
|
||||
public sealed class CoverLetterDocumentSettings
|
||||
{
|
||||
public int SchemaVersion { get; set; } = 1;
|
||||
public string SenderName { get; set; } = "";
|
||||
public string SenderTitle { get; set; } = "";
|
||||
public string SenderEmail { get; set; } = "";
|
||||
public string SenderPhone { get; set; } = "";
|
||||
public string SenderLocation { get; set; } = "";
|
||||
public string Recipient { get; set; } = "";
|
||||
public string Subject { get; set; } = "";
|
||||
public string Date { get; set; } = "";
|
||||
public string ThemeId { get; set; } = "modern";
|
||||
public string? AccentColor { get; set; }
|
||||
public string? BodyFont { get; set; }
|
||||
public double? BaseFontSizePt { get; set; }
|
||||
public double? LineHeight { get; set; }
|
||||
public double? PageMarginMm { get; set; }
|
||||
public string PageSize { get; set; } = "a4";
|
||||
public int? SourceCvId { get; set; }
|
||||
}
|
||||
|
||||
public static class CoverLetterDocumentSettingsJson
|
||||
{
|
||||
private static readonly JsonSerializerOptions Options = new(JsonSerializerDefaults.Web);
|
||||
public static string Serialize(CoverLetterDocumentSettings? settings) => JsonSerializer.Serialize(Normalize(settings), Options);
|
||||
public static CoverLetterDocumentSettings Deserialize(string? json)
|
||||
{
|
||||
try { return Normalize(string.IsNullOrWhiteSpace(json) ? null : JsonSerializer.Deserialize<CoverLetterDocumentSettings>(json, Options)); }
|
||||
catch (JsonException) { return Normalize(null); }
|
||||
}
|
||||
|
||||
public static CoverLetterDocumentSettings Normalize(CoverLetterDocumentSettings? value)
|
||||
{
|
||||
value ??= new();
|
||||
var theme = CvThemeCatalog.Resolve(value.ThemeId);
|
||||
var style = CvVariantSettingsJson.Normalize(new()
|
||||
{
|
||||
AccentColor = value.AccentColor, BodyFont = value.BodyFont,
|
||||
BaseFontSizePt = value.BaseFontSizePt, LineHeight = value.LineHeight, PageMarginMm = value.PageMarginMm,
|
||||
});
|
||||
static string Text(string? text, int limit) => (text ?? "")[..Math.Min(text?.Length ?? 0, limit)];
|
||||
return new()
|
||||
{
|
||||
SchemaVersion = 1, ThemeId = theme.Id,
|
||||
SenderName = Text(value.SenderName, 300), SenderTitle = Text(value.SenderTitle, 300),
|
||||
SenderEmail = Text(value.SenderEmail, 300), SenderPhone = Text(value.SenderPhone, 100), SenderLocation = Text(value.SenderLocation, 300),
|
||||
Recipient = Text(value.Recipient, 2000), Subject = Text(value.Subject, 500), Date = Text(value.Date, 100),
|
||||
AccentColor = style.AccentColor ?? theme.Accent, BodyFont = style.BodyFont ?? theme.BodyFont,
|
||||
BaseFontSizePt = style.BaseFontSizePt ?? theme.BodySizePt, LineHeight = style.LineHeight ?? theme.LineHeight,
|
||||
PageMarginMm = style.PageMarginMm ?? theme.PageMarginMm,
|
||||
PageSize = string.Equals(value.PageSize, "letter", StringComparison.OrdinalIgnoreCase) ? "letter" : "a4",
|
||||
SourceCvId = value.SourceCvId is > 0 ? value.SourceCvId : null,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ public sealed class CoverLetterVersion
|
||||
|
||||
public int Version { get; set; }
|
||||
public string Text { get; set; } = string.Empty;
|
||||
public string? DocumentSettingsJson { get; set; }
|
||||
|
||||
// manual | ai | template | restore — how this text came to exist, so the history list can show
|
||||
// whether the user wrote it or approved it from a suggestion.
|
||||
@@ -35,6 +36,7 @@ public static class CoverLetterSources
|
||||
public const string Ai = "ai";
|
||||
public const string Template = "template";
|
||||
public const string Restore = "restore";
|
||||
public const string Legacy = "legacy";
|
||||
|
||||
public static bool IsValid(string? value) =>
|
||||
value is Manual or Ai or Template or Restore;
|
||||
|
||||
@@ -59,6 +59,7 @@ public class JobApplication
|
||||
public DateTime? ResponseDate { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
public string? CoverLetterText { get; set; }
|
||||
public string? CoverLetterDocumentSettingsJson { get; set; }
|
||||
public string? JobUrl { get; set; }
|
||||
|
||||
// Imported job content
|
||||
|
||||
@@ -18,6 +18,8 @@ public sealed class SubmittedApplicationPackage
|
||||
public string? CareerProfileJson { get; set; }
|
||||
public string? RenderedCvHtml { get; set; }
|
||||
public string? CoverLetterText { get; set; }
|
||||
public string? CoverLetterDocumentSettingsJson { get; set; }
|
||||
public string? RenderedCoverLetterHtml { get; set; }
|
||||
public string ApplicationMaterialJson { get; set; } = "{}";
|
||||
public DateTimeOffset CreatedAtUtc { get; set; } = DateTimeOffset.UtcNow;
|
||||
public List<SubmittedPackageAttachment> Attachments { get; set; } = new();
|
||||
|
||||
Reference in New Issue
Block a user