From 0b3e11ac6a6b07138461f4a201fecaa7c7a943f7 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 9 Sep 2025 23:59:54 +0530 Subject: [PATCH] V1.0.3-beta --- .../propertyTemplateSelector.js | 668 ++++++++++++++++-- 1 file changed, 626 insertions(+), 42 deletions(-) diff --git a/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js b/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js index 680609b..a49ca80 100644 --- a/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js +++ b/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js @@ -2257,7 +2257,7 @@ export default class PropertyTemplateSelector extends LightningElement { .replace(/\"/g, """) .replace(/'/g, "'"); - const lines = raw.replace(/\r\n?/g, "\n").split("\n"); + const lines = raw.replace(/\r\n?/g, "\n").split("\n").map((l) => l.trim()); const bulletRe = /^\s*(?:[-*•]|\u2022)\s+(.*)$/; // -,*,• bullets const numberedRe = /^\s*(\d+)[\.)]\s+(.*)$/; // 1. or 1) @@ -3249,7 +3249,8 @@ export default class PropertyTemplateSelector extends LightningElement { - ${galleryPagesHTML} + +${galleryPagesHTML} @@ -3277,7 +3278,9 @@ export default class PropertyTemplateSelector extends LightningElement { "Property description not available."; // Get smart images - const exteriorImage = this.getExteriorImageUrl(); + const exteriorImage = + this.getExteriorImageUrl() || + "https://images.unsplash.com/photo-1600585154340-be6161a56a0c?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200"; const interiorImage = this.getSmartImageForSection( "interior", "https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200" @@ -3433,20 +3436,20 @@ export default class PropertyTemplateSelector extends LightningElement { data.Last_Sold_Price__c || data.lastSoldPrice ; // Location and POI data - const schools = data.Schools__c || data.schools ; + const schools = data.Schools__c || data.schools || "N/A"; const shoppingCenters = - data.Shopping_Centers__c || data.shoppingCenters ; + data.Shopping_Centers__c || data.shoppingCenters || "N/A"; const airportDistance = - data.Airport_Distance__c || data.airportDistance ; + data.Airport_Distance__c || data.airportDistance || "N/A"; const nearbyLandmarks = - data.Nearby_Landmarks__c || data.nearbyLandmarks; + data.Nearby_Landmarks__c || data.nearbyLandmarks || "N/A"; const transportation = - data.Transportation__c || data.transportation ; - const hospitals = data.Hospitals__c || data.hospitals ; + data.Transportation__c || data.transportation || "N/A"; + const hospitals = data.Hospitals__c || data.hospitals || "N/A"; const beachDistance = - data.Beach_Distance__c || data.beachDistance; + data.Beach_Distance__c || data.beachDistance || "N/A"; const metroDistance = - data.Metro_Distance__c || data.metroDistance; + data.Metro_Distance__c || data.metroDistance || "N/A"; // Additional information const petFriendly = data.Pet_Friendly__c || data.petFriendly; @@ -3863,41 +3866,41 @@ export default class PropertyTemplateSelector extends LightningElement {
-
-
+
+
Schools
${schools}
-
+
Shopping
${shoppingCenters}
-
+
Airport
${airportDistance}
-
+
Landmarks
${nearbyLandmarks}
-
+
Transportation
${transportation}
-
+
Hospitals
${hospitals}
-
+
Beach
${beachDistance}
@@ -3960,6 +3963,558 @@ ${galleryPagesHTML} ` } + createSerenityHouseTemplate() { + const data = this.propertyData || {}; + + // Extract all available property data with fallbacks + const propertyName = data.Name || data.propertyName || "Property Name"; + const location = data.Address__c || data.location || "Location"; + const referenceId = + data.pcrm__Title_English__c || data.Name || data.propertyName || ""; + const agentName = + data.contactName || data.Agent_Name__c || data.agentName || "N/A"; + const agentPhone = + data.contactPhone || data.Agent_Phone__c || data.agentPhone || "N/A"; + const agentEmail = + data.contactEmail || data.Agent_Email__c || data.agentEmail || "N/A"; + const ownerName = data.Owner_Name__c || data.ownerName || "N/A"; + const ownerPhone = data.Owner_Phone__c || data.ownerPhone || "N/A"; + const ownerEmail = data.Owner_Email__c || data.ownerEmail || "N/A"; + + // Dynamic pricing with fallbacks + const price = + data.Sale_Price_Min__c || + data.Rent_Price_Min__c || + data.Price__c || + data.salePriceMin || + data.rentPriceMin || + data.price || + "Price on Request"; + const priceDisplay = + price !== "Price on Request" ? `Offered at ${price}` : "Price on Request"; + + // Dynamic property details + const bedrooms = data.Bedrooms__c || data.bedrooms || "N/A"; + const bathrooms = data.Bathrooms__c || data.bathrooms || "N/A"; + const squareFeet = + data.Square_Feet__c || data.squareFeet || data.area || "N/A"; + const propertyType = data.Property_Type__c || data.propertyType || "N/A"; + const status = data.Status__c || data.status || data.offeringType || "N/A"; + const yearBuilt = + data.Build_Year__c || data.yearBuilt || data.buildYear || "N/A"; + const furnishing = data.Furnished__c || data.furnishing || "N/A"; + const parking = data.Parking_Spaces__c || data.parking || "N/A"; + + // Dynamic description + const description = this.formatDescriptionForPDF( + data.Description_English__c || + data.descriptionEnglish || + data.description || + "Property description not available." + ); + + // Get smart images + const exteriorImage = this.getExteriorImageUrl(); + const interiorImage = this.getSmartImageForSection( + "interior", + "https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200" + ); + const bedroomImage = this.getSmartImageForSection( + "bedroom", + "https://images.unsplash.com/photo-1586023492125-27b2c045efd7?ixlib=rb-4.0.3&q=85&fm=jpg&crop=entropy&cs=srgb&w=1200" + ); + + // Dynamic location details + const schools = data.Schools__c || data.schools || "N/A"; + const shopping = data.Shopping_Centers__c || data.shoppingCenters || "N/A"; + const hospitals = data.Hospitals__c || data.hospitals || "N/A"; + const countryClub = data.Country_Club__c || data.countryClub || "N/A"; + const airport = data.Airport_Distance__c || data.airportDistance || "N/A"; + + // Dynamic additional info + const petFriendly = data.Pet_Friendly__c || data.petFriendly || "N/A"; + const smoking = data.Smoking_Allowed__c || data.smokingAllowed || "N/A"; + const availability = data.Available_From__c || data.availableFrom || "N/A"; + const utilities = + data.Utilities_Included__c || data.utilitiesIncluded || "N/A"; + + // Additional dynamic fields + const floor = data.Floor__c || data.floor || "N/A"; + const maintenanceFee = data.Maintenance_Fee__c || data.maintenanceFee || "N/A"; + const serviceCharge = data.Service_Charge__c || data.serviceCharge || "N/A"; + const acres = data.Lot_Size__c || data.acres || "N/A"; + + // Build paginated gallery pages appended at the end (2 columns, last image full width) + const allImages = Array.isArray(this.realPropertyImages) + ? this.realPropertyImages + : []; + const imagesPerPage = 7; + let galleryPagesHTML = ""; + if (allImages.length > 0) { + for (let i = 0; i < allImages.length; i += imagesPerPage) { + const chunk = allImages.slice(i, i + imagesPerPage); + const chunkHTML = chunk + .map((img, idx) => { + const title = + img.title || img.pcrm__Title__c || `Property Image ${i + idx + 1}`; + const extraStyle = idx === chunk.length - 1 ? " grid-column: 1 / -1;" : ""; + return `${title}`; + }) + .join(""); + galleryPagesHTML += ` +
+
+

Property Gallery

+
${chunkHTML}
+
+
+
Agent: ${agentName} | ${agentPhone} | ${agentEmail}
+
Owner: ${ownerName} | ${ownerPhone} | ${ownerEmail}
+
+
`; + } + } + + return ` + + + + + Editorial Real Estate Brochure - Updated - A4 Size + + + + + + + + +
+
+
+
+
+
Elysian Estates Collection
+

${propertyName}

+

${location}

+

Reference ID: ${referenceId}

+
+
+
${squareFeet} Sq. Ft. • ${bedrooms} Bedrooms • ${bathrooms} Bathrooms
+ ${description} +
+ ${priceDisplay} +
+
+
+
+ +
+
+ 02 +

A Sanctuary of Modern Design

+

${propertyType} • ${status} • ${squareFeet} Sq. Ft.

+
+
+ ${description} +

A timeless residence built not just for living, but for thriving.

+
+
+
+
+
+ +
+
+ 03 +

Property Specifications

+

A comprehensive overview of the property's features, details, and amenities.

+ +
+
+
${bedrooms}
Bedrooms
+
${bathrooms}
Bathrooms
+
${squareFeet}
Square Feet
+
${acres}
Acres
+
+ +
+ +

Property Details

+
+
Status${status}
+
Year Built${yearBuilt}
+
Type${propertyType}
+
Furnishing${furnishing}
+
Floor${floor}
+
Maintenance Fee${maintenanceFee}
+
Parking${parking}
+
Service Charge${serviceCharge}
+
+ +
+ +

Amenities & Features

+
    ${this.generateAmenitiesListItems(data)}
+
+
+
+ +
+
+ 04 +

Floor Plan & Details

+ +
+
+

Location & Nearby

+
Schools ${schools}
+
Shopping ${shopping}
+
Hospitals ${hospitals}
+
Country Club ${countryClub}
+
Airport ${airport}
+
+
+

Additional Information

+
Pet-Friendly ${petFriendly}
+
Smoking ${smoking}
+
Availability ${availability}
+
Utilities ${utilities}
+
+
+ +
+ +

Floor Plan & Location

+
+ +
+
+
Owner Information
+
${ownerName}
+

${ownerPhone}

+ +
+
+
Agent Information
+
${agentName}
+

${agentPhone}

+ +
+
+
+
+ +${galleryPagesHTML} + + +`; + } + createLuxuryMansionTemplate() { const data = this.propertyData || {}; @@ -4652,6 +5207,8 @@ ${galleryPagesHTML}
+ ${galleryPagesHTML} + `; @@ -5941,9 +6498,27 @@ ${galleryPagesHTML} return; } - // Otherwise insert a visible tab (4 spaces) at caret - editor.focus(); - document.execCommand("insertText", false, " "); + // Otherwise add a visual tab (4 NBSP) at the start of the current block + const getBlock = (node) => { + let n = node.nodeType === Node.TEXT_NODE ? node.parentElement : node; + while ( + n && + !/(P|DIV|LI|H1|H2|H3|H4|H5|H6)/i.test(n.tagName) + ) { + n = n.parentElement; + } + return n || editor; + }; + const block = getBlock(range.startContainer); + if (!block) return; + const TAB = "\u00A0\u00A0\u00A0\u00A0"; // 4 NBSP + const first = block.firstChild; + if (first && first.nodeType === Node.TEXT_NODE) { + first.textContent = TAB + first.textContent; + } else { + block.insertBefore(document.createTextNode(TAB), first || null); + } + editor.dispatchEvent(new Event("input", { bubbles: true })); } handleOutdent() { @@ -5975,21 +6550,25 @@ ${galleryPagesHTML} } } - // Otherwise, remove one indentation level (4 leading spaces) from current line - editor.focus(); - const sel2 = window.getSelection(); - const range2 = sel2.getRangeAt(0); - let container = range2.startContainer.nodeType === Node.TEXT_NODE - ? range2.startContainer.parentElement - : range2.startContainer; - // Move up to a block element - while (container && !/^(P|DIV|LI|H1|H2|H3|H4|H5|H6)$/i.test(container.tagName)) { - container = container.parentElement; - } - if (container) { - const text = container.innerHTML.replace(/^( |\s){1,4}/, ""); - container.innerHTML = text; + // Otherwise, remove one indentation level (up to 4 NBSP/spaces) at start of the current block + const getBlock = (node) => { + let n = node.nodeType === Node.TEXT_NODE ? node.parentElement : node; + while ( + n && + !/(P|DIV|LI|H1|H2|H3|H4|H5|H6)/i.test(n.tagName) + ) { + n = n.parentElement; + } + return n || editor; + }; + const block = getBlock(range1.startContainer); + if (!block) return; + const first = block.firstChild; + if (first && first.nodeType === Node.TEXT_NODE) { + // Remove up to 4 leading NBSP/spaces + first.textContent = first.textContent.replace(/^(?:\u00A0|\s){1,4}/, ""); } + editor.dispatchEvent(new Event("input", { bubbles: true })); } handleFontFamilyChange(event) { @@ -10152,8 +10731,9 @@ ${galleryPagesHTML} const editorRect = editor ? editor.getBoundingClientRect() : { left: 0, top: 0 }; - const currentWidth = element.offsetWidth; - const currentHeight = element.offsetHeight; + const scale = this.zoom || 1; + const currentWidth = rect.width / scale; + const currentHeight = rect.height / scale; // Insert a placeholder to avoid layout shift in the original flow const placeholder = document.createElement("div"); @@ -10165,7 +10745,6 @@ ${galleryPagesHTML} container.className = "draggable-image-container"; container.style.position = "absolute"; // anchored to editor (set to relative elsewhere) // Account for preview zoom scale to avoid displacement - const scale = this.zoom || 1; container.style.left = (rect.left - editorRect.left + (editor ? editor.scrollLeft : 0)) / scale + @@ -10181,9 +10760,14 @@ ${galleryPagesHTML} // Set container and image sizing container.style.width = currentWidth + "px"; container.style.height = currentHeight + "px"; - element.style.width = currentWidth + "px"; - element.style.height = currentHeight + "px"; + container.style.boxSizing = "border-box"; + element.style.width = "100%"; + element.style.height = "100%"; + element.style.maxWidth = "none"; + element.style.maxHeight = "none"; + element.style.margin = "0"; element.style.display = "block"; + element.style.boxSizing = "border-box"; element.style.objectFit = window.getComputedStyle(element).objectFit || "cover"; // Replace the image in the flow with placeholder, then move image to absolute container