Skip to content

Commit

Permalink
fix: scorecard form
Browse files Browse the repository at this point in the history
Fixed issues with validations in the data configuration page
  • Loading branch information
nnkogift committed Sep 24, 2024
1 parent dc04006 commit 807ea74
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 41 deletions.
4 changes: 3 additions & 1 deletion packages/app/src/App.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@


.main-container {
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -561,3 +560,6 @@ td.extra-table-cell > svg {
text-align: justify;
}

.jsx-3375842594 {
height: 100% !important;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function DataGroupArea() {
<SearchDataItem />
</div>
<h4 className="pl-16">{i18n.t("Groups")}</h4>
<div style={{ maxHeight: "60vh", overflowY: "auto", flex: 1, justifySelf: "stretch" }}>
<div style={{ height: "100%", overflowY: "auto", flex: 1, justifySelf: "stretch" }}>
<DataGroups />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,30 @@ import DataGroupArea from "./DataGroupArea";
import { PreviewArea } from "./components/DataGroups/components/DataGroup/components/PreviewArea";
import { InstructionArea } from "./components/DataGroups/components/DataGroup/components/InstructionArea";
import { SelectedDataStateProvider } from "./states/selectionState";
import { colors, Field } from "@dhis2/ui";
import { useController } from "react-hook-form";
import { ScorecardConfig } from "@hisptz/dhis2-analytics";

export default function DataConfigurationScorecardForm() {

const { fieldState } = useController<ScorecardConfig, "dataSelection.dataGroups">({
name: "dataSelection.dataGroups"
});

return (
<SelectedDataStateProvider>
<div className="row h-100">
<div className="col-md-4 col-sm-6 p-16 groups-configuration-area">
<div
className=" container-bordered column"
style={{ minHeight: "100%", height: "100%" }}
>
<Suspense fallback={<ContainerLoader />}>
<DataGroupArea />
</Suspense>
</div>
<Field className="h-100" validationText={fieldState?.error?.message} error={!!fieldState.error}>
<div
className=" container-bordered column"
style={fieldState.error ? { height: "100%", borderColor: colors.red500 } : { height: "100%", borderColor: "#A0ADBA" }}
>
<Suspense fallback={<ContainerLoader />}>
<DataGroupArea />
</Suspense>
</div>
</Field>
</div>
<div className="col-md-8 p-16 h-100">
<Suspense fallback={<ContainerLoader />}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { generateLegendDefaults, getScorecardSummary } from "@scorecard/shared";
import { cloneDeep, find, isEmpty, set } from "lodash";
import { DATASTORE_NAMESPACE, generateLegendDefaults } from "@scorecard/shared";
import { cloneDeep, isEmpty, set } from "lodash";
import { LegendDefinition, ScorecardDataGroup, ScorecardDataHolder, ScorecardDataSource, SpecificTarget } from "@hisptz/dhis2-analytics";
import { useDataEngine } from "@dhis2/app-runtime";

export function resetLegends(groups: ScorecardDataGroup[], legendDefinitions: LegendDefinition[]) {
const newGroups = cloneDeep(groups);
Expand All @@ -12,23 +13,25 @@ export function resetLegends(groups: ScorecardDataGroup[], legendDefinitions: Le
dataSource,
"legends",
generateLegendDefaults(
getNonDefaultLegendDefinitions(legendDefinitions),
dataSource.weight,
dataSource.highIsGood
{
legendDefinitions: getNonDefaultLegendDefinitions(legendDefinitions),
weight: dataSource.weight,
highIsGood: dataSource.highIsGood
}
)
);
if (!isEmpty(dataSource.specificTargets)) {
dataSource.specificTargets.forEach(
dataSource.specificTargets?.forEach(
(specificTarget: SpecificTarget) => {
set(
specificTarget,
"legends",
generateLegendDefaults(
getNonDefaultLegendDefinitions(
legendDefinitions
),
dataSource.weight,
dataSource.highIsGood
{
legendDefinitions: getNonDefaultLegendDefinitions(legendDefinitions),
weight: dataSource.weight,
highIsGood: dataSource.highIsGood
}
)
);
}
Expand All @@ -49,14 +52,39 @@ export function getNonDefaultLegendDefinitions(legendDefinitions: any) {
);
}

export async function titleDoesNotExist(engine: any, id: any, title: any) {
const { summary } = await getScorecardSummary(engine);
if (isEmpty(summary)) {

const query: any = {
titleCheck: {
resource: `dataStore/${DATASTORE_NAMESPACE}`,
params: ({ title }: { title: string }) => ({
fields: ["title", "id"],
filter: `title:eq:${title}`
})
}
};

export async function checkTitleAvailability({ title, id, engine }: { engine: ReturnType<typeof useDataEngine>, id?: string, title?: string }) {
if (!title) {
return false;
}

const response = await engine.query(query, {
variables: {
title
}
});

const results = (response.titleCheck as { entries: Record<string, unknown>[] })?.entries;
if (isEmpty(results)) {
return true;
}
const scorecard = find(summary, { title });
if (scorecard) {
return scorecard.id === id;
if (results.length > 1) {
return false;
}
return !scorecard;
if (!id) {
return true;
}

const existingConfig = results.find((result) => result.id === id);
return !existingConfig;
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export function NavigationButtons() {
loading: true
});
const formValid = await trigger(currentStep.fieldIds as any);

if (formValid) {
const config = getValues();
await save(config);
Expand Down
10 changes: 4 additions & 6 deletions packages/app/src/modules/ScorecardManagement/hooks/schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { scorecardConfigSchema } from "@scorecard/shared";
import { z } from "zod";
import i18n from "@dhis2/d2-i18n";
import { titleDoesNotExist } from "../components/General/utils/utils";
import { checkTitleAvailability } from "../components/General/utils/utils";
import { useParams } from "react-router-dom";
import { useDataEngine } from "@dhis2/app-runtime";
import { dataGroupSchema, dataHolderSchema, organisationUnitSelectionSchema } from "@hisptz/dhis2-analytics";
Expand Down Expand Up @@ -31,11 +31,9 @@ export function useFormSchema() {
const engine = useDataEngine();
return scorecardConfigSchema.extend({
title: z.string({ required_error: i18n.t("Title is required") }).min(4, i18n.t("Title must have at least 4 characters")).refine(async (value) => {
const titleExists = await titleDoesNotExist(engine, id, value);
return !titleExists || i18n.t(
`A scorecard with the title '{{value}}' already exists. Please select another title`,
{ value }
);
return await checkTitleAvailability({ engine, id, title: value });
}, {
message: i18n.t(`A scorecard with this title already exists. Please select another title`)
}),
dataSelection: z.object({
dataGroups: z.array(dataGroupSchema.extend({
Expand Down
10 changes: 4 additions & 6 deletions packages/shared/src/services/getScorecardSummary.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { compact, filter, isEmpty } from "lodash";
import {
DATASTORE_ENDPOINT,
DATASTORE_SCORECARD_SUMMARY_KEY,
} from "../constants";
import { DATASTORE_ENDPOINT, DATASTORE_SCORECARD_SUMMARY_KEY } from "../constants";
import { generateScorecardSummary } from "../utils";
import { useDataEngine } from "@dhis2/app-runtime";

const query = {
summary: {
Expand All @@ -22,7 +20,7 @@ async function initializeKey(engine: any) {
return await engine.mutate(addMutation, { variables: { data: [] } });
}

export default async function getScorecardSummary(engine: any) {
export default async function getScorecardSummary(engine: ReturnType<typeof useDataEngine>) {
try {
const response = await engine.query(query);
return { summary: response?.summary };
Expand All @@ -47,7 +45,7 @@ const restoreMutation = {
id: DATASTORE_SCORECARD_SUMMARY_KEY,
data: ({ data }: any) => data,
};

const { summary } = await getScorecardSummary(engine);
const singleScorecardQuery = {
scorecard: {
resource: DATASTORE_ENDPOINT,
Expand Down

0 comments on commit 807ea74

Please sign in to comment.