From 4a2cf0fbadbcb99fd7aeed7a5861c88a70c63849 Mon Sep 17 00:00:00 2001 From: Dylanvenancio Date: Tue, 28 Oct 2025 10:21:50 +0100 Subject: [PATCH] T2690 ADD Prewritten Text selection modal - Enhance letter template fetching logic --- my_compassion/controllers/my2_letters.py | 18 +++- .../correspondence_prewritten_letter.py | 23 +---- .../models/correspondence_s2b_generator.py | 1 + .../src/js/my2_letter_template_loader.js | 92 ++++++++++++------- .../src/js/my2_new_letter_clear_button.js | 5 +- ...my2_new_letter_template_image_selection.js | 10 ++ .../templates/pages/my2_new_letter.xml | 69 +++++++++++++- 7 files changed, 158 insertions(+), 60 deletions(-) diff --git a/my_compassion/controllers/my2_letters.py b/my_compassion/controllers/my2_letters.py index 94064612e..2e443b9cc 100644 --- a/my_compassion/controllers/my2_letters.py +++ b/my_compassion/controllers/my2_letters.py @@ -237,6 +237,12 @@ def my2_render_new_letter_page(self, **kwargs): .with_context(bin_size=False) ) + popup_templates = ( + request.env["correspondence.prewritten.letter"] + .sudo() + .search([("status", "=", "active")]) + ) + return request.render( "my_compassion.my2_new_letter_page", { @@ -244,6 +250,7 @@ def my2_render_new_letter_page(self, **kwargs): "sponsorship_ids": sponsorships, "templates": templates, "draft": draft, + "text_templates": popup_templates, }, ) @@ -504,12 +511,20 @@ def my2_get_letter_status(self, **post): def get_letter_templates(self, **kw): """ This controller returns the currently active letter template. + MODIFIED: It now accepts a 'template_id' parameter to fetch a specific one. """ + template_id = self._safe_int(kw.get("template_id"), None) + domain = [("status", "=", "active")] + limit = 1 + + if template_id: + domain.append(("id", "=", template_id)) + templates = ( request.env["correspondence.prewritten.letter"] .sudo() - .search([("status", "=", "active")], limit=1) + .search(domain, limit=limit) ) template_text = templates.text or "" @@ -524,6 +539,7 @@ def get_letter_templates(self, **kw): self._check_sponsored_child_access(child) except (AccessError, ValueError): _logger.warning("Invalid child access for letter template.") + replacements = { "%child%": child.preferred_name or "", "%firstname%": partner.preferred_name or partner.name or "", diff --git a/my_compassion/models/correspondence_prewritten_letter.py b/my_compassion/models/correspondence_prewritten_letter.py index a8a803995..3c4fb575f 100644 --- a/my_compassion/models/correspondence_prewritten_letter.py +++ b/my_compassion/models/correspondence_prewritten_letter.py @@ -12,8 +12,8 @@ class My2CorrespondencePreWrittenLetter(models.Model): _rec_name = "name" # == Fields == - name = fields.Char(required=True) - text = fields.Text(string="Text") + name = fields.Char(required=True, translate=True) + text = fields.Text(required=True, translate=True) start_date = fields.Date( help="The date from which this template is valid.", required=True, @@ -122,22 +122,3 @@ def _check_non_overlapping_schedule(self): raise ValidationError( _("Cannot schedule a template that is already expired.") ) - - # Only check for overlaps if the current record is scheduled - if record.is_active and record.start_date and record.end_date: - domain = [ - ("id", "!=", record.id), - ("is_active", "=", True), - ("start_date", "<=", record.end_date), - ("end_date", ">=", record.start_date), - ] - - conflicting_records = self.search(domain) - if conflicting_records: - conflict_details = "\n".join( - f"{c.name} {c.start_date} to {c.end_date}" - for c in conflicting_records - ) - raise ValidationError( - _("Conflicts with the following records:\n" + conflict_details) - ) diff --git a/my_compassion/models/correspondence_s2b_generator.py b/my_compassion/models/correspondence_s2b_generator.py index 8915b0a6a..04b5aef99 100644 --- a/my_compassion/models/correspondence_s2b_generator.py +++ b/my_compassion/models/correspondence_s2b_generator.py @@ -7,6 +7,7 @@ class CorrespondenceS2BGenerator(models.Model): user_id = fields.Many2one("res.users", index=True) child_id = fields.Many2one("compassion.child", index=True) partner_id = fields.Many2one(related="user_id.partner_id", readonly=True) + text_template_id = fields.Many2one("correspondence.prewritten.letter") def set_sponsorship_from_user_and_child(self): for generator in self: diff --git a/my_compassion/static/src/js/my2_letter_template_loader.js b/my_compassion/static/src/js/my2_letter_template_loader.js index 6e5642410..fd2781e9b 100644 --- a/my_compassion/static/src/js/my2_letter_template_loader.js +++ b/my_compassion/static/src/js/my2_letter_template_loader.js @@ -1,43 +1,69 @@ /** + * Handles the selection of template images by adding an ID to the clicked image + * and removing it from any previously selected image. + * + * Is used in /templates/pages/my2_new_letter.xml * Fetches a letter template from the server and populates the text input field with it. * * Used in /templates/pages/my2_new_letter.xml */ document.addEventListener("DOMContentLoaded", () => { - const textInput = document.getElementById("letter-input"); - const childSelector = document.getElementById("child-dropdown"); - const TEMPLATE_URL = `/my2/children/letter/templates`; + // Open the modal when the select element is clicked + document.getElementById("letter_template").addEventListener("click", function (event) { + event.preventDefault(); + $("#textTemplateSelectionModal").modal("show"); + }); + document.body.addEventListener("click", function (event) { + const clickedButton = event.target.closest(".text-template-item"); - const fetchTemplate = (childId) => { - if (!textInput) { - console.error("Required HTML element #letter-input is missing."); - return; - } - fetch(`${TEMPLATE_URL}?child_id=${childId}`) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((data) => { - if (data && data.template_text) { - textInput.value = data.template_text; - } - }) - .catch((error) => { - console.error("Failed to fetch template:", error); - }); - }; + if (clickedButton) { + const templateId = clickedButton.dataset.templateId; + if (!templateId) { + console.error("'data-template-id' is undefined."); + return; + } + // Store the template ID in a hidden input for later use if needed + const hiddenInput = document.getElementById("selected_template_id"); + if (hiddenInput) { + hiddenInput.value = templateId; + } else { + console.error("Could not find '#selected_template_id' to store template ID."); + } + + const childSelector = document.getElementById("child-dropdown"); + if (!childSelector) { + console.error("Could not find '#child-dropdown'."); + return; + } + const childId = childSelector.value; + + const TEMPLATE_URL = `/my2/children/letter/templates`; - if (childSelector) { - // Fetch template on initial load only if input is empty - if (!textInput.value) { - fetchTemplate(childSelector.value); + fetch(`${TEMPLATE_URL}?child_id=${childId}&template_id=${templateId}`) + .then((response) => { + // 1. Open curly brace + if (!response.ok) { + throw new Error("Network response was not ok"); + } + return response.json(); // 2. Explicit return + }) // 3. Close curly brace + .then((data) => { + if (data && data.template_text) { + const targetInput = document.getElementById("letter-input"); + if (targetInput) { + targetInput.value = data.template_text; + // Trigger input event so framework/listeners detect the change + targetInput.dispatchEvent(new Event("input", { bubbles: true, cancelable: true })); + } else { + console.error("Could not find '#letter-input' for insertion."); + } + } else { + console.error("Fetch did not return 'template_text'."); + } + }) + .catch((error) => { + console.error("Fetch failed:", error); // Fixed typo "etch" + }); } - // Re-fetch template when child selection changes - childSelector.addEventListener("change", (event) => { - fetchTemplate(event.target.value); - }); - } + }); }); diff --git a/my_compassion/static/src/js/my2_new_letter_clear_button.js b/my_compassion/static/src/js/my2_new_letter_clear_button.js index 993382afb..14889134b 100644 --- a/my_compassion/static/src/js/my2_new_letter_clear_button.js +++ b/my_compassion/static/src/js/my2_new_letter_clear_button.js @@ -53,7 +53,7 @@ document.addEventListener("DOMContentLoaded", function () { this.$("#selected-template").remove(); // Restore the select template button label to default - const buttonLabel = this.$("#template-selection-label"); + const buttonLabel = this.$("#template-selection-label, #text-template-selection-label"); if (buttonLabel.length) { buttonLabel.text(_t("Select a template")); } @@ -81,7 +81,8 @@ document.addEventListener("DOMContentLoaded", function () { * @private */ _toggleClearButton: function () { - const hasText = this.$("#letter-input").val().trim().length > 0; + const letterText = this.$("#letter-input").val(); + const hasText = letterText && letterText.trim().length > 0; const selectedTemplate = this.$("#selected-template").length > 0; const hasAttachments = this.$("#letter-attachments")[0].files.length > 0; diff --git a/my_compassion/static/src/js/my2_new_letter_template_image_selection.js b/my_compassion/static/src/js/my2_new_letter_template_image_selection.js index 5d61ca3cf..15ebdea1f 100644 --- a/my_compassion/static/src/js/my2_new_letter_template_image_selection.js +++ b/my_compassion/static/src/js/my2_new_letter_template_image_selection.js @@ -13,6 +13,7 @@ document.addEventListener("DOMContentLoaded", function () { // Get all template images const templateImages = document.querySelectorAll(".template-image"); + const textInputs = document.querySelectorAll(".text-template-item"); // Add click event listener to each image templateImages.forEach((image) => { @@ -42,4 +43,13 @@ document.addEventListener("DOMContentLoaded", function () { targetDiv.appendChild(img); }); }); + + textInputs.forEach((textInput) => { + textInput.addEventListener("click", function () { + // Replace the button's label content with the template name selected + const button_label_element = document.getElementById("text-template-selection-label"); + const selectedTemplateName = textInput.innerText; + button_label_element.textContent = selectedTemplateName; + }); + }); }); diff --git a/my_compassion/templates/pages/my2_new_letter.xml b/my_compassion/templates/pages/my2_new_letter.xml index 8b7eab92c..dc9e53e9f 100644 --- a/my_compassion/templates/pages/my2_new_letter.xml +++ b/my_compassion/templates/pages/my2_new_letter.xml @@ -35,6 +35,12 @@
+
@@ -72,9 +78,9 @@
- +
-
+
@@ -99,7 +105,27 @@
-
+
+
+ +
+ + + + + Select a template + + + + + +
+
+
+
+ +