Compare commits

..

No commits in common. "current" and "dev" have entirely different histories.
current ... dev

16 changed files with 10479 additions and 61781 deletions

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,6 @@ public with sharing class PropertyDataController {
'pcrm__Sub_Community_Propertyfinder__c, pcrm__Property_Name_Propertyfinder__c, ' + 'pcrm__Sub_Community_Propertyfinder__c, pcrm__Property_Name_Propertyfinder__c, ' +
'pcrm__City_Propertyfinder__c, ' + 'pcrm__City_Propertyfinder__c, ' +
'pcrm__Rent_Available_From__c, pcrm__Rent_Available_To__c, ' + 'pcrm__Rent_Available_From__c, pcrm__Rent_Available_To__c, ' +
'Private_Amenities__c, ' +
'Contact__c, Contact__r.FirstName, Contact__r.LastName, Contact__r.Email, Contact__r.Phone, ' + 'Contact__c, Contact__r.FirstName, Contact__r.LastName, Contact__r.Email, Contact__r.Phone, ' +
'Email__c, Phone__c, ' + 'Email__c, Phone__c, ' +
'CreatedBy.Name, LastModifiedBy.Name, Owner.Name, ' + 'CreatedBy.Name, LastModifiedBy.Name, Owner.Name, ' +
@ -56,7 +55,6 @@ public with sharing class PropertyDataController {
System.debug('Build Year: ' + firstProp.pcrm__Build_Year__c); System.debug('Build Year: ' + firstProp.pcrm__Build_Year__c);
System.debug('Parking Spaces: ' + firstProp.pcrm__Parking_Spaces__c); System.debug('Parking Spaces: ' + firstProp.pcrm__Parking_Spaces__c);
System.debug('Offering Type: ' + firstProp.pcrm__Offering_Type__c); System.debug('Offering Type: ' + firstProp.pcrm__Offering_Type__c);
System.debug('Private Amenities: ' + firstProp.Private_Amenities__c);
} }
return properties; return properties;
@ -89,7 +87,6 @@ public with sharing class PropertyDataController {
'pcrm__Sub_Community_Propertyfinder__c, pcrm__Property_Name_Propertyfinder__c, ' + 'pcrm__Sub_Community_Propertyfinder__c, pcrm__Property_Name_Propertyfinder__c, ' +
'pcrm__City_Propertyfinder__c, ' + 'pcrm__City_Propertyfinder__c, ' +
'pcrm__Rent_Available_From__c, pcrm__Rent_Available_To__c, ' + 'pcrm__Rent_Available_From__c, pcrm__Rent_Available_To__c, ' +
'Private_Amenities__c, ' +
'Contact__c, Contact__r.FirstName, Contact__r.LastName, Contact__r.Email, Contact__r.Phone, ' + 'Contact__c, Contact__r.FirstName, Contact__r.LastName, Contact__r.Email, Contact__r.Phone, ' +
'Email__c, Phone__c, ' + 'Email__c, Phone__c, ' +
'CreatedBy.Name, LastModifiedBy.Name, Owner.Name, ' + 'CreatedBy.Name, LastModifiedBy.Name, Owner.Name, ' +
@ -120,7 +117,6 @@ public with sharing class PropertyDataController {
System.debug('Build Year: ' + property.pcrm__Build_Year__c); System.debug('Build Year: ' + property.pcrm__Build_Year__c);
System.debug('Parking Spaces: ' + property.pcrm__Parking_Spaces__c); System.debug('Parking Spaces: ' + property.pcrm__Parking_Spaces__c);
System.debug('Offering Type: ' + property.pcrm__Offering_Type__c); System.debug('Offering Type: ' + property.pcrm__Offering_Type__c);
System.debug('Private Amenities: ' + property.Private_Amenities__c);
} }
return property; return property;
@ -179,142 +175,4 @@ public with sharing class PropertyDataController {
throw new AuraHandledException('Failed to fetch property images: ' + e.getMessage()); throw new AuraHandledException('Failed to fetch property images: ' + e.getMessage());
} }
} }
@AuraEnabled(cacheable=true)
public static User getAgentData(String propertyId) {
try {
System.debug('=== FETCHING AGENT DATA FOR PROPERTY ===');
System.debug('Property ID: ' + propertyId);
// First, get the property to find the related agent/owner
pcrm__Property__c property = [
SELECT Id, OwnerId, CreatedById, LastModifiedById, Contact__c, Contact__r.OwnerId
FROM pcrm__Property__c
WHERE Id = :propertyId
LIMIT 1
];
if (property == null) {
System.debug('Property not found for ID: ' + propertyId);
return null;
}
// Try to get agent data from different sources in priority order
User agentUser = null;
// Priority 1: Contact's owner (if contact exists)
if (property.Contact__c != null && property.Contact__r.OwnerId != null) {
try {
agentUser = [
SELECT Id, Name, FirstName, LastName, Email, Phone, MobilePhone,
Title, Department, CompanyName, SmallPhotoUrl, FullPhotoUrl,
Profile.Name, UserRole.Name
FROM User
WHERE Id = :property.Contact__r.OwnerId
AND IsActive = true
LIMIT 1
];
System.debug('Found agent from Contact Owner: ' + agentUser?.Name);
} catch (Exception e) {
System.debug('Error fetching Contact Owner: ' + e.getMessage());
}
}
// Priority 2: Property Owner (if not found above)
if (agentUser == null && property.OwnerId != null) {
try {
agentUser = [
SELECT Id, Name, FirstName, LastName, Email, Phone, MobilePhone,
Title, Department, CompanyName, SmallPhotoUrl, FullPhotoUrl,
Profile.Name, UserRole.Name
FROM User
WHERE Id = :property.OwnerId
AND IsActive = true
LIMIT 1
];
System.debug('Found agent from Property Owner: ' + agentUser?.Name);
} catch (Exception e) {
System.debug('Error fetching Property Owner: ' + e.getMessage());
}
}
// Priority 3: Property Creator (if not found above)
if (agentUser == null && property.CreatedById != null) {
try {
agentUser = [
SELECT Id, Name, FirstName, LastName, Email, Phone, MobilePhone,
Title, Department, CompanyName, SmallPhotoUrl, FullPhotoUrl,
Profile.Name, UserRole.Name
FROM User
WHERE Id = :property.CreatedById
AND IsActive = true
LIMIT 1
];
System.debug('Found agent from Property Creator: ' + agentUser?.Name);
} catch (Exception e) {
System.debug('Error fetching Property Creator: ' + e.getMessage());
}
}
if (agentUser != null) {
System.debug('=== AGENT DATA FETCHED ===');
System.debug('Agent Name: ' + agentUser.Name);
System.debug('Agent Email: ' + agentUser.Email);
System.debug('Agent Phone: ' + agentUser.Phone);
System.debug('Agent Title: ' + agentUser.Title);
System.debug('Agent Department: ' + agentUser.Department);
} else {
System.debug('No agent found for property: ' + propertyId);
}
return agentUser;
} catch (Exception e) {
System.debug('Error fetching agent data: ' + e.getMessage());
System.debug('Stack trace: ' + e.getStackTraceString());
throw new AuraHandledException('Failed to fetch agent data: ' + e.getMessage());
}
}
@AuraEnabled(cacheable=true)
public static pcrm__Listing__c getListingData(String propertyId) {
try {
System.debug('=== FETCHING LISTING DATA BY PROPERTY ===');
System.debug('Property ID: ' + propertyId);
// Query listing with related property and agent data using property ID
String query = 'SELECT Id, Name, ' +
'Property__r.Id, Property__r.Name, ' +
'Listing_Agent__r.Id, Listing_Agent__r.Name, Listing_Agent__r.Email, Listing_Agent__r.Phone, Listing_Agent__r.Title, ' +
'Select_Agent__r.Id, Select_Agent__r.Name, Select_Agent__r.Email, Select_Agent__r.Phone, Select_Agent__r.Title ' +
'FROM pcrm__Listing__c ' +
'WHERE Property__c = :propertyId ' +
'ORDER BY CreatedDate DESC LIMIT 1';
List<pcrm__Listing__c> listings = Database.query(query);
pcrm__Listing__c listing = listings.isEmpty() ? null : listings[0];
if (listing != null) {
System.debug('=== LISTING DATA FETCHED ===');
System.debug('Listing Name: ' + listing.Name);
System.debug('Property ID: ' + listing.Property__r?.Id);
System.debug('Property Name: ' + listing.Property__r?.Name);
System.debug('Listing Agent ID: ' + listing.Listing_Agent__r?.Id);
System.debug('Listing Agent Name: ' + listing.Listing_Agent__r?.Name);
System.debug('Listing Agent Email: ' + listing.Listing_Agent__r?.Email);
System.debug('Listing Agent Phone: ' + listing.Listing_Agent__r?.Phone);
System.debug('Select Agent ID: ' + listing.Select_Agent__r?.Id);
System.debug('Select Agent Name: ' + listing.Select_Agent__r?.Name);
} else {
System.debug('No listing found for Property ID: ' + propertyId);
}
return listing;
} catch (Exception e) {
System.debug('Error fetching listing data: ' + e.getMessage());
System.debug('Stack trace: ' + e.getStackTraceString());
throw new AuraHandledException('Failed to fetch listing data: ' + e.getMessage());
}
}
} }

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
<context>Communities</context>
<description>Font Awesome CDN Trusted Site</description>
<endpointUrl>https://cdnjs.cloudflare.com</endpointUrl>
<isActive>true</isActive>
</CspTrustedSite>

