first commit
This commit is contained in:
936
src/components/Dashboard/ReportRunner/ReportRunner2Edit.js
Normal file
936
src/components/Dashboard/ReportRunner/ReportRunner2Edit.js
Normal file
@@ -0,0 +1,936 @@
|
||||
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 (
|
||||
<div className="container">
|
||||
{/* Report Header */}
|
||||
<h4 style={{ fontWeight: 300, display: "inline" }}>
|
||||
<b>Report Name URL - {reportName}</b>
|
||||
</h4>
|
||||
<hr />
|
||||
|
||||
{/* Date and Standard Parameters Section */}
|
||||
<div className="row">
|
||||
{/* Date Parameters */}
|
||||
{/* {dateParam && (
|
||||
<div className="col-md-6">
|
||||
<h5 style={{ fontWeight: 200, color: "black" }}>
|
||||
<b>Date Range</b>
|
||||
</h5>
|
||||
<div className="form-group mb-3">
|
||||
<label>Date Parameters</label>
|
||||
<select
|
||||
className="form-select"
|
||||
value={selectDateType}
|
||||
onChange={(e) => handleDateSelect(e.target.value)}
|
||||
>
|
||||
<option>--Select Particular--</option>
|
||||
<option>Today</option>
|
||||
<option>This Week</option>
|
||||
<option>Last Week</option>
|
||||
<option>This Month</option>
|
||||
<option>Last Month</option>
|
||||
<option>This Year</option>
|
||||
<option>Last Year</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-md-6">
|
||||
<label>From Date</label>
|
||||
<input
|
||||
type="date"
|
||||
className="form-control"
|
||||
value={fromDate}
|
||||
onChange={(e) => {
|
||||
setFromDate(e.target.value);
|
||||
setFromDateQuery(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<label>To Date</label>
|
||||
<input
|
||||
type="date"
|
||||
className="form-control"
|
||||
value={toDate}
|
||||
onChange={(e) => {
|
||||
setToDate(e.target.value);
|
||||
setToDateQuery(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)} */}
|
||||
|
||||
{/* Standard Parameters */}
|
||||
<div className="col-md-6">
|
||||
<h5 style={{ fontWeight: 200, color: "black" }}>
|
||||
<b>Standard Parameters</b>
|
||||
</h5>
|
||||
{dynamicFields.length === 0 ? (
|
||||
<div className="text-danger">No parameter found</div>
|
||||
) : (
|
||||
<div className="row">
|
||||
{dynamicFields.map((field, index) => (
|
||||
<div key={index} className="col-md-6 mb-3">
|
||||
<label>{field}</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
placeholder={`Enter ${field}`}
|
||||
value={dynamicFormValues[field] || ''}
|
||||
onChange={(e) => handleDynamicFormChange(field, e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Adhoc Parameters Section */}
|
||||
<div className="row mt-4">
|
||||
<div className="col-md-12">
|
||||
<h5 style={{ fontWeight: 200, color: "black" }}>
|
||||
<b>Adhoc Parameters</b>
|
||||
</h5>
|
||||
<table className="table">
|
||||
<tbody>
|
||||
{adhocParams.map((param, index) => (
|
||||
<tr key={index}>
|
||||
<td>
|
||||
<select
|
||||
className="form-select"
|
||||
value={param.andor}
|
||||
onChange={(e) =>
|
||||
handleAdhocChange(index, "andor", e.target.value)
|
||||
}
|
||||
>
|
||||
<option value="">Select Values</option>
|
||||
{andOrOptions.map((option, idx) => (
|
||||
<option key={idx} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
className="form-select"
|
||||
value={param.fields_name}
|
||||
onChange={(e) =>
|
||||
handleAdhocChange(index, "fields_name", e.target.value)
|
||||
}
|
||||
>
|
||||
<option value="">Select Values</option>
|
||||
{adhocList.map((field, idx) => (
|
||||
<option key={idx} value={field}>
|
||||
{field}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
className="form-select"
|
||||
value={param.condition}
|
||||
onChange={(e) =>
|
||||
handleAdhocChange(index, "condition", e.target.value)
|
||||
}
|
||||
>
|
||||
<option value="">Select Values</option>
|
||||
{conditionOptions.map((condition, idx) => (
|
||||
<option key={idx} value={condition}>
|
||||
{condition}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
value={param.value}
|
||||
onChange={(e) =>
|
||||
handleAdhocChange(index, "value", e.target.value)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
className="btn btn-danger me-2"
|
||||
onClick={() => deleteAdhocRow(index)}
|
||||
title="Delete Row"
|
||||
>
|
||||
<i className="bi bi-trash"></i>
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onClick={addAdhocRow}
|
||||
title="Add Row"
|
||||
>
|
||||
<i className="bi bi-plus"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Report Output Section */}
|
||||
<div className="row mt-4">
|
||||
<div className="col-md-6">
|
||||
<h5 style={{ fontWeight: 300 }}>
|
||||
<b>Report Output</b>
|
||||
</h5>
|
||||
</div>
|
||||
<div className="col-md-6 text-end">
|
||||
{/* Custom Export Dropdown */}
|
||||
<div
|
||||
id="export-dropdown-container"
|
||||
className="d-inline-block me-2"
|
||||
style={{ position: 'relative' }}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-primary mr-3"
|
||||
onClick={toggleExportDropdown}
|
||||
>
|
||||
<i className="bi bi-download me-1"></i> Export <i className="bi bi-caret-down-fill ms-1 small "></i>
|
||||
</button>
|
||||
{showExportDropdown && (
|
||||
<div
|
||||
className="shadow position-absolute end-0 bg-white border rounded mt-1 py-1"
|
||||
style={{ zIndex: 1000, minWidth: '160px' }}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="dropdown-item d-flex align-items-center px-3 py-2"
|
||||
onClick={() => {
|
||||
exportFile("xlsx");
|
||||
setShowExportDropdown(false);
|
||||
}}
|
||||
>
|
||||
<i className="bi bi-file-earmark-excel me-2 text-success"></i> XLSX
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="dropdown-item d-flex align-items-center px-3 py-2"
|
||||
onClick={() => {
|
||||
exportFile("csv");
|
||||
setShowExportDropdown(false);
|
||||
}}
|
||||
>
|
||||
<i className="bi bi-file-earmark-text me-2 text-primary"></i> CSV
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="dropdown-item d-flex align-items-center px-3 py-2"
|
||||
onClick={() => {
|
||||
exportFile("pdf");
|
||||
setShowExportDropdown(false);
|
||||
}}
|
||||
>
|
||||
<i className="bi bi-file-earmark-pdf me-2 text-danger"></i> PDF
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Back and Run Buttons */}
|
||||
<button className="btn btn-outline-secondary me-2" onClick={goBack}>
|
||||
Back
|
||||
</button>
|
||||
<button className="btn btn-primary" onClick={runQuery}>
|
||||
Run
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
{/* Data Table */}
|
||||
<div style={{ maxHeight: "500px", overflow: "auto", marginTop: "1rem" }}>
|
||||
{isLoading ? (
|
||||
<div className="text-center py-4">
|
||||
<div className="spinner-border text-primary" role="status"></div>
|
||||
<p className="mt-2">Loading data...</p>
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="alert alert-danger">{error}</div>
|
||||
) : (filtered ? filterRows : rows).length === 0 ? (
|
||||
<div className="alert alert-info">No data available</div>
|
||||
) : (
|
||||
<table className="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
{(filtered ? getFilteredHeaders() : getHeaders()).map((header, index) => (
|
||||
<th key={index}>{header}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(filtered ? filterRows : rows).map((row, rowIndex) => (
|
||||
<tr key={rowIndex}>
|
||||
{(filtered ? getFilteredHeaders() : getHeaders()).map((header, colIndex) => (
|
||||
<td key={colIndex}>
|
||||
{renderTableCell(row, header)}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReportRunner2Edit;
|
||||
Reference in New Issue
Block a user