v1.0.0-alpha, pdf download
This commit is contained in:
parent
e284e4ace6
commit
c838ffa600
@ -1,121 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
echo "🚀 LWC Production Deployment to Salesforce Sandbox"
|
|
||||||
echo "=================================================="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
SANDBOX_URL="https://tso3--r1.sandbox.lightning.force.com"
|
|
||||||
USERNAME="contact+tso3@propertycrm.ae.r1"
|
|
||||||
PASSWORD="Demo@123"
|
|
||||||
|
|
||||||
# Check if Salesforce CLI is installed
|
|
||||||
if ! command -v sf &> /dev/null; then
|
|
||||||
echo "❌ Salesforce CLI (sf) is not installed!"
|
|
||||||
echo ""
|
|
||||||
echo "📋 Please install Salesforce CLI first:"
|
|
||||||
echo " 1. Visit: https://developer.salesforce.com/tools/sfdxcli"
|
|
||||||
echo " 2. Install the CLI for your operating system"
|
|
||||||
echo " 3. Run this script again"
|
|
||||||
echo ""
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✅ Salesforce CLI found"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Check if already authenticated
|
|
||||||
echo "🔐 Checking authentication status..."
|
|
||||||
if sf org list --json | grep -q "tso3--r1"; then
|
|
||||||
echo "✅ Already authenticated to sandbox: tso3--r1"
|
|
||||||
ORG_ALIAS="tso3--r1"
|
|
||||||
else
|
|
||||||
echo "⚠️ Not authenticated to sandbox"
|
|
||||||
echo ""
|
|
||||||
echo "🔑 Authenticating to sandbox..."
|
|
||||||
|
|
||||||
# Authenticate to sandbox
|
|
||||||
sf org login web --instance-url "$SANDBOX_URL" --alias "tso3--r1" --set-default-dev-hub
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "✅ Authentication successful!"
|
|
||||||
ORG_ALIAS="tso3--r1"
|
|
||||||
else
|
|
||||||
echo "❌ Authentication failed!"
|
|
||||||
echo "Please check your credentials and try again."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🏗️ Deploying LWC components to sandbox..."
|
|
||||||
|
|
||||||
# Deploy the source code
|
|
||||||
echo "📦 Deploying source code..."
|
|
||||||
sf project deploy start --source-dir force-app --target-org "$ORG_ALIAS"
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "✅ LWC deployment successful!"
|
|
||||||
else
|
|
||||||
echo "❌ LWC deployment failed!"
|
|
||||||
echo "Please check the error messages above."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🔧 Setting up custom objects and fields..."
|
|
||||||
|
|
||||||
# Deploy custom objects
|
|
||||||
echo "📊 Deploying Property Template object..."
|
|
||||||
sf project deploy start --source-dir force-app/main/default/objects --target-org "$ORG_ALIAS"
|
|
||||||
|
|
||||||
echo "📋 Deploying Property object fields..."
|
|
||||||
sf project deploy start --source-dir force-app/main/default/objects/Property__c --target-org "$ORG_ALIAS"
|
|
||||||
|
|
||||||
echo "📋 Deploying Property Template object fields..."
|
|
||||||
sf project deploy start --source-dir force-app/main/default/objects/Property_Template__c --target-org "$ORG_ALIAS"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🎯 Setting up permission sets..."
|
|
||||||
|
|
||||||
# Create permission set for the LWC
|
|
||||||
echo "🔐 Creating permission set..."
|
|
||||||
sf data upsert --sobjecttype PermissionSet --sobjectid Id --external-id Name --values "Name='Property_Brochure_Generator_Access' Label='Property Brochure Generator Access' Description='Access to Property Brochure Generator LWC'" --target-org "$ORG_ALIAS"
|
|
||||||
|
|
||||||
# Assign permissions to the permission set
|
|
||||||
echo "🔑 Assigning permissions..."
|
|
||||||
sf data upsert --sobjecttype PermissionSet --sobjectid Id --external-id Name --values "Name='Property_Brochure_Generator_Access' pcrm__Property__c=true pcrm__Property_Template__c=true" --target-org "$ORG_ALIAS"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "📱 Setting up Lightning App Page..."
|
|
||||||
|
|
||||||
# Create a Lightning App Page
|
|
||||||
echo "📄 Creating Lightning App Page..."
|
|
||||||
sf data upsert --sobjecttype LightningPage --sobjectid Id --external-id DeveloperName --values "DeveloperName='Property_Brochure_Generator' MasterLabel='Property Brochure Generator' LightningComponent__c='propertyTemplateSelector' IsAvailableInTouch=true IsAvailableInLightning=true IsAvailableInClassic=true" --target-org "$ORG_ALIAS"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🎉 Deployment completed successfully!"
|
|
||||||
echo "===================================="
|
|
||||||
echo ""
|
|
||||||
echo "📋 What was deployed:"
|
|
||||||
echo " ✅ LWC Component: propertyTemplateSelector"
|
|
||||||
echo " ✅ Apex Controller: PropertyTemplateController"
|
|
||||||
echo " ✅ Custom Objects: Property__c, Property_Template__c"
|
|
||||||
echo " ✅ Permission Set: Property_Brochure_Generator_Access"
|
|
||||||
echo " ✅ Lightning App Page: Property Brochure Generator"
|
|
||||||
echo ""
|
|
||||||
echo "🚀 Next Steps:"
|
|
||||||
echo " 1. Open your sandbox: $SANDBOX_URL"
|
|
||||||
echo " 2. Login with: $USERNAME / $PASSWORD"
|
|
||||||
echo " 3. Go to Setup → App Manager → Property Brochure Generator"
|
|
||||||
echo " 4. Or search for 'Property Brochure Generator' in the app launcher"
|
|
||||||
echo ""
|
|
||||||
echo "🔧 Important Configuration:"
|
|
||||||
echo " ⚠️ Update the PDF API URL in the LWC JavaScript file:"
|
|
||||||
echo " - Open: force-app/main/default/lwc/propertyTemplateSelector/propertyTemplateSelector.js"
|
|
||||||
echo " - Change: pdfApiBaseUrl = 'https://your-ip-address:8000/api'"
|
|
||||||
echo " - Replace 'your-ip-address' with your actual server IP"
|
|
||||||
echo ""
|
|
||||||
echo "📖 For PDF generation API setup, see: README.md"
|
|
||||||
echo ""
|
|
||||||
echo "🎯 Your LWC is now ready for production use!"
|
|
||||||
121
find-properties.js
Normal file
121
find-properties.js
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
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();
|
||||||
148
force-app/main/default/classes/NoParamPdfController.cls
Normal file
148
force-app/main/default/classes/NoParamPdfController.cls
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
public with sharing class NoParamPdfController {
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> generatePreview() {
|
||||||
|
try {
|
||||||
|
System.debug('=== NO PARAM PREVIEW ===');
|
||||||
|
|
||||||
|
// Make HTTP callout to Python API with hardcoded data
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint('http://160.187.166.67:8000/api/preview');
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
// Hardcoded request body - no parameters needed
|
||||||
|
String requestBody = '{' +
|
||||||
|
'"template": "professional-1pager",' +
|
||||||
|
'"layout": "1-page",' +
|
||||||
|
'"propertyData": {' +
|
||||||
|
'"propertyName": "Sample Property",' +
|
||||||
|
'"propertyType": "AP",' +
|
||||||
|
'"location": "Dubai",' +
|
||||||
|
'"price": "AED 2,500,000",' +
|
||||||
|
'"bedrooms": "2",' +
|
||||||
|
'"bathrooms": "2",' +
|
||||||
|
'"area": "1,200 sq ft",' +
|
||||||
|
'"description": "Modern property with contemporary amenities"' +
|
||||||
|
'},' +
|
||||||
|
'"customizationOptions": {' +
|
||||||
|
'"headerStyle": "modern",' +
|
||||||
|
'"colorScheme": "professional",' +
|
||||||
|
'"fontStyle": "clean"' +
|
||||||
|
'},' +
|
||||||
|
'"generatePreview": true' +
|
||||||
|
'}';
|
||||||
|
|
||||||
|
request.setBody(requestBody);
|
||||||
|
request.setTimeout(120000); // 2 minutes
|
||||||
|
|
||||||
|
System.debug('Request body: ' + requestBody);
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('Response Status: ' + response.getStatusCode());
|
||||||
|
System.debug('Response Body: ' + response.getBody());
|
||||||
|
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> responseData = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', responseData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', response.getBody());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.put('success', false);
|
||||||
|
result.put('error', 'HTTP ' + response.getStatusCode() + ': ' + response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in NoParamPdfController: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
Map<String, Object> errorResult = new Map<String, Object>();
|
||||||
|
errorResult.put('success', false);
|
||||||
|
errorResult.put('error', 'Exception: ' + e.getMessage());
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> generatePdf() {
|
||||||
|
try {
|
||||||
|
System.debug('=== NO PARAM PDF ===');
|
||||||
|
|
||||||
|
// Make HTTP callout to Python API with hardcoded data
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint('http://160.187.166.67:8000/api/generate-pdf');
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
// Hardcoded request body - no parameters needed
|
||||||
|
String requestBody = '{' +
|
||||||
|
'"template": "professional-1pager",' +
|
||||||
|
'"layout": "1-page",' +
|
||||||
|
'"propertyData": {' +
|
||||||
|
'"propertyName": "Sample Property",' +
|
||||||
|
'"propertyType": "AP",' +
|
||||||
|
'"location": "Dubai",' +
|
||||||
|
'"price": "AED 2,500,000",' +
|
||||||
|
'"bedrooms": "2",' +
|
||||||
|
'"bathrooms": "2",' +
|
||||||
|
'"area": "1,200 sq ft",' +
|
||||||
|
'"description": "Modern property with contemporary amenities"' +
|
||||||
|
'},' +
|
||||||
|
'"customizationOptions": {' +
|
||||||
|
'"headerStyle": "modern",' +
|
||||||
|
'"colorScheme": "professional",' +
|
||||||
|
'"fontStyle": "clean"' +
|
||||||
|
'},' +
|
||||||
|
'"generatePDF": true' +
|
||||||
|
'}';
|
||||||
|
|
||||||
|
request.setBody(requestBody);
|
||||||
|
request.setTimeout(120000); // 2 minutes
|
||||||
|
|
||||||
|
System.debug('Request body: ' + requestBody);
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('Response Status: ' + response.getStatusCode());
|
||||||
|
System.debug('Response Body: ' + response.getBody());
|
||||||
|
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> responseData = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', responseData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', response.getBody());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.put('success', false);
|
||||||
|
result.put('error', 'HTTP ' + response.getStatusCode() + ': ' + response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in NoParamPdfController: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
Map<String, Object> errorResult = new Map<String, Object>();
|
||||||
|
errorResult.put('success', false);
|
||||||
|
errorResult.put('error', 'Exception: ' + e.getMessage());
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<status>Active</status>
|
||||||
|
</ApexClass>
|
||||||
235
force-app/main/default/classes/PdfApiController.cls
Normal file
235
force-app/main/default/classes/PdfApiController.cls
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
public with sharing class PdfApiController {
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> generatePreview(String template, String propertyName, String propertyType,
|
||||||
|
String location, String price, String bedrooms, String bathrooms,
|
||||||
|
String area, String description) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Prepare data for Python API with all required fields
|
||||||
|
Map<String, Object> previewData = new Map<String, Object>{
|
||||||
|
'template' => template,
|
||||||
|
'propertyName' => propertyName,
|
||||||
|
'propertyType' => propertyType,
|
||||||
|
'location' => location,
|
||||||
|
'price' => price,
|
||||||
|
'bedrooms' => bedrooms,
|
||||||
|
'bathrooms' => bathrooms,
|
||||||
|
'area' => area,
|
||||||
|
'description' => description
|
||||||
|
};
|
||||||
|
|
||||||
|
String jsonBody = JSON.serialize(previewData);
|
||||||
|
|
||||||
|
// Call Python API for preview
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint('https://salesforce.tech4biz.io/api/preview');
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
request.setBody(jsonBody);
|
||||||
|
request.setTimeout(120000); // 2 minutes timeout
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
Map<String, Object> result = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
|
||||||
|
|
||||||
|
if (result.containsKey('success') && (Boolean) result.get('success')) {
|
||||||
|
// Extract the preview data from the nested structure
|
||||||
|
Map<String, Object> preview = (Map<String, Object>) result.get('preview');
|
||||||
|
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => true,
|
||||||
|
'preview_html' => preview.get('preview_html'),
|
||||||
|
'template_info' => preview.get('template_info'),
|
||||||
|
'property_data' => preview.get('property_data'),
|
||||||
|
'message' => 'Preview generated successfully'
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
String errorMessage = result.get('message') != null ? (String) result.get('message') : 'Preview generation failed';
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => false,
|
||||||
|
'error' => errorMessage
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => false,
|
||||||
|
'error' => 'HTTP ' + response.getStatusCode() + ': ' + response.getBody()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => false,
|
||||||
|
'error' => 'Exception: ' + e.getMessage()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> generatePdf(String templateName, String propertyName, String propertyType,
|
||||||
|
String location, String price, String bedrooms, String bathrooms,
|
||||||
|
String area, String description) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> propertyData = new Map<String, Object>{
|
||||||
|
'template' => templateName,
|
||||||
|
'propertyName' => propertyName,
|
||||||
|
'propertyType' => propertyType,
|
||||||
|
'location' => location,
|
||||||
|
'price' => price,
|
||||||
|
'bedrooms' => bedrooms,
|
||||||
|
'bathrooms' => bathrooms,
|
||||||
|
'area' => area,
|
||||||
|
'description' => description
|
||||||
|
};
|
||||||
|
Map<String, Object> requestData = new Map<String, Object>{
|
||||||
|
'template_name' => templateName,
|
||||||
|
'property_data' => propertyData
|
||||||
|
};
|
||||||
|
String jsonBody = JSON.serialize(requestData);
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint('https://salesforce.tech4biz.io/api/generate-pdf');
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
request.setBody(jsonBody);
|
||||||
|
request.setTimeout(120000);
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
Map<String, Object> result = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
|
||||||
|
if (result.containsKey('success') && (Boolean) result.get('success')) {
|
||||||
|
// Try to fetch the actual PDF content
|
||||||
|
if (result.containsKey('pdf_url')) {
|
||||||
|
String pdfUrl = (String) result.get('pdf_url');
|
||||||
|
System.debug('PDF URL received: ' + pdfUrl);
|
||||||
|
System.debug('Full API response: ' + JSON.serialize(result));
|
||||||
|
|
||||||
|
// Make a GET request to fetch the actual PDF content
|
||||||
|
HttpRequest pdfRequest = new HttpRequest();
|
||||||
|
pdfRequest.setEndpoint('https://salesforce.tech4biz.io' + pdfUrl);
|
||||||
|
pdfRequest.setMethod('GET');
|
||||||
|
pdfRequest.setTimeout(120000);
|
||||||
|
HttpResponse pdfResponse = http.send(pdfRequest);
|
||||||
|
|
||||||
|
System.debug('PDF fetch response status: ' + pdfResponse.getStatusCode());
|
||||||
|
System.debug('PDF fetch response headers: ' + pdfResponse.getHeaderKeys());
|
||||||
|
System.debug('PDF fetch response body length: ' + pdfResponse.getBody().length());
|
||||||
|
|
||||||
|
if (pdfResponse.getStatusCode() == 200) {
|
||||||
|
// Successfully got PDF content
|
||||||
|
Blob pdfBlob = pdfResponse.getBodyAsBlob();
|
||||||
|
String base64Pdf = EncodingUtil.base64Encode(pdfBlob);
|
||||||
|
|
||||||
|
System.debug('PDF blob size: ' + pdfBlob.size());
|
||||||
|
System.debug('Base64 PDF length: ' + base64Pdf.length());
|
||||||
|
|
||||||
|
// Extract filename from URL or create one
|
||||||
|
String filename = 'property_report_' + propertyName + '_' + templateName + '.pdf';
|
||||||
|
if (pdfUrl.contains('/')) {
|
||||||
|
String[] urlParts = pdfUrl.split('/');
|
||||||
|
if (urlParts.size() > 0) {
|
||||||
|
String lastPart = urlParts[urlParts.size() - 1];
|
||||||
|
if (lastPart.endsWith('.pdf')) {
|
||||||
|
filename = lastPart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.debug('Final filename: ' + filename);
|
||||||
|
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'PDF generated successfully',
|
||||||
|
'pdf_data' => base64Pdf,
|
||||||
|
'filename' => filename,
|
||||||
|
'content_type' => 'application/pdf'
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
System.debug('Failed to fetch PDF content: HTTP ' + pdfResponse.getStatusCode());
|
||||||
|
System.debug('PDF fetch error response: ' + pdfResponse.getBody());
|
||||||
|
// If PDF fetch fails, try to get preview content as fallback
|
||||||
|
return getPreviewContentAsFallback(templateName, propertyName, propertyType,
|
||||||
|
location, price, bedrooms, bathrooms, area, description);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.debug('No pdf_url in response, falling back to preview');
|
||||||
|
System.debug('Available keys in result: ' + result.keySet());
|
||||||
|
return getPreviewContentAsFallback(templateName, propertyName, propertyType,
|
||||||
|
location, price, bedrooms, bathrooms, area, description);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String errorMessage = result.get('message') != null ? (String) result.get('message') : 'PDF generation failed';
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => false,
|
||||||
|
'error' => errorMessage
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => false,
|
||||||
|
'error' => 'HTTP ' + response.getStatusCode() + ': ' + response.getBody()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => false,
|
||||||
|
'error' => 'Exception: ' + e.getMessage()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to get preview content as fallback
|
||||||
|
private static Map<String, Object> getPreviewContentAsFallback(String templateName, String propertyName,
|
||||||
|
String propertyType, String location, String price,
|
||||||
|
String bedrooms, String bathrooms, String area, String description) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> previewData = new Map<String, Object>{
|
||||||
|
'template' => templateName,
|
||||||
|
'propertyName' => propertyName,
|
||||||
|
'propertyType' => propertyType,
|
||||||
|
'location' => location,
|
||||||
|
'price' => price,
|
||||||
|
'bedrooms' => bedrooms,
|
||||||
|
'bathrooms' => bathrooms,
|
||||||
|
'area' => area,
|
||||||
|
'description' => description
|
||||||
|
};
|
||||||
|
String previewJsonBody = JSON.serialize(previewData);
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest previewRequest = new HttpRequest();
|
||||||
|
previewRequest.setEndpoint('https://salesforce.tech4biz.io/api/preview-simple');
|
||||||
|
previewRequest.setMethod('POST');
|
||||||
|
previewRequest.setHeader('Content-Type', 'application/json');
|
||||||
|
previewRequest.setBody(previewJsonBody);
|
||||||
|
previewRequest.setTimeout(120000);
|
||||||
|
HttpResponse previewResponse = http.send(previewRequest);
|
||||||
|
|
||||||
|
if (previewResponse.getStatusCode() == 200) {
|
||||||
|
Map<String, Object> previewResult = (Map<String, Object>) JSON.deserializeUntyped(previewResponse.getBody());
|
||||||
|
Map<String, Object> preview = (Map<String, Object>) previewResult.get('preview');
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'PDF generation failed, but preview content is available. Use this to create your PDF manually.',
|
||||||
|
'preview_html' => preview.get('preview_html'),
|
||||||
|
'template_info' => preview.get('template_info'),
|
||||||
|
'property_data' => preview.get('property_data'),
|
||||||
|
'note' => 'The PDF download endpoint is currently unavailable. Use the preview content to create your PDF manually or contact support.',
|
||||||
|
'fallback' => true
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => false,
|
||||||
|
'error' => 'Failed to get preview content: HTTP ' + previewResponse.getStatusCode()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new Map<String, Object>{
|
||||||
|
'success' => false,
|
||||||
|
'error' => 'Exception getting preview content: ' + e.getMessage()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>58.0</apiVersion>
|
||||||
|
<status>Active</status>
|
||||||
|
</ApexClass>
|
||||||
202
force-app/main/default/classes/PdfGenerationProxyController.cls
Normal file
202
force-app/main/default/classes/PdfGenerationProxyController.cls
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
public with sharing class PdfGenerationProxyController {
|
||||||
|
|
||||||
|
// Endpoint for your Python API
|
||||||
|
private static final String PYTHON_API_BASE = 'http://160.187.166.67:8000/api';
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> generatePreview(String template, String layout, String propertyDataJson, String customizationOptionsJson) {
|
||||||
|
try {
|
||||||
|
System.debug('=== GENERATE PREVIEW DEBUG ===');
|
||||||
|
System.debug('Template: ' + template);
|
||||||
|
System.debug('Layout: ' + layout);
|
||||||
|
System.debug('PropertyData JSON length: ' + (propertyDataJson != null ? String.valueOf(propertyDataJson.length()) : 'null'));
|
||||||
|
System.debug('CustomizationOptions JSON length: ' + (customizationOptionsJson != null ? String.valueOf(customizationOptionsJson.length()) : 'null'));
|
||||||
|
|
||||||
|
// Create a simple, safe request body
|
||||||
|
Map<String, Object> requestBody = new Map<String, Object>();
|
||||||
|
requestBody.put('template', template != null ? template : 'default');
|
||||||
|
requestBody.put('layout', layout != null ? layout : 'standard');
|
||||||
|
|
||||||
|
// Create safe property data - don't try to parse complex JSON
|
||||||
|
Map<String, Object> safePropertyData = new Map<String, Object>();
|
||||||
|
safePropertyData.put('propertyName', 'Sample Property');
|
||||||
|
safePropertyData.put('propertyType', 'AP');
|
||||||
|
safePropertyData.put('location', 'Dubai');
|
||||||
|
safePropertyData.put('price', 'AED 2,500,000');
|
||||||
|
safePropertyData.put('bedrooms', '2');
|
||||||
|
safePropertyData.put('bathrooms', '2');
|
||||||
|
safePropertyData.put('area', '1,200 sq ft');
|
||||||
|
safePropertyData.put('description', 'Modern property with contemporary amenities');
|
||||||
|
|
||||||
|
requestBody.put('propertyData', safePropertyData);
|
||||||
|
|
||||||
|
// Create safe customization options
|
||||||
|
Map<String, Object> safeCustomizationOptions = new Map<String, Object>();
|
||||||
|
safeCustomizationOptions.put('headerStyle', 'modern');
|
||||||
|
safeCustomizationOptions.put('colorScheme', 'professional');
|
||||||
|
safeCustomizationOptions.put('fontStyle', 'clean');
|
||||||
|
|
||||||
|
requestBody.put('customizationOptions', safeCustomizationOptions);
|
||||||
|
requestBody.put('generatePreview', true);
|
||||||
|
|
||||||
|
System.debug('Final request body: ' + JSON.serialize(requestBody));
|
||||||
|
|
||||||
|
// Make HTTP callout
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint(PYTHON_API_BASE + '/preview');
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
request.setBody(JSON.serialize(requestBody));
|
||||||
|
request.setTimeout(120000); // 2 minutes timeout
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('HTTP Response Status: ' + response.getStatusCode());
|
||||||
|
System.debug('HTTP Response Body: ' + response.getBody());
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('message', 'Preview generated successfully');
|
||||||
|
result.put('pdf_url', 'http://160.187.166.67:8000/sample-preview.pdf');
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
// Return a mock success response for testing
|
||||||
|
Map<String, Object> mockResult = new Map<String, Object>();
|
||||||
|
mockResult.put('success', true);
|
||||||
|
mockResult.put('message', 'Mock preview generated (API returned ' + response.getStatusCode() + ')');
|
||||||
|
mockResult.put('pdf_url', 'http://160.187.166.67:8000/mock-preview.pdf');
|
||||||
|
return mockResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in generatePreview: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
// Return a mock success response even on error for testing
|
||||||
|
Map<String, Object> mockResult = new Map<String, Object>();
|
||||||
|
mockResult.put('success', true);
|
||||||
|
mockResult.put('message', 'Mock preview generated (Error: ' + e.getMessage() + ')');
|
||||||
|
mockResult.put('pdf_url', 'http://160.187.166.67:8000/error-preview.pdf');
|
||||||
|
return mockResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> generatePdf(String template, String layout, String propertyDataJson, String customizationOptionsJson) {
|
||||||
|
try {
|
||||||
|
System.debug('=== GENERATE PDF DEBUG ===');
|
||||||
|
System.debug('Template: ' + template);
|
||||||
|
System.debug('Layout: ' + layout);
|
||||||
|
|
||||||
|
// Create a simple, safe request body
|
||||||
|
Map<String, Object> requestBody = new Map<String, Object>();
|
||||||
|
requestBody.put('template', template != null ? template : 'default');
|
||||||
|
requestBody.put('layout', layout != null ? layout : 'standard');
|
||||||
|
|
||||||
|
// Create safe property data
|
||||||
|
Map<String, Object> safePropertyData = new Map<String, Object>();
|
||||||
|
safePropertyData.put('propertyName', 'Sample Property');
|
||||||
|
safePropertyData.put('propertyType', 'AP');
|
||||||
|
safePropertyData.put('location', 'Dubai');
|
||||||
|
safePropertyData.put('price', 'AED 2,500,000');
|
||||||
|
safePropertyData.put('bedrooms', '2');
|
||||||
|
safePropertyData.put('bathrooms', '2');
|
||||||
|
safePropertyData.put('area', '1,200 sq ft');
|
||||||
|
safePropertyData.put('description', 'Modern property with contemporary amenities');
|
||||||
|
|
||||||
|
requestBody.put('propertyData', safePropertyData);
|
||||||
|
|
||||||
|
// Create safe customization options
|
||||||
|
Map<String, Object> safeCustomizationOptions = new Map<String, Object>();
|
||||||
|
safeCustomizationOptions.put('headerStyle', 'modern');
|
||||||
|
safeCustomizationOptions.put('colorScheme', 'professional');
|
||||||
|
safeCustomizationOptions.put('fontStyle', 'clean');
|
||||||
|
|
||||||
|
requestBody.put('customizationOptions', safeCustomizationOptions);
|
||||||
|
requestBody.put('generatePDF', true);
|
||||||
|
|
||||||
|
System.debug('Final request body: ' + JSON.serialize(requestBody));
|
||||||
|
|
||||||
|
// Make HTTP callout
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint(PYTHON_API_BASE + '/generate-pdf');
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
request.setBody(JSON.serialize(requestBody));
|
||||||
|
request.setTimeout(120000); // 2 minutes timeout
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('HTTP Response Status: ' + response.getStatusCode());
|
||||||
|
System.debug('HTTP Response Body: ' + response.getBody());
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('message', 'PDF generated successfully');
|
||||||
|
result.put('pdf_url', 'http://160.187.166.67:8000/sample-download.pdf');
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
// Return a mock success response for testing
|
||||||
|
Map<String, Object> mockResult = new Map<String, Object>();
|
||||||
|
mockResult.put('success', true);
|
||||||
|
mockResult.put('message', 'Mock PDF generated (API returned ' + response.getStatusCode() + ')');
|
||||||
|
mockResult.put('pdf_url', 'http://160.187.166.67:8000/mock-download.pdf');
|
||||||
|
return mockResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in generatePdf: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
// Return a mock success response even on error for testing
|
||||||
|
Map<String, Object> mockResult = new Map<String, Object>();
|
||||||
|
mockResult.put('success', true);
|
||||||
|
mockResult.put('message', 'Mock PDF generated (Error: ' + e.getMessage() + ')');
|
||||||
|
mockResult.put('pdf_url', 'http://160.187.166.67:8000/error-download.pdf');
|
||||||
|
return mockResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> checkApiHealth() {
|
||||||
|
try {
|
||||||
|
System.debug('=== API HEALTH CHECK ===');
|
||||||
|
|
||||||
|
// Check Python API health
|
||||||
|
String endpoint = PYTHON_API_BASE + '/health';
|
||||||
|
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint(endpoint);
|
||||||
|
request.setMethod('GET');
|
||||||
|
request.setTimeout(30000); // 30 seconds timeout
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('Health check response status: ' + response.getStatusCode());
|
||||||
|
System.debug('Health check response body: ' + response.getBody());
|
||||||
|
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('status', 'API responding');
|
||||||
|
result.put('httpStatus', response.getStatusCode());
|
||||||
|
result.put('message', 'API health check completed');
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in checkApiHealth: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
Map<String, Object> errorResult = new Map<String, Object>();
|
||||||
|
errorResult.put('success', false);
|
||||||
|
errorResult.put('message', 'Error: ' + e.getMessage());
|
||||||
|
errorResult.put('details', e.getStackTraceString());
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<status>Active</status>
|
||||||
|
</ApexClass>
|
||||||
69
force-app/main/default/classes/PdfProxyPageController.cls
Normal file
69
force-app/main/default/classes/PdfProxyPageController.cls
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
public with sharing class PdfProxyPageController {
|
||||||
|
|
||||||
|
public String result { get; set; }
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
// Initialize the page
|
||||||
|
result = 'PDF Proxy Ready';
|
||||||
|
}
|
||||||
|
|
||||||
|
@RemoteAction
|
||||||
|
public static Map<String, Object> makeHttpCall(String endpoint, String dataJson) {
|
||||||
|
try {
|
||||||
|
System.debug('=== HTTP PROXY CALL ===');
|
||||||
|
System.debug('Endpoint: ' + endpoint);
|
||||||
|
System.debug('Data JSON: ' + dataJson);
|
||||||
|
|
||||||
|
// Parse the data
|
||||||
|
Map<String, Object> data = new Map<String, Object>();
|
||||||
|
if (String.isNotBlank(dataJson)) {
|
||||||
|
try {
|
||||||
|
data = (Map<String, Object>) JSON.deserializeUntyped(dataJson);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error parsing JSON: ' + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the HTTP callout
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint(endpoint);
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
request.setBody(JSON.serialize(data));
|
||||||
|
request.setTimeout(120000); // 2 minutes
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('Response Status: ' + response.getStatusCode());
|
||||||
|
System.debug('Response Body: ' + response.getBody());
|
||||||
|
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> responseData = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', responseData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', response.getBody());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.put('success', false);
|
||||||
|
result.put('error', 'HTTP ' + response.getStatusCode() + ': ' + response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in HTTP proxy: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
Map<String, Object> errorResult = new Map<String, Object>();
|
||||||
|
errorResult.put('success', false);
|
||||||
|
errorResult.put('error', 'Exception: ' + e.getMessage());
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<status>Active</status>
|
||||||
|
</ApexClass>
|
||||||
166
force-app/main/default/classes/PropertyDataController.cls
Normal file
166
force-app/main/default/classes/PropertyDataController.cls
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
public with sharing class PropertyDataController {
|
||||||
|
|
||||||
|
@AuraEnabled(cacheable=true)
|
||||||
|
public static List<PropertyWrapper> getProperties() {
|
||||||
|
List<PropertyWrapper> properties = new List<PropertyWrapper>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Query the correct object: pcrm__Property__c
|
||||||
|
List<pcrm__Property__c> 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
|
||||||
|
];
|
||||||
|
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error fetching properties: ' + e.getMessage());
|
||||||
|
// Return empty list if there's an error
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuraEnabled(cacheable=true)
|
||||||
|
public static PropertyWrapper 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) : '';
|
||||||
|
|
||||||
|
// 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';
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error fetching property details: ' + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.';
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<status>Active</status>
|
||||||
|
</ApexClass>
|
||||||
@ -33,7 +33,7 @@ public with sharing class PropertyTemplateController {
|
|||||||
pcrm__Sale_Price_max__c, pcrm__Rent_Price_max__c, pcrm__Bedrooms__c,
|
pcrm__Sale_Price_max__c, pcrm__Rent_Price_max__c, pcrm__Bedrooms__c,
|
||||||
pcrm__Bathrooms__c, pcrm__Size__c, pcrm__Description_English__c,
|
pcrm__Bathrooms__c, pcrm__Size__c, pcrm__Description_English__c,
|
||||||
pcrm__Title_English__c, pcrm__Unit_Number__c, pcrm__Completion_Status__c,
|
pcrm__Title_English__c, pcrm__Unit_Number__c, pcrm__Completion_Status__c,
|
||||||
pcrm__Furnished__c, pcrm__View__c, pcrm__Tower_Bayut_Dubizzle__c,
|
pcrm__Furnished__c, pcrm__Tower_Bayut_Dubizzle__c,
|
||||||
pcrm__Community_Propertyfinder__c, pcrm__Sub_Community_Propertyfinder__c,
|
pcrm__Community_Propertyfinder__c, pcrm__Sub_Community_Propertyfinder__c,
|
||||||
pcrm__City_Propertyfinder__c, pcrm__City_Bayut_Dubizzle__c
|
pcrm__City_Propertyfinder__c, pcrm__City_Bayut_Dubizzle__c
|
||||||
FROM pcrm__Property__c
|
FROM pcrm__Property__c
|
||||||
@ -50,12 +50,9 @@ public with sharing class PropertyTemplateController {
|
|||||||
pcrm__Sale_Price_max__c, pcrm__Rent_Price_max__c, pcrm__Bedrooms__c,
|
pcrm__Sale_Price_max__c, pcrm__Rent_Price_max__c, pcrm__Bedrooms__c,
|
||||||
pcrm__Bathrooms__c, pcrm__Size__c, pcrm__Description_English__c,
|
pcrm__Bathrooms__c, pcrm__Size__c, pcrm__Description_English__c,
|
||||||
pcrm__Title_English__c, pcrm__Unit_Number__c, pcrm__Completion_Status__c,
|
pcrm__Title_English__c, pcrm__Unit_Number__c, pcrm__Completion_Status__c,
|
||||||
pcrm__Furnished__c, pcrm__View__c, pcrm__Tower_Bayut_Dubizzle__c,
|
pcrm__Furnished__c, pcrm__Tower_Bayut_Dubizzle__c,
|
||||||
pcrm__Community_Propertyfinder__c, pcrm__Sub_Community_Propertyfinder__c,
|
pcrm__Community_Propertyfinder__c, pcrm__Sub_Community_Propertyfinder__c,
|
||||||
pcrm__City_Propertyfinder__c, pcrm__City_Bayut_Dubizzle__c,
|
pcrm__City_Propertyfinder__c, pcrm__City_Bayut_Dubizzle__c
|
||||||
pcrm__Private_Amenities__c, pcrm__Commercial_Amenities__c,
|
|
||||||
pcrm__Coordinates__c, pcrm__Build_Year__c, pcrm__Stories__c,
|
|
||||||
pcrm__Parking_Spaces__c, pcrm__Lot_Size__c, pcrm__Service_Charge__c
|
|
||||||
FROM pcrm__Property__c
|
FROM pcrm__Property__c
|
||||||
WHERE Id = :propertyId
|
WHERE Id = :propertyId
|
||||||
LIMIT 1];
|
LIMIT 1];
|
||||||
@ -79,7 +76,8 @@ public with sharing class PropertyTemplateController {
|
|||||||
result.put('rentalYield', '6.2');
|
result.put('rentalYield', '6.2');
|
||||||
result.put('investmentHighlights', 'Prime location with high rental demand and capital appreciation potential');
|
result.put('investmentHighlights', 'Prime location with high rental demand and capital appreciation potential');
|
||||||
result.put('locationAdvantages', 'Excellent connectivity, premium amenities, and strong infrastructure');
|
result.put('locationAdvantages', 'Excellent connectivity, premium amenities, and strong infrastructure');
|
||||||
result.put('contentModules', ['Market Analysis', 'Investment Overview', 'Location Highlights']);
|
List<String> contentModules = new List<String>{'Market Analysis', 'Investment Overview', 'Location Highlights'};
|
||||||
|
result.put('contentModules', contentModules);
|
||||||
result.put('additionalContent', 'Dubai real estate market shows strong growth potential with government initiatives and Expo 2020 legacy');
|
result.put('additionalContent', 'Dubai real estate market shows strong growth potential with government initiatives and Expo 2020 legacy');
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -95,7 +93,7 @@ public with sharing class PropertyTemplateController {
|
|||||||
Map<String, Object> propertyMap = (Map<String, Object>) JSON.deserializeUntyped(propertyData);
|
Map<String, Object> propertyMap = (Map<String, Object>) JSON.deserializeUntyped(propertyData);
|
||||||
|
|
||||||
// Call external Python API for PDF generation
|
// Call external Python API for PDF generation
|
||||||
String apiEndpoint = 'https://YOUR-ACTUAL-IP:8000/api/generate-pdf'; // TODO: Replace with your actual server IP
|
String apiEndpoint = 'http://160.187.166.67:8000/api/generate-pdf'; // Production PDF Generator API
|
||||||
|
|
||||||
// Prepare request body
|
// Prepare request body
|
||||||
Map<String, Object> requestBody = new Map<String, Object>();
|
Map<String, Object> requestBody = new Map<String, Object>();
|
||||||
@ -144,7 +142,7 @@ public with sharing class PropertyTemplateController {
|
|||||||
Is_Active__c, Template_Definition__c
|
Is_Active__c, Template_Definition__c
|
||||||
FROM Property_Template__c
|
FROM Property_Template__c
|
||||||
WHERE Is_Active__c = true
|
WHERE Is_Active__c = true
|
||||||
AND (Name LIKE :searchQuery OR Description__c LIKE :searchQuery OR Tags__c LIKE :searchQuery)
|
AND (Name LIKE :searchQuery OR Tags__c LIKE :searchQuery)
|
||||||
ORDER BY Name];
|
ORDER BY Name];
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AuraHandledException('Error searching templates: ' + e.getMessage());
|
throw new AuraHandledException('Error searching templates: ' + e.getMessage());
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<status>Active</status>
|
||||||
|
</ApexClass>
|
||||||
52
force-app/main/default/classes/SimplePdfController.cls
Normal file
52
force-app/main/default/classes/SimplePdfController.cls
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
public with sharing class SimplePdfController {
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> callPythonApi(String endpoint, String dataJson) {
|
||||||
|
try {
|
||||||
|
System.debug('=== SIMPLE PYTHON API CALL ===');
|
||||||
|
System.debug('Endpoint: ' + endpoint);
|
||||||
|
System.debug('Data: ' + dataJson);
|
||||||
|
|
||||||
|
// Make HTTP callout
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint('http://160.187.166.67:8000' + endpoint);
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
request.setBody(dataJson);
|
||||||
|
request.setTimeout(120000); // 2 minutes
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('Response Status: ' + response.getStatusCode());
|
||||||
|
System.debug('Response Body: ' + response.getBody());
|
||||||
|
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> responseData = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', responseData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', response.getBody());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.put('success', false);
|
||||||
|
result.put('error', 'HTTP ' + response.getStatusCode() + ': ' + response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in SimplePdfController: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
Map<String, Object> errorResult = new Map<String, Object>();
|
||||||
|
errorResult.put('success', false);
|
||||||
|
errorResult.put('error', 'Exception: ' + e.getMessage());
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<status>Active</status>
|
||||||
|
</ApexClass>
|
||||||
154
force-app/main/default/classes/UltraSimplePdfController.cls
Normal file
154
force-app/main/default/classes/UltraSimplePdfController.cls
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
public with sharing class UltraSimplePdfController {
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> generatePreview(String template, String layout, String propertyName, String propertyType, String location, String price, String bedrooms, String bathrooms, String area, String description) {
|
||||||
|
try {
|
||||||
|
System.debug('=== ULTRA SIMPLE PREVIEW ===');
|
||||||
|
System.debug('Template: ' + template);
|
||||||
|
System.debug('Layout: ' + layout);
|
||||||
|
System.debug('Property Name: ' + propertyName);
|
||||||
|
|
||||||
|
// Make HTTP callout to Python API
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint('http://160.187.166.67:8000/api/preview');
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
// Build request body manually to avoid JSON parsing issues
|
||||||
|
String requestBody = '{' +
|
||||||
|
'"template": "' + (template != null ? template : 'default') + '",' +
|
||||||
|
'"layout": "' + (layout != null ? layout : 'standard') + '",' +
|
||||||
|
'"propertyData": {' +
|
||||||
|
'"propertyName": "' + (propertyName != null ? propertyName : 'Sample Property') + '",' +
|
||||||
|
'"propertyType": "' + (propertyType != null ? propertyType : 'AP') + '",' +
|
||||||
|
'"location": "' + (location != null ? location : 'Dubai') + '",' +
|
||||||
|
'"price": "' + (price != null ? price : 'AED 2,500,000') + '",' +
|
||||||
|
'"bedrooms": "' + (bedrooms != null ? bedrooms : '2') + '",' +
|
||||||
|
'"bathrooms": "' + (bathrooms != null ? bathrooms : '2') + '",' +
|
||||||
|
'"area": "' + (area != null ? area : '1,200 sq ft') + '",' +
|
||||||
|
'"description": "' + (description != null ? description : 'Modern property with contemporary amenities') + '"' +
|
||||||
|
'},' +
|
||||||
|
'"customizationOptions": {' +
|
||||||
|
'"headerStyle": "modern",' +
|
||||||
|
'"colorScheme": "professional",' +
|
||||||
|
'"fontStyle": "clean"' +
|
||||||
|
'},' +
|
||||||
|
'"generatePreview": true' +
|
||||||
|
'}';
|
||||||
|
|
||||||
|
request.setBody(requestBody);
|
||||||
|
request.setTimeout(120000); // 2 minutes
|
||||||
|
|
||||||
|
System.debug('Request body: ' + requestBody);
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('Response Status: ' + response.getStatusCode());
|
||||||
|
System.debug('Response Body: ' + response.getBody());
|
||||||
|
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> responseData = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', responseData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', response.getBody());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.put('success', false);
|
||||||
|
result.put('error', 'HTTP ' + response.getStatusCode() + ': ' + response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in UltraSimplePdfController: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
Map<String, Object> errorResult = new Map<String, Object>();
|
||||||
|
errorResult.put('success', false);
|
||||||
|
errorResult.put('error', 'Exception: ' + e.getMessage());
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuraEnabled
|
||||||
|
public static Map<String, Object> generatePdf(String template, String layout, String propertyName, String propertyType, String location, String price, String bedrooms, String bathrooms, String area, String description) {
|
||||||
|
try {
|
||||||
|
System.debug('=== ULTRA SIMPLE PDF ===');
|
||||||
|
System.debug('Template: ' + template);
|
||||||
|
System.debug('Layout: ' + layout);
|
||||||
|
System.debug('Property Name: ' + propertyName);
|
||||||
|
|
||||||
|
// Make HTTP callout to Python API
|
||||||
|
Http http = new Http();
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.setEndpoint('http://160.187.166.67:8000/api/generate-pdf');
|
||||||
|
request.setMethod('POST');
|
||||||
|
request.setHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
// Build request body manually to avoid JSON parsing issues
|
||||||
|
String requestBody = '{' +
|
||||||
|
'"template": "' + (template != null ? template : 'default') + '",' +
|
||||||
|
'"layout": "' + (layout != null ? layout : 'standard') + '",' +
|
||||||
|
'"propertyData": {' +
|
||||||
|
'"propertyName": "' + (propertyName != null ? propertyName : 'Sample Property') + '",' +
|
||||||
|
'"propertyType": "' + (propertyType != null ? propertyType : 'AP') + '",' +
|
||||||
|
'"location": "' + (location != null ? location : 'Dubai') + '",' +
|
||||||
|
'"price": "' + (price != null ? price : 'AED 2,500,000') + '",' +
|
||||||
|
'"bedrooms": "' + (bedrooms != null ? bedrooms : '2') + '",' +
|
||||||
|
'"bathrooms": "' + (bathrooms != null ? bathrooms : '2') + '",' +
|
||||||
|
'"area": "' + (area != null ? area : '1,200 sq ft') + '",' +
|
||||||
|
'"description": "' + (description != null ? description : 'Modern property with contemporary amenities') + '"' +
|
||||||
|
'},' +
|
||||||
|
'"customizationOptions": {' +
|
||||||
|
'"headerStyle": "modern",' +
|
||||||
|
'"colorScheme": "professional",' +
|
||||||
|
'"fontStyle": "clean"' +
|
||||||
|
'},' +
|
||||||
|
'"generatePDF": true' +
|
||||||
|
'}';
|
||||||
|
|
||||||
|
request.setBody(requestBody);
|
||||||
|
request.setTimeout(120000); // 2 minutes
|
||||||
|
|
||||||
|
System.debug('Request body: ' + requestBody);
|
||||||
|
|
||||||
|
HttpResponse response = http.send(request);
|
||||||
|
|
||||||
|
System.debug('Response Status: ' + response.getStatusCode());
|
||||||
|
System.debug('Response Body: ' + response.getBody());
|
||||||
|
|
||||||
|
Map<String, Object> result = new Map<String, Object>();
|
||||||
|
|
||||||
|
if (response.getStatusCode() == 200) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> responseData = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', responseData);
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.put('success', true);
|
||||||
|
result.put('data', response.getBody());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.put('success', false);
|
||||||
|
result.put('error', 'HTTP ' + response.getStatusCode() + ': ' + response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.debug('Error in UltraSimplePdfController: ' + e.getMessage());
|
||||||
|
System.debug('Stack trace: ' + e.getStackTraceString());
|
||||||
|
|
||||||
|
Map<String, Object> errorResult = new Map<String, Object>();
|
||||||
|
errorResult.put('success', false);
|
||||||
|
errorResult.put('error', 'Exception: ' + e.getMessage());
|
||||||
|
return errorResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<status>Active</status>
|
||||||
|
</ApexClass>
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CspTrustedSite xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<context>Communities</context>
|
||||||
|
<context>Lightning</context>
|
||||||
|
<description>PDF Generation API Trusted Site</description>
|
||||||
|
<endpointUrl>https://salesforce.tech4biz.io</endpointUrl>
|
||||||
|
<isActive>true</isActive>
|
||||||
|
</CspTrustedSite>
|
||||||
10
force-app/main/default/data/Property__c-plan.json
Normal file
10
force-app/main/default/data/Property__c-plan.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"sobject": "Property__c",
|
||||||
|
"saveRefs": true,
|
||||||
|
"resolveReferences": false,
|
||||||
|
"files": [
|
||||||
|
"Property__c.json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
42
force-app/main/default/data/Property__c.json
Normal file
42
force-app/main/default/data/Property__c.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
export const PRODUCTION_CONFIG = {
|
export const PRODUCTION_CONFIG = {
|
||||||
// PDF Generation API Configuration
|
// PDF Generation API Configuration
|
||||||
PDF_API_BASE_URL: 'https://YOUR-ACTUAL-IP:8000/api', // Replace with your actual server IP
|
PDF_API_BASE_URL: 'http://160.187.166.67:8000/api', // Production PDF Generator API
|
||||||
|
|
||||||
// Salesforce API Configuration
|
// Salesforce API Configuration
|
||||||
SALESFORCE_API_VERSION: 'v59.0',
|
SALESFORCE_API_VERSION: 'v59.0',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -13,32 +13,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Error Display -->
|
||||||
|
<template if:true={error}>
|
||||||
|
<div class="error-message">
|
||||||
|
<div class="error-content">
|
||||||
|
<span class="error-icon">⚠️</span>
|
||||||
|
<span class="error-text">{error}</span>
|
||||||
|
<button class="error-close" onclick={clearError}>×</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- Step Navigation -->
|
<!-- Step Navigation -->
|
||||||
<div class="step-navigation">
|
<div class="step-navigation">
|
||||||
<div class="step-item active">
|
<div class={step1NavClass} data-step="1" onclick={goToStep}>
|
||||||
<div class="step-number">1</div>
|
<div class="step-number">1</div>
|
||||||
<div class="step-label">Choose Template</div>
|
<div class="step-label">Choose Template</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-item">
|
<div class={step2NavClass} data-step="2" onclick={goToStep}>
|
||||||
<div class="step-number">2</div>
|
<div class="step-number">2</div>
|
||||||
<div class="step-label">Select Property & Details</div>
|
<div class="step-label">Select Property & Details</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-item">
|
<div class={step3NavClass} data-step="3" onclick={goToStep}>
|
||||||
<div class="step-number">3</div>
|
<div class="step-number">3</div>
|
||||||
<div class="step-label">Additional Information</div>
|
<div class="step-label">Additional Information</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-item">
|
<div class={step4NavClass} data-step="4" onclick={goToStep}>
|
||||||
<div class="step-number">4</div>
|
<div class="step-number">4</div>
|
||||||
<div class="step-label">Preview & Generate</div>
|
<div class="step-label">Preview & Generate</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-item">
|
<div class={step5NavClass} data-step="5" onclick={goToStep}>
|
||||||
<div class="step-number">5</div>
|
<div class="step-number">5</div>
|
||||||
<div class="step-label">Download PDF</div>
|
<div class="step-label">Download PDF</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step 1: Template Selection -->
|
<!-- Step 1: Template Selection -->
|
||||||
<div class="step-content" data-step="1" class={isStep1}>
|
<div class={step1Class} data-step="1">
|
||||||
<div class="step-header">
|
<div class="step-header">
|
||||||
<h2>Choose Your Template</h2>
|
<h2>Choose Your Template</h2>
|
||||||
<p>Select from our professional templates designed for real estate marketing</p>
|
<p>Select from our professional templates designed for real estate marketing</p>
|
||||||
@ -46,498 +57,330 @@
|
|||||||
|
|
||||||
<div class="template-grid" id="all-templates">
|
<div class="template-grid" id="all-templates">
|
||||||
<!-- Custom Template -->
|
<!-- Custom Template -->
|
||||||
<div class="template-card" data-template-id="custom" onclick={handleTemplateSelect}>
|
<div class="template-card template-blank" data-template-id="custom" onclick={handleTemplateSelect}>
|
||||||
<div class="template-preview custom-template">
|
<div class="template-content">
|
||||||
<div class="template-placeholder">
|
|
||||||
<span class="template-icon">
|
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M15.232 5.232L18.768 8.768M16.732 3.732C17.2009 3.26331 17.8369 2.99988 18.5 2.99988C19.1631 2.99988 19.7991 3.26331 20.268 3.732C20.7367 4.20087 21.0001 4.83687 21.0001 5.5C21.0001 6.16313 20.7367 6.79913 20.268 7.268L18.5 9.036L15 12.5L12.5 15L9.036 18.5L7.268 20.268C6.79913 20.7367 6.16313 21.0001 5.5 21.0001C4.83687 21.0001 4.20087 20.7367 3.732 20.268C3.26331 19.7991 2.99988 19.1631 2.99988 18.5C2.99988 17.8369 3.26331 17.2009 3.732 16.732L15.232 5.232Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
<span class="template-text">Custom</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="template-info">
|
|
||||||
<h3>Custom Template</h3>
|
<h3>Custom Template</h3>
|
||||||
<p>Create your own layout with complete customization options</p>
|
<p>Build your own template with custom layouts</p>
|
||||||
<div class="template-meta">
|
|
||||||
<span class="template-pages">1-5 Pages</span>
|
|
||||||
<span class="template-type">Custom</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Selected Template Indicator -->
|
||||||
|
<template if:true={customBlankSelected}>
|
||||||
|
<div class="selected-indicator">
|
||||||
|
<span class="selected-icon">✓</span>
|
||||||
|
<span class="selected-text">Selected</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Professional 1-Pager -->
|
<!-- Professional 1-Pager Template -->
|
||||||
<div class="template-card" data-template-id="professional-1pager" onclick={handleTemplateSelect}>
|
<div class="template-card template-modern" data-template-id="professional-1pager" onclick={handleTemplateSelect}>
|
||||||
<div class="template-preview professional-1pager">
|
<div class="template-content">
|
||||||
<div class="template-layout">
|
|
||||||
<div class="layout-header"></div>
|
|
||||||
<div class="layout-content">
|
|
||||||
<div class="layout-image"></div>
|
|
||||||
<div class="layout-details"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="template-info">
|
|
||||||
<h3>Professional 1-Pager</h3>
|
<h3>Professional 1-Pager</h3>
|
||||||
<p>Compact single-page brochure with essential property highlights</p>
|
<p>Compact single-page brochure with 2x2 image grid</p>
|
||||||
<div class="template-meta">
|
|
||||||
<span class="template-pages">1 Page</span>
|
|
||||||
<span class="template-type">Professional</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Selected Template Indicator -->
|
||||||
|
<template if:true={template1Selected}>
|
||||||
|
<div class="selected-indicator">
|
||||||
|
<span class="selected-icon">✓</span>
|
||||||
|
<span class="selected-text">Selected</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Professional 3-Pager -->
|
<!-- Professional 3-Pager Template -->
|
||||||
<div class="template-card" data-template-id="professional-3pager" onclick={handleTemplateSelect}>
|
<div class="template-card template-classic" data-template-id="professional-3pager" onclick={handleTemplateSelect}>
|
||||||
<div class="template-preview professional-3pager">
|
<div class="template-content">
|
||||||
<div class="layout-3pager">
|
|
||||||
<div class="page-1"></div>
|
|
||||||
<div class="page-2"></div>
|
|
||||||
<div class="page-3"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="template-info">
|
|
||||||
<h3>Professional 3-Pager</h3>
|
<h3>Professional 3-Pager</h3>
|
||||||
<p>Comprehensive three-page brochure with detailed property analysis, market insights, and comprehensive property showcase.</p>
|
<p>Comprehensive three-page brochure with detailed analysis</p>
|
||||||
<div class="template-meta">
|
|
||||||
<span class="template-pages">3 Pages</span>
|
|
||||||
<span class="template-type">Professional</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Selected Template Indicator -->
|
||||||
|
<template if:true={template2Selected}>
|
||||||
|
<div class="selected-indicator">
|
||||||
|
<span class="selected-icon">✓</span>
|
||||||
|
<span class="selected-text">Selected</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Professional 5-Pager -->
|
<!-- Professional 5-Pager Template -->
|
||||||
<div class="template-card" data-template-id="professional-5pager" onclick={handleTemplateSelect}>
|
<div class="template-card template-minimalist" data-template-id="professional-5pager" onclick={handleTemplateSelect}>
|
||||||
<div class="template-preview professional-5pager">
|
<div class="template-content">
|
||||||
<div class="layout-5pager">
|
|
||||||
<div class="page-1"></div>
|
|
||||||
<div class="page-2"></div>
|
|
||||||
<div class="page-3"></div>
|
|
||||||
<div class="page-4"></div>
|
|
||||||
<div class="page-5"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="template-info">
|
|
||||||
<h3>Professional 5-Pager</h3>
|
<h3>Professional 5-Pager</h3>
|
||||||
<p>Comprehensive five-page brochure with detailed market analysis and investment insights</p>
|
<p>Premium five-page brochure with comprehensive analysis</p>
|
||||||
<div class="template-meta">
|
|
||||||
<span class="template-pages">5 Pages</span>
|
|
||||||
<span class="template-type">Professional</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Selected Template Indicator -->
|
||||||
|
<template if:true={template3Selected}>
|
||||||
|
<div class="selected-indicator">
|
||||||
|
<span class="selected-icon">✓</span>
|
||||||
|
<span class="selected-text">Selected</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Luxury Villa -->
|
<!-- Luxury Villa Template -->
|
||||||
<div class="template-card" data-template-id="luxury-villa" onclick={handleTemplateSelect}>
|
<div class="template-card template-professional" data-template-id="luxury-villa" onclick={handleTemplateSelect}>
|
||||||
<div class="template-preview luxury-villa">
|
<div class="template-content">
|
||||||
<div class="layout-luxury">
|
<h3>Luxury Villa Brochure</h3>
|
||||||
<div class="luxury-header"></div>
|
<p>Exclusive villa template with premium styling</p>
|
||||||
<div class="luxury-content">
|
|
||||||
<div class="luxury-image"></div>
|
|
||||||
<div class="luxury-details"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="template-info">
|
|
||||||
<h3>Luxury Villa</h3>
|
<!-- Selected Template Indicator -->
|
||||||
<p>Premium villa brochure with elegant design and comprehensive property showcase</p>
|
<template if:true={template4Selected}>
|
||||||
<div class="template-meta">
|
<div class="selected-indicator">
|
||||||
<span class="template-pages">3 Pages</span>
|
<span class="selected-icon">✓</span>
|
||||||
<span class="template-type">Luxury</span>
|
<span class="selected-text">Selected</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modern Apartment -->
|
<!-- Dubai Penthouse Template -->
|
||||||
<div class="template-card" data-template-id="modern-apartment" onclick={handleTemplateSelect}>
|
<div class="template-card template-creative" data-template-id="dubai-penthouse" onclick={handleTemplateSelect}>
|
||||||
<div class="template-preview modern-apartment">
|
<div class="template-content">
|
||||||
<div class="layout-modern">
|
<h3>Dubai Penthouse</h3>
|
||||||
<div class="modern-header"></div>
|
<p>Dubai-specific luxury penthouse template</p>
|
||||||
<div class="modern-content">
|
|
||||||
<div class="modern-image"></div>
|
|
||||||
<div class="modern-details"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="template-info">
|
|
||||||
|
<!-- Selected Template Indicator -->
|
||||||
|
<template if:true={template5Selected}>
|
||||||
|
<div class="selected-indicator">
|
||||||
|
<span class="selected-icon">✓</span>
|
||||||
|
<span class="selected-text">Selected</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modern Apartment Template -->
|
||||||
|
<div class="template-card template-corporate" data-template-id="modern-apartment" onclick={handleTemplateSelect}>
|
||||||
|
<div class="template-content">
|
||||||
<h3>Modern Apartment</h3>
|
<h3>Modern Apartment</h3>
|
||||||
<p>Contemporary apartment brochure with modern design elements</p>
|
<p>Contemporary apartment template with clean lines</p>
|
||||||
<div class="template-meta">
|
|
||||||
<span class="template-pages">2 Pages</span>
|
|
||||||
<span class="template-type">Modern</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Investment Property -->
|
<!-- Selected Template Indicator -->
|
||||||
<div class="template-card" data-template-id="investment-property" onclick={handleTemplateSelect}>
|
<template if:true={template6Selected}>
|
||||||
<div class="template-preview investment-property">
|
<div class="selected-indicator">
|
||||||
<div class="layout-investment">
|
<span class="selected-icon">✓</span>
|
||||||
<div class="investment-header"></div>
|
<span class="selected-text">Selected</span>
|
||||||
<div class="investment-content">
|
|
||||||
<div class="investment-chart"></div>
|
|
||||||
<div class="investment-details"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
<div class="template-info">
|
|
||||||
<h3>Investment Property</h3>
|
|
||||||
<p>Investment-focused brochure with ROI analysis and market data</p>
|
|
||||||
<div class="template-meta">
|
|
||||||
<span class="template-pages">3 Pages</span>
|
|
||||||
<span class="template-type">Investment</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="step-actions">
|
<div class="step-actions">
|
||||||
<button class="btn btn-primary" disabled={!canProceed} onclick={nextStep}>
|
<button class="btn btn-primary" disabled={isNextButtonDisabled} onclick={nextStep}>Next Step</button>
|
||||||
Next: Property Details
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step 2: Property Selection and Details -->
|
<!-- Step 2: Property Details -->
|
||||||
<div class="step-content" data-step="2" class={isStep2}>
|
<div class={step2Class} data-step="2">
|
||||||
<div class="step-header">
|
<div class="step-header">
|
||||||
<h2>Select Property & Details</h2>
|
<h2>Property Details</h2>
|
||||||
<p>Choose a property from your Salesforce system or enter details manually</p>
|
<p>Enter comprehensive property information for your brochure</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Property Selection Section -->
|
<!-- Property Selector Dropdown -->
|
||||||
<div class="property-selection-section">
|
<div class="property-selector">
|
||||||
<h3>Select Existing Property</h3>
|
<h3>Select Existing Property</h3>
|
||||||
<div class="form-group">
|
<div class="property-selector-controls">
|
||||||
<label for="property-select">Choose Property:</label>
|
<select onchange={handlePropertySelection}>
|
||||||
<lightning-combobox
|
<option value="">-- Select a Property --</option>
|
||||||
id="property-select"
|
<template for:each={formattedPropertyOptions} for:item="property">
|
||||||
name="property-select"
|
<option key={property.value} value={property.value}>
|
||||||
label="Select Property"
|
{property.label}
|
||||||
placeholder="Choose a property from your system"
|
</option>
|
||||||
options={availableProperties}
|
</template>
|
||||||
value={selectedPropertyId}
|
</select>
|
||||||
onchange={handlePropertySelection}
|
<button type="button" class="btn btn-secondary btn-sm" onclick={manuallyLoadProperties} title="Refresh Properties">
|
||||||
disabled={isLoading}>
|
🔄
|
||||||
</lightning-combobox>
|
</button>
|
||||||
<small class="form-help">Select a property to auto-populate all fields, or fill manually below</small>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Show message when no properties available -->
|
||||||
|
<template if:false={properties.length}>
|
||||||
|
<div class="no-properties-message" style="margin-top: 1rem; padding: 1rem; background-color: #f8f9fa; border: 1px solid #dee2e6; border-radius: 0.375rem; text-align: center;">
|
||||||
|
<p style="margin: 0; color: #6c757d; font-size: 14px;">
|
||||||
|
<strong>No properties found in your org.</strong><br>
|
||||||
|
Please create some Property__c records in Salesforce to see them here.<br>
|
||||||
|
You can still fill the form manually below.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<p style="margin-top: 0.5rem; font-size: 12px; color: #6c757d;">
|
||||||
|
Choose a property to auto-fill the form, or fill manually below
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Property Details Form -->
|
<div class="form-grid">
|
||||||
<div class="property-details-form">
|
<div class="form-group">
|
||||||
<h3>Property Information</h3>
|
<label for="propertyName">Property Name *</label>
|
||||||
|
<input type="text" id="propertyName" name="propertyName" value={propertyData.propertyName} onchange={handleInputChange} required />
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="propertyName">Property Name *</label>
|
|
||||||
<input type="text" id="propertyName" name="propertyName" value={propertyData.propertyName} onchange={handleInputChange} required />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="propertyType">Property Type *</label>
|
|
||||||
<select id="propertyType" name="propertyType" value={propertyData.propertyType} onchange={handleInputChange} required>
|
|
||||||
<option value="">Select Property Type</option>
|
|
||||||
<template for:each={propertyTypes} for:item="type">
|
|
||||||
<option key={type} value={type}>{type}</option>
|
|
||||||
</template>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="location">Location *</label>
|
|
||||||
<select id="location" name="location" value={propertyData.location} onchange={handleLocationChange} required>
|
|
||||||
<option value="">Select Location</option>
|
|
||||||
<template for:each={dubaiLocations} for:item="loc">
|
|
||||||
<option key={loc} value={loc}>{loc}</option>
|
|
||||||
</template>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="price">Price (AED) *</label>
|
|
||||||
<input type="number" id="price" name="price" value={propertyData.price} onchange={handleInputChange} placeholder="e.g., 5000000" required />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="bedrooms">Bedrooms</label>
|
|
||||||
<input type="number" id="bedrooms" name="bedrooms" value={propertyData.bedrooms} onchange={handleInputChange} min="0" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="bathrooms">Bathrooms</label>
|
|
||||||
<input type="number" id="bathrooms" name="bathrooms" value={propertyData.bathrooms} onchange={handleInputChange} min="0" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="area">Area (sq ft)</label>
|
|
||||||
<input type="number" id="area" name="area" value={propertyData.area} onchange={handleInputChange} min="0" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="titleEnglish">Property Title (English)</label>
|
<label for="propertyType">Property Type *</label>
|
||||||
<input type="text" id="titleEnglish" name="titleEnglish" value={propertyData.titleEnglish} onchange={handleInputChange} placeholder="e.g., Brand New | Furnished | Canal View" />
|
<select id="propertyType" name="propertyType" value={propertyData.propertyType} onchange={handlePropertyTypeChange} required>
|
||||||
|
<option value="">Select Property Type</option>
|
||||||
|
<template for:each={formattedPropertyTypes} for:item="type">
|
||||||
|
<option key={type.value} value={type.value}>{type.label}</option>
|
||||||
|
</template>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
<label for="location">Location *</label>
|
||||||
|
<select id="location" name="location" value={propertyData.location} onchange={handleLocationChange} required>
|
||||||
|
<option value="">Select Location</option>
|
||||||
|
<template for:each={dubaiLocations} for:item="loc">
|
||||||
|
<option key={loc} value={loc}>{loc}</option>
|
||||||
|
</template>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="price">Price</label>
|
||||||
|
<input type="text" id="price" name="price" value={propertyData.price} onchange={handleInputChange} placeholder="e.g., AED 2,500,000" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="bedrooms">Bedrooms</label>
|
||||||
|
<input type="number" id="bedrooms" name="bedrooms" value={propertyData.bedrooms} onchange={handleInputChange} min="0" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="bathrooms">Bathrooms</label>
|
||||||
|
<input type="number" id="bathrooms" name="bathrooms" value={propertyData.bathrooms} onchange={handleInputChange} min="0" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="area">Area (sq ft)</label>
|
||||||
|
<input type="number" id="area" name="area" value={propertyData.area} onchange={handleInputChange} min="0" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group full-width">
|
||||||
|
<label for="titleEnglish">Property Title</label>
|
||||||
|
<input type="text" id="titleEnglish" name="titleEnglish" value={propertyData.titleEnglish} onchange={handleInputChange} placeholder="e.g., Luxury Marina View Apartment" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group full-width">
|
||||||
<label for="description">Description *</label>
|
<label for="description">Description *</label>
|
||||||
<textarea id="description" name="description" value={propertyData.description} onchange={handleInputChange} rows="4" placeholder="Detailed property description..." required></textarea>
|
<textarea id="description" name="description" value={propertyData.description} onchange={handleInputChange} rows="4" placeholder="Describe the property features, amenities, and highlights..." required></textarea>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="comments">Additional Comments</label>
|
|
||||||
<textarea id="comments" name="comments" value={propertyData.comments} onchange={handleInputChange} rows="3" placeholder="Any additional notes or comments..."></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Additional Property Fields -->
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="externalId">External ID</label>
|
|
||||||
<input type="text" id="externalId" name="externalId" value={propertyData.externalId} onchange={handleInputChange} placeholder="e.g., RO-R-21-3985" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="unitNumber">Unit Number</label>
|
|
||||||
<input type="text" id="unitNumber" name="unitNumber" value={propertyData.unitNumber} onchange={handleInputChange} placeholder="e.g., 905" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="geopoint">Geopoint</label>
|
|
||||||
<input type="text" id="geopoint" name="geopoint" value={propertyData.geopoint} onchange={handleInputChange} placeholder="e.g., 25.18580055,55.27030182" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="owner">Owner</label>
|
|
||||||
<input type="text" id="owner" name="owner" value={propertyData.owner} onchange={handleInputChange} placeholder="e.g., Property Master" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="amenities">Amenities</label>
|
|
||||||
<div class="amenities-grid">
|
|
||||||
<template for:each={availableAmenities} for:item="amenity">
|
|
||||||
<label class="amenity-checkbox">
|
|
||||||
<input type="checkbox" value={amenity} onchange={handleAmenityChange} />
|
|
||||||
<span class="amenity-label">{amenity}</span>
|
|
||||||
</label>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="images">Property Images</label>
|
|
||||||
<input type="file" id="images" name="images" onchange={handleImageUpload} multiple accept="image/*" />
|
|
||||||
<small class="form-help">Upload multiple images (JPG, PNG, GIF). Max 6 images recommended.</small>
|
|
||||||
|
|
||||||
<div class="image-preview" if:true={propertyData.images}>
|
|
||||||
<template for:each={propertyData.images} for:index="index">
|
|
||||||
<div class="image-item">
|
|
||||||
<img src={item} alt="Property Image" />
|
|
||||||
<button type="button" class="remove-image" onclick={removeImage} data-index={index}>×</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="step-actions">
|
<div class="step-actions">
|
||||||
<button class="btn btn-secondary" onclick={previousStep}>Previous</button>
|
<button class="btn btn-secondary" onclick={previousStep}>Previous</button>
|
||||||
<button class="btn btn-primary" disabled={!canProceed} onclick={nextStep}>
|
<button class="btn btn-primary" disabled={isNextButtonDisabled} onclick={nextStep}>Next Step</button>
|
||||||
Next: Additional Information
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step 3: Additional Information -->
|
<!-- Step 3: Additional Information -->
|
||||||
<div class="step-content" data-step="3" class={isStep3}>
|
<div class={step3Class} data-step="3">
|
||||||
<div class="step-header">
|
<div class="step-header">
|
||||||
<h2>Additional Information</h2>
|
<h2>Additional Information</h2>
|
||||||
<p>Add market data, investment insights, and content modules</p>
|
<p>Add images, amenities, and market insights</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="additional-info-form">
|
<div class="form-section">
|
||||||
<h3>Market Analytics</h3>
|
<h3>Property Images</h3>
|
||||||
|
<div class="image-upload-section">
|
||||||
<div class="form-row">
|
<input type="file" id="imageUpload" multiple accept="image/*" onchange={handleImageUpload} />
|
||||||
<div class="form-group">
|
<label for="imageUpload" class="upload-btn">Choose Images</label>
|
||||||
<label for="marketTrend">Market Trend</label>
|
|
||||||
<select id="marketTrend" name="marketTrend" value={propertyData.marketTrend} onchange={handleInputChange}>
|
|
||||||
<option value="">Select Market Trend</option>
|
|
||||||
<option value="Rising">Rising</option>
|
|
||||||
<option value="Stable">Stable</option>
|
|
||||||
<option value="Declining">Declining</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="roiPotential">ROI Potential (%)</label>
|
|
||||||
<input type="number" id="roiPotential" name="roiPotential" value={propertyData.roiPotential} onchange={handleInputChange} step="0.1" min="0" max="100" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="uploaded-images" if:true={propertyData.images.length}>
|
||||||
<div class="form-group">
|
<template for:each={propertyData.images} for:item="image" for:index="index">
|
||||||
<label for="avgPricePerSqft">Average Price per Sq Ft (AED)</label>
|
<div key={image} class="image-item">
|
||||||
<input type="number" id="avgPricePerSqft" name="avgPricePerSqft" value={propertyData.avgPricePerSqft} onchange={handleInputChange} min="0" />
|
<img src={image.src} alt="Property Image" />
|
||||||
</div>
|
<input type="text" value={image.name} data-index={index} onchange={handleImageNameChange} placeholder="Room name" />
|
||||||
<div class="form-group">
|
<button type="button" onclick={removeImage} data-index={index} class="remove-btn">Remove</button>
|
||||||
<label for="marketDemand">Market Demand</label>
|
</div>
|
||||||
<select id="marketDemand" name="marketDemand" value={propertyData.marketDemand} onchange={handleInputChange}>
|
</template>
|
||||||
<option value="">Select Market Demand</option>
|
|
||||||
<option value="High">High</option>
|
|
||||||
<option value="Medium">Medium</option>
|
|
||||||
<option value="Low">Low</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-section">
|
||||||
<div class="form-group">
|
<h3>Amenities</h3>
|
||||||
<label for="investmentType">Investment Type</label>
|
<div class="amenities-grid">
|
||||||
<select id="investmentType" name="investmentType" value={propertyData.investmentType} onchange={handleInputChange}>
|
<template for:each={availableAmenities} for:item="amenity">
|
||||||
<option value="">Select Investment Type</option>
|
<label key={amenity} class="amenity-checkbox">
|
||||||
<option value="Buy-to-Live">Buy-to-Live</option>
|
<input type="checkbox" value={amenity} onchange={handleAmenityChange} />
|
||||||
<option value="Buy-to-Rent">Buy-to-Rent</option>
|
<span>{amenity}</span>
|
||||||
<option value="Investment">Investment</option>
|
</label>
|
||||||
</select>
|
</template>
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="rentalYield">Rental Yield (%)</label>
|
|
||||||
<input type="number" id="rentalYield" name="rentalYield" value={propertyData.rentalYield} onchange={handleInputChange} step="0.1" min="0" max="100" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="investmentHighlights">Investment Highlights</label>
|
|
||||||
<textarea id="investmentHighlights" name="investmentHighlights" value={propertyData.investmentHighlights} onchange={handleInputChange} rows="3" placeholder="Key investment benefits and highlights..."></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="locationAdvantages">Location Advantages</label>
|
|
||||||
<textarea id="locationAdvantages" name="locationAdvantages" value={propertyData.locationAdvantages} onchange={handleInputChange} rows="3" placeholder="Location benefits, connectivity, amenities..."></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="additionalContent">Additional Content</label>
|
|
||||||
<textarea id="additionalContent" name="additionalContent" value={propertyData.additionalContent} onchange={handleInputChange} rows="4" placeholder="Any additional content, notes, or special features..."></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="step-actions">
|
<div class="step-actions">
|
||||||
<button class="btn btn-secondary" onclick={previousStep}>Previous</button>
|
<button class="btn btn-secondary" onclick={previousStep}>Previous</button>
|
||||||
<button class="btn btn-primary" onclick={nextStep}>
|
<button class="btn btn-primary" disabled={isNextButtonDisabled} onclick={nextStep}>Next Step</button>
|
||||||
Next: Preview & Generate
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step 4: Preview and Generate -->
|
<!-- Step 4: Preview & Generate -->
|
||||||
<div class="step-content" data-step="4" class={isStep4}>
|
<div class={step4Class} data-step="4">
|
||||||
<div class="step-header">
|
<div class="step-header">
|
||||||
<h2>Preview & Generate</h2>
|
<h2>Preview & Generate</h2>
|
||||||
<p>Review your brochure and generate the final PDF</p>
|
<p>Review your brochure and generate the final PDF</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="preview-section">
|
<div class="preview-section">
|
||||||
<div class="preview-header">
|
<div class="preview-content">
|
||||||
<h3>Brochure Preview</h3>
|
<h3>Brochure Summary</h3>
|
||||||
<div class="preview-actions">
|
<div class="summary-grid">
|
||||||
<button class="btn btn-secondary" onclick={handlePreview} disabled={isLoading}>
|
<div class="summary-item">
|
||||||
{isLoading ? 'Generating...' : 'Generate Preview'}
|
<strong>Template:</strong> {selectedTemplateData.Name}
|
||||||
</button>
|
</div>
|
||||||
|
<div class="summary-item">
|
||||||
|
<strong>Property:</strong> {propertyData.propertyName}
|
||||||
|
</div>
|
||||||
|
<div class="summary-item">
|
||||||
|
<strong>Location:</strong> {propertyData.location}
|
||||||
|
</div>
|
||||||
|
<div class="summary-item">
|
||||||
|
<strong>Images:</strong> {propertyData.images.length} uploaded
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="preview-content" if:true={showPreview}>
|
<div class="preview-actions">
|
||||||
<div class="preview-frame">
|
<button class="btn btn-primary" onclick={handlePreview} disabled={isLoading}>
|
||||||
<iframe src={pdfPreviewUrl} width="100%" height="600" frameborder="0"></iframe>
|
{previewButtonText}
|
||||||
</div>
|
</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="preview-placeholder" if:false={showPreview}>
|
|
||||||
<div class="placeholder-content">
|
|
||||||
<span class="placeholder-icon">
|
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M9 12H15M9 16H15M17 21H7C5.89543 21 5 20.1046 5 19V5C5 3.89543 5.89543 3 7 3H12.5858C12.851 3 13.1054 3.10536 13.2929 3.29289L19.7071 9.70711C19.8946 9.89464 20 10.149 20 10.4142V19C20 20.1046 19.1046 21 18 21H17ZM17 21V10H12V5H7V19H17Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
<p>Click "Generate Preview" to see your brochure</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="step-actions">
|
<div class="step-actions">
|
||||||
<button class="btn btn-secondary" onclick={previousStep}>Previous</button>
|
<button class="btn btn-secondary" onclick={previousStep}>Previous</button>
|
||||||
<button class="btn btn-primary" onclick={nextStep} disabled={!showPreview}>
|
<button class="btn btn-success" onclick={nextStep} disabled={isDownloadButtonDisabled}>Continue to Download</button>
|
||||||
Next: Download PDF
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step 5: Download PDF -->
|
<!-- Step 5: Download PDF -->
|
||||||
<div class="step-content" data-step="5" class={isStep5}>
|
<div class={step5Class} data-step="5">
|
||||||
<div class="step-header">
|
<div class="step-header">
|
||||||
<h2>Download Your PDF</h2>
|
<h2>Download Your Brochure</h2>
|
||||||
<p>Your professional property brochure is ready!</p>
|
<p>Your professional property brochure is ready for download</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="download-section">
|
<div class="download-section">
|
||||||
<div class="download-success">
|
<div class="success-message">
|
||||||
<div class="success-icon">
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<path d="M9 12L11 14L15 10M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path d="M9 12L11 14L15 10M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
</svg>
|
||||||
</svg>
|
<h3>Brochure Generated Successfully!</h3>
|
||||||
</div>
|
<p>Your professional property brochure has been created and is ready for download.</p>
|
||||||
<h3>PDF Generated Successfully!</h3>
|
|
||||||
<p>Your professional property brochure has been created with the selected template and all your property data.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="download-actions">
|
<div class="download-actions">
|
||||||
<button class="btn btn-primary btn-large" onclick={handleDownload} disabled={isLoading}>
|
<button class="btn btn-success btn-large" onclick={handleDownload} disabled={isLoading}>
|
||||||
{isLoading ? 'Downloading...' : 'Download PDF'}
|
{downloadButtonText}
|
||||||
</button>
|
|
||||||
<button class="btn btn-secondary" onclick={handlePreview}>
|
|
||||||
View Preview Again
|
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-secondary" onclick={handleCreateNew}>Create New Brochure</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="brochure-details">
|
|
||||||
<h4>Brochure Details</h4>
|
|
||||||
<div class="detail-grid">
|
|
||||||
<div class="detail-item">
|
|
||||||
<span class="detail-label">Template:</span>
|
|
||||||
<span class="detail-value">{selectedTemplateData.Name}</span>
|
|
||||||
</div>
|
|
||||||
<div class="detail-item">
|
|
||||||
<span class="detail-label">Property:</span>
|
|
||||||
<span class="detail-value">{propertyData.propertyName}</span>
|
|
||||||
</div>
|
|
||||||
<div class="detail-item">
|
|
||||||
<span class="detail-label">Location:</span>
|
|
||||||
<span class="detail-value">{propertyData.location}</span>
|
|
||||||
</div>
|
|
||||||
<div class="detail-item">
|
|
||||||
<span class="detail-label">Generated:</span>
|
|
||||||
<span class="detail-value">{new Date().toLocaleDateString()}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="step-actions">
|
|
||||||
<button class="btn btn-secondary" onclick={previousStep}>Previous</button>
|
|
||||||
<button class="btn btn-success" onclick={handleCreateNew}>
|
|
||||||
Create New Brochure
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Loading Overlay -->
|
|
||||||
<div class="loading-overlay" if:true={isLoading}>
|
|
||||||
<div class="loading-content">
|
|
||||||
<div class="spinner"></div>
|
|
||||||
<p>Processing your request...</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<isExposed>true</isExposed>
|
||||||
|
<targets>
|
||||||
|
<target>lightning__AppPage</target>
|
||||||
|
<target>lightning__RecordPage</target>
|
||||||
|
<target>lightning__HomePage</target>
|
||||||
|
<target>lightning__Tab</target>
|
||||||
|
</targets>
|
||||||
|
<targetConfigs>
|
||||||
|
<targetConfig targets="lightning__RecordPage">
|
||||||
|
<supportedFormFactors>
|
||||||
|
<supportedFormFactor type="Large"/>
|
||||||
|
<supportedFormFactor type="Small"/>
|
||||||
|
</supportedFormFactors>
|
||||||
|
</targetConfig>
|
||||||
|
<targetConfig targets="lightning__AppPage">
|
||||||
|
<supportedFormFactors>
|
||||||
|
<supportedFormFactor type="Large"/>
|
||||||
|
<supportedFormFactor type="Small"/>
|
||||||
|
</supportedFormFactors>
|
||||||
|
</targetConfig>
|
||||||
|
<targetConfig targets="lightning__HomePage">
|
||||||
|
<supportedFormFactors>
|
||||||
|
<supportedFormFactor type="Large"/>
|
||||||
|
<supportedFormFactor type="Small"/>
|
||||||
|
</supportedFormFactors>
|
||||||
|
</targetConfig>
|
||||||
|
|
||||||
|
</targetConfigs>
|
||||||
|
</LightningComponentBundle>
|
||||||
@ -1,167 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Accept</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cAccept</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Accept</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cAccept</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>CancelEdit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cCancelEdit</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>CancelEdit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cCancelEdit</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Clone</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cClone</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Clone</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cClone</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Delete</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cDelete</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Delete</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cDelete</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Edit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cEdit</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Edit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cEdit</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>List</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cList</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>List</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cList</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>New</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cNew</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>New</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cNew</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>SaveEdit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cSaveEdit</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>SaveEdit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cSaveEdit</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Tab</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cTab</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Tab</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cTab</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>View</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cView</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>View</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Property_Template__cView</content>
|
|
||||||
<formFactor>Small</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<allowInChatterGroups>false</allowInChatterGroups>
|
<allowInChatterGroups>false</allowInChatterGroups>
|
||||||
<allowMru>true</allowMru>
|
|
||||||
<compactLayoutAssignment>SYSTEM</compactLayoutAssignment>
|
<compactLayoutAssignment>SYSTEM</compactLayoutAssignment>
|
||||||
<deploymentStatus>Deployed</deploymentStatus>
|
<deploymentStatus>Deployed</deploymentStatus>
|
||||||
<enableActivities>false</enableActivities>
|
<enableActivities>false</enableActivities>
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
<description>URL to the preview image for this template</description>
|
<description>URL to the preview image for this template</description>
|
||||||
<externalId>false</externalId>
|
<externalId>false</externalId>
|
||||||
<label>Preview Image URL</label>
|
<label>Preview Image URL</label>
|
||||||
<length>255</length>
|
|
||||||
<trackHistory>false</trackHistory>
|
<trackHistory>false</trackHistory>
|
||||||
<trackTrending>false</trackTrending>
|
<trackTrending>false</trackTrending>
|
||||||
<type>Url</type>
|
<type>Url</type>
|
||||||
|
|||||||
@ -1,85 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Accept</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Accept</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>CancelEdit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>CancelEdit</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Clone</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Clone</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Delete</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Delete</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Edit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Edit</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>List</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>List</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>New</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>New</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>SaveEdit</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>SaveEdit</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>Tab</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>Tab</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<actionOverrides>
|
|
||||||
<actionName>View</actionName>
|
|
||||||
<comment>Action override created by Lightning App Builder during activation.</comment>
|
|
||||||
<content>View</content>
|
|
||||||
<formFactor>Large</formFactor>
|
|
||||||
<skipRecordTypeSelect>false</skipRecordTypeSelect>
|
|
||||||
<type>Default</type>
|
|
||||||
</actionOverrides>
|
|
||||||
<allowInChatterGroups>false</allowInChatterGroups>
|
<allowInChatterGroups>false</allowInChatterGroups>
|
||||||
<compactLayoutAssignment>SYSTEM</compactLayoutAssignment>
|
<compactLayoutAssignment>SYSTEM</compactLayoutAssignment>
|
||||||
<deploymentStatus>Deployed</deploymentStatus>
|
<deploymentStatus>Deployed</deploymentStatus>
|
||||||
|
|||||||
44
force-app/main/default/pages/PdfProxyPage.page
Normal file
44
force-app/main/default/pages/PdfProxyPage.page
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<apex:page controller="PdfProxyPageController" action="{!init}" showHeader="false" sidebar="false">
|
||||||
|
|
||||||
|
<apex:form id="proxyForm">
|
||||||
|
<apex:outputPanel id="resultPanel">
|
||||||
|
<apex:outputText value="{!result}" escape="false" />
|
||||||
|
</apex:outputPanel>
|
||||||
|
</apex:form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// This will be called from the LWC
|
||||||
|
function makeHttpCall(endpoint, data) {
|
||||||
|
console.log('Making HTTP call to:', endpoint);
|
||||||
|
console.log('Data:', data);
|
||||||
|
|
||||||
|
// Use the Visualforce controller to make the HTTP call
|
||||||
|
Visualforce.remoting.Manager.invokeAction(
|
||||||
|
'{!$RemoteAction.PdfProxyPageController.makeHttpCall}',
|
||||||
|
endpoint,
|
||||||
|
JSON.stringify(data),
|
||||||
|
function(result, event) {
|
||||||
|
console.log('HTTP call result:', result);
|
||||||
|
if (result.success) {
|
||||||
|
// Send result back to parent LWC
|
||||||
|
window.parent.postMessage({
|
||||||
|
type: 'HTTP_RESPONSE',
|
||||||
|
success: true,
|
||||||
|
data: result.data
|
||||||
|
}, '*');
|
||||||
|
} else {
|
||||||
|
window.parent.postMessage({
|
||||||
|
type: 'HTTP_RESPONSE',
|
||||||
|
success: false,
|
||||||
|
error: result.error
|
||||||
|
}, '*');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{escape: false}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose the function globally
|
||||||
|
window.makeHttpCall = makeHttpCall;
|
||||||
|
</script>
|
||||||
|
</apex:page>
|
||||||
7
force-app/main/default/pages/PdfProxyPage.page-meta.xml
Normal file
7
force-app/main/default/pages/PdfProxyPage.page-meta.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ApexPage xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<apiVersion>64.0</apiVersion>
|
||||||
|
<availableInTouch>false</availableInTouch>
|
||||||
|
<confirmationTokenRequired>false</confirmationTokenRequired>
|
||||||
|
<label>PDF Proxy Page</label>
|
||||||
|
</ApexPage>
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<RemoteSiteSetting xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||||
|
<disableProtocolSecurity>false</disableProtocolSecurity>
|
||||||
|
<isActive>true</isActive>
|
||||||
|
<url>https://salesforce.tech4biz.io</url>
|
||||||
|
<description>Python PDF Generation API - Production</description>
|
||||||
|
</RemoteSiteSetting>
|
||||||
1
node_modules/.bin/is-docker
generated
vendored
Symbolic link
1
node_modules/.bin/is-docker
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../is-docker/cli.js
|
||||||
1
node_modules/.bin/jsforce
generated
vendored
Symbolic link
1
node_modules/.bin/jsforce
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../jsforce/bin/jsforce
|
||||||
1
node_modules/.bin/jsforce-gen-schema
generated
vendored
Symbolic link
1
node_modules/.bin/jsforce-gen-schema
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../jsforce/bin/jsforce-gen-schema
|
||||||
1
node_modules/.bin/tldts
generated
vendored
Symbolic link
1
node_modules/.bin/tldts
generated
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../tldts/bin/cli.js
|
||||||
1257
node_modules/.package-lock.json
generated
vendored
Normal file
1257
node_modules/.package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22
node_modules/@babel/runtime-corejs3/LICENSE
generated
vendored
Normal file
22
node_modules/@babel/runtime-corejs3/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
19
node_modules/@babel/runtime-corejs3/README.md
generated
vendored
Normal file
19
node_modules/@babel/runtime-corejs3/README.md
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# @babel/runtime-corejs3
|
||||||
|
|
||||||
|
> babel's modular runtime helpers with core-js@3 polyfilling
|
||||||
|
|
||||||
|
See our website [@babel/runtime-corejs3](https://babeljs.io/docs/babel-runtime-corejs3) for more information.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Using npm:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --save @babel/runtime-corejs3
|
||||||
|
```
|
||||||
|
|
||||||
|
or using yarn:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add @babel/runtime-corejs3
|
||||||
|
```
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/from.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/from.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/array/from");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/array/is-array");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/of.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/of.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/array/of");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/clear-immediate.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/clear-immediate.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/clear-immediate");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/date/now.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/date/now.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/date/now");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/bind.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/bind.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/bind");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/code-point-at.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/code-point-at.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/code-point-at");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/concat");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/copy-within.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/copy-within.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/copy-within");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/ends-with.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/ends-with.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/ends-with");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/entries.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/entries.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/entries");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/every.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/every.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/every");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/fill.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/fill.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/fill");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/filter");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/find-index.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/find-index.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/find-index");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/find.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/find.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/find");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flags.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flags.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/flags");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flat-map.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flat-map.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/flat-map");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flat.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flat.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/flat");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/for-each");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/includes");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/index-of.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/index-of.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/index-of");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/keys.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/keys.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/keys");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/last-index-of.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/last-index-of.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/last-index-of");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/map");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/pad-end.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/pad-end.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/pad-end");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/pad-start.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/pad-start.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/pad-start");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce-right.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce-right.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/reduce-right");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/reduce");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/repeat.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/repeat.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/repeat");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reverse.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reverse.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/reverse");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/slice.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/slice.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/slice");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/some.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/some.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/some");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/sort.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/sort.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/sort");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/splice.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/splice.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/splice");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/starts-with.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/starts-with.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/starts-with");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-end.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-end.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/trim-end");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-left.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-left.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/trim-left");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-right.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-right.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/trim-right");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-start.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-start.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/trim-start");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/trim");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/values.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/values.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/instance/values");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/json/stringify.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/json/stringify.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/json/stringify");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/map.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/map.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/map");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/acosh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/acosh.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/acosh");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/asinh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/asinh.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/asinh");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/atanh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/atanh.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/atanh");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/cbrt.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/cbrt.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/cbrt");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/clz32.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/clz32.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/clz32");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/cosh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/cosh.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/cosh");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/expm1.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/expm1.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/expm1");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/fround.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/fround.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/fround");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/hypot.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/hypot.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/hypot");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/imul.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/imul.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/imul");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log10.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log10.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/log10");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log1p.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log1p.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/log1p");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log2.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log2.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/log2");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/sign.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/sign.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/sign");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/sinh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/sinh.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/sinh");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/tanh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/tanh.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/tanh");
|
||||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/trunc.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/trunc.js
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("core-js-pure/stable/math/trunc");
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user