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:
dwindown
2025-09-28 23:30:44 +07:00
parent 78570f04f0
commit 68db19e076
13 changed files with 789 additions and 156 deletions

View File

@@ -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);
}
};