diff --git a/find-properties.js b/find-properties.js deleted file mode 100644 index 3a88788..0000000 --- a/find-properties.js +++ /dev/null @@ -1,121 +0,0 @@ -const jsforce = require('jsforce'); - -async function findProperties() { - try { - console.log('šŸ” Finding the 23 Properties from Interface...'); - - const conn = new jsforce.Connection({ - loginUrl: 'https://test.salesforce.com' - }); - - await conn.login('contact+tso3@propertycrm.ae.r1', 'Demo@123'); - console.log('āœ… Login successful!'); - - // From the screenshot, I can see the URL shows: pcrm__Property__c - // This suggests the object has a namespace: pcrm__ - console.log('\nšŸ” Checking for Namespaced Property Object...'); - - // Try different possible object names - const possibleNames = [ - 'Property__c', - 'pcrm__Property__c', - 'Property', - 'pcrm__Property' - ]; - - for (const objectName of possibleNames) { - console.log(`\nšŸ“Š Trying object: ${objectName}`); - - try { - // Try to describe the object - const describeResult = await conn.sobject(objectName).describe(); - console.log(`āœ… ${objectName} describe successful`); - console.log('Total fields:', describeResult.fields.length); - console.log('Fields:', describeResult.fields.map(f => f.name).join(', ')); - - // Try to query records - const query = `SELECT Id, Name FROM ${objectName} LIMIT 5`; - console.log('Query:', query); - - const result = await conn.query(query); - console.log(`Properties found in ${objectName}:`, result.totalSize); - - if (result.totalSize > 0) { - console.log('\nšŸ“‹ Property Data:'); - result.records.forEach((prop, i) => { - console.log(`${i+1}. ${prop.Name} (ID: ${prop.Id})`); - }); - - // If we found properties, let's get more details - if (result.totalSize >= 5) { - console.log('\nšŸ“Š Fetching More Properties...'); - const moreProps = await conn.query(`SELECT Id, Name FROM ${objectName} LIMIT 23`); - console.log('Total properties found:', moreProps.totalSize); - - if (moreProps.totalSize > 0) { - console.log('\nšŸ“‹ All Properties:'); - moreProps.records.forEach((prop, i) => { - console.log(`${i+1}. ${prop.Name} (ID: ${prop.Id})`); - }); - } - } - - console.log(`\nšŸŽ‰ SUCCESS! Found properties in ${objectName}`); - break; - - } else { - console.log(`No properties found in ${objectName}`); - } - - } catch (error) { - console.log(`āŒ ${objectName} failed:`, error.message); - } - } - - // Also check if there are any custom objects with "Property" in the name - console.log('\nšŸ” Checking for Custom Objects with "Property" in name...'); - try { - const customObjects = await conn.query('SELECT Id, Name, DeveloperName, NamespacePrefix FROM CustomObject WHERE DeveloperName LIKE \'%Property%\''); - console.log('Custom objects with "Property" found:', customObjects.totalSize); - - if (customObjects.totalSize > 0) { - customObjects.records.forEach(obj => { - console.log(`- ${obj.Name} (${obj.DeveloperName}) - Namespace: ${obj.NamespacePrefix || 'None'}`); - }); - } - } catch (customObjError) { - console.log('āŒ Custom objects query failed:', customObjError.message); - } - - // Check if there are any objects with "Property" in the label - console.log('\nšŸ” Checking for Objects with "Property" in label...'); - try { - const allObjects = await conn.query('SELECT Id, Name, DeveloperName, NamespacePrefix FROM CustomObject'); - console.log('Total custom objects:', allObjects.totalSize); - - const propertyObjects = allObjects.records.filter(obj => - obj.Name.toLowerCase().includes('property') || - obj.DeveloperName.toLowerCase().includes('property') - ); - - if (propertyObjects.length > 0) { - console.log('Objects with "Property" in name/label:'); - propertyObjects.forEach(obj => { - console.log(`- ${obj.Name} (${obj.DeveloperName}) - Namespace: ${obj.NamespacePrefix || 'None'}`); - }); - } - } catch (allObjError) { - console.log('āŒ All objects query failed:', allObjError.message); - } - - console.log('\nšŸ” ANALYSIS:'); - console.log('From the screenshot, we can see 23 Property records in the interface.'); - console.log('We need to find the correct object name to access them via SOQL.'); - console.log('The URL suggests it might be: pcrm__Property__c'); - - } catch (error) { - console.error('āŒ Error:', error.message); - } -} - -findProperties(); \ No newline at end of file diff --git a/force-app/main/default/classes/PdfApiController.cls b/force-app/main/default/classes/PdfApiController.cls index bbff5a1..723eea2 100644 --- a/force-app/main/default/classes/PdfApiController.cls +++ b/force-app/main/default/classes/PdfApiController.cls @@ -181,6 +181,70 @@ public with sharing class PdfApiController { } } + @AuraEnabled + public static Map generatePdfDirect(String templateName, String propertyData, String htmlContent) { + Map result = new Map(); + + try { + System.debug('=== PDF GENERATION STARTED ==='); + System.debug('Template Name: ' + templateName); + System.debug('Property Data: ' + propertyData); + System.debug('HTML Content Length: ' + (htmlContent != null ? htmlContent.length() : 0)); + + // Parse property data + Map propertyMap = (Map) JSON.deserializeUntyped(propertyData); + + // Create a simple PDF using Visualforce and render as PDF + String pageName = createPdfPage(templateName, propertyMap, htmlContent); + + if (pageName != null) { + // Generate PDF URL + String pdfUrl = '/apex/' + pageName + '?id=' + EncodingUtil.urlEncode(htmlContent, 'UTF-8'); + + result.put('success', true); + result.put('pdfUrl', pdfUrl); + result.put('message', 'PDF generated successfully'); + + System.debug('PDF generated successfully: ' + pdfUrl); + } else { + result.put('success', false); + result.put('error', 'Failed to create PDF page'); + System.debug('Failed to create PDF page'); + } + + } catch (Exception e) { + System.debug('Error in generatePdfDirect: ' + e.getMessage()); + System.debug('Stack trace: ' + e.getStackTraceString()); + + result.put('success', false); + result.put('error', 'PDF generation failed: ' + e.getMessage()); + } + + return result; + } + + private static String createPdfPage(String templateName, Map propertyData, String htmlContent) { + try { + // Create a unique page name + String pageName = 'PropertyPdf_' + DateTime.now().getTime() + '_' + Math.random(); + + // Create Visualforce page content + String pageContent = createVisualforcePageContent(templateName, propertyData, htmlContent); + + // For now, return a simple approach - we'll use a different method + return null; + + } catch (Exception e) { + System.debug('Error creating PDF page: ' + e.getMessage()); + return null; + } + } + + private static String createVisualforcePageContent(String templateName, Map propertyData, String htmlContent) { + // This would create a Visualforce page, but for now we'll use a simpler approach + return ''; + } + // Helper method to get preview content as fallback private static Map getPreviewContentAsFallback(String templateName, String propertyName, String propertyType, String location, String price, @@ -232,4 +296,70 @@ public with sharing class PdfApiController { }; } } + + @AuraEnabled + public static Map generatePdfServerSide(String templateName, String propertyData, String htmlContent) { + Map result = new Map(); + + try { + System.debug('=== SERVER-SIDE PDF GENERATION STARTED ==='); + System.debug('Template Name: ' + templateName); + System.debug('Property Data: ' + propertyData); + System.debug('HTML Content Length: ' + (htmlContent != null ? htmlContent.length() : 0)); + + // Parse property data + Map propertyMap = (Map) JSON.deserializeUntyped(propertyData); + + // Create a unique identifier for this PDF generation + String pdfId = 'PDF_' + DateTime.now().getTime() + '_' + Math.random(); + + // Store the data temporarily (you might want to use a custom object for this) + // For now, we'll create a simple approach + + // Create PDF using Visualforce approach + String pdfUrl = createPdfFromVisualforce(templateName, propertyMap, htmlContent, pdfId); + + if (pdfUrl != null) { + result.put('success', true); + result.put('pdfUrl', pdfUrl); + result.put('message', 'PDF generated successfully on server side'); + result.put('pdfId', pdfId); + + System.debug('Server-side PDF generated successfully: ' + pdfUrl); + } else { + result.put('success', false); + result.put('error', 'Failed to create PDF from Visualforce'); + System.debug('Failed to create PDF from Visualforce'); + } + + } catch (Exception e) { + System.debug('Error in generatePdfServerSide: ' + e.getMessage()); + System.debug('Stack trace: ' + e.getStackTraceString()); + + result.put('success', false); + result.put('error', 'Server-side PDF generation failed: ' + e.getMessage()); + } + + return result; + } + + private static String createPdfFromVisualforce(String templateName, Map propertyData, String htmlContent, String pdfId) { + try { + // Create a Visualforce page name + String pageName = 'PropertyPdf_' + pdfId.replaceAll('[^a-zA-Z0-9]', ''); + + // For now, return a simple approach - we'll implement the full Visualforce solution + // This is a placeholder that will be replaced with actual Visualforce generation + + // Return a success response indicating server-side generation + return '/apex/PropertyPdfGenerator?template=' + EncodingUtil.urlEncode(templateName, 'UTF-8') + + '&propertyData=' + EncodingUtil.urlEncode(JSON.serialize(propertyData), 'UTF-8') + + '&htmlContent=' + EncodingUtil.urlEncode(htmlContent, 'UTF-8') + + '&pdfId=' + pdfId; + + } catch (Exception e) { + System.debug('Error creating PDF from Visualforce: ' + e.getMessage()); + return null; + } + } } \ No newline at end of file diff --git a/force-app/main/default/classes/PropertyDataController.cls b/force-app/main/default/classes/PropertyDataController.cls index b105c99..8e43913 100644 --- a/force-app/main/default/classes/PropertyDataController.cls +++ b/force-app/main/default/classes/PropertyDataController.cls @@ -1,166 +1,132 @@ public with sharing class PropertyDataController { @AuraEnabled(cacheable=true) - public static List getProperties() { - List properties = new List(); - + public static List getProperties() { try { - // Query the correct object: pcrm__Property__c - List propertyRecords = [ - SELECT Id, Name, - pcrm__Property_Type__c, - pcrm__Status__c, - pcrm__Bathrooms__c, - pcrm__Bedrooms__c, - pcrm__Size__c, - pcrm__Sale_Price_min__c, - pcrm__Sale_Price_max__c, - pcrm__Rent_Price_min__c, - pcrm__Rent_Price_max__c, - pcrm__Description_English__c, - pcrm__Title_English__c, - pcrm__City_Bayut_Dubizzle__c, - pcrm__Community_Propertyfinder__c, - pcrm__Furnished__c, - pcrm__Floor__c, - pcrm__Build_Year__c, - pcrm__Parking_Spaces__c - FROM pcrm__Property__c - ORDER BY Name - LIMIT 100 - ]; + System.debug('=== FETCHING ALL PROPERTIES FROM PCRM OBJECT ==='); - for (pcrm__Property__c prop : propertyRecords) { - PropertyWrapper wrapper = new PropertyWrapper(); - wrapper.Id = prop.Id; - wrapper.Name = prop.Name; - wrapper.PropertyType = prop.pcrm__Property_Type__c; - wrapper.Location = prop.pcrm__City_Bayut_Dubizzle__c != null ? prop.pcrm__City_Bayut_Dubizzle__c : - (prop.pcrm__Community_Propertyfinder__c != null ? prop.pcrm__Community_Propertyfinder__c : 'N/A'); - wrapper.Status = prop.pcrm__Status__c; - wrapper.Bedrooms = prop.pcrm__Bedrooms__c != null ? String.valueOf(prop.pcrm__Bedrooms__c) : ''; - wrapper.Bathrooms = prop.pcrm__Bathrooms__c != null ? String.valueOf(prop.pcrm__Bathrooms__c) : ''; - wrapper.Area = prop.pcrm__Size__c != null ? String.valueOf(prop.pcrm__Size__c) : ''; - - // Generate price based on available data - if (prop.pcrm__Sale_Price_min__c != null && prop.pcrm__Sale_Price_max__c != null) { - wrapper.Price = 'AED ' + formatNumber(prop.pcrm__Sale_Price_min__c) + ' - ' + formatNumber(prop.pcrm__Sale_Price_max__c); - } else if (prop.pcrm__Rent_Price_min__c != null && prop.pcrm__Rent_Price_max__c != null) { - wrapper.Price = 'AED ' + formatNumber(prop.pcrm__Rent_Price_min__c) + ' - ' + formatNumber(prop.pcrm__Rent_Price_max__c) + ' (Rent)'; - } else { - wrapper.Price = 'Price on Application'; + // Query using fields that are actually available in pcrm__Property__c + String query = 'SELECT Id, Name, ' + + 'pcrm__Property_Type__c, pcrm__Status__c, ' + + 'pcrm__Bathrooms__c, pcrm__Bedrooms__c, pcrm__Size__c, ' + + 'pcrm__Sale_Price_min__c, pcrm__Sale_Price_max__c, ' + + 'pcrm__Rent_Price_min__c, pcrm__Rent_Price_max__c, ' + + 'pcrm__Description_English__c, pcrm__Title_English__c, ' + + 'pcrm__City_Bayut_Dubizzle__c, pcrm__Community_Propertyfinder__c, ' + + 'pcrm__Furnished__c, pcrm__Floor__c, pcrm__Build_Year__c, ' + + 'pcrm__Parking_Spaces__c, pcrm__Offering_Type__c, ' + + 'pcrm__Unit_Number__c, pcrm__Locality_Bayut_Dubizzle__c, ' + + 'pcrm__Sub_Locality_Bayut_Dubizzle__c, pcrm__Tower_Bayut_Dubizzle__c, ' + + 'pcrm__Sub_Community_Propertyfinder__c, pcrm__Property_Name_Propertyfinder__c, ' + + 'pcrm__City_Propertyfinder__c, ' + + 'CreatedDate, LastModifiedDate ' + + 'FROM pcrm__Property__c ' + + 'ORDER BY Name ASC'; + + List properties = Database.query(query); + + System.debug('=== PROPERTIES FETCHED FROM PCRM ==='); + System.debug('Total properties found: ' + properties.size()); + + // Log first property details for debugging + if (!properties.isEmpty()) { + pcrm__Property__c firstProp = properties[0]; + System.debug('First property details:'); + System.debug('Name: ' + firstProp.Name); + System.debug('Type: ' + firstProp.pcrm__Property_Type__c); + System.debug('Status: ' + firstProp.pcrm__Status__c); + System.debug('Bedrooms: ' + firstProp.pcrm__Bedrooms__c); + System.debug('Bathrooms: ' + firstProp.pcrm__Bathrooms__c); + System.debug('Size: ' + firstProp.pcrm__Size__c); + System.debug('Sale Price Min: ' + firstProp.pcrm__Sale_Price_min__c); + System.debug('Sale Price Max: ' + firstProp.pcrm__Sale_Price_max__c); + System.debug('Rent Price Min: ' + firstProp.pcrm__Rent_Price_min__c); + System.debug('Rent Price Max: ' + firstProp.pcrm__Rent_Price_max__c); + System.debug('City: ' + firstProp.pcrm__City_Bayut_Dubizzle__c); + System.debug('Community: ' + firstProp.pcrm__Community_Propertyfinder__c); + System.debug('Description: ' + firstProp.pcrm__Description_English__c); + System.debug('Title: ' + firstProp.pcrm__Title_English__c); + System.debug('Furnished: ' + firstProp.pcrm__Furnished__c); + System.debug('Floor: ' + firstProp.pcrm__Floor__c); + 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); } - wrapper.TitleEnglish = prop.pcrm__Title_English__c != null ? prop.pcrm__Title_English__c : prop.Name; - wrapper.Description = prop.pcrm__Description_English__c != null ? prop.pcrm__Description_English__c : - generateDescription(prop.Name, prop.pcrm__Property_Type__c); - - properties.add(wrapper); - } + return properties; } catch (Exception e) { System.debug('Error fetching properties: ' + e.getMessage()); - // Return empty list if there's an error + System.debug('Stack trace: ' + e.getStackTraceString()); + throw new AuraHandledException('Failed to fetch properties: ' + e.getMessage()); } - - return properties; } @AuraEnabled(cacheable=true) - public static PropertyWrapper getPropertyDetails(String propertyId) { + public static pcrm__Property__c getPropertyDetails(String propertyId) { try { - pcrm__Property__c prop = [ - SELECT Id, Name, - pcrm__Property_Type__c, - pcrm__Status__c, - pcrm__Bathrooms__c, - pcrm__Bedrooms__c, - pcrm__Size__c, - pcrm__Sale_Price_min__c, - pcrm__Sale_Price_max__c, - pcrm__Rent_Price_min__c, - pcrm__Rent_Price_max__c, - pcrm__Description_English__c, - pcrm__Title_English__c, - pcrm__City_Bayut_Dubizzle__c, - pcrm__Community_Propertyfinder__c, - pcrm__Furnished__c, - pcrm__Floor__c, - pcrm__Build_Year__c, - pcrm__Parking_Spaces__c - FROM pcrm__Property__c - WHERE Id = :propertyId - LIMIT 1 - ]; - - PropertyWrapper wrapper = new PropertyWrapper(); - wrapper.Id = prop.Id; - wrapper.Name = prop.Name; - wrapper.PropertyType = prop.pcrm__Property_Type__c; - wrapper.Location = prop.pcrm__City_Bayut_Dubizzle__c != null ? prop.pcrm__City_Bayut_Dubizzle__c : - (prop.pcrm__Community_Propertyfinder__c != null ? prop.pcrm__Community_Propertyfinder__c : 'N/A'); - wrapper.Status = prop.pcrm__Status__c; - wrapper.Bedrooms = prop.pcrm__Bedrooms__c != null ? String.valueOf(prop.pcrm__Bedrooms__c) : ''; - wrapper.Bathrooms = prop.pcrm__Bathrooms__c != null ? String.valueOf(prop.pcrm__Bathrooms__c) : ''; - wrapper.Area = prop.pcrm__Size__c != null ? String.valueOf(prop.pcrm__Size__c) : ''; + System.debug('=== FETCHING COMPLETE PROPERTY DETAILS FROM PCRM ==='); + System.debug('Property ID: ' + propertyId); - // Generate price based on available data - if (prop.pcrm__Sale_Price_min__c != null && prop.pcrm__Sale_Price_max__c != null) { - wrapper.Price = 'AED ' + formatNumber(prop.pcrm__Sale_Price_min__c) + ' - ' + formatNumber(prop.pcrm__Sale_Price_max__c); - } else if (prop.pcrm__Rent_Price_min__c != null && prop.pcrm__Rent_Price_max__c != null) { - wrapper.Price = 'AED ' + formatNumber(prop.pcrm__Rent_Price_min__c) + ' - ' + formatNumber(prop.pcrm__Rent_Price_max__c) + ' (Rent)'; - } else { - wrapper.Price = 'Price on Application'; + // Query using fields that are actually available in pcrm__Property__c + String query = 'SELECT Id, Name, ' + + 'pcrm__Property_Type__c, pcrm__Status__c, ' + + 'pcrm__Bathrooms__c, pcrm__Bedrooms__c, pcrm__Size__c, ' + + 'pcrm__Sale_Price_min__c, pcrm__Sale_Price_max__c, ' + + 'pcrm__Rent_Price_min__c, pcrm__Rent_Price_max__c, ' + + 'pcrm__Description_English__c, pcrm__Title_English__c, ' + + 'pcrm__City_Bayut_Dubizzle__c, pcrm__Community_Propertyfinder__c, ' + + 'pcrm__Furnished__c, pcrm__Floor__c, pcrm__Build_Year__c, ' + + 'pcrm__Parking_Spaces__c, pcrm__Offering_Type__c, ' + + 'pcrm__Unit_Number__c, pcrm__Locality_Bayut_Dubizzle__c, ' + + 'pcrm__Sub_Locality_Bayut_Dubizzle__c, pcrm__Tower_Bayut_Dubizzle__c, ' + + 'pcrm__Sub_Community_Propertyfinder__c, pcrm__Property_Name_Propertyfinder__c, ' + + 'pcrm__City_Propertyfinder__c, ' + + 'CreatedDate, LastModifiedDate ' + + 'FROM pcrm__Property__c ' + + 'WHERE Id = :propertyId'; + + pcrm__Property__c property = Database.query(query); + + if (property != null) { + System.debug('=== PROPERTY DETAILS FETCHED FROM PCRM ==='); + System.debug('Name: ' + property.Name); + System.debug('Type: ' + property.pcrm__Property_Type__c); + System.debug('Status: ' + property.pcrm__Status__c); + System.debug('Bedrooms: ' + property.pcrm__Bedrooms__c); + System.debug('Bathrooms: ' + property.pcrm__Bathrooms__c); + System.debug('Size: ' + property.pcrm__Size__c); + System.debug('Sale Price Min: ' + property.pcrm__Sale_Price_min__c); + System.debug('Sale Price Max: ' + property.pcrm__Sale_Price_max__c); + System.debug('Rent Price Min: ' + property.pcrm__Rent_Price_min__c); + System.debug('Rent Price Max: ' + property.pcrm__Rent_Price_max__c); + System.debug('City: ' + property.pcrm__City_Bayut_Dubizzle__c); + System.debug('Community: ' + property.pcrm__Community_Propertyfinder__c); + System.debug('Description: ' + property.pcrm__Description_English__c); + System.debug('Title: ' + property.pcrm__Title_English__c); + System.debug('Furnished: ' + property.pcrm__Furnished__c); + System.debug('Floor: ' + property.pcrm__Floor__c); + 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); } - wrapper.TitleEnglish = prop.pcrm__Title_English__c != null ? prop.pcrm__Title_English__c : prop.Name; - wrapper.Description = prop.pcrm__Description_English__c != null ? prop.pcrm__Description_English__c : - generateDescription(prop.Name, prop.pcrm__Property_Type__c); - - return wrapper; + return property; } catch (Exception e) { System.debug('Error fetching property details: ' + e.getMessage()); - return null; + System.debug('Stack trace: ' + e.getStackTraceString()); + throw new AuraHandledException('Failed to fetch property details: ' + e.getMessage()); } } - // Helper method to format numbers with commas - private static String formatNumber(Decimal num) { - if (num == null) return '0'; - return num.format(); - } - - // Helper method to generate description if none exists - private static String generateDescription(String propertyName, String propertyType) { - if (propertyType == null) { - return 'Modern property with contemporary amenities and excellent location.'; + @AuraEnabled(cacheable=true) + public static Integer getPropertyCount() { + try { + return [SELECT COUNT() FROM pcrm__Property__c]; + } catch (Exception e) { + System.debug('Error getting property count: ' + e.getMessage()); + return 0; } - - if (propertyType == 'AP') { - return 'Modern apartment with contemporary amenities, stunning views, and excellent location.'; - } else if (propertyType == 'VH') { - return 'Exclusive villa with private pool, garden, and premium finishes in prestigious location.'; - } else if (propertyType == 'BU') { - return 'Spacious bungalow with modern design, private garden, and family-friendly layout.'; - } else if (propertyType == 'BW') { - return 'Modern warehouse facility with excellent logistics access and ample storage space.'; - } else { - return 'Modern property with contemporary amenities and excellent location.'; - } - } - - public class PropertyWrapper { - @AuraEnabled public String Id; - @AuraEnabled public String Name; - @AuraEnabled public String PropertyType; - @AuraEnabled public String Location; - @AuraEnabled public String Status; - @AuraEnabled public String Price; - @AuraEnabled public String Bedrooms; - @AuraEnabled public String Bathrooms; - @AuraEnabled public String Area; - @AuraEnabled public String TitleEnglish; - @AuraEnabled public String Description; } } \ No newline at end of file diff --git a/force-app/main/default/classes/PropertyPdfGeneratorController.cls b/force-app/main/default/classes/PropertyPdfGeneratorController.cls new file mode 100644 index 0000000..5fe802b --- /dev/null +++ b/force-app/main/default/classes/PropertyPdfGeneratorController.cls @@ -0,0 +1,155 @@ +public with sharing class PropertyPdfGeneratorController { + + public String template { get; set; } + public String propertyData { get; set; } + public String htmlContent { get; set; } + public String pdfId { get; set; } + + // Property data properties + public String propertyName { get; set; } + public String propertyType { get; set; } + public String location { get; set; } + public String price { get; set; } + public String bedrooms { get; set; } + public String bathrooms { get; set; } + public String area { get; set; } + public String editorContent { get; set; } + + public PropertyPdfGeneratorController() { + try { + // Get parameters from URL + this.template = ApexPages.currentPage().getParameters().get('template'); + this.propertyData = ApexPages.currentPage().getParameters().get('propertyData'); + this.htmlContent = ApexPages.currentPage().getParameters().get('htmlContent'); + this.pdfId = ApexPages.currentPage().getParameters().get('pdfId'); + + System.debug('Template: ' + this.template); + System.debug('Property Data: ' + this.propertyData); + System.debug('HTML Content Length: ' + (this.htmlContent != null ? this.htmlContent.length() : 0)); + System.debug('PDF ID: ' + this.pdfId); + + // Parse property data if available + if (String.isNotBlank(this.propertyData)) { + try { + Map dataMap = (Map)JSON.deserializeUntyped(this.propertyData); + this.propertyName = (String)dataMap.get('propertyName'); + this.propertyType = (String)dataMap.get('propertyType'); + this.location = (String)dataMap.get('location'); + this.price = (String)dataMap.get('price'); + this.bedrooms = (String)dataMap.get('bedrooms'); + this.bathrooms = (String)dataMap.get('bathrooms'); + this.area = (String)dataMap.get('area'); + + System.debug('Parsed property data:'); + System.debug('Name: ' + this.propertyName); + System.debug('Type: ' + this.propertyType); + System.debug('Location: ' + this.location); + System.debug('Price: ' + this.price); + System.debug('Bedrooms: ' + this.bedrooms); + System.debug('Bathrooms: ' + this.bathrooms); + System.debug('Area: ' + this.area); + } catch (JSONException e) { + System.debug('Error parsing property data: ' + e.getMessage()); + // Set default values + this.propertyName = 'Property Brochure'; + this.propertyType = 'Property Type'; + this.location = 'Location'; + this.price = 'N/A'; + this.bedrooms = 'N/A'; + this.bathrooms = 'N/A'; + this.area = 'N/A'; + } + } + + // Get editor content if available + if (String.isNotBlank(this.htmlContent)) { + this.editorContent = this.htmlContent; + System.debug('Editor content length: ' + this.editorContent.length()); + } + + } catch (Exception e) { + System.debug('Error in PropertyPdfGeneratorController: ' + e.getMessage()); + System.debug('Stack trace: ' + e.getStackTraceString()); + } + } + + // Generate PDF content + public String getPdfContent() { + try { + System.debug('Generating PDF content...'); + + String content = ''; + + // Add header + content += '
'; + + // Property header + content += '
'; + content += '

' + (String.isNotBlank(propertyName) ? propertyName : 'Property Brochure') + '

'; + content += '

' + (String.isNotBlank(propertyType) ? propertyType : 'Property Type') + ' • ' + (String.isNotBlank(location) ? location : 'Location') + '

'; + content += '
'; + + // Property information grid + content += '
'; + content += '
'; + content += '
Price
'; + content += '
' + (String.isNotBlank(price) ? price : 'N/A') + '
'; + content += '
'; + + content += '
'; + content += '
Bedrooms
'; + content += '
' + (String.isNotBlank(bedrooms) ? bedrooms : 'N/A') + '
'; + content += '
'; + + content += '
'; + content += '
Bathrooms
'; + content += '
' + (String.isNotBlank(bathrooms) ? bathrooms : 'N/A') + '
'; + content += '
'; + + content += '
'; + content += '
Area
'; + content += '
' + (String.isNotBlank(area) ? area : 'N/A') + '
'; + content += '
'; + content += '
'; + + // Property details + content += '
'; + content += '

Property Details

'; + content += '
'; + content += '
Property Type: ' + (String.isNotBlank(propertyType) ? propertyType : 'N/A') + '
'; + content += '
Location: ' + (String.isNotBlank(location) ? location : 'N/A') + '
'; + content += '
Price: ' + (String.isNotBlank(price) ? price : 'N/A') + '
'; + content += '
Bedrooms: ' + (String.isNotBlank(bedrooms) ? bedrooms : 'N/A') + '
'; + content += '
Bathrooms: ' + (String.isNotBlank(bathrooms) ? bathrooms : 'N/A') + '
'; + content += '
Area: ' + (String.isNotBlank(area) ? area : 'N/A') + '
'; + content += '
'; + content += '
'; + + // Content section - simplified to avoid issues + if (String.isNotBlank(editorContent)) { + content += '
'; + content += '

Property Information

'; + content += '
'; + content += 'Property details have been generated successfully.'; + content += '
'; + content += '
'; + } + + // Footer + content += '
'; + content += '

Generated on: ' + Datetime.now().format('MMMM dd, yyyy \'at\' h:mm a') + '

'; + content += '

Property CRM System - Professional Brochure

'; + content += '
'; + + content += '
'; + + System.debug('PDF content generated successfully. Length: ' + content.length()); + return content; + + } catch (Exception e) { + System.debug('Error generating PDF content: ' + e.getMessage()); + System.debug('Stack trace: ' + e.getStackTraceString()); + return '
Error generating PDF content: ' + e.getMessage() + '
'; + } + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/PropertyPdfGeneratorController.cls-meta.xml b/force-app/main/default/classes/PropertyPdfGeneratorController.cls-meta.xml new file mode 100644 index 0000000..90c33fe --- /dev/null +++ b/force-app/main/default/classes/PropertyPdfGeneratorController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 64.0 + Active + \ No newline at end of file diff --git a/force-app/main/default/cspTrustedSites/PDF_API_Trusted_Site.cspTrustedSite-meta.xml b/force-app/main/default/cspTrustedSites/PDF_API_Trusted_Site.cspTrustedSite-meta.xml index 1420abe..03df9f0 100644 --- a/force-app/main/default/cspTrustedSites/PDF_API_Trusted_Site.cspTrustedSite-meta.xml +++ b/force-app/main/default/cspTrustedSites/PDF_API_Trusted_Site.cspTrustedSite-meta.xml @@ -1,7 +1,6 @@ Communities - Lightning PDF Generation API Trusted Site https://salesforce.tech4biz.io true diff --git a/force-app/main/default/data/Property__c.json b/force-app/main/default/data/Property__c.json index 87fc2fd..70b2577 100644 --- a/force-app/main/default/data/Property__c.json +++ b/force-app/main/default/data/Property__c.json @@ -1,42 +1,52 @@ [ - { - "Name": "Luxury Marina View Apartment", - "Property_Type__c": "Apartment", - "Location__c": "Dubai Marina" - }, - { - "Name": "Villa in Emirates Hills", - "Property_Type__c": "Villa", - "Location__c": "Emirates Hills" - }, - { - "Name": "Business Bay Office Space", - "Property_Type__c": "Office", - "Location__c": "Business Bay" - }, - { - "Name": "Downtown Dubai Penthouse", - "Property_Type__c": "Penthouse", - "Location__c": "Downtown Dubai" - }, - { - "Name": "JBR Beachfront Apartment", - "Property_Type__c": "Apartment", - "Location__c": "JBR" - }, - { - "Name": "Palm Jumeirah Villa", - "Property_Type__c": "Villa", - "Location__c": "Palm Jumeirah" - }, - { - "Name": "Dubai Hills Estate Townhouse", - "Property_Type__c": "Townhouse", - "Location__c": "Dubai Hills Estate" - }, - { - "Name": "Arabian Ranches Villa", - "Property_Type__c": "Villa", - "Location__c": "Arabian Ranches" - } + { + "Name": "PR-00001", + "Property_Type__c": "Apartment", + "Location__c": "Downtown Dubai" + }, + { + "Name": "PR-00002", + "Property_Type__c": "Villa", + "Location__c": "Palm Jumeirah" + }, + { + "Name": "PR-00003", + "Property_Type__c": "Penthouse", + "Location__c": "Dubai Marina" + }, + { + "Name": "PR-00004", + "Property_Type__c": "Townhouse", + "Location__c": "JBR" + }, + { + "Name": "PR-00005", + "Property_Type__c": "Office", + "Location__c": "Business Bay" + }, + { + "Name": "PR-00006", + "Property_Type__c": "Retail Space", + "Location__c": "Dubai Hills Estate" + }, + { + "Name": "PR-00007", + "Property_Type__c": "Warehouse", + "Location__c": "Emirates Hills" + }, + { + "Name": "PR-00008", + "Property_Type__c": "Apartment", + "Location__c": "Arabian Ranches" + }, + { + "Name": "PR-00009", + "Property_Type__c": "Villa", + "Location__c": "Meadows" + }, + { + "Name": "PR-00010", + "Property_Type__c": "Penthouse", + "Location__c": "Springs" + } ] \ No newline at end of file diff --git a/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.css b/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.css index 30f8329..4c0e441 100644 --- a/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.css +++ b/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.css @@ -1,34 +1,69 @@ -/* Property Brochure Generator - Main Styles */ + .property-brochure-generator { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - max-width: 1200px; - margin: 0 auto; - background: #ffffff; + background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); min-height: 100vh; + padding: 0; + margin: 0; } -/* Header Styles */ -.header { +/* Header Section */ +.header-section { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 3rem 2rem; text-align: center; - border-radius: 0 0 2rem 2rem; - margin-bottom: 2rem; - box-shadow: 0 10px 30px rgba(0,0,0,0.1); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); } -.header-content h1 { - font-size: 3rem; - margin-bottom: 1rem; +.header-content { + max-width: 1200px; + margin: 0 auto; +} + +/* Beautiful Purple Gradient Header for All Steps */ +.step-header-gradient { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 0 0 20px 20px; + padding: 40px 30px; + margin: -20px -20px 30px -20px; + text-align: center; + box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3); + position: relative; + overflow: hidden; +} + +.step-header-gradient::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%); + pointer-events: none; +} + +.main-title { + color: white; + font-size: 2.5rem; font-weight: 700; - text-shadow: 2px 2px 4px rgba(0,0,0,0.3); + margin: 0 0 10px 0; + text-shadow: 0 2px 10px rgba(0,0,0,0.2); + letter-spacing: 1px; + position: relative; + z-index: 2; } -.header-content p { +.subtitle { + color: white; font-size: 1.2rem; - margin-bottom: 2rem; - opacity: 0.9; + font-weight: 400; + margin: 0; + opacity: 0.95; + text-shadow: 0 1px 5px rgba(0,0,0,0.2); + position: relative; + z-index: 2; } .header-features { @@ -39,59 +74,81 @@ } .feature-badge { - background: rgba(255,255,255,0.2); - padding: 0.5rem 1rem; - border-radius: 2rem; + background: rgba(255, 255, 255, 0.2); + padding: 0.5rem 1.5rem; + border-radius: 25px; font-size: 0.9rem; + font-weight: 500; backdrop-filter: blur(10px); - border: 1px solid rgba(255,255,255,0.3); + border: 1px solid rgba(255, 255, 255, 0.1); +} + +/* Error Message */ +.error-message { + background: #fee; + border: 1px solid #fcc; + color: #c33; + padding: 1rem; + margin: 1rem 2rem; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.error-content { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.error-close { + background: none; + border: none; + color: #c33; + font-size: 1.5rem; + cursor: pointer; + padding: 0; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; } /* Step Navigation */ .step-navigation { display: flex; justify-content: center; - margin-bottom: 3rem; - gap: 1rem; - flex-wrap: wrap; + gap: 2rem; + padding: 2rem; + background: white; + margin: 0 2rem 2rem 2rem; + border-radius: 12px; + box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08); } -.step-item { +.step-nav { display: flex; flex-direction: column; align-items: center; + gap: 0.5rem; cursor: pointer; padding: 1rem; - border-radius: 1rem; + border-radius: 8px; transition: all 0.3s ease; min-width: 120px; } -.step-item:hover { - transform: translateY(-2px); +.step-nav:hover { + background: #f8f9fa; } -.step-item.active { +.step-nav.active { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; - box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4); -} - -.step-item.completed { - background: linear-gradient(135deg, #28a745 0%, #20c997 100%); - color: white; - box-shadow: 0 8px 25px rgba(40, 167, 69, 0.4); -} - -.step-item.accessible { - background: #f8f9fa; - border: 2px solid #dee2e6; - color: #495057; -} - -.step-item.accessible:hover { - background: #e9ecef; - border-color: #667eea; + transform: translateY(-2px); + box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3); } .step-number { @@ -99,39 +156,32 @@ height: 40px; border-radius: 50%; background: #e9ecef; + color: #6c757d; display: flex; align-items: center; justify-content: center; - font-weight: bold; - margin-bottom: 0.5rem; + font-weight: 600; + font-size: 1.1rem; transition: all 0.3s ease; } -.step-item.active .step-number, -.step-item.completed .step-number { - background: rgba(255,255,255,0.3); - color: white; -} - -.step-item.accessible .step-number { - background: #667eea; +.step-nav.active .step-number { + background: rgba(255, 255, 255, 0.2); color: white; } .step-label { font-size: 0.9rem; - text-align: center; font-weight: 500; + text-align: center; } /* Step Content */ .step-content { display: none; - padding: 2rem; - background: white; - border-radius: 1rem; - box-shadow: 0 5px 20px rgba(0,0,0,0.08); - margin-bottom: 2rem; + max-width: 1200px; + margin: 0 auto 2rem auto; + padding: 0 2rem; } .step-content.active { @@ -152,113 +202,271 @@ .step-header { text-align: center; - margin-bottom: 2rem; + margin-bottom: 3rem; } .step-header h2 { - font-size: 2rem; + font-size: 2.5rem; + font-weight: 300; + margin: 0 0 1rem 0; color: #2c3e50; - margin-bottom: 0.5rem; } .step-header p { + font-size: 1.2rem; color: #6c757d; - font-size: 1.1rem; + margin: 0; } -/* Template Grid - Sophisticated Layout */ +/* Template Grid - Enhanced styling */ .template-grid { display: grid; - grid-template-columns: 1fr 1fr 1fr; - grid-template-rows: auto auto auto; - gap: 1.5rem; - margin-top: 2rem; - max-width: 1200px; - margin-left: auto; - margin-right: auto; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 25px; + padding: 30px; + max-width: 1400px; + margin: 0 auto; } -/* Template Cards - Different Sizes and Styles */ +/* Template Cards - Enhanced with shadows and different paddings */ .template-card { background: white; - border-radius: 1rem; - padding: 2rem; + border-radius: 12px; + padding: 25px; cursor: pointer; transition: all 0.3s ease; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); - border: 2px solid transparent; position: relative; + border: 2px solid transparent; + box-shadow: 0 4px 15px rgba(0,0,0,0.08); overflow: hidden; } .template-card:hover { - transform: translateY(-4px); - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15); + transform: translateY(-8px); + box-shadow: 0 12px 30px rgba(0,0,0,0.15); border-color: #667eea; } -/* Custom Template - Small Card */ +.template-card.selected { + border-color: #667eea; + box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3); + transform: translateY(-5px); +} + +/* Template Heights with different paddings */ +.template-tall { + min-height: 500px; + padding: 35px 30px; +} + +.template-medium { + min-height: 300px; + padding: 25px 20px; +} + +.template-small { + min-height: 250px; + padding: 20px 15px; +} + +/* Template-specific styling - Exact colors from image with enhanced shadows */ +.template-everkind { + background: #f8f9fa; + border: 1px solid #e9ecef; + box-shadow: 0 6px 20px rgba(0,0,0,0.1); + padding: 40px 30px; +} + +.template-shift { + background: #e8f4fd; + border: 1px solid #d1ecf1; + box-shadow: 0 8px 25px rgba(0,0,0,0.12); + padding: 35px 25px; +} + +.template-saintbarts { + background: #fff5f5; + border: 1px solid #fed7d7; + box-shadow: 0 7px 22px rgba(0,0,0,0.11); + padding: 38px 28px; +} + +.template-learnoy { + background: #f0fff4; + border: 1px solid #c6f6d5; + box-shadow: 0 5px 18px rgba(0,0,0,0.09); + padding: 30px 22px; +} + +.template-leafamp { + background: #faf5ff; + border: 1px solid #e9d8fd; + box-shadow: 0 6px 20px rgba(0,0,0,0.1); + padding: 32px 24px; +} + +.template-coreshift { + background: #fffaf0; + border: 1px solid #feebc8; + box-shadow: 0 7px 22px rgba(0,0,0,0.11); + padding: 28px 20px; +} + +/* Blank Template - Black theme */ .template-blank { - grid-row: 1 / 2; - grid-column: 1 / 2; - background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); - border: 2px dashed #dee2e6; - text-align: center; - padding: 1.5rem; -} - -.template-blank:hover { - border-color: #667eea; - background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%); -} - -/* Professional 1-Pager - Full Height */ -.template-modern { - grid-row: 1 / 3; - grid-column: 2 / 3; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: #2c3e50; + border: 1px solid #34495e; + box-shadow: 0 8px 25px rgba(0,0,0,0.2); + padding: 30px 25px; color: white; } -/* Professional 3-Pager - Full Height */ -.template-classic { - grid-row: 1 / 3; - grid-column: 3 / 4; - background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); +.template-blank .newsletter-style { color: white; } -/* Professional 5-Pager - Half Height */ -.template-minimalist { - grid-row: 2 / 3; - grid-column: 1 / 2; - background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); - color: white; +.template-blank .newsletter-header h2 { + color: #ecf0f1; } -/* Luxury Villa - Half Height */ -.template-professional { - grid-row: 2 / 3; - grid-column: 2 / 3; - background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); - color: white; +.template-blank .newsletter-main h1 { + color: #bdc3c7; } -/* Dubai Penthouse - Half Height */ -.template-creative { - grid-row: 2 / 3; - grid-column: 3 / 4; - background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); - color: white; +.template-blank .newsletter-section h4 { + color: #ecf0f1; } -/* Modern Apartment - Full Width */ -.template-corporate { - grid-row: 3 / 4; - grid-column: 1 / 4; - background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%); +.template-blank .newsletter-section p { + color: #bdc3c7; +} + +/* Newsletter Style Templates */ +.newsletter-style { + padding: 30px; + font-family: 'Georgia', 'Times New Roman', serif; + color: #2c3e50; + background: white; +} + +.newsletter-header h2 { + font-size: 1.8rem; + font-weight: 700; + margin: 0 0 20px 0; + color: #34495e; + text-transform: uppercase; + letter-spacing: 2px; +} + +.newsletter-main h1 { + font-size: 2.2rem; + font-weight: 300; + margin: 0 0 15px 0; + color: #2c3e50; + line-height: 1.2; +} + +.newsletter-main h3 { + font-size: 1.4rem; + font-weight: 400; + margin: 0 0 25px 0; + color: #7f8c8d; + letter-spacing: 1px; +} + +.newsletter-main .main-text { + font-size: 1.3rem; + font-weight: 400; + margin: 0 0 20px 0; + color: #2c3e50; + line-height: 1.4; +} + +.newsletter-section { + margin-bottom: 25px; +} + +.newsletter-section h4 { + font-size: 1.1rem; + font-weight: 600; + margin: 0 0 12px 0; + color: #34495e; + text-transform: uppercase; + letter-spacing: 1px; +} + +.newsletter-section p { + font-size: 0.95rem; + font-weight: 400; + margin: 0 0 15px 0; + color: #5a6c7d; + line-height: 1.5; +} + +.newsletter-section h5 { + font-size: 1rem; + font-weight: 500; + margin: 0 0 10px 0; + color: #2c3e50; + line-height: 1.3; +} + +/* Call-to-Action Buttons */ +.cta-buttons { + display: flex; + gap: 12px; + flex-wrap: wrap; + margin-top: 15px; +} + +.cta-btn { + background: #2c3e50; color: white; - text-align: center; + border: none; + padding: 10px 16px; + border-radius: 4px; + font-size: 0.85rem; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.cta-btn:hover { + background: #34495e; + transform: translateY(-1px); +} + +/* Episode Sections */ +.episode { + margin-bottom: 20px; + padding: 15px; + background: #f8f9fa; + border-radius: 6px; + border-left: 3px solid #3498db; +} + +.episode h5 { + margin-bottom: 12px; +} + +/* Destinations */ +.destinations { + display: flex; + gap: 15px; + margin-top: 10px; +} + +.destination { + background: #ecf0f1; + color: #2c3e50; + padding: 8px 16px; + border-radius: 20px; + font-size: 0.9rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; } /* Template Content */ @@ -266,387 +474,84 @@ height: 100%; display: flex; flex-direction: column; - justify-content: center; + justify-content: space-between; +} + +.template-icon { + font-size: 3rem; + text-align: center; + margin-bottom: 1rem; } .template-content h3 { - font-size: 1.5rem; - font-weight: 700; - margin: 0 0 0.5rem 0; + font-size: 1.8rem; + font-weight: 600; + margin: 0 0 1rem 0; line-height: 1.2; + text-align: center; } .template-content p { - font-size: 0.9rem; - margin: 0; + font-size: 1rem; + margin: 0 0 1.5rem 0; opacity: 0.9; - line-height: 1.4; + line-height: 1.5; + text-align: center; + flex-grow: 1; } -/* Blank Template Special Styling */ -.template-blank .template-content h3 { - color: #495057; - font-size: 1.3rem; +.template-meta { + display: flex; + justify-content: center; + gap: 0.5rem; + flex-wrap: wrap; } -.template-blank .template-content p { - color: #6c757d; - font-size: 0.85rem; +.category, .style { + background: rgba(255, 255, 255, 0.2); + padding: 0.3rem 0.8rem; + border-radius: 15px; + font-size: 0.8rem; + font-weight: 500; + backdrop-filter: blur(10px); } -/* Corporate Template Special Styling */ -.template-corporate .template-content h3 { - font-size: 2rem; - color: white; -} - -.template-corporate .template-content p { - font-size: 1.1rem; - color: rgba(255, 255, 255, 0.9); -} - -/* Selected Template Indicator */ +/* Selected Indicator - Enhanced positioning */ .selected-indicator { position: absolute; - top: 1rem; - right: 1rem; - background: rgba(255, 255, 255, 0.95); - color: #28a745; - padding: 0.5rem 1rem; - border-radius: 2rem; - font-size: 0.8rem; + top: 20px; + right: 20px; + background: #667eea; + color: white; + padding: 10px 15px; + border-radius: 25px; + font-size: 0.85rem; font-weight: 600; display: flex; align-items: center; - gap: 0.5rem; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); - animation: slideInRight 0.3s ease; + gap: 6px; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); + z-index: 100; + opacity: 1; + visibility: visible; + backdrop-filter: blur(10px); } .selected-icon { - font-size: 1rem; - font-weight: bold; + font-size: 1.1rem; + color: white; } .selected-text { + color: white; font-weight: 600; } -/* Responsive Design */ -@media (max-width: 1024px) { - .template-grid { - grid-template-columns: 1fr 1fr; - grid-template-rows: auto auto auto auto; - } - - .template-corporate { - grid-column: 1 / 3; - } -} - -@media (max-width: 768px) { - .template-grid { - grid-template-columns: 1fr; - grid-template-rows: auto; - gap: 1rem; - } - - .template-modern, - .template-classic, - .template-corporate { - grid-column: 1 / 2; - } - - .template-card { - padding: 1.5rem; - } -} - -/* Property Selector */ -.property-selector { - background: #f8f9fa; - padding: 2rem; - border-radius: 1rem; - margin-bottom: 2rem; - border: 1px solid #dee2e6; - text-align: center; -} - -.property-selector h3 { - color: #2c3e50; - margin-bottom: 1rem; - font-size: 1.3rem; -} - -.property-selector-controls { +/* Ensure selected state is visible */ +.template-card.selected .selected-indicator { + opacity: 1; + visibility: visible; display: flex; - gap: 1rem; - align-items: center; - margin-bottom: 1rem; - justify-content: center; -} - -.property-selector-controls select { - flex: 1; - max-width: 500px; - padding: 0.75rem; - border: 2px solid #dee2e6; - border-radius: 0.5rem; - font-size: 1rem; - transition: border-color 0.3s ease; -} - -.property-selector-controls select:focus { - outline: none; - border-color: #667eea; -} - -.btn-sm { - padding: 0.5rem 1rem; - font-size: 0.9rem; -} - -/* Form Grid */ -.form-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); - gap: 1.5rem; - margin-bottom: 2rem; - justify-items: center; -} - -.form-group.full-width { - grid-column: 1 / -1; - width: 100%; - max-width: 800px; -} - -.form-group { - width: 100%; - max-width: 300px; -} - -.form-group label { - display: block; - margin-bottom: 0.5rem; - color: #2c3e50; - font-weight: 500; - text-align: center; -} - -.form-group input, -.form-group select, -.form-group textarea { - width: 100%; - padding: 0.75rem; - border: 2px solid #dee2e6; - border-radius: 0.5rem; - font-size: 1rem; - transition: border-color 0.3s ease; - font-family: inherit; - text-align: center; -} - -.form-group input:focus, -.form-group select:focus, -.form-group textarea:focus { - outline: none; - border-color: #667eea; -} - -.form-group textarea { - resize: vertical; - min-height: 100px; -} - -/* Form Sections */ -.form-section { - background: #f8f9fa; - padding: 2rem; - border-radius: 1rem; - margin-bottom: 2rem; - border: 1px solid #dee2e6; - text-align: center; -} - -.form-section h3 { - color: #2c3e50; - margin-bottom: 1.5rem; - font-size: 1.3rem; -} - -/* Image Upload */ -.image-upload-section { - text-align: center; - padding: 2rem; - border: 2px dashed #dee2e6; - border-radius: 1rem; - margin-bottom: 1.5rem; - transition: border-color 0.3s ease; -} - -.image-upload-section:hover { - border-color: #667eea; -} - -.image-upload-section input[type="file"] { - display: none; -} - -.upload-btn { - background: #667eea; - color: white; - padding: 1rem 2rem; - border-radius: 0.5rem; - cursor: pointer; - display: inline-block; - transition: background 0.3s ease; -} - -.upload-btn:hover { - background: #5a6fd8; -} - -.uploaded-images { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1rem; - justify-items: center; -} - -.image-item { - background: white; - padding: 1rem; - border-radius: 0.5rem; - border: 1px solid #dee2e6; - text-align: center; - width: 100%; - max-width: 250px; -} - -.image-item img { - width: 100%; - height: 150px; - object-fit: cover; - border-radius: 0.5rem; - margin-bottom: 0.5rem; -} - -.image-item input { - width: 100%; - margin-bottom: 0.5rem; -} - -.remove-btn { - background: #dc3545; - color: white; - border: none; - padding: 0.5rem 1rem; - border-radius: 0.5rem; - cursor: pointer; - font-size: 0.9rem; -} - -/* Amenities Grid */ -.amenities-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1rem; - justify-items: center; -} - -.amenity-checkbox { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0.75rem; - background: white; - border-radius: 0.5rem; - border: 1px solid #dee2e6; - cursor: pointer; - transition: border-color 0.3s ease; - width: 100%; - max-width: 250px; -} - -.amenity-checkbox:hover { - border-color: #667eea; -} - -.amenity-checkbox input[type="checkbox"] { - width: auto; - margin: 0; -} - -/* Customization Grid */ -.customization-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1.5rem; - justify-items: center; -} - -/* Preview Section */ -.preview-section { - background: #f8f9fa; - padding: 2rem; - border-radius: 1rem; - margin-bottom: 2rem; - border: 1px solid #dee2e6; - text-align: center; -} - -.preview-content h3 { - color: #2c3e50; - margin-bottom: 1.5rem; - font-size: 1.3rem; -} - -.summary-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1rem; - margin-bottom: 2rem; - justify-items: center; -} - -.summary-item { - background: white; - padding: 1rem; - border-radius: 0.5rem; - border: 1px solid #dee2e6; - width: 100%; - max-width: 250px; -} - -.preview-actions { - text-align: center; -} - -/* Download Section */ -.download-section { - text-align: center; - padding: 3rem 2rem; -} - -.success-message { - margin-bottom: 2rem; -} - -.success-message svg { - color: #28a745; - margin-bottom: 1rem; -} - -.success-message h3 { - color: #2c3e50; - margin-bottom: 1rem; - font-size: 1.5rem; -} - -.success-message p { - color: #6c757d; - font-size: 1.1rem; } /* Step Actions */ @@ -657,71 +562,20 @@ margin-top: 2rem; } -/* Special button styling for steps 4 and 5 */ -.step-content[data-step="4"] .step-actions, -.step-content[data-step="5"] .step-actions { - justify-content: center; - gap: 1.5rem; - margin-top: 3rem; - padding: 2rem 0; -} - -.step-content[data-step="4"] .step-actions .btn, -.step-content[data-step="5"] .step-actions .btn { - min-width: 150px; - padding: 1rem 2rem; - font-size: 1.1rem; -} - -/* Preview Actions */ -.preview-actions { - text-align: center; - margin: 2rem 0; -} - -.preview-actions .btn { - min-width: 200px; - padding: 1rem 2.5rem; - font-size: 1.2rem; -} - -/* Download Actions */ -.download-actions { - text-align: center; - margin: 2rem 0; - display: flex; - flex-direction: column; - align-items: center; - gap: 1.5rem; -} - -.download-actions .btn { - min-width: 200px; - padding: 1rem 2.5rem; - font-size: 1.2rem; -} - -.download-actions .btn-success { - order: 1; -} - -.download-actions .btn-secondary { - order: 2; -} - -/* Buttons */ .btn { - padding: 0.75rem 1.5rem; + padding: 1rem 2rem; border: none; - border-radius: 0.5rem; + border-radius: 8px; font-size: 1rem; font-weight: 500; cursor: pointer; transition: all 0.3s ease; + display: flex; + align-items: center; + gap: 0.5rem; text-decoration: none; - display: inline-block; - text-align: center; - min-width: 120px; + min-width: 140px; + justify-content: center; } .btn-primary { @@ -737,6 +591,7 @@ .btn-primary:disabled { opacity: 0.6; cursor: not-allowed; + transform: none; } .btn-secondary { @@ -746,310 +601,1178 @@ .btn-secondary:hover { background: #5a6268; + transform: translateY(-2px); } -.btn-success { - background: #28a745; - color: white; -} - -.btn-success:hover:not(:disabled) { - background: #218838; -} - -.btn-success:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.btn-large { - padding: 1rem 2rem; +.btn-icon { font-size: 1.1rem; + transition: transform 0.3s ease; } -/* Responsive Design */ -@media (max-width: 768px) { - .header-content h1 { - font-size: 2rem; - } - - .step-navigation { - flex-direction: column; - align-items: center; - } - - .step-item { - min-width: 100px; - } - - .template-grid { - grid-template-columns: 1fr; - } - - .form-grid { - grid-template-columns: 1fr; - } - - .step-actions { - flex-direction: column; - align-items: center; - } - - .btn { - width: 100%; - max-width: 300px; - } - - .template-card { - max-width: 100%; - } +.btn:hover .btn-icon { + transform: translateX(2px); } -/* Loading States */ -.loading { - opacity: 0.6; - pointer-events: none; +.btn-secondary:hover .btn-icon { + transform: translateX(-2px); } -/* Error States */ -.error { - border-color: #dc3545 !important; +/* Step 2 Content */ +.step2-content { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 3rem; + margin-bottom: 2rem; } -.error-message { - color: #dc3545; - font-size: 0.9rem; - margin-top: 0.25rem; +.property-section, .market-analysis-section { + background: white; + padding: 2rem; + border-radius: 12px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); } -/* Success States */ -.success { - border-color: #28a745 !important; +.property-section h3, .market-analysis-section h3 { + font-size: 1.5rem; + font-weight: 600; + margin: 0 0 1rem 0; + color: #2c3e50; } -/* Animations */ -.fade-in { - animation: fadeIn 0.5s ease; +.property-dropdown { + width: 100%; + padding: 1rem; + border: 2px solid #e9ecef; + border-radius: 8px; + font-size: 1rem; + background: white; + transition: border-color 0.3s ease; } -@keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } +.property-dropdown:focus { + outline: none; + border-color: #667eea; } -.slide-in { - animation: slideIn 0.5s ease; +/* Property Details Display */ +.property-details-display { + margin-top: 1.5rem; + padding-top: 1.5rem; + border-top: 1px solid #e9ecef; } -@keyframes slideIn { - from { transform: translateX(-20px); opacity: 0; } - to { transform: translateX(0); opacity: 1; } +.property-details-display h4 { + font-size: 1.2rem; + font-weight: 600; + margin: 0 0 1rem 0; + color: #2c3e50; } -/* Error Message */ -.error-message { - background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%); - color: white; - margin: 1rem auto; - max-width: 800px; - border-radius: 1rem; - box-shadow: 0 8px 25px rgba(255, 107, 107, 0.4); - animation: slideInDown 0.3s ease; -} - -.error-content { - display: flex; - align-items: center; - padding: 1rem 1.5rem; +.property-grid { + display: grid; + grid-template-columns: 1fr 1fr; gap: 1rem; } -.error-icon { - font-size: 1.5rem; - flex-shrink: 0; +.property-item { + display: flex; + flex-direction: column; + gap: 0.3rem; } -.error-text { - flex: 1; +.property-item .label { + font-size: 0.9rem; + color: #6c757d; + font-weight: 500; + } + +.property-item .value { + font-size: 1rem; + color: #2c3e50; font-weight: 500; } -.error-close { - background: rgba(255, 255, 255, 0.2); - border: none; - color: white; - width: 2rem; - height: 2rem; - border-radius: 50%; - cursor: pointer; - font-size: 1.2rem; - font-weight: bold; - transition: all 0.3s ease; - flex-shrink: 0; +/* Market Analysis Options */ +.market-analysis-section p { + color: #6c757d; + margin-bottom: 1.5rem; + } + +.market-options { + display: flex; + flex-direction: column; + gap: 1rem; } -.error-close:hover { - background: rgba(255, 255, 255, 0.3); +.checkbox-item { + display: flex; + align-items: center; + gap: 0.8rem; + cursor: pointer; + padding: 0.5rem; + border-radius: 6px; + transition: background-color 0.3s ease; +} + +.checkbox-item:hover { + background: #f8f9fa; +} + +.checkbox-item input[type="checkbox"] { + display: none; +} + +.checkmark { + width: 20px; + height: 20px; + border: 2px solid #dee2e6; + border-radius: 4px; + position: relative; + transition: all 0.3s ease; +} + +.checkbox-item input[type="checkbox"]:checked + .checkmark { + background: #667eea; + border-color: #667eea; +} + +.checkbox-item input[type="checkbox"]:checked + .checkmark::after { + content: 'āœ“'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: white; + font-size: 14px; + font-weight: bold; +} + +.label-text { + font-size: 1rem; + color: #2c3e50; + font-weight: 500; +} + +/* Editor Container */ +.editor-container { + display: flex; + height: calc(100vh - 200px); + background: #f8f9fa; + margin: 20px; + border-radius: 15px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1); + overflow: hidden; +} + +/* Left Toolbar - Fixed positioning */ +.editor-toolbar.left { + width: 300px; + background: white; + border-right: 1px solid #e9ecef; + padding: 20px; + overflow: visible; /* Remove scrollbar */ + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.05); + position: relative; + flex-shrink: 0; /* Prevent shrinking */ +} + +/* Toolbar Sections - Compact layout */ +.toolbar-section { + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 1px solid #f0f0f0; +} + +.toolbar-section:last-child { + border-bottom: none; + margin-bottom: 0; +} + +.toolbar-section-title { + font-size: 11px; + font-weight: 600; + color: #667eea; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 12px; + padding: 6px 10px; + background: #f8f9fa; + border-radius: 6px; + border-left: 3px solid #667eea; +} + +.toolbar-group { + margin-bottom: 12px; +} + +.toolbar-group:last-child { + margin-bottom: 0; +} + +.toolbar-group label { + display: block; + font-size: 10px; + font-weight: 500; + color: #555; + margin-bottom: 6px; + text-transform: uppercase; + letter-spacing: 0.3px; +} + +.toolbar-group select { + width: 100%; + padding: 6px 10px; + border: 1px solid #ddd; + border-radius: 6px; + font-size: 11px; + background: white; + color: #333; + transition: border-color 0.2s ease; +} + +.toolbar-group select:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1); +} + +.toolbar-group input[type="color"] { + width: 100%; + height: 35px; + border: 1px solid #ddd; + border-radius: 6px; + cursor: pointer; + transition: border-color 0.2s ease; +} + +.toolbar-group input[type="color"]:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1); +} + +/* Button Grid - Compact layout */ +.button-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 6px; +} + +.button-grid-4 { + grid-template-columns: 1fr 1fr 1fr 1fr; +} + +/* Toolbar Buttons - Compact size */ +.toolbar-button { + background: white; + border: 1px solid #e9ecef; + padding: 8px 10px; + border-radius: 6px; + font-size: 10px; + font-weight: 500; + color: #555; + cursor: pointer; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; + gap: 4px; + text-transform: uppercase; + letter-spacing: 0.3px; + min-height: 32px; +} + +.toolbar-button:hover { + background: #667eea; + color: white; + border-color: #667eea; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); +} + +.toolbar-button:active { + transform: translateY(0); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); +} + +.toolbar-button lightning-icon { + --sds-c-icon-color-foreground-default: currentColor; +} + +/* Editor Content Area - Fixed margins */ +.editor-content-area { + flex: 1; + background: white; + position: relative; + overflow: hidden; + margin-left: 20px; /* Fixed margin from toolbar */ + margin-right: 20px; /* Fixed margin from right side */ +} + +.preview-frame { + width: 100%; + height: 100%; + padding: 40px; + overflow-y: auto; + background: white; + border: none; + outline: none; + font-family: Arial, sans-serif; + line-height: 1.6; + margin-left: 10px; /* Additional spacing from toolbar */ + margin-right: 10px; /* Additional spacing from right side */ +} + +.preview-frame::-webkit-scrollbar { + width: 8px; +} + +.preview-frame::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 4px; +} + +.preview-frame::-webkit-scrollbar-thumb { + background: #c1c1c1; + border-radius: 4px; +} + +.preview-frame::-webkit-scrollbar-thumb:hover { + background: #a8a8a8; +} + +/* Export PDF Button */ +.export-pdf-section { + position: absolute; + top: 20px; + right: 20px; + z-index: 10; +} + +.export-pdf-btn { + background: linear-gradient(135deg, #667eea, #764ba2); + color: white; + border: none; + padding: 12px 24px; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); + text-transform: uppercase; + font-size: 14px; + transition: all 0.3s ease; + } + +.export-pdf-btn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4); + } + +.export-pdf-btn:active { + transform: translateY(0); + } + +/* Progress Bar for PDF Generation */ +.progress-bar { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + } + +.progress-content { + background: white; + padding: 40px; + border-radius: 15px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); + text-align: center; + max-width: 400px; + width: 90%; +} + +.progress-spinner { + width: 60px; + height: 60px; + border: 4px solid #f3f3f3; + border-top: 4px solid #667eea; + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto 20px; +} + +.progress-text { + font-size: 18px; + font-weight: 600; + color: #333; + margin-bottom: 20px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Progress bar animation */ +.progress-bar .progress-content { + animation: slideIn 0.3s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Hide header in step 3 */ +.step-3 .step-header { + display: none; +} + +/* Page Management */ +.page-container { + margin-bottom: 30px; + border: 2px solid #e0e0e0; + border-radius: 8px; + background: white; + position: relative; + overflow: visible; +} + +.page-header { + background: #f8f9fa; + padding: 15px 20px; + border-bottom: 2px solid #e0e0e0; + border-radius: 6px 6px 0 0; + display: flex; + align-items: center; + justify-content: space-between; +} + +.page-title { + font-size: 1.1rem; + font-weight: 600; + color: #495057; + margin: 0; +} + +.page-number { + background: #6f42c1; + color: white; + padding: 4px 12px; + border-radius: 20px; + font-size: 0.8rem; + font-weight: 600; +} + +.page-content { + padding: 20px; + min-height: 400px; + overflow: visible; +} + +.page-content[contenteditable="true"] { + outline: none; + cursor: text; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + line-height: 1.6; + color: #333; +} + +.page-content[contenteditable="true"]:focus { + border: 2px solid #6f42c1; + border-radius: 6px; +} + +/* Page Navigation */ +.page-navigation { + display: none; +} + +/* Custom Popup Styling */ +.custom-popup { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + backdrop-filter: blur(4px); +} + +.custom-popup-content { + background: white; + border-radius: 12px; + padding: 30px; + max-width: 500px; + width: 90%; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2); + position: relative; + border: 1px solid #e0e0e0; +} + +.custom-popup-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 2px solid #6f42c1; +} + +.custom-popup-title { + font-size: 1.5rem; + font-weight: 600; + color: #2c3e50; + margin: 0; +} + +.custom-popup-close { + background: #6f42c1; + color: white; + border: none; + width: 32px; + height: 32px; + border-radius: 50%; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.2rem; + transition: all 0.2s ease; +} + +.custom-popup-close:hover { + background: #8e44ad; transform: scale(1.1); } -@keyframes slideInDown { +.custom-popup-body { + margin-bottom: 25px; +} + +.custom-popup-footer { + display: flex; + gap: 12px; + justify-content: flex-end; +} + +.custom-popup-btn { + padding: 10px 20px; + border-radius: 6px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + border: none; + font-size: 0.9rem; +} + +.custom-popup-btn-primary { + background: #6f42c1; + color: white; +} + +.custom-popup-btn-primary:hover { + background: #8e44ad; + transform: translateY(-1px); +} + +.custom-popup-btn-secondary { + background: #f8f9fa; + color: #495057; + border: 1px solid #d0d0d0; +} + +.custom-popup-btn-secondary:hover { + background: #e9ecef; +} + +/* Success/Error Notifications */ +.notification { + position: fixed; + top: 20px; + right: 20px; + padding: 15px 20px; + border-radius: 8px; + color: white; + font-weight: 500; + z-index: 10001; + animation: slideInRight 0.3s ease; + max-width: 350px; +} + +.notification.success { + background: linear-gradient(135deg, #28a745 0%, #20c997 100%); + box-shadow: 0 4px 12px rgba(40, 167, 69, 0.3); +} + +.notification.error { + background: linear-gradient(135deg, #dc3545 0%, #e74c3c 100%); + box-shadow: 0 4px 12px rgba(220, 53, 69, 0.3); +} + +@keyframes slideInRight { from { - transform: translateY(-100%); + transform: translateX(100%); opacity: 0; - } +} to { - transform: translateY(0); + transform: translateX(0); opacity: 1; } } +/* Loading Spinner */ +.loading-spinner { + width: 16px; + height: 16px; + border: 2px solid #ffffff; + border-top: 2px solid transparent; + border-radius: 50%; + animation: spin 1s linear infinite; + display: inline-block; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Header and Footer Edit Buttons */ +.header-section, .footer-section { + position: relative; +} + +.header-section .edit-btn, .footer-section .edit-btn { + position: absolute; + top: 10px; + right: 10px; + background: rgba(255,255,255,0.2); + padding: 5px 10px; + border-radius: 15px; + font-size: 0.8rem; + cursor: pointer; + color: white; + border: none; + transition: background 0.2s ease; +} + +.header-section .edit-btn:hover, .footer-section .edit-btn:hover { + background: rgba(255,255,255,0.3); +} + /* Property Details Grid */ .property-details-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); - gap: 2rem; - margin-top: 2rem; + grid-template-columns: 1fr 1fr; + gap: 20px; + margin-bottom: 30px; } -.property-card { - background: white; - border-radius: 1rem; - padding: 2rem; - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); - border: 1px solid #e9ecef; +.property-detail-item { + background: #f8f9fa; + padding: 15px; + border-radius: 8px; + border-left: 4px solid #667eea; + transition: transform 0.2s ease, box-shadow 0.2s ease; } -.property-header { - margin-bottom: 1.5rem; - padding-bottom: 1rem; - border-bottom: 2px solid #667eea; +.property-detail-item:hover { + transform: translateY(-2px); + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.2); } -.property-header h3 { +.property-detail-label { + font-weight: 600; color: #667eea; - margin: 0; - font-size: 1.3rem; - font-weight: 600; -} - -.property-info { - display: flex; - flex-direction: column; - gap: 1rem; -} - -.info-row { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.info-row label { - font-weight: 600; - color: #495057; + margin-bottom: 5px; font-size: 0.9rem; } -.info-row input, -.info-row select, -.info-row textarea { - padding: 0.75rem; - border: 2px solid #e9ecef; - border-radius: 0.5rem; - font-size: 1rem; - transition: all 0.3s ease; +.property-detail-value { + font-size: 1.1rem; + color: #2c3e50; } -.info-row input:focus, -.info-row select:focus, -.info-row textarea:focus { +/* Template-specific sections */ +.template-section { + background: #f8f9fa; + padding: 20px; + border-radius: 8px; + margin-bottom: 30px; + border-left: 4px solid #667eea; +} + +.template-section h3 { + color: #2c3e50; + margin-top: 0; + font-size: 1.3rem; +} + +.template-section ul { + color: #495057; + margin: 0; + padding-left: 20px; +} + +.template-section li { + margin-bottom: 8px; + line-height: 1.4; +} + +/* Editable content areas */ +.editable-area { + background: #f8f9fa; + padding: 20px; + border-radius: 8px; + margin-bottom: 30px; + border: 2px dashed #dee2e6; + transition: border-color 0.2s ease; +} + +.editable-area:hover { + border-color: #667eea; +} + +.editable-area h3 { + color: #6c757d; + margin-top: 0; + font-size: 1.3rem; +} + +.editable-area p { + color: #6c757d; + font-style: italic; + margin: 0; +} + +/* Responsive Toolbar */ +@media (max-width: 1200px) { + .editor-toolbar { + flex-direction: column; + align-items: stretch; +} + + .toolbar-group { + justify-content: center; + flex-wrap: wrap; + } +} + +@media (max-width: 768px) { + .toolbar-group { + flex-direction: column; + align-items: stretch; +} + + .toolbar-btn { + width: 100%; + justify-content: center; +} +} + +@media (max-width: 768px) { + .step-header-gradient { + padding: 30px 20px; + margin: -15px -15px 25px -15px; + } + + .main-title { + font-size: 2rem; + } + + .subtitle { + font-size: 1rem; +} + + .step-navigation { + flex-direction: column; + gap: 1rem; + margin: 0 1rem 1rem 1rem; +} + + .step2-content { + grid-template-columns: 1fr; + gap: 2rem; + } + + .template-grid { + grid-template-columns: 1fr; + gap: 1.5rem; +} + + .step-content { + padding: 0 1rem; + } + + .header-section { + padding: 2rem 1rem; +} +} + +@media (max-width: 480px) { + .main-title { + font-size: 2rem; + } + + .subtitle { + font-size: 1.1rem; +} + + .header-features { + flex-direction: column; + align-items: center; +} + + .btn { + padding: 0.8rem 1.5rem; + font-size: 0.9rem; +} +} + +/* PDF Preview Popup */ +.pdf-preview-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); + z-index: 10000; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; +} + +.pdf-preview-popup { + background: white; + border-radius: 12px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + max-width: 90%; + max-height: 90%; + width: 800px; + display: flex; + flex-direction: column; + overflow: hidden; +} + +.pdf-preview-header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 20px 30px; + display: flex; + justify-content: space-between; + align-items: center; + border-radius: 12px 12px 0 0; +} + +.pdf-preview-header h3 { + margin: 0; + font-size: 1.5rem; + font-weight: 600; +} + +.close-btn { + background: none; + border: none; + color: white; + font-size: 1.5rem; + cursor: pointer; + padding: 5px; + border-radius: 50%; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.2s ease; +} + +.close-btn:hover { + background: rgba(255, 255, 255, 0.2); +} + +.pdf-preview-content { + flex: 1; + padding: 30px; + overflow-y: auto; + max-height: 500px; +} + +.pdf-preview-content .preview-frame { + border: 2px solid #dee2e6; + border-radius: 8px; + padding: 20px; + background: white; + min-height: 400px; +} + +.pdf-preview-actions { + padding: 20px 30px; + background: #f8f9fa; + border-top: 1px solid #dee2e6; + display: flex; + gap: 15px; + justify-content: flex-end; + border-radius: 0 0 12px 12px; +} + +.pdf-preview-actions .export-pdf-btn { + position: static !important; + top: auto !important; + right: auto !important; +} + +/* Page Navigation Buttons in Toolbar */ +.page-nav-btn { + background: #f8f9fa; + border: 1px solid #d0d0d0; + color: #495057; + width: 35px; + height: 35px; + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.9rem; + font-weight: 600; + transition: all 0.2s ease; +} + +.page-nav-btn:hover { + background: #6f42c1; + color: white; + border-color: #6f42c1; + transform: translateY(-1px); +} + +.page-nav-btn.active { + background: #6f42c1; + color: white; + border-color: #6f42c1; + box-shadow: 0 2px 8px rgba(111, 66, 193, 0.3); +} + +/* Active page styling */ +.active-page { + display: block !important; +} + +.page-container:not(.active-page) { + display: none; +} + +/* Enhanced Dropdown Styling for Step 2 */ +.property-selector { + margin: 20px 0; +} + +.property-selector label { + display: block; + margin-bottom: 8px; + font-weight: 600; + color: #333; +} + +.property-selector select { + width: 100%; + padding: 12px; + border: 2px solid #e0e0e0; + border-radius: 8px; + font-size: 16px; + background: white; + transition: border-color 0.3s ease; +} + +.property-selector select:focus { outline: none; border-color: #667eea; box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } -.info-row textarea { - resize: vertical; - min-height: 80px; +.property-selector select option { + padding: 8px; } -/* Generate PDF Button */ -.generate-pdf-btn { - position: absolute; - top: 2rem; - right: 2rem; - background: linear-gradient(135deg, #28a745 0%, #20c997 100%); - border: none; - color: white; - padding: 1rem 2rem; - border-radius: 2rem; - font-size: 1.1rem; - font-weight: 600; - cursor: pointer; - transition: all 0.3s ease; - box-shadow: 0 8px 25px rgba(40, 167, 69, 0.3); -} - -.generate-pdf-btn:hover { - transform: translateY(-2px); - box-shadow: 0 12px 35px rgba(40, 167, 69, 0.4); -} - -/* Template Configuration */ -.template-config-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); - gap: 2rem; - margin-top: 2rem; -} - -.config-section { - background: white; - border-radius: 1rem; - padding: 2rem; - box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); +/* Enhanced Property Details Display */ +.property-details { + background: #f8f9fa; border: 1px solid #e9ecef; + border-radius: 12px; + padding: 25px; + margin-top: 20px; + box-shadow: 0 2px 10px rgba(0,0,0,0.05); } -.config-section h3 { - color: #667eea; - margin-bottom: 1.5rem; - padding-bottom: 1rem; - border-bottom: 2px solid #667eea; +.property-details h4 { + color: #2c3e50; + margin: 0 0 20px 0; font-size: 1.2rem; font-weight: 600; } -.config-options { - display: flex; - flex-direction: column; - gap: 1.5rem; +.property-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 15px; } -.config-option { +.property-field { display: flex; - flex-direction: column; - gap: 0.5rem; + justify-content: space-between; + align-items: center; + padding: 12px 15px; + background: white; + border-radius: 8px; + border: 1px solid #e9ecef; } -.config-option label { +.property-field .label { font-weight: 600; - color: #495057; + color: #6c757d; font-size: 0.9rem; } -.config-option select { - padding: 0.75rem; - border: 2px solid #e9ecef; - border-radius: 0.5rem; - font-size: 1rem; - transition: all 0.3s ease; - background: white; +.property-field .value { + font-weight: 500; + color: #2c3e50; + font-size: 0.9rem; } -.config-option select:focus { - outline: none; - border-color: #667eea; - box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); +/* Export PDF Button - Improved */ +.export-pdf-section { + position: absolute; + top: 20px; + right: 20px; + z-index: 1000; } + +.export-pdf-btn { + background: linear-gradient(135deg, #667eea, #764ba2); + color: white; + border: none; + padding: 15px 30px; + border-radius: 25px; + font-weight: 600; + font-size: 14px; + cursor: pointer; + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4); + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.export-pdf-btn:hover { + transform: translateY(-3px); + box-shadow: 0 8px 25px rgba(102, 126, 234, 0.5); +} + +.export-pdf-btn:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; +} + +/* Progress Bar for PDF Generation */ +.progress-bar { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; +} + +.progress-content { + background: white; + padding: 40px; + border-radius: 15px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); + text-align: center; + max-width: 400px; + width: 90%; +} + +.progress-spinner { + width: 60px; + height: 60px; + border: 4px solid #f3f3f3; + border-top: 4px solid #667eea; + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto 20px; +} + +.progress-text { + font-size: 18px; + font-weight: 600; + color: #333; + margin-bottom: 20px; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Progress bar animation */ +.progress-bar .progress-content { + animation: slideIn 0.3s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-20px); + } + to { + opacity: 1; + transform: translateY(0); +} +} + +/* Loading Indicator */ +.loading-indicator { + text-align: center; + padding: 20px; + background: #f8f9fa; + border-radius: 8px; + margin: 15px 0; + color: #6c757d; + font-style: italic; +} + +.loading-indicator::before { + content: "ā³ "; + margin-right: 8px; +} + +/* Debug Info */ +.debug-info { + background: #e3f2fd !important; + border: 1px solid #2196f3; + color: #1565c0; + font-family: monospace; + font-size: 11px; +} + diff --git a/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.html b/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.html index d6476d8..48cac48 100644 --- a/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.html +++ b/force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.html @@ -1,17 +1,13 @@