diff --git a/force-app/main/default/lwc/developmentPage/developmentPage.css b/force-app/main/default/lwc/developmentPage/developmentPage.css index 6f678c1..f4314ec 100644 --- a/force-app/main/default/lwc/developmentPage/developmentPage.css +++ b/force-app/main/default/lwc/developmentPage/developmentPage.css @@ -85,6 +85,25 @@ font-style: normal; } +.dev-close-btn { + margin-top: 10px; + padding: 8px 16px; + background: #ff6b6b; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 0.9rem; + font-weight: 600; + transition: all 0.3s ease; +} + +.dev-close-btn:hover { + background: #ff5252; + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + .dev-content { padding: 30px; diff --git a/force-app/main/default/lwc/developmentPage/developmentPage.html b/force-app/main/default/lwc/developmentPage/developmentPage.html index f198256..feb1ce6 100644 --- a/force-app/main/default/lwc/developmentPage/developmentPage.html +++ b/force-app/main/default/lwc/developmentPage/developmentPage.html @@ -10,7 +10,9 @@ value={tbizzInput} onchange={handleTbizzInputChange} onkeydown={handleKeyPress} + placeholder="Enter 'bweixx' to show/hide dev mode" /> + diff --git a/force-app/main/default/lwc/developmentPage/developmentPage.js b/force-app/main/default/lwc/developmentPage/developmentPage.js index 1d5436b..4dff42b 100644 --- a/force-app/main/default/lwc/developmentPage/developmentPage.js +++ b/force-app/main/default/lwc/developmentPage/developmentPage.js @@ -1,7 +1,7 @@ import { LightningElement, track } from 'lwc'; export default class DevelopmentPage extends LightningElement { - @track showDevPage = true; // Visible by default, hidden when tbizz is entered + @track showDevPage = false; // Hidden by default, can be shown by entering bweixx @track currentStep = 1; @track selectedTemplateId = ''; @track selectedPropertyId = ''; @@ -38,7 +38,7 @@ export default class DevelopmentPage extends LightningElement { // Listen for Enter key to check bweixx input if (event.key === 'Enter') { if (this.tbizzInput.toLowerCase() === 'bweixx') { - this.showDevPage = false; + this.showDevPage = true; // Show development page when bweixx is entered this.tbizzInput = ''; // Clear input } } @@ -49,6 +49,11 @@ export default class DevelopmentPage extends LightningElement { this.tbizzInput = event.target.value; } + // Hide development page + hideDevPage() { + this.showDevPage = false; + } + updateTimestamp() { this.currentTimestamp = new Date().toLocaleString(); } diff --git a/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js b/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js index b3b1da0..a8b2c38 100644 --- a/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js +++ b/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js @@ -1318,10 +1318,11 @@ export default class PropertyTemplateSelector extends LightningElement { setTimeout(() => { this.forceHTMLRendering(); - // Add pencil icon to hero section for modern home template, serenity house template, and luxury mansion template + // Add pencil icon to hero section for modern home template, serenity house template, luxury mansion template, and grand oak villa template if (this.selectedTemplateId === 'modern-home-template' || this.selectedTemplateId === 'modern-home-a3-template' || this.selectedTemplateId === 'serenity-house-template' || this.selectedTemplateId === 'serenity-house-a3-template' || - this.selectedTemplateId === 'luxury-mansion-template' || this.selectedTemplateId === 'luxury-mansion-a3-template') { + this.selectedTemplateId === 'luxury-mansion-template' || this.selectedTemplateId === 'luxury-mansion-a3-template' || + this.selectedTemplateId === 'grand-oak-villa-template' || this.selectedTemplateId === 'grand-oak-villa-a3-template') { this.addPencilIconToHeroSection(); } }, 100); @@ -1693,10 +1694,11 @@ export default class PropertyTemplateSelector extends LightningElement { // Force proper HTML rendering to match PDF exactly this.forceHTMLRendering(); - // Add pencil icon to hero section for modern home template, serenity house template, and luxury mansion template + // Add pencil icon to hero section for modern home template, serenity house template, luxury mansion template, and grand oak villa template if (this.selectedTemplateId === 'modern-home-template' || this.selectedTemplateId === 'modern-home-a3-template' || this.selectedTemplateId === 'serenity-house-template' || this.selectedTemplateId === 'serenity-house-a3-template' || - this.selectedTemplateId === 'luxury-mansion-template' || this.selectedTemplateId === 'luxury-mansion-a3-template') { + this.selectedTemplateId === 'luxury-mansion-template' || this.selectedTemplateId === 'luxury-mansion-a3-template' || + this.selectedTemplateId === 'grand-oak-villa-template' || this.selectedTemplateId === 'grand-oak-villa-a3-template') { this.addPencilIconToHeroSection(); } }, 100); @@ -1766,10 +1768,11 @@ export default class PropertyTemplateSelector extends LightningElement { // Force proper HTML rendering to match PDF exactly this.forceHTMLRendering(); - // Add pencil icon to hero section for modern home template, serenity house template, and luxury mansion template + // Add pencil icon to hero section for modern home template, serenity house template, luxury mansion template, and grand oak villa template if (this.selectedTemplateId === 'modern-home-template' || this.selectedTemplateId === 'modern-home-a3-template' || this.selectedTemplateId === 'serenity-house-template' || this.selectedTemplateId === 'serenity-house-a3-template' || - this.selectedTemplateId === 'luxury-mansion-template' || this.selectedTemplateId === 'luxury-mansion-a3-template') { + this.selectedTemplateId === 'luxury-mansion-template' || this.selectedTemplateId === 'luxury-mansion-a3-template' || + this.selectedTemplateId === 'grand-oak-villa-template' || this.selectedTemplateId === 'grand-oak-villa-a3-template') { this.addPencilIconToHeroSection(); } }, 100); @@ -4545,12 +4548,19 @@ export default class PropertyTemplateSelector extends LightningElement { .join(""); } // Template methods + // Helper method to escape HTML and prevent injection + escapeHtml(text) { + if (!text) return ''; + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + createBlankTemplate() { const data = this.propertyData || {}; const propertyName = data.Name || data.propertyName || "Property Name"; const location = data.Address__c || data.location || "Location"; - // Use price toggle to determine what to display - const price = this.showPrice ? (data.Price__c || data.price || "Price") : "Price on Request"; + const price = data.Price__c || data.price || "Price"; const bedrooms = data.Bedrooms__c || data.bedrooms || "N/A"; const bathrooms = data.Bathrooms__c || data.bathrooms || "N/A"; const size = data.Square_Feet__c || data.size || "N/A"; @@ -4567,20 +4577,21 @@ export default class PropertyTemplateSelector extends LightningElement { const buildYear = data.Build_Year__c || data.buildYear || "N/A"; const titleEnglish = data.Title_English__c || data.titleEnglish || "Property Title"; - - const descriptionEnglish = this.formatDescriptionForPDF( + let descriptionEnglish = data.Description_English__c || data.descriptionEnglish || - data.description || - "please add your description here..." - ); + "Property Description"; + const rawDescription = data.Description_English__c || + data.descriptionEnglish || + data.description || + "This beautiful property offers exceptional value and modern amenities. Located in a prime area, it represents an excellent investment opportunity."; + + const description = this.formatDescriptionForPDF(rawDescription); + descriptionEnglish = description; const rentPriceMin = data.Rent_Price_Min__c || data.rentPriceMin || "N/A"; const salePriceMin = data.Sale_Price_Min__c || data.salePriceMin || "N/A"; - // Define logoUrl for template usage - const logoUrl = this.logoUrl; - // Build gallery pages so ALL images render in the empty template const allImages = Array.isArray(this.realPropertyImages) ? this.realPropertyImages @@ -4592,186 +4603,178 @@ export default class PropertyTemplateSelector extends LightningElement { for (let i = imagesPerPage; i < allImages.length; i += imagesPerPage) { const chunk = allImages.slice(i, i + imagesPerPage); additionalGalleryPagesHTML += ` -
- -
`; +
+
+

Property Gallery

+ + const rawDescription = data.Description_English__c || + data.descriptionEnglish || + data.description || + "This beautiful property offers exceptional value and modern amenities. Located in a prime area, it represents an excellent investment opportunity."; + + const description = this.formatDescriptionForPDF(rawDescription);
+
`; } } - return ` - - -
- -
- Header Image -
-

${propertyName}

-

${location}

-

${price}

-
-
- - -
-

Basic Information

-
-
Property Type: ${propertyType}
-
Status: ${status}
-
City: ${city}
-
Community: ${community}
-
Sub Community: ${subCommunity}
-
Furnished: ${furnished}
-
-
- - -
-

Contact Details

-
-
Name: ${data.contactName || "N/A"}
-
Email: ${data.contactEmail || "N/A"}
-
Phone: ${data.contactPhone || "N/A"}
-
-
- - -
-

Location Details

-
-
City (Bayut): ${data.cityBayut || "N/A"}
-
City (Propertyfinder): ${data.cityPropertyfinder || "N/A"}
-
Community (Bayut): ${data.communityBayut || "N/A"}
-
Sub Community (Bayut): ${data.subCommunityBayut || "N/A"}
-
Locality (Bayut): ${data.localityBayut || "N/A"}
-
Sub Locality (Bayut): ${data.subLocalityBayut || "N/A"}
-
Tower (Bayut): ${data.towerBayut || "N/A"}
-
Unit Number: ${data.unitNumber || "N/A"}
-
-
- - -
-

Specifications

-
-
Bedrooms: ${bedrooms}
-
Bathrooms: ${bathrooms}
-
Size: ${size} ${sizeUnit}
-
Parking Spaces: ${parkingSpaces}
-
Build Year: ${buildYear}
-
Floor: ${data.floor || "N/A"}
-
-
- - - ${this.generatePricingSection()} - - -
-

Rent Availability

-
-
Available From: ${data.rentAvailableFrom || "N/A"}
-
Available To: ${data.rentAvailableTo || "N/A"}
-
-
- - -
-

Property Description

-

${titleEnglish}

-

${descriptionEnglish}

-
- - -
-

Amenities & Features

-
-
Parking Spaces: ${data.parkingSpaces || "N/A"}
-
Furnished: ${data.furnished || "N/A"}
-
Offering Type: ${data.offeringType || "N/A"}
-
Build Year: ${data.buildYear || "N/A"}
- ${data.privateAmenities && data.privateAmenities !== 'N/A' ? - `
- Private Amenities:
-
- ${this.mapAmenityCodes(data.privateAmenities).map(amenity => - `${amenity}` - ).join('')} -
-
` : '' - } -
-
- - -
- -
-
- - ${additionalGalleryPagesHTML} - `; +
+ +
+ Property Header Image +
+
+

