v1.0.5-bet

This commit is contained in:
Ubuntu 2025-09-13 20:34:53 +05:30
parent 2bb4747426
commit 9a33862445
10 changed files with 19338 additions and 1144 deletions

View File

@ -20,6 +20,7 @@ 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, ' +
@ -55,6 +56,7 @@ 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;
@ -87,6 +89,7 @@ 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, ' +
@ -117,6 +120,7 @@ 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;
@ -175,4 +179,142 @@ 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());
}
}
} }

File diff suppressed because one or more lines are too long

View File

@ -440,15 +440,54 @@
<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}>
<option value="">-- Select a Property --</option> <!-- Simple Searchable Dropdown -->
<template for:each={propertiesWithSelected} for:item="property"> <div class="simple-dropdown-container">
<option key={property.Id} value={property.Id} selected={property._selected}> <!-- Search Input -->
{property.Name} - {property.pcrm__Title_English__c} - {property.pcrm__Property_Type__c} - <div class="simple-search-container">
{property.pcrm__City_Bayut_Dubizzle__c} <input
</option> type="text"
</template> placeholder="Search..."
</select> value={propertySearchTerm}
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>
@ -498,9 +537,73 @@
</div> </div>
</div> </div>
<!-- Row 2: Property Details Display - Full Width --> <!-- Row 1.5: Pricing Information Options -->
<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-2"> <div class="step2-grid-row-3">
<div class="property-details-layout"> <div class="property-details-layout">
<h3>Property Details Preview</h3> <h3>Property Details Preview</h3>
@ -545,6 +648,33 @@
</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 -->
@ -576,28 +706,6 @@
</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>
@ -669,6 +777,17 @@
<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 -->
@ -814,6 +933,7 @@
</button> </button>
</div> </div>
</div> </div>
</template> </template>
</div> </div>
@ -875,7 +995,7 @@
title="Insert Square Footage"> title="Insert Square Footage">
Sq Ft Sq Ft
</button> </button>
<button class="property-insert-btn" onclick={insertPropertyFloor} <button class="property-insert-btn" onclick={insertProplsertyFloor}
title="Insert Floor"> title="Insert Floor">
Floor Floor
</button> </button>
@ -1041,12 +1161,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(1) Number
</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>
@ -1104,8 +1224,6 @@
</div> </div>
</div> <!-- Close enhanced-toolbar-scroll --> </div> <!-- Close enhanced-toolbar-scroll -->
</div> </div>
</div> </div>
@ -1163,17 +1281,17 @@
<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={handleContentChange} <div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChangeWithDynamicSizing}
onpaste={handleContentChange} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}> onpaste={handleContentChangeWithDynamicSizing} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
{page.content} {page.content}
</div> </div>
</div> </div>
</template> </template>
</template> </template>
<template if:false={previewPages}> <template if:false={previewPages}>
<div class="preview-page" data-page-size={selectedPageSize} data-page-number="1"> <div class="preview-page" data-page-size={selectedPageSize} data-page-number="1">
<div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChange} <div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChangeWithDynamicSizing}
onpaste={handleContentChange} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}> onpaste={handleContentChangeWithDynamicSizing} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
<!-- Template content will be loaded here --> <!-- Template content will be loaded here -->
{htmlContent} {htmlContent}
</div> </div>
@ -1331,6 +1449,7 @@
<!-- 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>
@ -1429,4 +1548,59 @@
</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>
<button class="btn btn-primary" onclick={insertNewSection} disabled={insertSectionDisabled}>
Add Section
</button>
</div>
</div>
</div>
</template> </template>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
<?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

@ -0,0 +1,5 @@
<?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

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File