crane-cloud/frontend

View on GitHub
src/pages/AdminUserOverviewPage/index.jsx

Summary

Maintainability
A
2 hrs
Test Coverage
F
0%
import React, { useState, useEffect, useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom/cjs/react-router-dom.min";
import getUsersList from "../../redux/actions/users";
import Header from "../../components/Header";
import InformationBar from "../../components/InformationBar";
import { handleGetRequest } from "../../apis/apis.js";
import Spinner from "../../components/Spinner";
import Select from "../../components/Select";
import {
  Line,
  CartesianGrid,
  XAxis,
  YAxis,
  AreaChart,
  Area,
  Tooltip,
  PieChart,
  Pie,
  Cell,
} from "recharts";
import { filterGraphData } from "../../helpers/filterGraphData.js";
import { retrieveMonthNames } from "../../helpers/monthNames.js";
import NewResourceCard from "../../components/NewResourceCard";
import { getUserCategories } from "../../helpers/userCategories";
import "./AdminUserOverviewPage.css";
import { createUsersPieChartData } from "../../helpers/usersPieChartData";
import { createUserGraphData } from "../../helpers/usersGraphData";
import { ReactComponent as SearchButton } from "../../assets/images/search.svg";
import { ReactComponent as BackButton } from "../../assets/images/arrow-left.svg";
import UserListing from "../../components/UserListing";
import usePaginator from "../../hooks/usePaginator";
import AppFooter from "../../components/appFooter";

const AdminUserOverviewPage = () => {
  const [usersSummary, setUsersSummary] = useState([]);
  const [feedback, setFeedback] = useState("");
  const [loading, setLoading] = useState(false);
  const [period, setPeriod] = useState("all");
  const [sectionValue, setSectionValue] = useState("all");
  const [word, setWord] = useState("");
  const [currentPage, handleChangePage] = usePaginator();
  const [dateRange, setDateRange] = useState("7");
  const dispatch = useDispatch();

  const COLORS = ["#0088FE", "#0DBC00", "#F9991A"];

  let graphDataArray = [];
  let filteredGraphData = [];

  const gettingUsers = useCallback(
    () => dispatch(getUsersList(dateRange, sectionValue, currentPage, word)),
    [currentPage, dispatch, sectionValue, word, dateRange]
  );

  useEffect(() => {
    getAllUsers();
    gettingUsers();
  }, [gettingUsers]);

  const getAllUsers = async () => {
    setLoading(true);

    try {
      const response = await handleGetRequest("/users");
      if (response.data.data.users.length > 0) {
        const totalNumberOfUsers = response.data.data.pagination.total;
        handleGetRequest(`/users?per_page=${totalNumberOfUsers}`)
          .then((response) => {
            if (response.data.data.users.length > 0) {
              setUsersSummary(response.data.data.users);
              setLoading(false);
            } else {
              throw new Error("No users found");
            }
          })
          .catch(() => {
            setFeedback("Failed to fetch all users, please try again");
          });
      } else {
        setFeedback("No users found");
      }
    } catch (error) {
      setFeedback("Failed to fetch users, please try again");
    }
  };

  const { isFetching, users, isFetched, pagination } = useSelector(
    (state) => state.usersListReducer
  );

  useEffect(() => {
    dispatch(getUsersList(dateRange, sectionValue, currentPage));
  }, [sectionValue, currentPage, dateRange, dispatch]);

  const userCounts = {
    total: usersSummary.length,
    verified: usersSummary.filter((user) => user.verified === true).length,
    unverified: usersSummary.filter((user) => user.verified === false).length,
    beta: usersSummary.filter((user) => user.is_beta_user === true).length,
    disabled: 0,
  };

  const handleChange = ({ target }) => {
    setPeriod(target.getAttribute("value"));
  };

  // Filter out verified users
  const verifiedUsers = usersSummary.filter((user) => user.verified === true);

  // function call to create the user graph data
  graphDataArray = createUserGraphData(verifiedUsers);

  // calling the filterGraphData() to filter basing on period
  filteredGraphData = filterGraphData(graphDataArray, period);

  const availableUserCategories = getUserCategories();

  const handleSectionChange = (selectedOption) => {
    const selectedValue = selectedOption.value;
    setSectionValue(selectedValue);
  };

  const handleCallbackSearchword = ({ target: { value } }) => setWord(value);

  const handlePageChange = (currentPage) => {
    handleChangePage(currentPage);
    gettingUsers();
  };

  const handleDateRangeChange = (range) => {
    setDateRange(range);
  };

  return (
    <div className="APage">
      <div className="TopRow">
        <Header />
        <InformationBar
          header={
            <span className="ProjectsInformationBarTitle">
              <Link className={`breadcrumb flex_back_link`} to={`/clusters`}>
                <BackButton />
                <div className="back_link">Users Overview</div>
              </Link>
            </span>
          }
        />
      </div>
      <div className="AMainSection">
        <div className="ContentSection">
          <div className="TitleArea">
            <div className="SectionTitle">Users Category Summary</div>
          </div>

          {loading && sectionValue !== "active" ? (
            <div className="ResourceSpinnerWrapper">
              <Spinner size="big" />
            </div>
          ) : feedback !== "" ? (
            <div className="NoResourcesMessage">{feedback}</div>
          ) : Object.keys(userCounts).length > 0 ? (
            <div className="ResourceClusterContainer">
              {Object.keys(userCounts).map((countType) => (
                <NewResourceCard
                  key={countType}
                  title={countType}
                  count={userCounts[countType]}
                />
              ))}
            </div>
          ) : null}

          <div className="TitleArea">
            <div className="SectionTitle">
              Graph and Pie Chart Summary on Users
            </div>
          </div>

          <div className="ChartContainer">
            <div className="VisualArea">
              <div className="VisualAreaHeader">
                <span className="SectionTitle">Platform Users</span>
                <span>
                  <div className="PeriodContainer">
                    <div className="PeriodButtonsSection">
                      <div
                        className={`${
                          period === "3" && "PeriodButtonActive"
                        } PeriodButton`}
                        name="3month"
                        value="3"
                        role="presentation"
                        onClick={handleChange}
                      >
                        3m
                      </div>
                      <div
                        className={`${
                          period === "4" && "PeriodButtonActive"
                        } PeriodButton`}
                        name="4months"
                        value="4"
                        role="presentation"
                        onClick={handleChange}
                      >
                        4m
                      </div>
                      <div
                        className={`${
                          period === "6" && "PeriodButtonActive"
                        } PeriodButton`}
                        name="6months"
                        value="6"
                        role="presentation"
                        onClick={handleChange}
                      >
                        6m
                      </div>
                      <div
                        className={`${
                          period === "8" && "PeriodButtonActive"
                        } PeriodButton`}
                        name="8months"
                        value="8"
                        role="presentation"
                        onClick={handleChange}
                      >
                        8m
                      </div>
                      <div
                        className={`${
                          period === "12" && "PeriodButtonActive"
                        } PeriodButton`}
                        name="1year"
                        value="12"
                        role="presentation"
                        onClick={handleChange}
                      >
                        1y
                      </div>
                      <div
                        className={`${
                          period === "all" && "PeriodButtonActive"
                        } PeriodButton`}
                        name="all"
                        value="all"
                        role="presentation"
                        onClick={handleChange}
                      >
                        all
                      </div>
                    </div>
                  </div>
                </span>
              </div>

              {graphDataArray.length > 0 ? (
                <AreaChart
                  width={600}
                  height={350}
                  margin={{
                    top: 20,
                    right: 30,
                    left: 0,
                    bottom: 0,
                  }}
                  syncId="anyId"
                  data={period !== "all" ? filteredGraphData : graphDataArray}
                >
                  <Line type="monotone" dataKey="Value" stroke="#8884d8" />
                  <CartesianGrid stroke="#ccc" />
                  <XAxis dataKey="Month" />
                  <XAxis
                    xAxisId={1}
                    dx={10}
                    label={{
                      value: "Months",
                      angle: 0,
                      position: "outside",
                    }}
                    height={70}
                    interval={12}
                    dataKey="Year"
                    tickLine={false}
                    tick={{ fontSize: 12, angle: 0 }}
                  />
                  <CartesianGrid strokeDasharray="3 3" />
                  <YAxis
                    label={{
                      value: "Number of Users",
                      angle: 270,
                      position: "outside",
                    }}
                    width={80}
                  />
                  <Area
                    type="monotone"
                    dataKey="Value"
                    stroke="#82ca9d"
                    fill="#82ca9d"
                  />
                  <Tooltip
                    labelFormatter={(value) => {
                      const monthNames = retrieveMonthNames();
                      const month = parseInt(value) - 1;
                      return monthNames[month].name;
                    }}
                    formatter={(value) => {
                      if (value === 1) {
                        return [`${value} user`];
                      } else {
                        return [`${value} users`];
                      }
                    }}
                  />
                </AreaChart>
              ) : (
                <div className="ResourceSpinnerWrapper">
                  <Spinner size="big" />
                </div>
              )}
            </div>

            <div className="VisualArea">
              <div className="VisualAreaHeader">
                <span className="SectionTitle">
                  Pie Chart for Users Categories
                </span>
              </div>

              {Object.keys(usersSummary).length === 0 ? (
                <div className="ResourceSpinnerWrapper">
                  <Spinner size="big" />
                </div>
              ) : (
                <div className="PieContainer">
                  <div className="ChartColumn">
                    <PieChart width={300} height={300}>
                      <Pie
                        data={createUsersPieChartData(userCounts)}
                        dataKey="value"
                        nameKey="category"
                        cx="50%"
                        cy="50%"
                        outerRadius={140}
                        paddingAngle={3}
                        label={true}
                      >
                        {createUsersPieChartData(userCounts).map(
                          (entry, index) => (
                            <Cell
                              key={`cell-${index}`}
                              fill={COLORS[index % COLORS.length]}
                            />
                          )
                        )}
                      </Pie>
                      <Tooltip />
                    </PieChart>
                  </div>
                  <div className="PercentageColumn">
                    <ul className="KeyItems">
                      {createUsersPieChartData(userCounts).map(
                        (entry, index) => (
                          <>
                            {" "}
                            <li key={`list-item-${index}`}>
                              <span
                                style={{ color: COLORS[index % COLORS.length] }}
                              >
                                {entry.category}:
                              </span>{" "}
                              {((entry.value / userCounts.total) * 100).toFixed(
                                0
                              )}
                              %
                            </li>
                            <hr style={{ width: "100%" }} />
                          </>
                        )
                      )}
                    </ul>
                  </div>
                </div>
              )}
            </div>
          </div>

          <div className="TitleArea">
            <div className="SectionTitle">
              <span>
                <Select
                  placeholder="Users Listing"
                  options={availableUserCategories}
                  onChange={(selectedOption) =>
                    handleSectionChange(selectedOption)
                  }
                />
              </span>
              <span>
                <div className="XSearchBar">
                  <div className="AdminSearchInput">
                    <input
                      type="text"
                      className="searchTerm"
                      name="Searchword"
                      placeholder="Search for account"
                      value={word}
                      onChange={(e) => {
                        handleCallbackSearchword(e);
                      }}
                    />
                    <SearchButton className="SearchIcon" />
                  </div>
                </div>
              </span>
            </div>
          </div>

          <UserListing
            sectionValue={sectionValue}
            setSelectedDateRange={handleDateRangeChange}
            isFetching={isFetching}
            isFetched={isFetched}
            users={users}
            pagination={pagination}
            handlePageChange={handlePageChange}
            currentPage={currentPage}
          />
        </div>
      </div>
      <hr />
      <AppFooter />
    </div>
  );
};

export default AdminUserOverviewPage;