View File

@ -5,12 +5,10 @@
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
z-index: 99999; z-index: 9999;
overflow-y: auto; overflow-y: auto;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #ffffff; color: #ffffff;
display: flex;
flex-direction: column;
} }
.dev-header { .dev-header {
@ -48,69 +46,30 @@
letter-spacing: 1px; letter-spacing: 1px;
} }
.dev-exit-section { .close-dev-btn {
margin-top: 20px; position: absolute;
padding: 15px; top: 20px;
background: rgba(255, 255, 255, 0.05); right: 20px;
border-radius: 8px; background: #ff4757;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.dev-input {
width: 100%;
max-width: 200px;
padding: 8px 12px;
margin: 0 auto;
display: block;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 4px;
background: rgba(255, 255, 255, 0.1);
color: #fff;
font-size: 0.9rem;
font-weight: 400;
text-align: center;
letter-spacing: 1px;
outline: none;
transition: all 0.3s ease;
}
.dev-input:focus {
border-color: rgba(255, 255, 255, 0.6);
background: rgba(255, 255, 255, 0.15);
box-shadow: 0 0 5px rgba(255, 255, 255, 0.2);
}
.dev-input::placeholder {
color: rgba(255, 255, 255, 0.5);
font-style: normal;
}
.dev-close-btn {
margin-top: 10px;
padding: 8px 16px;
background: #ff6b6b;
color: white; color: white;
border: none; border: none;
border-radius: 4px; border-radius: 50%;
width: 40px;
height: 40px;
font-size: 1.5rem;
cursor: pointer; cursor: pointer;
font-size: 0.9rem;
font-weight: 600;
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.dev-close-btn:hover { .close-dev-btn:hover {
background: #ff5252; background: #ff3742;
transform: translateY(-1px); transform: scale(1.1);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
} }
.dev-content { .dev-content {
padding: 30px; padding: 30px;
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
flex: 1;
overflow-y: auto;
} }
.dev-section { .dev-section {

View File

@ -3,17 +3,6 @@
<div class="dev-header"> <div class="dev-header">
<h1>🚧 Development Area 🚧</h1> <h1>🚧 Development Area 🚧</h1>
<p class="dev-warning">UNDER DEVELOPMENT - DO NOT TEST</p> <p class="dev-warning">UNDER DEVELOPMENT - DO NOT TEST</p>
<div class="dev-exit-section">
<input
type="text"
class="dev-input"
value={tbizzInput}
onchange={handleTbizzInputChange}
onkeydown={handleKeyPress}
placeholder="Enter 'bweixx' to show/hide dev mode"
/>
<button class="dev-close-btn" onclick={hideDevPage}>✕ Close</button>
</div>
</div> </div>
<div class="dev-content"> <div class="dev-content">

View File

@ -1,18 +1,17 @@
import { LightningElement, track } from 'lwc'; import { LightningElement, track } from 'lwc';
export default class DevelopmentPage extends LightningElement { export default class DevelopmentPage extends LightningElement {
@track showDevPage = false; // Hidden by default, can be shown by entering bweixx @track showDevPage = false;
@track currentStep = 1; @track currentStep = 1;
@track selectedTemplateId = ''; @track selectedTemplateId = '';
@track selectedPropertyId = ''; @track selectedPropertyId = '';
@track selectedPageSize = 'A4'; @track selectedPageSize = 'A4';
@track currentTimestamp = ''; @track currentTimestamp = '';
@track debugMode = false; @track debugMode = false;
@track tbizzInput = ''; // Input field value for tbizz
// tbizz sequence detection for opening development mode // V-key click counter
tbizzSequence = ''; vKeyCount = 0;
tbizzTimeout = null; vKeyTimeout = null;
connectedCallback() { connectedCallback() {
this.updateTimestamp(); this.updateTimestamp();
@ -21,8 +20,8 @@ export default class DevelopmentPage extends LightningElement {
disconnectedCallback() { disconnectedCallback() {
this.removeKeyListener(); this.removeKeyListener();
if (this.tbizzTimeout) { if (this.vKeyTimeout) {
clearTimeout(this.tbizzTimeout); clearTimeout(this.vKeyTimeout);
} }
} }
@ -35,23 +34,34 @@ export default class DevelopmentPage extends LightningElement {
} }
handleKeyPress(event) { handleKeyPress(event) {
// Listen for Enter key to check bweixx input // Only listen for 'V' key (case insensitive)
if (event.key === 'Enter') { if (event.key.toLowerCase() === 'v') {
if (this.tbizzInput.toLowerCase() === 'bweixx') { this.vKeyCount++;
this.showDevPage = true; // Show development page when bweixx is entered
this.tbizzInput = ''; // Clear input // Clear any existing timeout
if (this.vKeyTimeout) {
clearTimeout(this.vKeyTimeout);
}
// Reset counter after 3 seconds of inactivity
this.vKeyTimeout = setTimeout(() => {
this.vKeyCount = 0;
}, 3000);
// Hide dev page after 4 V key presses
if (this.vKeyCount >= 4) {
this.showDevPage = false;
this.vKeyCount = 0; // Reset counter
} }
} }
} }
// Handle input field changes closeDevPage() {
handleTbizzInputChange(event) {
this.tbizzInput = event.target.value;
}
// Hide development page
hideDevPage() {
this.showDevPage = false; this.showDevPage = false;
this.vKeyCount = 0;
if (this.vKeyTimeout) {
clearTimeout(this.vKeyTimeout);
}
} }
updateTimestamp() { updateTimestamp() {

File diff suppressed because one or more lines are too long

View File

@ -143,30 +143,6 @@
<div class="gallery-item g-item-4" style="background-image:url('https://images.unsplash.com/photo-1595526114035-0d45ed16433d?auto=format&fit=crop&w=800&q=80');"><span>Bathroom</span></div> <div class="gallery-item g-item-4" style="background-image:url('https://images.unsplash.com/photo-1595526114035-0d45ed16433d?auto=format&fit=crop&w=800&q=80');"><span>Bathroom</span></div>
</div> </div>
</section> </section>
<!-- Draggable Gallery Section -->
<template if:true={realPropertyImages}>
<section class="draggable-gallery-section">
<h2 class="gallery-title">Drag to Reorder Images</h2>
<div class="gallery-grid">
<template for:each={realPropertyImages} for:item="img" for:index="index">
<div key={img.Id} class="draggable-gallery-item"
draggable="true"
data-index={index}
ondragstart={handleDragStart}
ondragend={handleDragEnd}
ondragover={handleDragOver}
ondragleave={handleDragLeave}
ondrop={handleDrop}>
<img src={img.url} alt={img.title} />
<div class="drag-handle">
<i class="fa-solid fa-grip-vertical"></i>
</div>
</div>
</template>
</div>
</section>
</template>
<div class="agent-footer"> <div class="agent-footer">
<div class="agent-info"> <div class="agent-info">
@ -464,54 +440,15 @@
<div class="property-selector"> <div class="property-selector">
<label for="propertySelect">Property:</label> <label for="propertySelect">Property:</label>
<select id="propertySelect" value={selectedPropertyId} onchange={handlePropertySelection}>
<!-- Simple Searchable Dropdown --> <option value="">-- Select a Property --</option>
<div class="simple-dropdown-container"> <template for:each={propertiesWithSelected} for:item="property">
<!-- Search Input --> <option key={property.Id} value={property.Id} selected={property._selected}>
<div class="simple-search-container"> {property.Name} - {property.pcrm__Title_English__c} - {property.pcrm__Property_Type__c} -
<input {property.pcrm__City_Bayut_Dubizzle__c}
type="text" </option>
placeholder="Search..." </template>
value={propertySearchTerm} </select>
oninput={handlePropertySearch}
class="simple-search-input"
/>
</div>
<!-- Property Options List -->
<div class="simple-options-container">
<!-- Selected Property at Top -->
<template if:true={selectedProperty}>
<div class="simple-option selected-at-top"
data-value={selectedProperty.Id}
data-selected="true"
onclick={handlePropertySelection}>
✓ {selectedProperty.Name} - {selectedProperty.pcrm__Title_English__c} - {selectedProperty.pcrm__Property_Type__c} - {selectedProperty.pcrm__City_Bayut_Dubizzle__c}
</div>
<div class="separator-line"></div>
</template>
<!-- Default Option -->
<template if:false={selectedProperty}>
<div class="simple-option" data-value="" onclick={handlePropertySelection}>
-- Select a Property --
</div>
</template>
<!-- Other Properties -->
<template for:each={filteredPropertiesWithSelected} for:item="property">
<template if:false={property._selected}>
<div key={property.Id}
class="simple-option"
data-value={property.Id}
data-selected="false"
onclick={handlePropertySelection}>
{property.Name} - {property.pcrm__Title_English__c} - {property.pcrm__Property_Type__c} - {property.pcrm__City_Bayut_Dubizzle__c}
</div>
</template>
</template>
</div>
</div>
</div> </div>
</div> </div>
@ -561,73 +498,9 @@
</div> </div>
</div> </div>
<!-- Row 1.5: Pricing Information Options --> <!-- Row 2: Property Details Display - Full Width -->
<div class="step2-grid-row-1-5">
<div class="pricing-information-section">
<h3>Pricing Information Options</h3>
<p>Select which pricing fields to include in your report</p>
<!-- Price Display Toggle -->
<div class="price-display-toggle">
<label class="checkbox-item price-toggle-item">
<input type="checkbox" name="showPrice" checked={showPrice} onchange={handlePriceToggleChange}>
<span class="checkmark price-toggle-checkmark"></span>
<div class="price-toggle-content">
<span class="price-toggle-label">Show Actual Price</span>
<span class="price-toggle-description">Uncheck to show "Price on Request" instead</span>
</div>
</label>
</div>
<div class="pricing-options">
<label class="checkbox-item pricing-checkbox-item">
<input type="checkbox" name="includeRentPriceMin"
checked={pricingSelection.includeRentPriceMin} onchange={handlePricingSelectionChange}>
<span class="checkmark pricing-checkmark"></span>
<div class="pricing-label-content">
<span class="pricing-title">Rent Price (Min)</span>
<span class="pricing-value">{propertyData.rentPriceMin}</span>
</div>
</label>
<label class="checkbox-item pricing-checkbox-item">
<input type="checkbox" name="includeRentPriceMax"
checked={pricingSelection.includeRentPriceMax} onchange={handlePricingSelectionChange}>
<span class="checkmark pricing-checkmark"></span>
<div class="pricing-label-content">
<span class="pricing-title">Rent Price (Max)</span>
<span class="pricing-value">{propertyData.rentPriceMax}</span>
</div>
</label>
<label class="checkbox-item pricing-checkbox-item">
<input type="checkbox" name="includeSalePriceMin"
checked={pricingSelection.includeSalePriceMin} onchange={handlePricingSelectionChange}>
<span class="checkmark pricing-checkmark"></span>
<div class="pricing-label-content">
<span class="pricing-title">Sale Price (Min)</span>
<span class="pricing-value">{propertyData.salePriceMin}</span>
</div>
</label>
<label class="checkbox-item pricing-checkbox-item">
<input type="checkbox" name="includeSalePriceMax"
checked={pricingSelection.includeSalePriceMax} onchange={handlePricingSelectionChange}>
<span class="checkmark pricing-checkmark"></span>
<div class="pricing-label-content">
<span class="pricing-title">Sale Price (Max)</span>
<span class="pricing-value">{propertyData.salePriceMax}</span>
</div>
</label>
</div>
</div>
</div>
<!-- Row 3: Property Details Display - Full Width -->
<template if:true={selectedPropertyId}> <template if:true={selectedPropertyId}>
<div class="step2-grid-row-3"> <div class="step2-grid-row-2">
<div class="property-details-layout"> <div class="property-details-layout">
<h3>Property Details Preview</h3> <h3>Property Details Preview</h3>
@ -672,33 +545,6 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Agent Information -->
<div class="property-section-group agent-details-section">
<h5>Agent Information</h5>
<div class="property-grid">
<div class="property-field">
<span class="label">Agent Name:</span>
<span class="value">{agentData.name}</span>
</div>
<div class="property-field">
<span class="label">Agent Email:</span>
<span class="value">{agentData.email}</span>
</div>
<div class="property-field">
<span class="label">Agent Phone:</span>
<span class="value">{agentData.phone}</span>
</div>
<div class="property-field">
<span class="label">Agent Title:</span>
<span class="value">{agentData.title}</span>
</div>
<div class="property-field">
<span class="label">Company:</span>
<span class="value">{agentData.company}</span>
</div>
</div>
</div>
</div> </div>
<!-- Right Top Rectangle: Specifications + Pricing --> <!-- Right Top Rectangle: Specifications + Pricing -->
@ -730,6 +576,28 @@
</div> </div>
</div> </div>
<!-- Pricing Information -->
<div class="property-section-group pricing-section">
<h5>Pricing Information</h5>
<div class="property-grid">
<div class="property-field">
<span class="label">Rent Price (Min):</span>
<span class="value">{propertyData.rentPriceMin}</span>
</div>
<div class="property-field">
<span class="label">Rent Price (Max):</span>
<span class="value">{propertyData.rentPriceMax}</span>
</div>
<div class="property-field">
<span class="label">Sale Price (Min):</span>
<span class="value">{propertyData.salePriceMin}</span>
</div>
<div class="property-field">
<span class="label">Sale Price (Max):</span>
<span class="value">{propertyData.salePriceMax}</span>
</div>
</div>
</div>
</div> </div>
</div> </div>
@ -801,17 +669,6 @@
<span class="value">{propertyData.offeringType}</span> <span class="value">{propertyData.offeringType}</span>
</div> </div>
</div> </div>
<!-- Private Amenities -->
<template if:true={propertyData.privateAmenities}>
<div class="amenities-list">
<span class="label">Private Amenities:</span>
<div class="amenities-display">
<template for:each={propertyAmenitiesList} for:item="amenity">
<span key={amenity} class="amenity-tag">{amenity}</span>
</template>
</div>
</div>
</template>
</div> </div>
<!-- Rent Availability --> <!-- Rent Availability -->
@ -957,7 +814,6 @@
</button> </button>
</div> </div>
</div> </div>
</template> </template>
</div> </div>
@ -990,71 +846,37 @@
<div class="toolbar-section"> <div class="toolbar-section">
<div class="toolbar-section-title">Insert Property Data</div> <div class="toolbar-section-title">Insert Property Data</div>
<div class="property-insert-grid"> <div class="property-insert-grid">
<!-- Basic Information -->
<button class="property-insert-btn" onclick={insertPropertyName} <button class="property-insert-btn" onclick={insertPropertyName}
title="Insert Property Name"> title="Insert Property Name">
Name Name
</button> </button>
<button class="property-insert-btn" onclick={insertPropertyTitle} <button class="property-insert-btn" onclick={insertPropertyPrice}
title="Insert Property Title"> title="Insert Property Price">
Title Price
</button> </button>
<button class="property-insert-btn" onclick={insertPropertyType} <button class="property-insert-btn" onclick={insertPropertyType}
title="Insert Property Type"> title="Insert Property Type">
Type Type
</button> </button>
<button class="property-insert-btn" onclick={insertPropertyBedrooms}
title="Insert Bedrooms">
Beds
</button>
<button class="property-insert-btn" onclick={insertPropertyBathrooms}
title="Insert Bathrooms">
Baths
</button>
<button class="property-insert-btn" onclick={insertPropertySqft} <button class="property-insert-btn" onclick={insertPropertySqft}
title="Insert Square Footage"> title="Insert Square Footage">
Sq Ft Sq Ft
</button> </button>
<button class="property-insert-btn" onclick={insertProplsertyFloor} <button class="property-insert-btn" onclick={insertPropertyAddress} title="Insert Address">
title="Insert Floor"> Address
Floor
</button> </button>
<button class="property-insert-btn" onclick={insertPropertyBuildYear} <button class="property-insert-btn" onclick={insertPropertyDescription}
title="Insert Build Year"> title="Insert Description">
Year Description
</button> </button>
<button class="property-insert-btn" onclick={insertPropertyParking}
title="Insert Parking">
Parking
</button>
<button class="property-insert-btn" onclick={insertPropertyFurnished}
title="Insert Furnished Status">
Furnished
</button>
<button class="property-insert-btn" onclick={insertPropertyOfferingType}
title="Insert Offering Type">
Offering
</button>
<!-- Location Information -->
<button class="property-insert-btn" onclick={insertPropertyCity}
title="Insert City">
City
</button>
<button class="property-insert-btn" onclick={insertPropertyContactEmail}
title="Insert Contact Email">
Email
</button>
<button class="property-insert-btn" onclick={insertPropertyContactPhone}
title="Insert Contact Phone">
Phone
</button>
</div> </div>
</div> </div>
@ -1180,12 +1002,12 @@
<button class="toolbar-button" onclick={handleBulletList}> <button class="toolbar-button" onclick={handleBulletList}>
<lightning-icon icon-name="utility:bullet_list" <lightning-icon icon-name="utility:bullet_list"
size="x-small"></lightning-icon> size="x-small"></lightning-icon>
Bullet Bullet(*)
</button> </button>
<button class="toolbar-button" onclick={handleNumberList}> <button class="toolbar-button" onclick={handleNumberList}>
<lightning-icon icon-name="utility:numbered_list" <lightning-icon icon-name="utility:numbered_list"
size="x-small"></lightning-icon> size="x-small"></lightning-icon>
Number Number(1)
</button> </button>
<button class="toolbar-button" onclick={handleIndent}> <button class="toolbar-button" onclick={handleIndent}>
<lightning-icon icon-name="utility:indent" size="x-small"></lightning-icon> <lightning-icon icon-name="utility:indent" size="x-small"></lightning-icon>
@ -1211,12 +1033,6 @@
Image Image
</button> </button>
</div> </div>
<!-- <div class="toolbar-group">
<button class="toolbar-button" onclick={addNewPageWithDataType} disabled>
<lightning-icon icon-name="utility:page" size="x-small"></lightning-icon>
Add Page
</button>
</div> -->
<div class="toolbar-group"> <div class="toolbar-group">
<button class="toolbar-button" onclick={toggleSelectorMode}> <button class="toolbar-button" onclick={toggleSelectorMode}>
<lightning-icon icon-name="utility:target" size="x-small"></lightning-icon> <lightning-icon icon-name="utility:target" size="x-small"></lightning-icon>
@ -1249,6 +1065,8 @@
</div> </div>
</div> <!-- Close enhanced-toolbar-scroll --> </div> <!-- Close enhanced-toolbar-scroll -->
</div> </div>
</div> </div>
@ -1260,42 +1078,40 @@
<div class="editor-right"> <div class="editor-right">
<!-- Page Size and PDF Generation Header --> <!-- Page Size and PDF Generation Header -->
<div class="template-header-area"> <div class="template-header-area">
<!-- All buttons in a single line --> <!-- New Back Button -->
<div class="header-controls-line"> <div class="header-left-actions">
<!-- Back Button -->
<button class="btn btn-secondary" onclick={previousStep} title="Back"> <button class="btn btn-secondary" onclick={previousStep} title="Back">
← Back ← Back
</button> </button>
</div>
<!-- Page Size Options --> <!-- Page Size Options -->
<div class="page-size-group"> <div class="page-size-section">
<label class="page-size-label">Page Size:</label> <label class="page-size-label">Page Size:</label>
<div class="page-size-options"> <div class="page-size-options">
<label class="page-size-option"> <label class="page-size-option">
<input type="radio" name="pageSize" value="A4" checked <input type="radio" name="pageSize" value="A4" checked
onchange={handlePageSizeChange}> onchange={handlePageSizeChange}>
<span class="page-size-text">A4</span> <span class="page-size-text">A4</span>
</label> </label>
<!-- <label class="page-size-option"> <label class="page-size-option">
<input type="radio" name="pageSize" value="A3" onchange={handlePageSizeChange}> <input type="radio" name="pageSize" value="A3" onchange={handlePageSizeChange}>
<span class="page-size-text">A3</span> <span class="page-size-text">A3</span>
</label> --> </label>
</div>
</div> </div>
</div>
<!-- Generate PDF Button -->
<template if:true={showGeneratePdfButton}> <!-- Generate PDF Button -->
<button class="btn btn-primary generate-pdf-btn" onclick={generatePdfSimple} disabled={isGeneratingPdf}> <div class="generate-pdf-section">
<template if:false={isGeneratingPdf}> <button class="btn btn-primary generate-pdf-btn" onclick={generatePdfSimple} disabled={isGeneratingPdf}>
<span class="btn-icon">📄</span> <template if:false={isGeneratingPdf}>
Generate PDF <span class="btn-icon">📄</span>
</template> Generate PDF
<template if:true={isGeneratingPdf}> </template>
<span class="loading-spinner"></span> <template if:true={isGeneratingPdf}>
Wait, our AI is generating the report... <span class="loading-spinner"></span>
</template> Wait, our AI is generating the report...
</button> </template>
</template> </button>
</div> </div>
</div> </div>
@ -1308,13 +1124,22 @@
<template if:true={previewPages}> <template if:true={previewPages}>
<template for:each={previewPages} for:item="page" for:index="pageIndex"> <template for:each={previewPages} for:item="page" for:index="pageIndex">
<div key={page.id} class="preview-page" data-page-size={selectedPageSize} data-page-number={pageIndex}> <div key={page.id} class="preview-page" data-page-size={selectedPageSize} data-page-number={pageIndex}>
<div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChangeWithDynamicSizing} <div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChange}
onpaste={handleContentChangeWithDynamicSizing} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}> onpaste={handleContentChange} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
{page.content} {page.content}
</div> </div>
</div> </div>
</template> </template>
</template> </template>
<template if:false={previewPages}>
<div class="preview-page" data-page-size={selectedPageSize} data-page-number="1">
<div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChange}
onpaste={handleContentChange} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
<!-- Template content will be loaded here -->
{htmlContent}
</div>
</div>
</template>
</div> </div>
<template if:false={hasPropertyImages}> <template if:false={hasPropertyImages}>
<div class="floating-placeholder" data-preview-only="true" style="position: absolute; bottom: 12px; left: 12px; display: flex; align-items: center; gap: 8px; z-index: 2000; pointer-events: none;"> <div class="floating-placeholder" data-preview-only="true" style="position: absolute; bottom: 12px; left: 12px; display: flex; align-items: center; gap: 8px; z-index: 2000; pointer-events: none;">
@ -1332,7 +1157,6 @@
<!-- Image Review Modal --> <!-- Image Review Modal -->
<div if:true={showImageReview} class="image-review-overlay"> <div if:true={showImageReview} class="image-review-overlay">
<div class="image-review-modal"> <div class="image-review-modal">
@ -1468,7 +1292,6 @@
<!-- Action Buttons --> <!-- Action Buttons -->
<div class="image-replacement-actions"> <div class="image-replacement-actions">
<button class="btn btn-secondary" onclick={closeImageReplacement}>Cancel</button> <button class="btn btn-secondary" onclick={closeImageReplacement}>Cancel</button>
<button class="btn btn-primary" onclick={insertSelectedReplacementImage}>Insert Image</button>
</div> </div>
</div> </div>
</div> </div>
@ -1567,99 +1390,4 @@
</div> </div>
</div> </div>
</div> </div>
<!-- New Section Modal -->
<div if:true={showNewSectionModal} class="new-section-modal-overlay">
<div class="new-section-modal">
<div class="new-section-modal-header">
<h3>Add New Section</h3>
<button class="close-btn" onclick={closeNewSectionModal}></button>
</div>
<div class="new-section-modal-content">
<div class="section-type-selection">
<h4>Choose Section Type:</h4>
<div class="section-type-grid">
<div class="section-type-option" onclick={selectSectionType} data-type="text">
<div class="section-type-icon">📝</div>
<div class="section-type-title">Text Section</div>
<div class="section-type-description">Add a text-based section with title and content</div>
</div>
<div class="section-type-option" onclick={selectSectionType} data-type="image">
<div class="section-type-icon">🖼️</div>
<div class="section-type-title">Image Gallery</div>
<div class="section-type-description">Add an image gallery section</div>
</div>
<div class="section-type-option" onclick={selectSectionType} data-type="features">
<div class="section-type-icon"></div>
<div class="section-type-title">Features List</div>
<div class="section-type-description">Add a features and amenities section</div>
</div>
<div class="section-type-option" onclick={selectSectionType} data-type="contact">
<div class="section-type-icon">📞</div>
<div class="section-type-title">Contact Info</div>
<div class="section-type-description">Add contact information section</div>
</div>
</div>
</div>
<div if:true={selectedSectionType} class="section-configuration">
<h4>Section Configuration:</h4>
<div class="form-group">
<label>Section Title:</label>
<input type="text" class="form-input" value={newSectionTitle} onchange={handleSectionTitleChange} placeholder="Enter section title">
</div>
<div if:true={showSectionContentInput} class="form-group">
<label>Section Content:</label>
<textarea class="form-textarea" value={newSectionContent} onchange={handleSectionContentChange} placeholder="Enter section content"></textarea>
</div>
</div>
</div>
<div class="new-section-modal-actions">
<button class="btn btn-secondary" onclick={closeNewSectionModal}>Cancel</button>
</div>
</div>
</div>
<!-- Data Type Selection Modal -->
<div if:true={showDataTypeModal} class="data-type-modal-overlay" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); z-index: 9999; display: flex; align-items: center; justify-content: center; animation: fadeIn 0.3s ease-out;">
<div class="data-type-modal" style="background: white; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.4); max-width: 700px; width: 90%; max-height: 85vh; overflow-y: auto; position: relative; animation: slideIn 0.3s ease-out; border: 1px solid #e0e0e0;">
<div class="data-type-modal-header" style="padding: 24px 24px 16px 24px; border-bottom: 1px solid #e0e0e0; display: flex; justify-content: space-between; align-items: center;">
<h3 style="margin: 0; font-size: 24px; font-weight: 600; color: #333;">Select Page Type</h3>
<button class="close-btn" onclick={closeDataTypeModal} style="background: none; border: none; font-size: 24px; color: #666; cursor: pointer; padding: 4px; border-radius: 4px; transition: all 0.2s;"></button>
</div>
<div class="data-type-modal-content" style="padding: 24px;">
<div class="data-type-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px;">
<div class="data-type-option" onclick={handleDataTypeSelection} data-type="text" style="border: 2px solid #e0e0e0; border-radius: 12px; padding: 20px; cursor: pointer; transition: all 0.3s ease; background: #fafafa; hover:border-color: #007bff; hover:background: #f0f8ff;">
<div class="data-type-icon" style="font-size: 32px; margin-bottom: 12px;">📝</div>
<div class="data-type-title" style="font-size: 18px; font-weight: 600; color: #333; margin-bottom: 8px;">Text Page</div>
<div class="data-type-description" style="font-size: 14px; color: #666; line-height: 1.4;">Add a text-focused page for detailed content</div>
</div>
<div class="data-type-option" onclick={handleDataTypeSelection} data-type="gallery" style="border: 2px solid #e0e0e0; border-radius: 12px; padding: 20px; cursor: pointer; transition: all 0.3s ease; background: #fafafa; hover:border-color: #007bff; hover:background: #f0f8ff;">
<div class="data-type-icon" style="font-size: 32px; margin-bottom: 12px;">🖼️</div>
<div class="data-type-title" style="font-size: 18px; font-weight: 600; color: #333; margin-bottom: 8px;">Gallery Page</div>
<div class="data-type-description" style="font-size: 14px; color: #666; line-height: 1.4;">Add an image gallery page</div>
</div>
<div class="data-type-option" onclick={handleDataTypeSelection} data-type="features" style="border: 2px solid #e0e0e0; border-radius: 12px; padding: 20px; cursor: pointer; transition: all 0.3s ease; background: #fafafa; hover:border-color: #007bff; hover:background: #f0f8ff;">
<div class="data-type-icon" style="font-size: 32px; margin-bottom: 12px;"></div>
<div class="data-type-title" style="font-size: 18px; font-weight: 600; color: #333; margin-bottom: 8px;">Features Page</div>
<div class="data-type-description" style="font-size: 14px; color: #666; line-height: 1.4;">Add a features and amenities page</div>
</div>
<div class="data-type-option" onclick={handleDataTypeSelection} data-type="contact" style="border: 2px solid #e0e0e0; border-radius: 12px; padding: 20px; cursor: pointer; transition: all 0.3s ease; background: #fafafa; hover:border-color: #007bff; hover:background: #f0f8ff;">
<div class="data-type-icon" style="font-size: 32px; margin-bottom: 12px;">📞</div>
<div class="data-type-title" style="font-size: 18px; font-weight: 600; color: #333; margin-bottom: 8px;">Contact Page</div>
<div class="data-type-description" style="font-size: 14px; color: #666; line-height: 1.4;">Add a contact information page</div>
</div>
<div class="data-type-option" onclick={handleDataTypeSelection} data-type="blank" style="border: 2px solid #e0e0e0; border-radius: 12px; padding: 20px; cursor: pointer; transition: all 0.3s ease; background: #fafafa; hover:border-color: #007bff; hover:background: #f0f8ff;">
<div class="data-type-icon" style="font-size: 32px; margin-bottom: 12px;">📄</div>
<div class="data-type-title" style="font-size: 18px; font-weight: 600; color: #333; margin-bottom: 8px;">Blank Page</div>
<div class="data-type-description" style="font-size: 14px; color: #666; line-height: 1.4;">Add a blank page for custom content</div>
</div>
</div>
</div>
<div class="data-type-modal-actions" style="padding: 16px 24px 24px 24px; border-top: 1px solid #e0e0e0; display: flex; justify-content: flex-end; gap: 12px;">
<button class="btn btn-secondary" onclick={closeDataTypeModal} style="padding: 10px 20px; border: 1px solid #ccc; background: white; color: #333; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500;">Cancel</button>
<button class="btn btn-primary" onclick={addPageWithSelectedDataType} disabled={selectedDataTypeDisabled} style="padding: 10px 20px; border: none; background: #007bff; color: white; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 500;">Add Page</button>
</div>
</div>
</div>
</template> </template>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<StaticResource xmlns="http://soap.sforce.com/2006/04/metadata">
<cacheControl>Public</cacheControl>
<contentType>image/svg+xml</contentType>
</StaticResource>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<StaticResource xmlns="http://soap.sforce.com/2006/04/metadata">
<cacheControl>Public</cacheControl>
<contentType>image/svg+xml</contentType>
</StaticResource>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB