Skip to content

Commit

Permalink
Upgrade Recharts. (PP-1531) (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
tdilauro authored Aug 23, 2024
1 parent f54d231 commit a8e6da9
Show file tree
Hide file tree
Showing 12 changed files with 633 additions and 410 deletions.
361 changes: 237 additions & 124 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"react-dom": "^16.8.6",
"react-redux": "^7.2.9",
"react-router": "^3.2.0",
"recharts": "^1.8.6",
"recharts": "^2.12.7",
"redux": "^4.2.1",
"redux-thunk": "^2.4.2",
"request": "^2.85.0",
Expand Down Expand Up @@ -119,6 +119,7 @@
"react-axe": "^3.3.0",
"react-test-renderer": "^16.14.0",
"redux-mock-store": "^1.5.4",
"resize-observer-polyfill": "^1.5.1",
"sass": "^1.64.2",
"sass-lint": "^1.13.1",
"sass-loader": "^13.2.0",
Expand Down
10 changes: 8 additions & 2 deletions src/components/ContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import * as React from "react";
import { Store } from "@reduxjs/toolkit";
import * as PropTypes from "prop-types";
import buildStore, { RootState } from "../store";
import { FeatureFlags, PathFor } from "../interfaces";
import {
DashboardCollectionsBarChart,
FeatureFlags,
PathFor,
} from "../interfaces";
import Admin from "../models/Admin";
import PathForProvider from "@thepalaceproject/web-opds-client/lib/components/context/PathForContext";
import ActionCreator from "../actions";
import AppContextProvider, { AppContextType } from "../context/appContext";

// Note: Not all elements of these props make it into the `ContextProvider`.
// Some are exposed only through the `AppContextProvider` component (which
// this component wraps.
// this component wraps).
// TODO: We should get this interface to the point where we can just extend
// the `ConfigurationSettings` interface.
export interface ContextProviderProps extends React.Props<ContextProvider> {
Expand All @@ -25,6 +29,7 @@ export interface ContextProviderProps extends React.Props<ContextProvider> {
}[];
featureFlags: FeatureFlags;
quicksightPagePath?: string;
dashboardCollectionsBarChart?: DashboardCollectionsBarChart;
}

/** Provides a redux store, configuration options, and a function to create URLs
Expand Down Expand Up @@ -109,6 +114,7 @@ export default class ContextProvider extends React.Component<
admin: this.admin,
featureFlags: this.props.featureFlags,
quicksightPagePath: this.props.quicksightPagePath,
dashboardCollectionsBarChart: this.props.dashboardCollectionsBarChart,
};
return (
<PathForProvider pathFor={this.pathFor}>
Expand Down
2 changes: 1 addition & 1 deletion src/components/LibraryStats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const inventoryKeyToLabelMap = {
export const ALL_LIBRARIES_HEADING = "Dashboard for All Authorized Libraries";

/** Displays statistics about patrons, licenses, and collections from the server,
for a single library or all libraries the admin has access to. */
for a single library or all libraries to which the admin has access. */
const LibraryStats = ({ stats, library }: LibraryStatsProps) => {
const {
name: libraryName,
Expand Down
47 changes: 30 additions & 17 deletions src/components/StatsCollectionsBarChart.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as React from "react";
import { useDashboardCollectionsBarChartSettings } from "../context/appContext";
import { CollectionInventory } from "../interfaces";
import { ValueType } from "recharts/types/component/DefaultTooltipContent";
import {
Bar,
BarChart,
Expand All @@ -12,6 +14,17 @@ import {
import { inventoryKeyToLabelMap } from "./LibraryStats";
import { formatNumber } from "../utils/sharedFunctions";

const stackId = "collections";
const barSize = 50;
const meteredColor = "#606060";
const unlimitedColor = "#404040";
const openAccessColor = "#202020";

type Props = {
collections: CollectionInventory[];
ResponsiveContainer?: any;
};

const StatsCollectionsBarChart = ({ collections }: Props) => {
const chartItems = collections
?.map(({ name, inventory, inventoryByMedium }) => ({
Expand All @@ -20,46 +33,49 @@ const StatsCollectionsBarChart = ({ collections }: Props) => {
_by_medium: inventoryByMedium || {},
}))
.sort((a, b) => (a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1));
const chartWidth = useDashboardCollectionsBarChartSettings()?.width || "100%";

return (
<ResponsiveContainer height={chartItems.length * 100 + 75} width="100%">
<ResponsiveContainer
height={chartItems.length * 100 + 75}
width={chartWidth}
>
<BarChart
data={chartItems}
layout="vertical"
margin={{ top: 5, right: 30, left: 0, bottom: 50 }}
margin={{ top: 5, right: 30, left: 10, bottom: 50 }}
>
<YAxis
type="category"
dataKey="name"
interval={0}
angle={-45}
tick={{ dx: -20 }}
tick={{ dx: -5 }}
padding={{ top: 0, bottom: 0 }}
height={175}
width={125}
/>
<XAxis type="number" />
<Tooltip content={<CustomTooltip />} />
<Bar
stackId="collections"
stackId={stackId}
name={inventoryKeyToLabelMap.meteredLicenseTitles}
dataKey={"meteredLicenseTitles"}
barSize={50}
fill="#606060"
barSize={barSize}
fill={meteredColor}
/>
<Bar
stackId="collections"
stackId={stackId}
name={inventoryKeyToLabelMap.unlimitedLicenseTitles}
dataKey={"unlimitedLicenseTitles"}
barSize={50}
fill="#404040"
barSize={barSize}
fill={unlimitedColor}
/>
<Bar
stackId="collections"
stackId={stackId}
name={inventoryKeyToLabelMap.openAccessTitles}
dataKey={"openAccessTitles"}
barSize={50}
fill="#202020"
barSize={barSize}
fill={openAccessColor}
/>
</BarChart>
</ResponsiveContainer>
Expand All @@ -76,15 +92,12 @@ type chartTooltipData = {
perMedium?: OneLevelStatistics;
};

type Props = {
collections: CollectionInventory[];
};
/* Customize the Rechart tooltip to provide additional information */
export const CustomTooltip = ({
active,
payload,
label: collectionName,
}: TooltipProps) => {
}: TooltipProps<ValueType, string>) => {
if (!active) {
return null;
}
Expand Down
2 changes: 0 additions & 2 deletions src/components/StatsUsageReportsGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React = require("react");
import { Button } from "library-simplified-reusable-components";
import StatsGroup from "./StatsGroup";
import { InventoryStatistics } from "../interfaces";
import InventoryReportRequestModal from "./InventoryReportRequestModal";
import { useState } from "react";
import { useAppContext } from "../context/appContext";

type Props = {
heading?: string;
Expand Down
2 changes: 2 additions & 0 deletions src/components/__tests__/LibraryStats-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const getAllProviders = ({ isSysAdmin = false } = {}) => {
return componentWithProviders({ contextProviderProps });
};

global.ResizeObserver = require("resize-observer-polyfill");

describe("LibraryStats", () => {
// Convert from the API format to our in-app format.
const statisticsData = normalizeStatistics(statisticsApiResponseData);
Expand Down
9 changes: 7 additions & 2 deletions src/context/appContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createContext, useContext } from "react";
import { FeatureFlags } from "../interfaces";
import { DashboardCollectionsBarChart, FeatureFlags } from "../interfaces";
import Admin from "../models/Admin";

export type AppContextType = {
Expand All @@ -8,6 +8,7 @@ export type AppContextType = {
admin: Admin;
featureFlags: FeatureFlags;
quicksightPagePath: string;
dashboardCollectionsBarChart?: DashboardCollectionsBarChart;
};

// Don't export this, since we always want the error handling behavior of our hook.
Expand All @@ -16,7 +17,9 @@ const AppContext = createContext<AppContextType | undefined>(undefined);
export const useAppContext = (): AppContextType => {
const context = useContext(AppContext);
if (context === undefined) {
throw new Error("useAppContext must be used within an AppContext povider.");
throw new Error(
"useAppContext must be used within an AppContext provider."
);
}
return context;
};
Expand All @@ -25,5 +28,7 @@ export const useCsrfToken = () => useAppContext().csrfToken;
export const useAppAdmin = () => useAppContext().admin;
export const useAppEmail = () => useAppAdmin().email;
export const useAppFeatureFlags = () => useAppContext().featureFlags;
export const useDashboardCollectionsBarChartSettings = () =>
useAppContext().dashboardCollectionsBarChart;

export default AppContext.Provider;
11 changes: 11 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ export interface ConfigurationSettings {
/** `quickSightPagePath` contains the URL to the QuickSight dashboard page.
Currently, this value does not change, so we can share it via fixed config. */
quicksightPagePath: string;

/** Configuration for dashboard collections barchart. */
dashboardCollectionsBarChart?: DashboardCollectionsBarChart;
}

export interface DashboardCollectionsBarChart {
width?: number;
}

export interface TestingFlags {
[key: string]: boolean;
}

export interface FeatureFlags {
Expand Down
2 changes: 2 additions & 0 deletions src/stylesheets/stats.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
text-align: left;
font-style: italic;
font-size: small;
text-wrap: balance;
}

.stat-usage-reports {
Expand All @@ -102,6 +103,7 @@
h3 {
font-weight: bolder;
text-transform: uppercase;
text-wrap: balance;
margin: 10px;
margin-bottom: 2px;
}
Expand Down
Loading

0 comments on commit a8e6da9

Please sign in to comment.