${propertyName}

+

${location}

+

${price}

+
+
+ + +
+

Basic Information

+
+
Property Type: ${propertyType}
+
Status: ${status}
+
City: ${city}
+
Community: ${community}
+
Sub Community: ${subCommunity}
+
Furnished: ${furnished}
+
+
+ + +
+

Contact Details

+
+
Name: ${ + data.contactName || "N/A" + }
+
Email: ${ + data.contactEmail || "N/A" + }
+
Phone: ${ + data.contactPhone || "N/A" + }
+
+
+ + +
+

Location Details

+
+
City (Bayut): ${ + data.cityBayut || "N/A" + }
+
City (Propertyfinder): ${ + data.cityPropertyfinder || "N/A" + }
+
Community (Bayut): ${ + data.communityBayut || "N/A" + }
+
Sub Community (Bayut): ${ + data.subCommunityBayut || "N/A" + }
+
Locality (Bayut): ${ + data.localityBayut || "N/A" + }
+
Sub Locality (Bayut): ${ + data.subLocalityBayut || "N/A" + }
+
Tower (Bayut): ${ + data.towerBayut || "N/A" + }
+
Unit Number: ${ + data.unitNumber || "N/A" + }
+
+
+ + +
+

Specifications

+
+
Bedrooms: ${bedrooms}
+
Bathrooms: ${bathrooms}
+
Size: ${size} ${sizeUnit}
+
Parking Spaces: ${parkingSpaces}
+
Build Year: ${buildYear}
+
Floor: ${ + data.floor || "N/A" + }
+
+
+ +
+

