diff --git a/Apis/api/Controllers/CvMatcherController.cs b/Apis/api/Controllers/CvMatcherController.cs
index 03098f2..3b0bcc1 100644
--- a/Apis/api/Controllers/CvMatcherController.cs
+++ b/Apis/api/Controllers/CvMatcherController.cs
@@ -246,38 +246,24 @@ public sealed class CvMatcherController : ControllerBase
{
var result = await _jobSearchApi.StartSearchAsync(t, ct);
var lang = "en";
- var html = result.Status switch
+ var (title, message) = result.Status switch
{
- StartJobSearchStatus.Started =>
- HtmlPage(_templates.Get("html.job-search.started.title", lang), _templates.Get("html.job-search.started.message", lang)),
- StartJobSearchStatus.AlreadyUsed =>
- HtmlPage(_templates.Get("html.job-search.already-used.title", lang), _templates.Get("html.job-search.already-used.message", lang)),
- StartJobSearchStatus.Expired =>
- HtmlPage(_templates.Get("html.job-search.expired.title", lang), _templates.Get("html.job-search.expired.message", lang)),
- _ =>
- HtmlPage(_templates.Get("html.job-search.invalid.title", lang), _templates.Get("html.job-search.invalid.message", lang))
+ StartJobSearchStatus.Started => (_templates.Get("html.job-search.started.title", lang), _templates.Get("html.job-search.started.message", lang)),
+ StartJobSearchStatus.AlreadyUsed => (_templates.Get("html.job-search.already-used.title", lang), _templates.Get("html.job-search.already-used.message", lang)),
+ StartJobSearchStatus.Expired => (_templates.Get("html.job-search.expired.title", lang), _templates.Get("html.job-search.expired.message", lang)),
+ _ => (_templates.Get("html.job-search.invalid.title", lang), _templates.Get("html.job-search.invalid.message", lang))
};
- return Content(html, "text/html");
+ return Content(_templates.Render("html.job-search.shell", "*", ("title", title), ("message", message)), "text/html");
}
catch (Exception ex)
{
_logger.LogError(ex, "Job search start failed for token {Token}.", t);
- return Content(HtmlPage(_templates.Get("html.job-search.error.title", "en"), _templates.Get("html.job-search.error.message", "en")), "text/html");
+ var title = _templates.Get("html.job-search.error.title", "en");
+ var message = _templates.Get("html.job-search.error.message", "en");
+ return Content(_templates.Render("html.job-search.shell", "*", ("title", title), ("message", message)), "text/html");
}
}
- private static string HtmlPage(string title, string message) => $$"""
-
-
-
{{title}} - MyAi.ro
-
-
-
-
- """;
-
private async Task CacheUploadedCvAsync(IFormFile file, string documentId, CancellationToken ct)
{
try
diff --git a/Apis/myai-data/Migrations/20260524145351_AddTemplates.cs b/Apis/myai-data/Migrations/20260524145351_AddTemplates.cs
index 7099ee3..3b68ef7 100644
--- a/Apis/myai-data/Migrations/20260524145351_AddTemplates.cs
+++ b/Apis/myai-data/Migrations/20260524145351_AddTemplates.cs
@@ -71,6 +71,11 @@ namespace MyAi.Data.Migrations
Row("email.search-results.empty", "en", "MyAi.ro found no jobs matching your CV. Try again later or update your CV.", "No results message for job search results email");
Row("email.search-results.empty", "ro", "MyAi.ro nu a gasit joburi care sa corespunda CV-ului tau. Incercati mai tarziu sau ajustati CV-ul.", "Mesaj fara rezultate pentru emailul de cautare joburi");
+ // HTML job-search page shell — wraps title + message in a centered card page
+ Row("html.job-search.shell", "*",
+ "{{title}} - MyAi.ro",
+ "Full HTML shell for job-search status pages. Placeholders: {{title}}, {{message}}.");
+
// HTML job-search start page messages
Row("html.job-search.started.title", "en", "Job search started", "Title for job search started page");
Row("html.job-search.started.message", "en", "Your job search has started. Results will be sent to your email shortly.", "Message for job search started page");
diff --git a/Apis/myai-data/Migrations/20260601190000_AddHtmlJobSearchShell.cs b/Apis/myai-data/Migrations/20260601190000_AddHtmlJobSearchShell.cs
new file mode 100644
index 0000000..87b638a
--- /dev/null
+++ b/Apis/myai-data/Migrations/20260601190000_AddHtmlJobSearchShell.cs
@@ -0,0 +1,37 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using MyAi.Data;
+
+#nullable disable
+
+namespace MyAi.Data.Migrations
+{
+ ///
+ public partial class AddHtmlJobSearchShell : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.InsertData(
+ table: "Templates",
+ columns: ["Key", "Language", "Value", "Description"],
+ values: new object[]
+ {
+ "html.job-search.shell",
+ "*",
+ "{{title}} - MyAi.ro",
+ "Full HTML shell for job-search status pages. Placeholders: {{title}}, {{message}}."
+ },
+ schema: MigrationConstants.SchemaName);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DeleteData(
+ table: "Templates",
+ keyColumns: ["Key", "Language"],
+ keyValues: new object[] { "html.job-search.shell", "*" },
+ schema: MigrationConstants.SchemaName);
+ }
+ }
+}