UI consistency & code quality improvements
- Standardized InvoiceEditor CreateNew tab styling to match ObjectEditor design - Fixed CodeMirror focus issues during editing by removing problematic dependencies - Removed copy button from mindmap view for cleaner interface - Resolved ESLint warnings in PostmanTreeTable.js with useCallback optimization - Enhanced PDF generation with dynamic style swapping for better print output - Updated commits.json with latest changes
This commit is contained in:
@@ -101,22 +101,130 @@ const InvoicePreview = () => {
|
||||
|
||||
// Format number with thousand separator
|
||||
const formatNumber = (num) => {
|
||||
if (!invoiceData?.settings?.thousandSeparator) return num.toString();
|
||||
return num.toLocaleString('en-US', { minimumFractionDigits: 2 });
|
||||
const decimalDigits = invoiceData?.settings?.decimalDigits ?? 2;
|
||||
if (!invoiceData?.settings?.thousandSeparator) return num.toFixed(decimalDigits);
|
||||
return num.toLocaleString('en-US', { minimumFractionDigits: decimalDigits, maximumFractionDigits: decimalDigits });
|
||||
};
|
||||
|
||||
// Format currency
|
||||
const formatCurrency = (amount, useThousandSeparator = false) => {
|
||||
const symbol = invoiceData?.settings?.currency?.symbol || '$';
|
||||
const formattedAmount = useThousandSeparator ? formatNumber(amount) : amount.toFixed(2);
|
||||
const decimalDigits = invoiceData?.settings?.decimalDigits ?? 2;
|
||||
const formattedAmount = useThousandSeparator ? formatNumber(amount) : amount.toFixed(decimalDigits);
|
||||
return `${symbol} ${formattedAmount}`;
|
||||
};
|
||||
|
||||
// Utility function to temporarily apply print-optimized styles
|
||||
const applyPrintStyles = () => {
|
||||
const element = document.getElementById('invoice-content');
|
||||
if (!element) return null;
|
||||
|
||||
// Store original styles
|
||||
const originalStyles = new Map();
|
||||
|
||||
// Find all table elements and store their original styles
|
||||
const tables = element.querySelectorAll('table');
|
||||
tables.forEach((table, index) => {
|
||||
originalStyles.set(`table-${index}`, table.style.cssText);
|
||||
table.style.borderCollapse = 'collapse';
|
||||
});
|
||||
|
||||
// Find all th and td elements and apply print styles
|
||||
const cells = element.querySelectorAll('th, td');
|
||||
cells.forEach((cell, index) => {
|
||||
originalStyles.set(`cell-${index}`, cell.style.cssText);
|
||||
cell.style.verticalAlign = 'middle';
|
||||
cell.style.padding = '4px 12px 20px';
|
||||
cell.style.lineHeight = '1.4';
|
||||
});
|
||||
|
||||
// Find all totals rows and apply print styles
|
||||
const totalsRows = element.querySelectorAll('.invoice-totals-row, .invoice-total-final');
|
||||
totalsRows.forEach((row, index) => {
|
||||
originalStyles.set(`totals-${index}`, row.style.cssText);
|
||||
row.style.display = 'flex';
|
||||
row.style.alignItems = 'center';
|
||||
row.style.justifyContent = 'space-between';
|
||||
row.style.padding = '4px 12px 20px';
|
||||
row.style.minHeight = '44px';
|
||||
});
|
||||
|
||||
// Find all stamp cards and apply print styles
|
||||
const stampCards = element.querySelectorAll('.invoice-payment-status-stamp');
|
||||
stampCards.forEach((stampCard, index) => {
|
||||
originalStyles.set(`stamp-${index}`, stampCard.style.cssText);
|
||||
stampCard.style.padding = '4px 12px 20px';
|
||||
});
|
||||
|
||||
// Find all cards and apply print styles
|
||||
const fromToCards = element.querySelectorAll('.invoice-from-to-card');
|
||||
fromToCards.forEach((fromToCard, index) => {
|
||||
originalStyles.set(`fromTo-${index}`, fromToCard.style.cssText);
|
||||
fromToCard.style.padding = '4px 12px 20px';
|
||||
});
|
||||
|
||||
return originalStyles;
|
||||
};
|
||||
|
||||
// Utility function to restore original styles
|
||||
const restoreOriginalStyles = (originalStyles) => {
|
||||
if (!originalStyles) return;
|
||||
|
||||
const element = document.getElementById('invoice-content');
|
||||
if (!element) return;
|
||||
|
||||
// Restore table styles
|
||||
const tables = element.querySelectorAll('table');
|
||||
tables.forEach((table, index) => {
|
||||
const originalStyle = originalStyles.get(`table-${index}`);
|
||||
if (originalStyle !== undefined) {
|
||||
table.style.cssText = originalStyle;
|
||||
}
|
||||
});
|
||||
|
||||
// Restore cell styles
|
||||
const cells = element.querySelectorAll('th, td');
|
||||
cells.forEach((cell, index) => {
|
||||
const originalStyle = originalStyles.get(`cell-${index}`);
|
||||
if (originalStyle !== undefined) {
|
||||
cell.style.cssText = originalStyle;
|
||||
}
|
||||
});
|
||||
|
||||
// Restore totals row styles
|
||||
const totalsRows = element.querySelectorAll('.invoice-totals-row, .invoice-total-final');
|
||||
totalsRows.forEach((row, index) => {
|
||||
const originalStyle = originalStyles.get(`totals-${index}`);
|
||||
if (originalStyle !== undefined) {
|
||||
row.style.cssText = originalStyle;
|
||||
}
|
||||
});
|
||||
|
||||
// Restore stamp card styles
|
||||
const stampCards = element.querySelectorAll('.invoice-payment-status-stamp');
|
||||
stampCards.forEach((stampCard, index) => {
|
||||
const originalStyle = originalStyles.get(`stamp-${index}`);
|
||||
if (originalStyle !== undefined) {
|
||||
stampCard.style.cssText = originalStyle;
|
||||
}
|
||||
});
|
||||
|
||||
// Restore fromTo card styles
|
||||
const fromToCards = element.querySelectorAll('.invoice-from-to-card');
|
||||
fromToCards.forEach((fromToCard, index) => {
|
||||
const originalStyle = originalStyles.get(`fromTo-${index}`);
|
||||
if (originalStyle !== undefined) {
|
||||
fromToCard.style.cssText = originalStyle;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Generate PDF from the visible invoice
|
||||
const handleDownloadPDF = async () => {
|
||||
if (!invoiceData) return;
|
||||
|
||||
setIsGenerating(true);
|
||||
let originalStyles = null;
|
||||
|
||||
try {
|
||||
const element = document.getElementById('invoice-content');
|
||||
@@ -124,8 +232,14 @@ const InvoicePreview = () => {
|
||||
throw new Error('Invoice content not found');
|
||||
}
|
||||
|
||||
// Apply print-optimized styles temporarily
|
||||
originalStyles = applyPrintStyles();
|
||||
|
||||
// Small delay to ensure styles are applied
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
const opt = {
|
||||
margin: [0.2, 0.4, 0.5, 0.4], // top, left, bottom, right margins in inches - reduced top margin for first page
|
||||
margin: [0.2, 0.4, 0.8, 0.4], // top, left, bottom, right margins in inches - increased bottom margin to prevent elements dropping
|
||||
filename: `invoice-${invoiceData.invoiceNumber || 'draft'}.pdf`,
|
||||
image: { type: 'png', quality: 0.98 },
|
||||
html2canvas: {
|
||||
@@ -151,6 +265,11 @@ const InvoicePreview = () => {
|
||||
console.error('PDF generation failed:', error);
|
||||
alert('Failed to generate PDF. Please try again.');
|
||||
} finally {
|
||||
// Restore original styles after a short delay
|
||||
setTimeout(() => {
|
||||
restoreOriginalStyles(originalStyles);
|
||||
}, 500);
|
||||
|
||||
setIsGenerating(false);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user