add comm coor report w/ download and copy abilities
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
import {Flex, Button, Spinner, Text} from "@chakra-ui/react";
|
||||
import useBuildUrl from "../../hooks/useBuildUrl.js";
|
||||
import VdapApi from '../../hooks/useVdapApi.js';
|
||||
import { useRef, useEffect } from 'react';
|
||||
import {useDashboardStore} from "../../store/useDashboardStore.jsx";
|
||||
|
||||
export default function CommCoorReport({ settings, widgetID }) {
|
||||
const reportRef = useRef(null);
|
||||
|
||||
const updateSettings = useDashboardStore(state => state.updateWidgetSettings);
|
||||
|
||||
// build url, defaults to 7 days past
|
||||
const url = useBuildUrl('/api/v2/comm_coor_report', settings?.startDate, settings?.endDate);
|
||||
console.log(url);
|
||||
|
||||
// VdapApi hook only calls api if the url changes and apiData remains stable since vdapApi uses state to track the data
|
||||
const {data: apiData, isLoading, error} = VdapApi(url);
|
||||
console.log(apiData);
|
||||
|
||||
const handleDownloadReport = () => {
|
||||
if (apiData.length === 0) return;
|
||||
const element = document.createElement('a');
|
||||
element.style.display = 'none';
|
||||
// Appends HTML right inside the element, after its last child
|
||||
element.insertAdjacentHTML('afterbegin', apiData?.report_html);
|
||||
|
||||
// 1. Create a blob object with text content and text/plain mime type
|
||||
const blob = new Blob([element.textContent || ""], { type: 'text/plain' });
|
||||
|
||||
// 2. Generate a temporary URL pointing to that blob
|
||||
const fileUrl = URL.createObjectURL(blob);
|
||||
|
||||
// 3. Create a hidden anchor element
|
||||
const linkElement = document.createElement('a');
|
||||
linkElement.href = fileUrl;
|
||||
linkElement.download = `comm_coor_report_${apiData?.start_date}_${apiData?.end_date}`; // Sets the target file name
|
||||
linkElement.style.display = 'none';
|
||||
|
||||
// 4. Append to body, trigger click, and remove it immediately
|
||||
document.body.appendChild(linkElement);
|
||||
linkElement.click();
|
||||
document.body.removeChild(linkElement);
|
||||
document.body.removeChild(element);
|
||||
|
||||
// 5. Free up memory by revoking the blob URL
|
||||
URL.revokeObjectURL(fileUrl);
|
||||
}
|
||||
|
||||
const handleCopyReport = () => {
|
||||
if (apiData.length === 0) return;
|
||||
const element = document.createElement('a');
|
||||
element.style.display = 'none';
|
||||
// Appends HTML right inside the element, after its last child
|
||||
element.insertAdjacentHTML('afterbegin', apiData?.report_html);
|
||||
|
||||
navigator.clipboard.writeText(element.textContent || "")
|
||||
.then(() => {
|
||||
alert('Copied to clipboard!');
|
||||
})
|
||||
.catch((err => {
|
||||
console.error('Failed to copy: ', err);
|
||||
}));
|
||||
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (reportRef.current) {
|
||||
reportRef.current.innerHTML = apiData?.report_html;
|
||||
const p = reportRef.current.querySelectorAll('p');
|
||||
const b = reportRef.current.querySelectorAll('b');
|
||||
p[0].remove();
|
||||
b[0].remove();
|
||||
}
|
||||
}, [apiData]);
|
||||
|
||||
// copy data to clipboard in formatted way when user clicks on copy btn in widget settings
|
||||
useEffect(() => {
|
||||
if (settings?.copyToClipboard === true && reportRef.current) {
|
||||
navigator.clipboard.writeText(reportRef.current.innerText)
|
||||
.then(() => {
|
||||
alert('Copied to clipboard!');
|
||||
})
|
||||
.catch((err => {
|
||||
console.error('Failed to copy: ', err);
|
||||
}));
|
||||
updateSettings(widgetID, {copyToClipboard: false});
|
||||
}
|
||||
}, [settings, widgetID, updateSettings]);
|
||||
|
||||
// download report
|
||||
useEffect(() => {
|
||||
if (settings?.downloadReport === true && reportRef.current) {
|
||||
// 1. Create a blob object with text content and text/plain mime type
|
||||
const blob = new Blob([reportRef.current.innerText || ""], { type: 'text/plain' });
|
||||
|
||||
// 2. Generate a temporary URL pointing to that blob
|
||||
const fileUrl = URL.createObjectURL(blob);
|
||||
|
||||
// 3. Create a hidden anchor element
|
||||
const linkElement = document.createElement('a');
|
||||
linkElement.href = fileUrl;
|
||||
linkElement.download = `comm_coor_report_${apiData?.start_date}_${apiData?.end_date}`; // Sets the target file name
|
||||
linkElement.style.display = 'none';
|
||||
|
||||
// 4. Append to body, trigger click, and remove it immediately
|
||||
document.body.appendChild(linkElement);
|
||||
linkElement.click();
|
||||
document.body.removeChild(linkElement);
|
||||
|
||||
// 5. Free up memory by revoking the blob URL
|
||||
URL.revokeObjectURL(fileUrl);
|
||||
updateSettings(widgetID, {downloadReport: false});
|
||||
}
|
||||
}, [settings, widgetID, updateSettings, apiData]);
|
||||
|
||||
if (isLoading) return (
|
||||
<Flex w="100%" h="100%" align="center" justify="center" borderRadius="lg" bg="gray.800">
|
||||
<Spinner size="xl" color="blue.400" thickness="4px"/>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
if (error) return (
|
||||
<Flex w="100%" h="100%" align="center" justify="center" textAlign="center" borderRadius="lg" bg="gray.800">
|
||||
<Text color="red.400">{error}</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
if (!apiData) return (
|
||||
<Flex w="100%" h="100%" align="center" justify="center" borderRadius="lg" bg="gray.800">
|
||||
<Text textAlign="center" color="gray.400">No data</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex direction="row" w="100%" h="100%" p={1} overflowY="auto">
|
||||
<Text ref={reportRef}></Text>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user