Pricing Information

+
+
Rent Price: ${rentPriceMin}
+
Sale Price: ${salePriceMin}
+
Rent Price (Max): ${ + data.rentPriceMax || "N/A" + }
+
Sale Price (Max): ${ + data.salePriceMax || "N/A" + }
+
+
+ + +
+

Rent Availability

+
+
Rent Available From: ${ + data.rentAvailableFrom || "N/A" + }
+
Rent Available To: ${ + data.rentAvailableTo || "N/A" + }
+
+
+ + +
+

Property Description

+
+

${titleEnglish}

+
+
+ ${descriptionEnglish} +
+
+
+
Property Type: ${propertyType}
+
Status: ${status}
+
Furnished: ${furnished}
+
Build Year: ${buildYear}
+
+
+
+ +
+

Amenities & Features

+
+
Parking Spaces: ${ + data.parkingSpaces || "N/A" + }
+
Furnished: ${ + data.furnished || "N/A" + }
+
Offering Type: ${ + data.offeringType || "N/A" + }
+
Build Year: ${ + data.buildYear || "N/A" + }
+
+
+ + +
+ + `; } createModernHomeTemplate() { @@ -7890,9 +7893,10 @@ ${galleryPagesHTML} flex-grow: 1; display: flex; flex-direction: column; - gap: 15px; + gap: 20px; height: calc(100% - 120px); - overflow: hidden; + overflow: visible; + padding: 0 10px; } .floorplan-showcase { display: grid; @@ -7903,11 +7907,14 @@ ${galleryPagesHTML} border-left: 5px solid var(--color-accent-green); page-break-inside: avoid; break-inside: avoid; + position: relative; + margin-bottom: 10px; } .floorplan-image-p5 { background-size: cover; background-position: center; min-height: 200px; + position: relative; } .floorplan-image-p5.residence { background-image: url('https://images.unsplash.com/photo-1740446568651-1d31966b228a?q=80&w=1600&h=1066&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'); @@ -7948,21 +7955,36 @@ ${galleryPagesHTML} gap: 15px; margin-top: 15px; } - .spec-item { + .additional-specs-grid .spec-item { background-color: var(--color-grey-bg); padding: 15px; } - .spec-item .label { + .additional-specs-grid .spec-item .label { font-size: 0.8rem; color: var(--color-text-muted); margin-bottom: 5px; display: block; } - .spec-item .value { + .additional-specs-grid .spec-item .value { font-weight: 600; font-size: 1rem; color: var(--color-dark); } + + /* Additional Information Section for Luxury Mansion */ + .additional-info-section-luxury { + margin-top: 25px; + padding: 20px 0; + } + + .additional-info-section-luxury .section-title { + font-size: 1.1rem; + font-weight: 600; + color: var(--color-dark); + margin-bottom: 15px; + text-transform: uppercase; + letter-spacing: 1px; + } /* --- PAGE 6: LOCATION & CONTACT (REVISED V3) --- */ .page6-main { @@ -8196,8 +8218,8 @@ ${galleryPagesHTML} -
-

Additional Information

+
+

Additional Information

Available from
${this.propertyData.rentAvailableFrom}
Rent Available To
${this.propertyData.rentAvailableTo}
@@ -16930,14 +16952,14 @@ ${galleryPagesHTML} style.textContent = ` .hero-edit-icon, .visual-header-edit-icon { position: absolute; - top: 20px; - right: 20px; + top: 10px; + right: 10px; z-index: 1000; background: rgba(0,0,0,0.7); color: white; border-radius: 50%; - width: 40px; - height: 40px; + width: 35px; + height: 35px; display: flex; align-items: center; justify-content: center; @@ -16978,6 +17000,12 @@ ${galleryPagesHTML} heroSection = editorContent.querySelector('.cover-page'); } + // For grand oak villa template, look for .cover-page instead + if (!heroSection && (this.selectedTemplateId === 'grand-oak-villa-template' || this.selectedTemplateId === 'grand-oak-villa-a3-template')) { + console.log('Looking for grand oak villa template cover page...'); + heroSection = editorContent.querySelector('.cover-page'); + } + if (heroSection) { console.log('Hero section found'); if (!heroSection.querySelector('.hero-edit-icon')) { @@ -17003,32 +17031,39 @@ ${galleryPagesHTML} console.log('Hero section not found in editor content'); } - // Add pencil icon to visual header (page 2) - console.log('Looking for visual header...'); - const visualHeader = editorContent.querySelector('.visual-header'); + // Add pencil icon to visual header (page 2) or location map container (page 3 for Grand Oak Villa) + console.log('Looking for visual header or location map container...'); + let visualHeader = editorContent.querySelector('.visual-header'); + + // For Grand Oak Villa template, look for location map container instead + if (!visualHeader && (this.selectedTemplateId === 'grand-oak-villa-template' || this.selectedTemplateId === 'grand-oak-villa-a3-template')) { + console.log('Looking for Grand Oak Villa location map container...'); + visualHeader = editorContent.querySelector('.location-map-container'); + } + if (visualHeader) { - console.log('Visual header found'); + console.log('Visual header or location map container found'); if (!visualHeader.querySelector('.visual-header-edit-icon')) { - console.log('Creating pencil icon for visual header...'); + console.log('Creating pencil icon for visual header or location map container...'); // Create pencil icon element const pencilIcon = document.createElement('div'); pencilIcon.className = 'visual-header-edit-icon'; pencilIcon.innerHTML = ''; pencilIcon.title = 'Replace Page 2 Image'; pencilIcon.onclick = () => { - console.log('Visual header pencil icon clicked'); - // Trigger image replacement for visual header + console.log('Visual header or location map pencil icon clicked'); + // Trigger image replacement for visual header or location map this.handleVisualHeaderImageReplacement(); }; - // Add the pencil icon to the visual header + // Add the pencil icon to the visual header or location map container visualHeader.appendChild(pencilIcon); - console.log('Pencil icon added to visual header successfully'); + console.log('Pencil icon added to visual header or location map container successfully'); } else { - console.log('Visual header pencil icon already exists'); + console.log('Visual header or location map container pencil icon already exists'); } } else { - console.log('Visual header not found in editor content'); + console.log('Visual header or location map container not found in editor content'); } // Add pencil icon to floor plans section for luxury mansion template @@ -17085,6 +17120,12 @@ ${galleryPagesHTML} heroSection = editorContent.querySelector('.cover-page'); } + // For grand oak villa template, look for .cover-page instead + if (!heroSection && (this.selectedTemplateId === 'grand-oak-villa-template' || this.selectedTemplateId === 'grand-oak-villa-a3-template')) { + console.log('Looking for grand oak villa template cover page for replacement...'); + heroSection = editorContent.querySelector('.cover-page'); + } + if (heroSection) { // Get the computed background image const computedStyle = window.getComputedStyle(heroSection); @@ -17110,19 +17151,26 @@ ${galleryPagesHTML} } } - // Handle visual header image replacement (page 2) + // Handle visual header image replacement (page 2) or location map container (page 3 for Grand Oak Villa) handleVisualHeaderImageReplacement() { - // Find the visual header background image + // Find the visual header background image or location map container const editorContent = this.template.querySelector('.enhanced-editor-content'); if (editorContent) { - const visualHeader = editorContent.querySelector('.visual-header'); + let visualHeader = editorContent.querySelector('.visual-header'); + + // For Grand Oak Villa template, look for location map container instead + if (!visualHeader && (this.selectedTemplateId === 'grand-oak-villa-template' || this.selectedTemplateId === 'grand-oak-villa-a3-template')) { + console.log('Looking for Grand Oak Villa location map container for replacement...'); + visualHeader = editorContent.querySelector('.location-map-container'); + } + if (visualHeader) { // Get the computed background image const computedStyle = window.getComputedStyle(visualHeader); const backgroundImage = computedStyle.backgroundImage; if (backgroundImage && backgroundImage !== 'none') { - // Create a virtual image element for the visual header background + // Create a virtual image element for the visual header or location map background const virtualImg = document.createElement('img'); virtualImg.src = backgroundImage.replace(/url\(['"]?(.+?)['"]?\)/, '$1'); virtualImg.isBackgroundImage = true; @@ -17131,10 +17179,10 @@ ${galleryPagesHTML} // Open image replacement for this virtual image this.openImageReplacement(virtualImg); } else { - console.log('No background image found on visual header'); + console.log('No background image found on visual header or location map container'); } } else { - console.log('Visual header not found'); + console.log('Visual header or location map container not found'); } } else { console.log('Enhanced editor content not found'); @@ -17421,39 +17469,47 @@ ${galleryPagesHTML} // Generate Property Gallery HTML for uncategorized images generatePropertyGalleryHTML() { if (!this.realPropertyImages || this.realPropertyImages.length === 0) { - return ""; + return ``.repeat(6); } let galleryHTML = ""; this.realPropertyImages.forEach((image, index) => { - const title = - image.title || image.pcrm__Title__c || `Property Image ${index + 1}`; - galleryHTML += ``; }); + // Fill remaining slots with placeholders if needed (6 images per page) + const remainingSlots = 6 - this.realPropertyImages.length; + for (let i = 0; i < remainingSlots; i++) { + galleryHTML += ``; + } + return galleryHTML; } // Generate gallery HTML for a provided subset of images generatePropertyGalleryHTMLForImages(imagesSubset) { if (!imagesSubset || imagesSubset.length === 0) { - return ""; + return ``.repeat(6); } + let galleryHTML = ""; imagesSubset.forEach((image, index) => { - const title = - image.title || image.pcrm__Title__c || `Property Image ${index + 1}`; - galleryHTML += ``; }); + + // Fill remaining slots with placeholders if needed (6 images per page) + const remainingSlots = 6 - imagesSubset.length; + for (let i = 0; i < remainingSlots; i++) { + galleryHTML += ``; + } + return galleryHTML; }