Create lighting web component as an action in record detail page in salesforce to allow users to download all related files on opportunity with a single click and consider time out issues as i tried to create it today and it has this issue sometimes worked sometimes not and there zip file solutions try to depend on resources like salesforce stack overflow , salesforce ben and with your recommended solutions considering these things mentioned above
The apex code
public with sharing class OpportunityFilesController {
@AuraEnabled(cacheable=false)
public static List<FileWrapper> getOpportunityFiles(Id oppId) {
List<FileWrapper> results = new List<FileWrapper>();
// Get all files linked to Opportunity
List<ContentDocumentLink> links = [
SELECT ContentDocumentId, ContentDocument.Title,
ContentDocument.LatestPublishedVersionId
FROM ContentDocumentLink
WHERE LinkedEntityId = :oppId
];
// Fetch file versions
for (ContentDocumentLink l : links) {
ContentVersion v = [
SELECT Id, Title, FileExtension, VersionData, ContentSize
FROM ContentVersion
WHERE Id = :l.ContentDocument.LatestPublishedVersionId
LIMIT 1
];
// ⚠️ Add limit to avoid hitting heap size
if (v.ContentSize < 3000000) { // 3MB limit per file for safety
results.add(new FileWrapper(
v.Title + '.' + v.FileExtension,
EncodingUtil.base64Encode(v.VersionData)
));
} else {
// Instead of crashing, skip large file
results.add(new FileWrapper(
v.Title + '.' + v.FileExtension,
null,
true
));
}
}
return results;
}
public class FileWrapper {
@AuraEnabled public String fileName;
@AuraEnabled public String base64Data;
@AuraEnabled public Boolean skipped;
public FileWrapper(String f, String b) {
fileName = f;
base64Data = b;
skipped = false;
}
public FileWrapper(String f, String b, Boolean s) {
fileName = f;
base64Data = b;
skipped = s;
}
}
}
Html code
<template>
<lightning-card title="Download Files">
<lightning-button
variant="brand"
label="Download All Files"
onclick={handleDownload}
disabled={isLoading}>
</lightning-button>
<template if:true={isLoading}>
<lightning-spinner size="medium"></lightning-spinner>
</template>
</lightning-card>
</template>
Javascript code
import { LightningElement, api, track } from 'lwc';
import getOpportunityFiles from '@salesforce/apex/OpportunityFilesController.getOpportunityFiles';
import JSZip from '@salesforce/resourceUrl/jszip';
import { loadScript } from 'lightning/platformResourceLoader';
export default class OpportunityDownloadFiles extends LightningElement {
@api recordId;
isLoading = false;
jsZipInitialized = false;
renderedCallback() {
if (this.jsZipInitialized) return;
this.jsZipInitialized = true;
loadScript(this, JSZip + '/jszip.min.js');
}
async handleDownload() {
this.isLoading = true;
try {
const files = await getOpportunityFiles({ oppId: this.recordId });
const zip = new JSZip();
files.forEach(file => {
if (!file.skipped && file.base64Data) {
const content = atob(file.base64Data);
const arrayBuffer = new Uint8Array(content.length);
for (let i = 0; i < content.length; i++) {
arrayBuffer[i] = content.charCodeAt(i);
}
zip.file(file.fileName, arrayBuffer);
}
});
const blob = await zip.generateAsync({ type: 'blob' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'OpportunityFiles.zip';
link.click();
} catch (error) {
console.error(error);
} finally {
this.isLoading = false;
}
}
}
Please i want your input if they are correct
#Salesforce Developer #Apex Class #Lightning Web Components