Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
21 kB
1
Indexable
Never
import React, { useEffect, useRef, useState } from "react";
import ReactECharts from "echarts-for-react";
import MaskedDate from "../custom-components/MaskedDate";
import Button from "../custom-components/Button";
import { KeyCodes } from "renderer/util/keycodes";
import { Dropdown } from "primereact/dropdown";
import { TreeSelect } from 'primereact/treeselect';
import { checkDateIsSameOrAfter } from "renderer/util/validator/globalValidator";
import { useLazyGetOrganisationDataByIdQuery } from "renderer/store/createOrganization/organizationApi";
import { getSelectedOrgId } from "renderer/util/miscUtil";
import { toast } from "react-toastify";
import CustomLoader from "../custom-components/CustomLoader";
// import echarts from 'echarts';

const CreateChart = ({ data, el, i, edit, onQuestionClick = () => { } }) => {
  const [filters, setFilters] = useState([])
  const filt = useRef([])
  const [result, setResult] = useState()
  const [showRevert, setShowRevert] = useState(false)
  const currentOrgID = getSelectedOrgId();
  const [getOrganisationDetails] = useLazyGetOrganisationDataByIdQuery()
  const [organizationData, setOrganizationData] = useState({})


  const [options, setOptions] = useState({})
  const [showLoader, setShowLoader] = useState(true)


  useEffect(() => {
    let opts = { ...options }
    if (Object.keys(opts).length > 0) {
      if (el.w > 6) {
        opts.yAxis = opts?.yAxis && { ...opts?.yAxis, show: true }
        opts.xAxis = opts?.xAxis && { ...opts?.xAxis, show: true }
        opts.grid = { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true }
      } else {
        opts.yAxis = opts?.yAxis && { ...opts?.yAxis, show: false }
        opts.xAxis = opts?.xAxis && { ...opts?.xAxis, show: false }
        opts.grid = { top: 2, right: "4%", bottom: 24, left: 36, containLabel: false }
      }
    }
    setOptions(opts)
    setShowRevert(el?.parentQuestionId > 0 ? true : false)
  }, [el])
  const chartStyle = {
    height: el.h * 31,
    width: "100%",
    padding: "10px 10px 0",
  };
  const chartRef = useRef(null);


  const apiCall = (data) => {

    const options = {
      method: 'POST',
      headers: {
        "X-Organization-ID": getSelectedOrgId()
      },
      body: data.payload
    };
    fetch(data.endPoint, options)
      .then(response => response.json())
      .then(qdata => {
        // Process the returned data
        const { results } = qdata
        const currentChart = data.charts.filter(e => e.chartType === data.defaultView)[0]
        const defaultX = currentChart.xAxisList.filter(e => e.default)[0]
        const defaultY = currentChart.yAxisList.filter(e => e.default)[0]
        setResult(results)
        let xaxisData = []
        let yaxisData = []
        results?.forEach(e => {
          yaxisData.push(e[`${defaultY?.key}`])
          xaxisData.push(e[`${defaultX?.key}`])
        })
        if (data.defaultView === 'Pie') {
          let xAxis; let yAxis;
          data.charts.forEach((obj) => {
            if (obj.chartType === "Pie") {
              xAxis = obj?.xAxisList?.find(ele => ele.default)
              yAxis = obj?.yAxisList?.find(ele => ele.default)
            }
          })

          let pieData = results.map((item) => {
            return {
              value: item[`${yAxis?.key}`],
              name: item[`${xAxis?.key}`],
            }
          })
          setOptions({
            grid: el.w > 6 ? { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true } : { top: 2, right: "4%", bottom: 24, left: 2, containLabel: false },
            series: [
              {
                type: data.defaultView?.toLowerCase() ?? "pie",
                data: pieData
              }
            ]
          })
        } else if (data.defaultView === 'Tree Map') {
          let xAxis; let yAxis;
          data.charts.forEach((obj) => {
            if (obj.chartType === "Tree Map") {
              xAxis = obj?.xAxisList?.find(ele => ele.default)
              yAxis = obj?.yAxisList?.find(ele => ele.default)
            }
          })
          const treemapData = {
            name: 'Root',
            children: results?.map((item) => ({
              name: item[`${xAxis?.key}`],
              value: item[`${yAxis?.key}`]
            }))
          };
          setOptions({
            grid: el.w > 6 ? { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true } : { top: 2, right: "4%", bottom: 24, left: 2, containLabel: false },
            series: [
              {
                type: 'treemap',
                data: [treemapData],
                label: {
                  show: true,
                },
              },
            ],
            tooltip: {}
          })
        } else if (data.defaultView === "Dough Nut") {
          let xAxis; let yAxis;
          data.charts.forEach((obj) => {
            if (obj.chartType === "Dough Nut") {
              xAxis = obj?.xAxisList?.find(ele => ele.default)
              yAxis = obj?.yAxisList?.find(ele => ele.default)
            }
          })
          const donutData = results?.map((item) => ({
            name: item[`${xAxis?.key}`],
            value: item[`${yAxis?.key}`]
          }))
          setOptions({
            grid: el.w > 6 ? { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true } : { top: 2, right: "4%", bottom: 24, left: 2, containLabel: false },
            series: [
              {
                type: 'pie',
                radius: ['40%', '70%'],
                avoidLabelOverlap: false,
                label: {
                  show: false,
                },
                emphasis: {
                  label: {
                    show: true,
                    fontSize: 20,
                    fontWeight: 'bold'
                  }
                },
                labelLine: {
                  show: false
                },
                data: donutData
              }],
            tooltip: {}
          })

        } else if (data.defaultView === 'Scatter') {
          let xAxis; let yAxis;
          data.charts.forEach((obj) => {
            if (obj.chartType === "Scatter") {
              xAxis = obj?.xAxisList?.find(ele => ele.default)
              yAxis = obj?.yAxisList?.find(ele => ele.default)
            }
          })
          const xAxisData = results?.map(item => item[`${xAxis?.key}`])
          const yAxisData = results?.map(item => item[`${yAxis?.key}`]);
          setOptions({
            grid: el.w > 6 ? { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true } : { top: 2, right: "4%", bottom: 24, left: 2, containLabel: false },
            xAxis: {
              data: xAxisData
            },
            yAxis: {},
            series: [
              {
                type: data?.defaultView?.toLowerCase() ?? 'scatter',
                data: yAxisData
              }
            ],
            tooltip: {
              trigger: "axis",
              position: 'top'
            }
          })
        } else if (data.defaultView === 'Bubble') {
          let xAxis; let yAxis;
          data.charts.forEach((obj) => {
            if (obj.chartType === "Bubble") {
              xAxis = obj?.xAxisList?.find(ele => ele.default)
              yAxis = obj?.yAxisList?.find(ele => ele.default)
            }
          })
          const { tooltip, ...rest } = options
          let d = []
          d = results?.map(e => {
            return [e['ledgerId'], e[`${yAxis?.key}`], e[`${xAxis?.key}`]];
          });
          setOptions({
            ...rest,
            grid: el.w > 6 ? { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true } : { top: 2, right: "4%", bottom: 24, left: 2, containLabel: false },
            xAxis: {
              splitLine: {
                lineStyle: {
                  type: 'dashed'
                }
              },
              scale: true
            },
            yAxis: {
              splitLine: {
                lineStyle: {
                  type: 'dashed'
                },
              },
              scale: true
            },
            series: [
              {
                name: '',
                data: d,
                type: 'scatter',
                symbolSize: function (d) {
                  return Math.sqrt(d[1]) / 25; // Adjust the divisor (scaling factor)
                },
                emphasis: {
                  focus: 'series',
                  label: {
                    show: true,
                    formatter: function (param) {
                      return param.data[2];
                    },
                    position: 'bottom'
                  }
                },

              }
            ]
          })
        } else if (data.defaultView === 'Column Bar' || data.defaultView === 'Line') {
          setOptions({
            grid: el.w > 6 ? { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true } : { top: 2, right: "4%", bottom: 24, left: 2, containLabel: false },
            xAxis: {
              show: el.w > 6,
              type: "category",
              // boundaryGap: [0, 0.001],
              data: xaxisData,

            },

            yAxis: {
              show: el.w > 6,
              type: "value",
            },
            series: [

              {
                // name: '2021-22', 
                type: data.defaultView?.toLowerCase() === 'column bar' ? 'bar' : data.defaultView?.toLowerCase(),
                data: yaxisData
              }
            ],
            tooltip: {
              trigger: "axis",
              position: 'top'
            }
          })
        } else if (data.defaultView === "Area") {
          setOptions({
            grid: el.w > 6 ? { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true } : { top: 2, right: "4%", bottom: 24, left: 2, containLabel: false },
            xAxis: {
              show: el.w > 6,
              type: "category",
              data: xaxisData,
            },

            yAxis: {
              show: el.w > 6,
              type: "value",

            },
            series: [

              {
                // name: '2021-22',
                type: "line",
                data: yaxisData,
                areaStyle: {}
              }
            ],
          })
        } else {
          setOptions({
            grid: el.w > 6 ? { top: 2, right: "4%", bottom: 24, left: 2, containLabel: true } : { top: 2, right: "4%", bottom: 24, left: 2, containLabel: false },
            xAxis: {
              show: el.w > 6,
              type: 'value',
              // boundaryGap: [0, 0.001],
            },

            yAxis: {
              show: el.w > 6,
              type: "category",
              data: xaxisData,

            },
            series: [

              {
                // name: '2021-22',
                type: "bar",
                data: yaxisData
              }
            ],
            tooltip: {
              trigger: "axis",
              position: 'top'
            }
          })
        }
        if(data.endPoint!=='https://devapi.finsights.biz/kitaabreportsapi/v1/dashboard/TopExpensesAggregatesReportByLedgerId'){
          setShowLoader(false)
        } else {
          setShowLoader(true)
        }

      })
      .catch(error => {
        // Handle any errors
        console.error('Error:', error);
      });
  }

  useEffect(() => {
    if (data) {
      fetchOrganisationDetails();
      let payload = JSON.parse(data.payload)
      const updatedFilters = data.filters.map((element) => {
        if (element.payloadKey) {
          return {
            ...element, value: payload[`${element.payloadKey}`]
          }
        } else {
          return { ...element, value: '' }
        }
      });
      filt.current = updatedFilters
      setFilters(updatedFilters)
      if(data?.reportName!==60001) {
        apiCall(data)
      }
      const dynamicElements = data?.filters.filter((element) => element?.status === 'dynamic');
      dynamicElements?.forEach((element) => dynamicOptions(element));
    }
  }, [data])

  const getOptions = (options) => {
    let flatten = [];
    if (options?.length > 1) {
      options.forEach((option) => {
        flatten.push({
          key: option?.Id.toString(),
          label: option?.Name,
          data: option?.Name,
          icon: "",
          children: getOptions(option.Children),
        })

      });
    }
    return flatten;
  };

  const dynamicOptions = (data) => {
    const options = {
      method: 'POST',
      headers: {
        "X-Organization-ID": getSelectedOrgId()
      },
      body: data.payload
    };
    fetch(data.endPoint, options)
      .then(response => response.json())
      .then(qdata => {
        // Process the returned data
        const results = getOptions(qdata?.results)
        setFilters(prevFilters => {
          const updatedFilters = prevFilters.map((element) => {
            if (element?.status === 'dynamic') {
              return {
                ...element,
                options: results
              };
            }
            return element;
          });
          filt.current = updatedFilters
          return updatedFilters;
        });

      })

  }
  const fetchOrganisationDetails = async () => {
    try {
      const resp = await getOrganisationDetails(currentOrgID);
      if (resp?.data?.success) {
        setOrganizationData(resp?.data)
      }
    }
    catch (error) {
      console.log(error);
    }
  }

  const handleChange = (e, ele) => {
    ele.value = e.target.value
  }
  const handleMouseDown = () => {

  }
  const submitHandler = (e, ele, filters) => {
    const updatedData = { ...data };

    if (!updatedData["defaultPayload"]) {
      updatedData["defaultPayload"] = updatedData.payload;
    }
    let shouldCallApi = true;
    let parsedPayload = JSON.parse(updatedData.payload);
    filt.current?.forEach((element) => {
      if (!shouldCallApi) return;
      if (element.type === "Date") {
        if (element.payloadKey && element.payloadKey.trim() !== '') {
          if (element.payloadKey === 'fromDate') {
            const isDateValid = checkDateIsSameOrAfter(element.value, organizationData?.data?.preferences?.booksBeginningFrom)
            if (isDateValid) {
              parsedPayload[`${element.payloadKey}`] = element.value;
            } else {
              toast.error('From Date should not be earlier than Books Beginning Date')
              shouldCallApi = false;
              return
            }
          } else {
            parsedPayload[`${element.payloadKey}`] = element.value;
          }
        }
      } else if (element.type === "Dropdown") {
        if (element.status === 'dynamic') {
          const selectedOption = findTreeNodeByKey(element?.value, element?.options); // as treeselect selection based on "key" 
          if (selectedOption) {
            parsedPayload[`${element.payloadKey}`] = selectedOption?.data;
          }
        } else {
          if (element.payloadKey && element.payloadKey.trim() !== '') {
            parsedPayload[`${element.payloadKey}`] = element.value;
          }
        }
      }
    });

    if (shouldCallApi) {
      updatedData.payload = JSON.stringify(parsedPayload);
      apiCall(updatedData);
    }

  };

  const findTreeNodeByKey = (key, nodes) => {
    for (const node of nodes) {
      if (node.key === key) {
        return node;
      }
      if (node.children?.length) {
        const foundNode = findTreeNodeByKey(key, node.children);
        if (foundNode) {
          return foundNode;
        }
      }
    }
    return null;
  };

  const handleChangeDate = (e, i) => {
    let flt = [...filt.current]
    flt[i].value = e.target.value
    filt.current = flt
  }
  const onChangeDropDown = (e, i) => {
    let flt = [...filters]
    flt[i].value = e.value
    filt.current = flt
    setFilters(flt)
  }
  const renderFilters = filt.current?.map((ele, i) => (
    <div className="me-2">
      {ele?.type && ele?.type?.toLowerCase() === "date" && <MaskedDate
        onMouseUp={handleMouseDown}
        id="VCHC4"
        value={ele.value}
        name={"entryDate"}
        onChange={(e) => handleChangeDate(e, i)}
        placeholder={ele.label}
        className="form-control h-40px  f-c-b bg-white"
      />}
      {ele?.type && ele?.type?.toLowerCase() === "dropdown" && ele?.status === 'static' && <div className="p-rel select-inp">
        <span className="p-input-icon-rem w-100">
          <Dropdown
            className="shadow-none"
            value={ele.value}
            options={ele.options}
            optionValue="label"
            optionLabel="label"
            onChange={(e) => onChangeDropDown(e, i)}
            panelStyle={{ maxWidth: "250px" }}
            filter
            filterBy="label"
            placeholder="Select Type"
          />
        </span>
      </div>

      }
      {ele?.type && ele?.type?.toLowerCase() === "dropdown" && ele?.status === 'dynamic' && <div className="tree-inp">
        <TreeSelect
          value={ele.value}
          options={ele?.options}
          selectionMode="single"
          onChange={(e) => onChangeDropDown(e, i)}
          placeholder="Select Type"
        /></div>
      }
      {ele?.type && ele?.type?.toLowerCase() === "button" &&
        <button
          className="btn btn-primary btn-sm"
          onClick={(e) =>
            submitHandler(e, ele, filters)
          }
        >
          {ele.label}
        </button>
      }
    </div>
  ));
  const handleBarClick = (params) => {
    const d = { ...data }

    let clickedLedger = {}

    if (d.defaultView === "Bubble") {
      clickedLedger = result?.find(item => {
        return Object.values(item).some(e => params.value?.includes(e))
      })
    } else {
      clickedLedger = result?.find(item => Object.values(item).includes(params?.name) && Object.values(item).includes(params.value));
    }
    // to find top expenses aggregate by ledger id of top expenses
    if (clickedLedger && d?.reportName === 4) {
      const payloadObj = JSON.parse(d.payload);
      payloadObj.ledgerId = clickedLedger?.ledgerId;
      d.payload = JSON.stringify(payloadObj);
      d.endPoint = 'https://devapi.finsights.biz/kitaabreportsapi/v1/dashboard/TopExpensesAggregatesReportByLedgerId'
      apiCall(d);
      d['questionId'] = (el?.childQuestionId !== undefined && el?.childQuestionId !== 0) ? el?.childQuestionId : 60001;
      setShowLoader(true)
      onQuestionClick(d, 'top expenses', el, setShowLoader);
    }
  };

  const revertQuestionId = () => {
    const d = { ...data }
    d['questionId'] = el?.parentQuestionId;
    setShowLoader(true)
    onQuestionClick(d, 'top expenses', el, setShowLoader);
  }

  return (
    <>
      <div className="chart-container" style={!edit ? { overflow: "hidden auto", height: el.h * 38 } : { overflow: "hidden auto", height: el.h * 38, pointerEvents: 'none' }}>
        <div className="card rounded-0 border-0">
          <div className="card-header p-15-total figma-bg bottom-color dashed-color-card-header">
            {/* remove above dashed-color-card-header*/}
            <div className="row align-items-center">
              <div className="col-xxl-4 col-xl-4 col-lg-4 col-md-4 col-sm-4">
                <p className="font-size-14 f-500 mb-0">
                  {el?.question ?? data?.question}
                </p>
              </div>
              <div className="col-xxl-8 col-xl-8 col-lg-8 col-md-8 col-sm-8 text-end">
                <div className="d-flex justify-content-end">
                  {renderFilters}
                  {showRevert &&
                    <button
                      className="btn btn-success btn-sm"
                      onClick={revertQuestionId}
                    >Revert
                    </button>
                  }
                </div>
              </div>
            </div>
          </div>

          <div className="card-body p-15-total">
            <div className="row">
            {showLoader ? <CustomLoader load={true} /> :
             <div className="col-md-12" style={{ overflow: "auto" }}>
                <ReactECharts ref={chartRef} option={options} style={chartStyle} onEvents={{ click: handleBarClick }} />
              </div>
            }
            </div>
          </div>
        </div>
      </div>

    </>


  );
}

export default CreateChart;