From bcb518f7ed2dd03dcd8df719b8266826995eb28e Mon Sep 17 00:00:00 2001 From: Gift Nnko Date: Thu, 8 Aug 2024 18:02:13 +0300 Subject: [PATCH] feat: scorecard view Improved scorecard header --- packages/app/i18n/en.pot | 13 +++- packages/app/package.json | 2 +- packages/app/src/locales/en/translations.json | 3 + .../ScorecardViewPage/ScorecardViewPage.tsx | 44 +++++++++++++- .../DimensionFilterArea.tsx | 15 ++++- .../components/BackButton.tsx | 17 ++++++ .../components/HelpButton.tsx | 29 +++++++++ .../ScorecardActions/ScorecardActions.tsx | 18 ++++++ .../components/ScorecardDownloadButton.tsx | 6 ++ .../components/ScorecardEditButton.tsx | 6 ++ .../ScorecardOptionsControlButton.tsx | 10 ++++ .../components/ScorecardResetButton.tsx | 6 ++ .../components/ScorecardHeader.tsx | 59 +++++++++++++++++++ .../components/ScorecardView.tsx | 38 ++++++++++++ .../ScorecardViewPage/hooks/dimensions.ts | 5 ++ .../ScorecardViewPage/state/config.tsx | 28 +++++++++ .../ScorecardViewPage/state/state.tsx | 10 +++- 17 files changed, 301 insertions(+), 8 deletions(-) create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/components/BackButton.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/components/HelpButton.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/ScorecardActions.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardDownloadButton.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardEditButton.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardOptionsControlButton.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardResetButton.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardHeader.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardView.tsx create mode 100644 packages/app/src/modules/Main/components/ScorecardViewPage/state/config.tsx diff --git a/packages/app/i18n/en.pot b/packages/app/i18n/en.pot index dd6731ca5..9e9b891fc 100644 --- a/packages/app/i18n/en.pot +++ b/packages/app/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-08-08T12:12:32.681Z\n" -"PO-Revision-Date: 2024-08-08T12:12:32.681Z\n" +"POT-Creation-Date: 2024-08-08T12:57:40.085Z\n" +"PO-Revision-Date: 2024-08-08T12:57:40.086Z\n" msgid "Welcome to Scorecard App!" msgstr "Welcome to Scorecard App!" @@ -333,6 +333,9 @@ msgstr "of" msgid "Getting your scorecard configuration..." msgstr "Getting your scorecard configuration..." +msgid "Back to all scorecards" +msgstr "Back to all scorecards" + msgid "Select organisation unit" msgstr "Select organisation unit" @@ -342,6 +345,12 @@ msgstr "Select period" msgid "and {{number}} more" msgstr "and {{number}} more" +msgid "Download" +msgstr "Download" + +msgid "Reset" +msgstr "Reset" + msgid "Create a new scorecard in the scorecard app to see it here." msgstr "Create a new scorecard in the scorecard app to see it here." diff --git a/packages/app/package.json b/packages/app/package.json index fb05d0f03..8a3c36eba 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -46,7 +46,7 @@ "dependencies": { "@dhis2/app-runtime": "^3.10.6", "@dhis2/app-service-datastore": "^1.0.0-alpha.2", - "@dhis2/multi-calendar-dates": "^1.2.3", + "@dhis2/multi-calendar-dates": "^1.2.4", "@dhis2/ui": "^9.11.0", "@hisptz/dhis2-analytics": "^2.0.16", "@hisptz/dhis2-ui": "^2.0.14", diff --git a/packages/app/src/locales/en/translations.json b/packages/app/src/locales/en/translations.json index 294935abc..01734cb63 100644 --- a/packages/app/src/locales/en/translations.json +++ b/packages/app/src/locales/en/translations.json @@ -106,9 +106,12 @@ "Migrating scorecards": "Migrating scorecards", "of": "of", "Getting your scorecard configuration...": "Getting your scorecard configuration...", + "Back to all scorecards": "Back to all scorecards", "Select organisation unit": "Select organisation unit", "Select period": "Select period", "and {{number}} more": "and {{number}} more", + "Download": "Download", + "Reset": "Reset", "Create a new scorecard in the scorecard app to see it here.": "Create a new scorecard in the scorecard app to see it here.", "Confirm scorecard selection": "Confirm scorecard selection", "Are you sure you want to select this scorecard for this dashboard?": "Are you sure you want to select this scorecard for this dashboard?", diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/ScorecardViewPage.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/ScorecardViewPage.tsx index 92de0a18e..063d9385d 100644 --- a/packages/app/src/modules/Main/components/ScorecardViewPage/ScorecardViewPage.tsx +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/ScorecardViewPage.tsx @@ -5,9 +5,14 @@ import i18n from "@dhis2/d2-i18n"; import { useEffect } from "react"; import { useDimensions } from "./hooks/dimensions"; import { OrgUnitSelection } from "@hisptz/dhis2-utils"; +import { ScorecardActions } from "./components/ScorecardActions/ScorecardActions"; +import { ScorecardStateProvider } from "./state/state"; +import { ScorecardView } from "./components/ScorecardView"; +import { ScorecardConfigProvider } from "./state/config"; +import { ScorecardHeader } from "./components/ScorecardHeader"; export function ScorecardViewPage() { - const { setDimensions } = useDimensions(); + const { setDimensions, orgUnit, periods } = useDimensions(); const { config, loading, error, refetch } = useScorecardConfig(); useEffect(() => { @@ -36,6 +41,16 @@ export function ScorecardViewPage() { /> ); } + if (!config) { + return ( + { + refetch(); + }} + error={Error("Could not get information about the scorecard")} + /> + ); + } return (
- + + ({ id: period })) ?? + [], + }, + orgUnitSelection: { + ...orgUnit, + orgUnits: orgUnit.orgUnits ?? [], + groups: orgUnit.groups ?? [], + levels: orgUnit.levels ?? [], + }, + }} + > + + + +
+ +
+
+
); } diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/DimensionFilterArea.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/DimensionFilterArea.tsx index d978d5570..408794393 100644 --- a/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/DimensionFilterArea.tsx +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/DimensionFilterArea.tsx @@ -3,16 +3,29 @@ import { Card } from "@dhis2/ui"; import classes from "./DimensionFilterArea.module.css"; import { OrgUnitDimensionSelection } from "./components/CustomOrgUnitSelectorModal"; import { PeriodDimensionSelector } from "./components/PeriodDimensionSelector"; +import { BackButton } from "./components/BackButton"; +import { HelpButton } from "./components/HelpButton"; +import { SCORECARD_VIEW_HELP_STEPS } from "@scorecard/shared"; export function DimensionFilterArea() { return (
-
+
+
+ + +
diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/components/BackButton.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/components/BackButton.tsx new file mode 100644 index 000000000..197b6e3b8 --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/components/BackButton.tsx @@ -0,0 +1,17 @@ +import i18n from "@dhis2/d2-i18n"; +import { Button } from "@dhis2/ui"; +import React from "react"; +import { useNavigate } from "react-router-dom"; + +export function BackButton() { + const navigate = useNavigate(); + const onBackClick = () => { + navigate("/"); + }; + + return ( + + ); +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/components/HelpButton.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/components/HelpButton.tsx new file mode 100644 index 000000000..aa7cbce6f --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/DimensionFilterArea/components/HelpButton.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { Button, IconQuestion24 } from "@dhis2/ui"; +import i18n from "@dhis2/d2-i18n"; +import { useBoolean } from "usehooks-ts"; +import { Steps } from "intro.js-react"; +import { STEP_OPTIONS } from "@scorecard/shared"; + +export interface HelpButtonProps { + steps: any[]; +} + +export function HelpButton({ steps }: HelpButtonProps) { + const { value: hide, setTrue: onHide, setFalse: onShow } = useBoolean(true); + + return ( + <> + + + + ); +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/ScorecardActions.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/ScorecardActions.tsx new file mode 100644 index 000000000..4b26c4066 --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/ScorecardActions.tsx @@ -0,0 +1,18 @@ +import { ButtonStrip } from "@dhis2/ui"; +import { ScorecardOptionsControlButton } from "./components/ScorecardOptionsControlButton"; +import { ScorecardEditButton } from "./components/ScorecardEditButton"; +import { ScorecardDownloadButton } from "./components/ScorecardDownloadButton"; +import { ScorecardResetButton } from "./components/ScorecardResetButton"; + +export function ScorecardActions() { + return ( +
+ + + + + + +
+ ); +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardDownloadButton.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardDownloadButton.tsx new file mode 100644 index 000000000..2e4b81e75 --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardDownloadButton.tsx @@ -0,0 +1,6 @@ +import { Button } from "@dhis2/ui"; +import i18n from "@dhis2/d2-i18n"; + +export function ScorecardDownloadButton() { + return ; +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardEditButton.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardEditButton.tsx new file mode 100644 index 000000000..1ad783b07 --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardEditButton.tsx @@ -0,0 +1,6 @@ +import { Button } from "@dhis2/ui"; +import i18n from "@dhis2/d2-i18n"; + +export function ScorecardEditButton() { + return ; +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardOptionsControlButton.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardOptionsControlButton.tsx new file mode 100644 index 000000000..ba0bfb3cb --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardOptionsControlButton.tsx @@ -0,0 +1,10 @@ +import i18n from "@dhis2/d2-i18n"; +import { Button } from "@dhis2/ui"; + +export function ScorecardOptionsControlButton() { + return ( + <> + + + ); +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardResetButton.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardResetButton.tsx new file mode 100644 index 000000000..bd069d038 --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardActions/components/ScorecardResetButton.tsx @@ -0,0 +1,6 @@ +import { Button } from "@dhis2/ui"; +import i18n from "@dhis2/d2-i18n"; + +export function ScorecardResetButton() { + return ; +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardHeader.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardHeader.tsx new file mode 100644 index 000000000..77b3d2be0 --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardHeader.tsx @@ -0,0 +1,59 @@ +import JsxParser from "react-jsx-parser"; +import { useScorecardConfigFromContext } from "../state/config"; +import { head } from "lodash"; +import { colors } from "@dhis2/ui"; +import { useMemo } from "react"; +import { PeriodUtility } from "@hisptz/dhis2-utils"; +import { useScorecardState } from "../state/state"; + +export function ScorecardHeader() { + const config = useScorecardConfigFromContext(); + const { customHeader, title, subtitle, periodSelection } = config ?? {}; + const periods = periodSelection.periods ?? []; + + const [state] = useScorecardState(); + + const period = useMemo(() => { + if (periods.length > 1) { + return; + } + return PeriodUtility.getPeriodById(head(periods)?.id as string); + }, [periods]); + + if (!state.options.title) { + return null; + } + + return ( +
+
+ {customHeader ? ( + + ) : ( +
+

+ {title}{" "} + {`${periods.length === 1 ? ` - ${period?.name}` : ""}`} +

+

+ {subtitle} +

+
+ )} +
+
+ ); +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardView.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardView.tsx new file mode 100644 index 000000000..8a4e3eaa5 --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/components/ScorecardView.tsx @@ -0,0 +1,38 @@ +import { useScorecardState } from "../state/state"; +import { ScorecardConfig } from "@hisptz/dhis2-analytics"; +import { useDimensions } from "../hooks/dimensions"; +import i18n from "@dhis2/d2-i18n"; +import { colors } from "@dhis2/ui"; + +export interface ScorecardViewProps { + config: ScorecardConfig; +} + +export function ScorecardView({ config }: ScorecardViewProps) { + const { noDimensionsSelected } = useDimensions(); + const [state, setState] = useScorecardState(); + + if (noDimensionsSelected) { + return ( +
+ + {i18n.t( + "Select organisation unit and period to view scorecard", + )} + +
+ ); + } + + return ( +
+ {/**/} +
+ ); +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/hooks/dimensions.ts b/packages/app/src/modules/Main/components/ScorecardViewPage/hooks/dimensions.ts index 1797746b1..ac06961ae 100644 --- a/packages/app/src/modules/Main/components/ScorecardViewPage/hooks/dimensions.ts +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/hooks/dimensions.ts @@ -63,9 +63,14 @@ export function useDimensions() { setParam("ou")(ous.join(";")); }; + const noDimensionsSelected = useMemo(() => { + return !params.get("ou") || !params.get("pe"); + }, [params.get("ou"), params.get("pe")]); + return { periods, orgUnit, + noDimensionsSelected, setPeriod, setOrgUnit, setDimensions, diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/state/config.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/state/config.tsx new file mode 100644 index 000000000..483441c37 --- /dev/null +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/state/config.tsx @@ -0,0 +1,28 @@ +import { createContext, ReactNode, useContext } from "react"; +import { ScorecardConfig } from "@hisptz/dhis2-analytics"; +import i18n from "@dhis2/d2-i18n"; + +const ScorecardConfigContext = createContext(null); + +export function useScorecardConfigFromContext() { + const config = useContext(ScorecardConfigContext); + if (!config) { + throw Error(i18n.t("Could not get scorecard config")); + } + + return config; +} + +export function ScorecardConfigProvider({ + children, + config, +}: { + children: ReactNode; + config: ScorecardConfig; +}) { + return ( + + {children} + + ); +} diff --git a/packages/app/src/modules/Main/components/ScorecardViewPage/state/state.tsx b/packages/app/src/modules/Main/components/ScorecardViewPage/state/state.tsx index 25fa43042..152a1b715 100644 --- a/packages/app/src/modules/Main/components/ScorecardViewPage/state/state.tsx +++ b/packages/app/src/modules/Main/components/ScorecardViewPage/state/state.tsx @@ -1,16 +1,22 @@ -import { createContext, ReactNode, useState } from "react"; +import { createContext, ReactNode, useContext, useState } from "react"; import { ScorecardState } from "@hisptz/dhis2-analytics"; import { ScorecardSetState } from "@hisptz/dhis2-analytics/dist/types/components/Scorecard/components/StateSetProvider"; const ScorecardStateContext = createContext(null); const ScorecardSetStateContext = createContext(null); +export function useScorecardState() { + const scorecardState = useContext(ScorecardStateContext)!; + const setState = useContext(ScorecardSetStateContext)!; + return [scorecardState, setState]; +} + export function ScorecardStateProvider({ children, initialState, }: { children: ReactNode; - initialState?: ScorecardState; + initialState: ScorecardState; }) { const [scorecardState, setScorecardState] = useState(initialState);