diff --git a/Apis/email-data/Migrations/20260601133043_InitialSchema.cs b/Apis/email-data/Migrations/20260601133043_InitialSchema.cs index 567a214..aeb0295 100644 --- a/Apis/email-data/Migrations/20260601133043_InitialSchema.cs +++ b/Apis/email-data/Migrations/20260601133043_InitialSchema.cs @@ -47,22 +47,22 @@ namespace Email.Data.Migrations // Match result email — body (HTML formatted) Row("email.match.body", "en", @"

CV Match Report

- +
- - + + - - + + - - + + - - + +
CV ID{{cvDocumentId}}CV ID{{cvDocumentId}}
Job{{jobLabel}}Job{{jobLabel}}
URL{{jobUrl}}URL{{jobUrl}}
Score{{score}}%Score{{score}}%

Summary

@@ -76,22 +76,22 @@ namespace Email.Data.Migrations "Body for the CV match result email (HTML formatted)"); Row("email.match.body", "ro", @"

Report Potrivire CV

- +
- - + + - - + + - - + + - - + +
ID Document CV{{cvDocumentId}}ID Document CV{{cvDocumentId}}
Job{{jobLabel}}Job{{jobLabel}}
URL{{jobUrl}}URL{{jobUrl}}
Scor{{score}}%Scor{{score}}%

Rezumat

@@ -108,13 +108,25 @@ namespace Email.Data.Migrations Row("email.match.job-search-footer", "en", @"

Want to find more jobs matching your CV?

-

Search Jobs

+ + + + +
+ Search Jobs +

(link valid for {{expiryDays}} days)

", "Job search CTA appended to match result email (HTML formatted)"); Row("email.match.job-search-footer", "ro", @"

Vrei să găsești mai multe joburi potrivite CV-ului tău?

-

Caută Joburi

+ + + + +
+ Caută Joburi +

(link valabil {{expiryDays}} zile)

", "CTA cautare joburi adaugat la emailul de potrivire CV (format HTML)"); @@ -126,34 +138,84 @@ namespace Email.Data.Migrations Row("email.search-results.body", "en", @"

Job Search Results

MyAi.ro found {{count}} jobs matching your CV:

-
-{{items}} -
", +{{items}}", "Body preamble for job search results email (HTML formatted)"); Row("email.search-results.body", "ro", @"

Rezultate Căutare Joburi

MyAi.ro a găsit {{count}} joburi potrivite CV-ului tău:

-
-{{items}} -
", +{{items}}", "Corpul emailului de rezultate cautare joburi (format HTML)"); + // Job search results email — scan summary block (keywords + providers used) + Row("email.search-results.scan-summary", "en", + @" + + + +
+
Keywords used: {{keywordsHtml}}
+
Providers scanned: {{providers}}
+
", + "Scan summary block prepended to job search results email (HTML formatted)"); + Row("email.search-results.scan-summary", "ro", + @" + + + +
+
Cuvinte cheie folosite: {{keywordsHtml}}
+
Furnizori scanați: {{providers}}
+
", + "Bloc rezumat scanare adaugat la emailul de rezultate cautare joburi (format HTML)"); + + // Job search results email — single job result item card + Row("email.search-results.item", "en", + @" + + + +
+ {{index}}. {{jobTitle}} + {{score}}% match + [{{providerName}}]
+ {{jobUrl}} + {{summary}} +
", + "Single job result card in job search results email (HTML formatted)"); + Row("email.search-results.item", "ro", + @" + + + +
+ {{index}}. {{jobTitle}} + {{score}}% potrivire + [{{providerName}}]
+ {{jobUrl}} + {{summary}} +
", + "Card job individual in emailul de rezultate cautare joburi (format HTML)"); + // Job search results email — no results found - HTML formatted Row("email.search-results.empty", "en", - @"
-

-No jobs found
-MyAi.ro found no jobs matching your CV at this moment. Please try again later or update your CV to improve your match results. -

-
", + @" + + + +
+

No jobs found
+ MyAi.ro found no jobs matching your CV at this moment. Please try again later or update your CV to improve your match results.

+
", "No results message for job search results email (HTML formatted)"); Row("email.search-results.empty", "ro", - @"
-

-Niciun job găsit
-MyAi.ro nu a găsit joburi potrivite CV-ului tău în acest moment. Te rugăm să încerci din nou mai târziu sau să-ți actualizezi CV-ul pentru a obține rezultate mai bune. -

-
", + @" + + + +
+

Niciun job găsit
+ MyAi.ro nu a găsit joburi potrivite CV-ului tău în acest moment. Te rugăm să încerci din nou mai târziu sau să-ți actualizezi CV-ul pentru a obține rezultate mai bune.

+
", "Mesaj fara rezultate pentru emailul de cautare joburi (format HTML)"); // HTML job-search start page messages diff --git a/Jobs/cv-search-job/Services/CvSearchEmailSender.cs b/Jobs/cv-search-job/Services/CvSearchEmailSender.cs index 3262d8e..08fac2b 100644 --- a/Jobs/cv-search-job/Services/CvSearchEmailSender.cs +++ b/Jobs/cv-search-job/Services/CvSearchEmailSender.cs @@ -89,7 +89,7 @@ public sealed class CvSearchEmailSender /// private string BuildBody(IReadOnlyList results, IReadOnlyList keywords, IReadOnlyList providerNames, string language) { - var scanSummary = BuildScanSummary(keywords, providerNames); + var scanSummary = BuildScanSummary(keywords, providerNames, language); if (results.Count == 0) return scanSummary + _emailTemplates.Get("email.search-results.empty", language); @@ -98,18 +98,18 @@ public sealed class CvSearchEmailSender for (int i = 0; i < results.Count; i++) { var r = results[i]; - var matchResp = TryParseResult(r.ResultJson); - var summary = matchResp?.Summary; + var summary = TryParseResult(r.ResultJson)?.Summary; + var summaryHtml = string.IsNullOrWhiteSpace(summary) + ? "" + : $"

{summary}

"; - items.Append($""" -
- {i + 1}. {r.JobTitle} - {r.Score}% match - [{r.ProviderName}]
- {r.JobUrl} - {(string.IsNullOrWhiteSpace(summary) ? "" : $"

{summary}

")} -
- """); + items.Append(_emailTemplates.Render("email.search-results.item", language, + ("index", (i + 1).ToString()), + ("jobTitle", r.JobTitle), + ("score", r.Score.ToString()), + ("providerName", r.ProviderName), + ("jobUrl", r.JobUrl), + ("summary", summaryHtml))); } return _emailTemplates.Render("email.search-results.body", language, @@ -118,25 +118,23 @@ public sealed class CvSearchEmailSender } /// - /// Builds the scan summary block showing the CV keywords and providers used for the search. + /// Renders the scan summary block via template, passing keyword tags and provider list as data. + /// Keyword tags are built here because they are variable-count inline elements, not structural HTML. /// - private static string BuildScanSummary(IReadOnlyList keywords, IReadOnlyList providerNames) + private string BuildScanSummary(IReadOnlyList keywords, IReadOnlyList providerNames, string language) { var keywordsHtml = keywords.Count > 0 ? string.Join(" ", keywords.Select(k => - $"{k}")) - : "none detected"; + $"{k}")) + : "none detected"; - var providersText = providerNames.Count > 0 + var providers = providerNames.Count > 0 ? string.Join(", ", providerNames) : "none"; - return $""" -
-
Keywords used: {keywordsHtml}
-
Providers scanned: {providersText}
-
- """; + return _emailTemplates.Render("email.search-results.scan-summary", language, + ("keywordsHtml", keywordsHtml), + ("providers", providers)); } ///