Compare commits

...

12 Commits
dev ... current

Author SHA1 Message Date
17a89486e0 v1.0.0-rc 2025-09-15 20:47:41 +05:30
eab0d41a64 replaced 3clicks with pointer 2025-09-15 18:22:24 +05:30
0c721ef7ed image replace stable 2025-09-15 17:17:41 +05:30
c978c48fb6 bullets font preserved 2025-09-15 11:50:35 +05:30
8b183d96be stable 2025-09-15 04:01:15 +05:30
55c207b3cf a4 stable 2025-09-15 00:31:43 +05:30
Ubuntu
1e9dda64a6 A4 stable 2025-09-14 18:04:49 +05:30
Ubuntu
82ef064e5e temp2-back 2025-09-14 15:09:50 +05:30
Ubuntu
3cb9090248 a3 removed 2025-09-13 22:05:08 +05:30
Ubuntu
9a33862445 v1.0.5-bet 2025-09-13 20:34:53 +05:30
Ubuntu
2bb4747426 insert property data 2025-09-10 17:40:07 +05:30
Ubuntu
9bb7f6a727 V1.0.0-rc 2025-09-10 03:49:08 +05:30
16 changed files with 61628 additions and 10326 deletions

File diff suppressed because one or more lines are too long

View File

@ -20,6 +20,7 @@ public with sharing class PropertyDataController {
'pcrm__Sub_Community_Propertyfinder__c, pcrm__Property_Name_Propertyfinder__c, ' +
'pcrm__City_Propertyfinder__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, ' +
'Email__c, Phone__c, ' +
'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('Parking Spaces: ' + firstProp.pcrm__Parking_Spaces__c);
System.debug('Offering Type: ' + firstProp.pcrm__Offering_Type__c);
System.debug('Private Amenities: ' + firstProp.Private_Amenities__c);
}
return properties;
@ -87,6 +89,7 @@ public with sharing class PropertyDataController {
'pcrm__Sub_Community_Propertyfinder__c, pcrm__Property_Name_Propertyfinder__c, ' +
'pcrm__City_Propertyfinder__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, ' +
'Email__c, Phone__c, ' +
'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('Parking Spaces: ' + property.pcrm__Parking_Spaces__c);
System.debug('Offering Type: ' + property.pcrm__Offering_Type__c);
System.debug('Private Amenities: ' + property.Private_Amenities__c);
}
return property;
@ -175,4 +179,142 @@ public with sharing class PropertyDataController {
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

@ -0,0 +1,7 @@
<?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,10 +5,12 @@
width: 100vw;
height: 100vh;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
z-index: 9999;
z-index: 99999;
overflow-y: auto;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #ffffff;
display: flex;
flex-direction: column;
}
.dev-header {
@ -46,30 +48,69 @@
letter-spacing: 1px;
}
.close-dev-btn {
position: absolute;
top: 20px;
right: 20px;
background: #ff4757;
color: white;
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
font-size: 1.5rem;
cursor: pointer;
.dev-exit-section {
margin-top: 20px;
padding: 15px;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
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;
}
.close-dev-btn:hover {
background: #ff3742;
transform: scale(1.1);
.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;
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;
max-width: 1200px;
margin: 0 auto;
flex: 1;
overflow-y: auto;
}
.dev-section {

View File

@ -3,6 +3,17 @@
<div class="dev-header">
<h1>🚧 Development Area 🚧</h1>
<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 class="dev-content">

View File

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

File diff suppressed because one or more lines are too long

View File

@ -144,6 +144,30 @@
</div>
</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-info">
<h3 style="font-size: 0.95rem;">Sarah Johnson</h3>
@ -440,15 +464,54 @@
<div class="property-selector">
<label for="propertySelect">Property:</label>
<select id="propertySelect" value={selectedPropertyId} onchange={handlePropertySelection}>
<option value="">-- Select a Property --</option>
<template for:each={propertiesWithSelected} for:item="property">
<option key={property.Id} value={property.Id} selected={property._selected}>
{property.Name} - {property.pcrm__Title_English__c} - {property.pcrm__Property_Type__c} -
{property.pcrm__City_Bayut_Dubizzle__c}
</option>
<!-- Simple Searchable Dropdown -->
<div class="simple-dropdown-container">
<!-- Search Input -->
<div class="simple-search-container">
<input
type="text"
placeholder="Search..."
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>
</select>
<!-- 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>
@ -498,9 +561,73 @@
</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}>
<div class="step2-grid-row-2">
<div class="step2-grid-row-3">
<div class="property-details-layout">
<h3>Property Details Preview</h3>
@ -545,6 +672,33 @@
</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>
<!-- Right Top Rectangle: Specifications + Pricing -->
@ -576,28 +730,6 @@
</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>
@ -669,6 +801,17 @@
<span class="value">{propertyData.offeringType}</span>
</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>
<!-- Rent Availability -->
@ -814,6 +957,7 @@
</button>
</div>
</div>
</template>
</div>
@ -846,37 +990,71 @@
<div class="toolbar-section">
<div class="toolbar-section-title">Insert Property Data</div>
<div class="property-insert-grid">
<!-- Basic Information -->
<button class="property-insert-btn" onclick={insertPropertyName}
title="Insert Property Name">
Name
</button>
<button class="property-insert-btn" onclick={insertPropertyPrice}
title="Insert Property Price">
Price
<button class="property-insert-btn" onclick={insertPropertyTitle}
title="Insert Property Title">
Title
</button>
<button class="property-insert-btn" onclick={insertPropertyType}
title="Insert Property Type">
Type
</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}
title="Insert Square Footage">
Sq Ft
</button>
<button class="property-insert-btn" onclick={insertPropertyAddress} title="Insert Address">
Address
<button class="property-insert-btn" onclick={insertProplsertyFloor}
title="Insert Floor">
Floor
</button>
<button class="property-insert-btn" onclick={insertPropertyDescription}
title="Insert Description">
Description
<button class="property-insert-btn" onclick={insertPropertyBuildYear}
title="Insert Build Year">
Year
</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>
@ -1002,12 +1180,12 @@
<button class="toolbar-button" onclick={handleBulletList}>
<lightning-icon icon-name="utility:bullet_list"
size="x-small"></lightning-icon>
Bullet(*)
Bullet
</button>
<button class="toolbar-button" onclick={handleNumberList}>
<lightning-icon icon-name="utility:numbered_list"
size="x-small"></lightning-icon>
Number(1)
Number
</button>
<button class="toolbar-button" onclick={handleIndent}>
<lightning-icon icon-name="utility:indent" size="x-small"></lightning-icon>
@ -1033,6 +1211,12 @@
Image
</button>
</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">
<button class="toolbar-button" onclick={toggleSelectorMode}>
<lightning-icon icon-name="utility:target" size="x-small"></lightning-icon>
@ -1065,8 +1249,6 @@
</div>
</div> <!-- Close enhanced-toolbar-scroll -->
</div>
</div>
@ -1078,14 +1260,15 @@
<div class="editor-right">
<!-- Page Size and PDF Generation Header -->
<div class="template-header-area">
<!-- New Back Button -->
<div class="header-left-actions">
<!-- All buttons in a single line -->
<div class="header-controls-line">
<!-- Back Button -->
<button class="btn btn-secondary" onclick={previousStep} title="Back">
← Back
</button>
</div>
<!-- Page Size Options -->
<div class="page-size-section">
<div class="page-size-group">
<label class="page-size-label">Page Size:</label>
<div class="page-size-options">
<label class="page-size-option">
@ -1093,15 +1276,15 @@
onchange={handlePageSizeChange}>
<span class="page-size-text">A4</span>
</label>
<label class="page-size-option">
<!-- <label class="page-size-option">
<input type="radio" name="pageSize" value="A3" onchange={handlePageSizeChange}>
<span class="page-size-text">A3</span>
</label>
</label> -->
</div>
</div>
<!-- Generate PDF Button -->
<div class="generate-pdf-section">
<template if:true={showGeneratePdfButton}>
<button class="btn btn-primary generate-pdf-btn" onclick={generatePdfSimple} disabled={isGeneratingPdf}>
<template if:false={isGeneratingPdf}>
<span class="btn-icon">📄</span>
@ -1112,6 +1295,7 @@
Wait, our AI is generating the report...
</template>
</button>
</template>
</div>
</div>
@ -1124,22 +1308,13 @@
<template if:true={previewPages}>
<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 class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChange}
onpaste={handleContentChange} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
<div class="enhanced-editor-content" contenteditable="true" onkeyup={handleContentChangeWithDynamicSizing}
onpaste={handleContentChangeWithDynamicSizing} ondragover={handleEditorDragOver} ondrop={handleEditorDrop}>
{page.content}
</div>
</div>
</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>
<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;">
@ -1157,6 +1332,7 @@
<!-- Image Review Modal -->
<div if:true={showImageReview} class="image-review-overlay">
<div class="image-review-modal">
@ -1292,6 +1468,7 @@
<!-- Action Buttons -->
<div class="image-replacement-actions">
<button class="btn btn-secondary" onclick={closeImageReplacement}>Cancel</button>
<button class="btn btn-primary" onclick={insertSelectedReplacementImage}>Insert Image</button>
</div>
</div>
</div>
@ -1390,4 +1567,99 @@
</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>

File diff suppressed because one or more lines are too long

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