import React, { useEffect, useState } from "react"; import { fetchStandardParameters, downloadFile } from "../../../APIServices/ReportRunnerAPI"; import ReportBuilderService from "../../../APIServices/ReportBuilderService"; import { toast } from "react-toastify"; import './ReportrunnerEdit.css' import { saveAs } from 'file-saver'; import axios from 'axios'; import { useNavigate, useParams } from 'react-router-dom'; const ReportRunner2Edit = () => { const navigate = useNavigate(); const { id } = useParams(); // Report data state const [reportName, setReportName] = useState("Sample Report"); const [reportId, setReportId] = useState(id || null); // Date parameters state const [dateParam, setDateParam] = useState(true); const [selectDateType, setSelectDateType] = useState(""); const [fromDate, setFromDate] = useState(""); const [toDate, setToDate] = useState(""); const [fromDateQuery, setFromDateQuery] = useState(""); const [toDateQuery, setToDateQuery] = useState(""); // Standard parameters state const [dynamicFields, setDynamicFields] = useState([]); const [dynamicFormValues, setDynamicFormValues] = useState({}); // Adhoc parameters state const [adhocList, setAdhocList] = useState([]); const [adhocParams, setAdhocParams] = useState([ { andor: "AND", fields_name: "", condition: "=", value: "" }, ]); // Condition options const conditionOptions = ["=", "!=", "<", ">", "<=", ">=", "LIKE", "BETWEEN", "IN"]; const andOrOptions = ["AND", "OR", "NOT"]; // Results state const [rows, setRows] = useState([]); const [filterRows, setFilterRows] = useState([]); const [filtered, setFiltered] = useState(false); const [headers, setHeaders] = useState([]); // Query state const [SQLQuery, setSQLQuery] = useState(''); const [dateKey, setDateKey] = useState('createdat'); const [formattedAdhocParameters, setFormattedAdhocParameters] = useState(''); const [selectedValues, setSelectedValues] = useState({}); // Loading state const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); // Get today's date const todayDate = new Date().toISOString().slice(0, 10); // Add this at the beginning of the component with other state variables const [showExportDropdown, setShowExportDropdown] = useState(false); useEffect(() => { // Fetch report details if (reportId) { fetchReportDetails(reportId); } // Set default date to today handleDateSelect('Today'); // Run query after a delay to allow data to load const timer = setTimeout(() => { runQuery(); }, 2000); return () => clearTimeout(timer); }, [reportId]); useEffect(() => { // Function to handle clicks outside the dropdown const handleClickOutside = (event) => { // Get reference to the dropdown container const dropdownContainer = document.getElementById('export-dropdown-container'); // Close dropdown if click is outside the container if (dropdownContainer && !dropdownContainer.contains(event.target)) { setShowExportDropdown(false); } }; // Function to handle escape key press const handleEscapeKey = (event) => { if (event.key === 'Escape') { setShowExportDropdown(false); } }; // Add event listeners if dropdown is open if (showExportDropdown) { document.addEventListener('mousedown', handleClickOutside); document.addEventListener('keydown', handleEscapeKey); } // Clean up event listeners when dropdown closes or component unmounts return () => { document.removeEventListener('mousedown', handleClickOutside); document.removeEventListener('keydown', handleEscapeKey); }; }, [showExportDropdown]); const fetchReportDetails = async (id) => { try { setIsLoading(true); // Fetch report details const response = await ReportBuilderService.getrbDetailsById(id); const data = response?.data; if (!data) { throw new Error("No data received from the API"); } console.log("Report details received:", data); setReportName(data.reportName); // Parse builder line data const builderLine = data.rpt_builder2_lines?.[0]; if (builderLine) { const lineData = JSON.parse(builderLine.model)?.[0]; console.log("lineData: ",lineData); if (lineData) { setAdhocList(lineData.adhoc_param_html || []); setDateParam(lineData.date_param_req || false); setSQLQuery(lineData.url || ""); // Set dynamic fields from standard parameters const dynamicFields = lineData.std_param_html || []; setDynamicFields(dynamicFields); // Initialize dynamic form values const initialFormValues = dynamicFields.reduce((acc, field) => { acc[field] = ""; return acc; }, {}); setDynamicFormValues(initialFormValues); // Fetch data if a URL exists if (lineData.url) { fetchData(lineData.url); } } } } catch (error) { console.error("Error fetching report details:", error); setError("Error loading report details"); toast.error("Failed to load report details"); } finally { setIsLoading(false); } }; const fetchData = async (url) => { try { const response = await ReportBuilderService.getAllDetailsByurl(url); console.log("responce of data fetch from url:", response.data) const data = response.data?.body ? JSON.parse(response.data.body) : []; setRows(data); setFilterRows(data); // Set headers from the first row if available if (data.length > 0) { setHeaders(Object.keys(data[0])); } } catch (error) { console.error("Error fetching data:", error); setError("Error loading data"); } }; // Handle changes to adhoc parameters const handleAdhocChange = (index, field, value) => { const updatedParams = [...adhocParams]; updatedParams[index][field] = value; setAdhocParams(updatedParams); }; // Add a new adhoc parameter row const addAdhocRow = () => { const lastRow = adhocParams[adhocParams.length - 1]; // Only add a new row if the last row has a field name if (lastRow && lastRow.fields_name !== '') { // Format the adhoc parameters for the query let formattedString = ''; for (const condition of adhocParams) { const { andor, fields_name, condition: cond, value } = condition; formattedString += ` ${andor} ${fields_name} ${cond} '${value}' `; } setFormattedAdhocParameters(formattedString); // Add a new row setAdhocParams([ ...adhocParams, { andor: "AND", fields_name: "", condition: "=", value: "" }, ]); // Update selected values for filtering selectColumn(adhocParams); } }; // Delete an adhoc parameter row const deleteAdhocRow = (index) => { if (adhocParams.length > 1) { // Get the item to be deleted const deletedItem = adhocParams[index]; // Remove the item from the adhocParams array const updatedParams = adhocParams.filter((_, i) => i !== index); setAdhocParams(updatedParams); // Update selected values const updatedSelectedValues = { ...selectedValues }; const columnName = deletedItem.fields_name; if (updatedSelectedValues[columnName]) { const value = deletedItem.value; const indexInArray = updatedSelectedValues[columnName].indexOf(value); if (indexInArray !== -1) { updatedSelectedValues[columnName].splice(indexInArray, 1); // If the array is now empty, remove the property if (updatedSelectedValues[columnName].length === 0) { delete updatedSelectedValues[columnName]; } } } setSelectedValues(updatedSelectedValues); filterRowsBySelectedValues(updatedSelectedValues); } }; // Handle dynamic form values change const handleDynamicFormChange = (field, value) => { setDynamicFormValues({ ...dynamicFormValues, [field]: value }); }; // Handle date type selection const handleDateSelect = (dateType) => { setSelectDateType(dateType); setFromDateQuery(null); setToDateQuery(null); const currentDate = new Date(); let fromDateValue, toDateValue; switch (dateType) { case 'Today': fromDateValue = new Date(); toDateValue = new Date(); break; case 'This Week': // Calculate this week (Monday to Sunday) const dayOfWeek = currentDate.getDay(); const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; fromDateValue = new Date(currentDate); fromDateValue.setDate(currentDate.getDate() - daysToMonday); toDateValue = new Date(fromDateValue); toDateValue.setDate(fromDateValue.getDate() + 6); break; case 'Last Week': // Calculate last week const lastWeekDayOfWeek = currentDate.getDay(); const lastWeekDaysToMonday = lastWeekDayOfWeek === 0 ? 6 : lastWeekDayOfWeek - 1; fromDateValue = new Date(currentDate); fromDateValue.setDate(currentDate.getDate() - lastWeekDaysToMonday - 7); toDateValue = new Date(fromDateValue); toDateValue.setDate(fromDateValue.getDate() + 6); break; case 'This Month': // First day of current month fromDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1); // Last day of current month toDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0); break; case 'Last Month': // First day of previous month fromDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, 1); // Last day of previous month toDateValue = new Date(currentDate.getFullYear(), currentDate.getMonth(), 0); break; case 'This Year': // First day of current year fromDateValue = new Date(currentDate.getFullYear(), 0, 1); // Last day of current year toDateValue = new Date(currentDate.getFullYear(), 11, 31); break; case 'Last Year': // First day of previous year fromDateValue = new Date(currentDate.getFullYear() - 1, 0, 1); // Last day of previous year toDateValue = new Date(currentDate.getFullYear() - 1, 11, 31); break; default: fromDateValue = null; toDateValue = null; } if (fromDateValue) { const fromDateString = fromDateValue.toISOString().substring(0, 10); setFromDate(fromDateString); setFromDateQuery(fromDateString); } else { setFromDate(''); setFromDateQuery(''); } if (toDateValue) { const toDateString = toDateValue.toISOString().substring(0, 10); setToDate(toDateString); setToDateQuery(toDateString); } else { setToDate(''); setToDateQuery(''); } }; // Run the query const runQuery = () => { console.log("Dynamic form values:", dynamicFormValues); console.log("Date range:", fromDate, toDate); let query = SQLQuery || ''; // Add standard parameters to the query if (Object.keys(dynamicFormValues).length > 0) { Object.keys(dynamicFormValues).forEach((key) => { if (dynamicFormValues[key] !== null && dynamicFormValues[key] !== '') { query += ` AND ${key} = '${dynamicFormValues[key]}'`; } }); // Update selected values for filtering selectColumn(dynamicFormValues); } // Add date range to the query if date parameter is required if (dateParam) { // Determine the correct date key based on adhoc list let tempDateKey = 'createdat'; adhocList.forEach(key => { if (key.includes('created_at')) tempDateKey = 'created_at'; if (key.includes('createdAt')) tempDateKey = 'createdAt'; }); setDateKey(tempDateKey); if (fromDate && toDate) { const fromDateObj = new Date(fromDate); const toDateObj = new Date(toDate); query += ` AND ${tempDateKey} BETWEEN '${fromDateObj.toISOString().split('T')[0]}' AND '${toDateObj.toISOString().split('T')[0]}'`; } } // Format and add adhoc parameters to the query let formattedString = ''; for (const condition of adhocParams) { // Only add conditions that have a field name selected if (condition.fields_name) { const { andor, fields_name, condition: cond, value } = condition; formattedString += ` ${andor} ${fields_name} ${cond} '${value}' `; } } setFormattedAdhocParameters(formattedString); // Add adhoc parameters to the query if (formattedString) { query += formattedString; } // Update selected values for filtering based on adhoc parameters selectColumn(adhocParams.filter(param => param.fields_name)); console.log("Final query:", query); // Make API request // axios.post('/api/report-runner/run', { query }) // .then((response) => { // const data = response.data; // if (data && data.length > 0) { // setRows(data); // setFilterRows(data); // setHeaders(Object.keys(data[0])); // toast.success("Query executed successfully"); // } else { // toast.warning("No data returned"); // } // }) // .catch((error) => { // console.error("Error running query:", error); // toast.error("Error running the query"); // }); }; // Export file function const exportFile = (format) => { try { const dataToExport = filtered ? filterRows : rows; if (!dataToExport || dataToExport.length === 0) { toast.warning("No data to export"); return; } const name = reportName.replace(/\s+/g, '_'); const timestamp = new Date().toISOString().replace(/[-:T.]/g, '_').slice(0, 17); const fileName = `${name}_${timestamp}`; // Show loading toast const loadingToast = toast.info("Preparing file for export...", { autoClose: false }); // Use the imported downloadFile service downloadFile(format, dataToExport, fileName); // Success message setTimeout(() => { toast.dismiss(loadingToast); toast.success(`File exported as ${format.toUpperCase()} successfully`); }, 1000); } catch (error) { console.error("Error in export function:", error); toast.error("Error exporting file"); } }; // Get table headers const getHeaders = () => { if (!rows || rows.length === 0) return []; const headerSet = new Set(); rows.forEach(row => { Object.keys(row).forEach(key => headerSet.add(key)); }); return Array.from(headerSet); }; // Get filtered table headers const getFilteredHeaders = () => { if (!filterRows || filterRows.length === 0) return []; const headerSet = new Set(); filterRows.forEach(row => { Object.keys(row).forEach(key => headerSet.add(key)); }); return Array.from(headerSet); }; // Check if a value is a date const isDate = (value) => { if (!value) return false; if (value instanceof Date) return true; if (typeof value === 'object' && value.year !== undefined && value.monthValue !== undefined && value.dayOfMonth !== undefined) { return true; } const date = new Date(value); return !isNaN(date.getTime()); }; // Format a date for display const formatDate = (value) => { if (!value) return ''; if (typeof value === 'object' && value.year !== undefined && value.monthValue !== undefined && value.dayOfMonth !== undefined) { // Handle Java-style date objects const { year, monthValue, dayOfMonth, hour = 0, minute = 0, second = 0 } = value; const date = new Date(year, monthValue - 1, dayOfMonth, hour, minute, second); return date.toLocaleString(); } // Standard JS date return new Date(value).toLocaleString(); }; // Process data for filtering const selectColumn = (data) => { const newSelectedValues = { ...selectedValues }; if (Array.isArray(data)) { // Handle array of objects (like adhoc parameters) data.forEach(item => { const { fields_name, value } = item; if (fields_name && fields_name.trim() !== '') { if (!newSelectedValues[fields_name]) { newSelectedValues[fields_name] = []; } if (value !== null && value.trim() !== '') { if (!newSelectedValues[fields_name].includes(value)) { newSelectedValues[fields_name].push(value); } } } }); } else if (typeof data === 'object') { // Handle object (like dynamic form values) Object.keys(data).forEach(key => { const value = data[key]; if (!newSelectedValues[key]) { newSelectedValues[key] = []; } if (value !== null && value.trim && value.trim() !== '') { if (!newSelectedValues[key].includes(value)) { newSelectedValues[key].push(value); } } }); } setSelectedValues(newSelectedValues); filterRowsBySelectedValues(newSelectedValues); }; // Filter rows based on selected values const filterRowsBySelectedValues = (values = selectedValues) => { const filteredRows = []; for (const row of rows) { let isMatch = true; // Check each column in the selected values for (const columnName in values) { if (values.hasOwnProperty(columnName) && row.hasOwnProperty(columnName)) { const selectedValuesForColumn = values[columnName]; const rowValue = row[columnName]; if (typeof rowValue === 'boolean') { // Handle boolean values if (selectedValuesForColumn.length === 0) continue; const selectedBooleanValue = selectedValuesForColumn[0] === 'true'; if (selectedBooleanValue !== rowValue) { isMatch = false; break; } } else { // Handle other data types const convertedValues = selectedValuesForColumn.map(value => { if (typeof rowValue === 'number') { return parseFloat(value); } return value; }); if (!convertedValues.includes(rowValue)) { isMatch = false; break; } } } } // Check date range if both dates are provided if (fromDateQuery && toDateQuery && isMatch) { const from = new Date(fromDateQuery); const to = new Date(toDateQuery); // Set hours to 0 for proper comparison from.setHours(0, 0, 0, 0); to.setHours(23, 59, 59, 999); // Get the date from the row using dateKey const rowDate = new Date(row[dateKey]); if (rowDate < from || rowDate > to) { isMatch = false; } } if (isMatch) { filteredRows.push(row); } } setFilterRows(filteredRows); // Determine if we are filtering or not const isFiltering = Object.values(values).some(arr => arr.length > 0) || (fromDateQuery && toDateQuery); setFiltered(isFiltering); }; // Render date cell with formatting const renderTableCell = (row, key) => { const isDateField = key === 'createdat' || key === 'createdAt' || key === 'updated_at' || key === 'updatedAt' || key === 'created_at' || key === 'creat_at'; if (isDateField && row[key]) { return formatDate(row[key]); } // Handle boolean values if (typeof row[key] === 'boolean') { return row[key] ? 'True' : 'False'; } return row[key]; }; // Navigate back to the reports list const goBack = () => { navigate("/admin/report-runner"); }; // Add this function at an appropriate place in the component const toggleExportDropdown = () => { setShowExportDropdown(!showExportDropdown); }; return (
{/* Report Header */}

Report Name URL - {reportName}


{/* Date and Standard Parameters Section */}
{/* Date Parameters */} {/* {dateParam && (
Date Range
{ setFromDate(e.target.value); setFromDateQuery(e.target.value); }} />
{ setToDate(e.target.value); setToDateQuery(e.target.value); }} />
)} */} {/* Standard Parameters */}
Standard Parameters
{dynamicFields.length === 0 ? (
No parameter found
) : (
{dynamicFields.map((field, index) => (
handleDynamicFormChange(field, e.target.value)} />
))}
)}
{/* Adhoc Parameters Section */}
Adhoc Parameters
{adhocParams.map((param, index) => ( ))}
handleAdhocChange(index, "value", e.target.value) } />
{/* Report Output Section */}
Report Output
{/* Custom Export Dropdown */}
{showExportDropdown && (
)}
{/* Back and Run Buttons */}

{/* Data Table */}
{isLoading ? (

Loading data...

) : error ? (
{error}
) : (filtered ? filterRows : rows).length === 0 ? (
No data available
) : ( {(filtered ? getFilteredHeaders() : getHeaders()).map((header, index) => ( ))} {(filtered ? filterRows : rows).map((row, rowIndex) => ( {(filtered ? getFilteredHeaders() : getHeaders()).map((header, colIndex) => ( ))} ))}
{header}
{renderTableCell(row, header)}
)}
); }; export default ReportRunner2Edit;