Compare commits

..

No commits in common. "88b55910666120d56095a0544d9fe0270fd79d88" and "1e7c500f904fbb261b33ee149559caf14d3741cc" have entirely different histories.

1 changed files with 12 additions and 23 deletions

View File

@ -15,6 +15,7 @@ import {
MenuItem, MenuItem,
Paper, Paper,
Select, Select,
Snackbar,
Tab, Tab,
Tabs, Tabs,
TextField, TextField,
@ -152,22 +153,12 @@ function ReportHtmlFrame({ html }: { html: string }) {
const iframe = iframeRef.current; const iframe = iframeRef.current;
if (!iframe) return; if (!iframe) return;
let resizeObserver: ResizeObserver | null = null;
const updateHeight = () => { const updateHeight = () => {
try { try {
const doc = iframe.contentDocument || iframe.contentWindow?.document; const doc = iframe.contentDocument || iframe.contentWindow?.document;
if (doc?.body) { if (doc?.body) {
const newHeight = Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight) + 40; const newHeight = doc.body.scrollHeight + 20;
if (newHeight > 50) setHeight(newHeight); if (newHeight > 50) setHeight(newHeight);
if (!resizeObserver) {
resizeObserver = new ResizeObserver(() => {
const h = Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight) + 40;
if (h > 50) setHeight(h);
});
resizeObserver.observe(doc.body);
}
} }
} catch { /* cross-origin safety */ } } catch { /* cross-origin safety */ }
}; };
@ -178,7 +169,6 @@ function ReportHtmlFrame({ html }: { html: string }) {
return () => { return () => {
iframe.removeEventListener('load', updateHeight); iframe.removeEventListener('load', updateHeight);
timers.forEach(clearTimeout); timers.forEach(clearTimeout);
resizeObserver?.disconnect();
}; };
}, [html]); }, [html]);
@ -186,7 +176,6 @@ function ReportHtmlFrame({ html }: { html: string }) {
<iframe <iframe
ref={iframeRef} ref={iframeRef}
srcDoc={html} srcDoc={html}
scrolling="no"
style={{ style={{
width: '100%', width: '100%',
height, height,
@ -297,7 +286,7 @@ function WeeklyReport({ installationId, installationName, installationEmail }: W
const [autoSend, setAutoSend] = useState({ sendWeekly: false, sendMonthly: false, sendYearly: false }); const [autoSend, setAutoSend] = useState({ sendWeekly: false, sendMonthly: false, sendYearly: false });
const [autoSendDirty, setAutoSendDirty] = useState(false); const [autoSendDirty, setAutoSendDirty] = useState(false);
const [savingAutoSend, setSavingAutoSend] = useState(false); const [savingAutoSend, setSavingAutoSend] = useState(false);
const [autoSendStatus, setAutoSendStatus] = useState<{ message: string; severity: 'success' | 'error' } | null>(null); const [autoSendSnackbar, setAutoSendSnackbar] = useState<string | null>(null);
useEffect(() => { useEffect(() => {
axiosConfig.get('/GetEmailPreference', { params: { installationId } }) axiosConfig.get('/GetEmailPreference', { params: { installationId } })
@ -320,11 +309,9 @@ function WeeklyReport({ installationId, installationName, installationEmail }: W
params: { installationId, ...autoSend } params: { installationId, ...autoSend }
}); });
setAutoSendDirty(false); setAutoSendDirty(false);
setAutoSendStatus({ message: intl.formatMessage({ id: 'autoSendSaved', defaultMessage: 'Auto-send preferences saved.' }), severity: 'success' }); setAutoSendSnackbar(intl.formatMessage({ id: 'autoSendSaved', defaultMessage: 'Auto-send preferences saved.' }));
setTimeout(() => setAutoSendStatus(null), 4000);
} catch { } catch {
setAutoSendStatus({ message: intl.formatMessage({ id: 'autoSendSaveFailed', defaultMessage: 'Failed to save auto-send preferences.' }), severity: 'error' }); setAutoSendSnackbar(intl.formatMessage({ id: 'autoSendSaveFailed', defaultMessage: 'Failed to save auto-send preferences.' }));
setTimeout(() => setAutoSendStatus(null), 4000);
} finally { } finally {
setSavingAutoSend(false); setSavingAutoSend(false);
} }
@ -540,13 +527,15 @@ function WeeklyReport({ installationId, installationName, installationEmail }: W
<FormattedMessage id="autoSendNoEmail" defaultMessage="Set email address in Information tab to enable auto-send" /> <FormattedMessage id="autoSendNoEmail" defaultMessage="Set email address in Information tab to enable auto-send" />
</Typography> </Typography>
)} )}
{autoSendStatus && (
<Typography variant="caption" sx={{ color: autoSendStatus.severity === 'success' ? '#27ae60' : '#e74c3c', ml: 1, textTransform: 'uppercase', fontWeight: 600 }}>
{autoSendStatus.message}
</Typography>
)}
</Box> </Box>
<Snackbar
open={!!autoSendSnackbar}
autoHideDuration={4000}
onClose={() => setAutoSendSnackbar(null)}
message={autoSendSnackbar}
/>
<Box sx={{ display: tabs[safeTab]?.key === 'daily' ? 'block' : 'none', minHeight: '50vh' }}> <Box sx={{ display: tabs[safeTab]?.key === 'daily' ? 'block' : 'none', minHeight: '50vh' }}>
<DailySection installationId={installationId} onHasData={setDailyHasData} onPeriodChange={(date: string) => setReportPeriods(prev => ({ ...prev, daily: { start: date, end: date } }))} /> <DailySection installationId={installationId} onHasData={setDailyHasData} onPeriodChange={(date: string) => setReportPeriods(prev => ({ ...prev, daily: { start: date, end: date } }))} />
</Box> </Box>