From e22f9ed45829faeec902b19986b595bbab01fdeb Mon Sep 17 00:00:00 2001 From: Joy A Date: Fri, 28 Jun 2024 18:22:06 +0530 Subject: [PATCH] #1263 | Configure duration input for 'Recent' type Standard Report Cards --- src/common/components/ValueTextUnitSelect.js | 26 ++++++++ src/common/model/WebReportCard.js | 35 ++++++++-- .../ReportCard/CreateEditReportCard.js | 66 ++++++++++++++----- .../ReportCard/ReportCardReducer.js | 13 +++- .../components/ReportCard/ReportCardShow.js | 7 ++ yarn.lock | 55 ++++++++++------ 6 files changed, 157 insertions(+), 45 deletions(-) create mode 100644 src/common/components/ValueTextUnitSelect.js diff --git a/src/common/components/ValueTextUnitSelect.js b/src/common/components/ValueTextUnitSelect.js new file mode 100644 index 000000000..64db7c48b --- /dev/null +++ b/src/common/components/ValueTextUnitSelect.js @@ -0,0 +1,26 @@ +import React from "react"; +import TextField from "@material-ui/core/TextField"; +import Select from "@material-ui/core/Select"; +import InputLabel from "@material-ui/core/InputLabel"; + +export const ValueTextUnitSelect = ({ label, value, unit, units, textProps, selectProps, errorMsg, onValueChange, onUnitChange }) => { + return ( + +

+

+ {label && {label}} + onValueChange(event)} + {...textProps} + /> + +
+ {errorMsg && errorMsg} +
+ ); +}; diff --git a/src/common/model/WebReportCard.js b/src/common/model/WebReportCard.js index 12eebb257..ba2ad1e3d 100644 --- a/src/common/model/WebReportCard.js +++ b/src/common/model/WebReportCard.js @@ -1,5 +1,5 @@ import { ReportCard } from "openchs-models"; -import { isEmpty, isNil } from "lodash"; +import { isEmpty, isNil, isInteger, toNumber, lowerCase } from "lodash"; import WebStandardReportCardType from "./WebStandardReportCardType"; import WebSubjectType from "./WebSubjectType"; import WebProgram from "./WebProgram"; @@ -16,7 +16,8 @@ function populateRecordCardFields( countOfCards, standardReportCardInputSubjectTypes, standardReportCardInputPrograms, - standardReportCardInputEncounterTypes + standardReportCardInputEncounterTypes, + standardReportCardInputRecentDuration ) { reportCard.id = id; reportCard.iconFileS3Key = iconFileS3Key; @@ -28,6 +29,7 @@ function populateRecordCardFields( reportCard.standardReportCardInputSubjectTypes = standardReportCardInputSubjectTypes; reportCard.standardReportCardInputPrograms = standardReportCardInputPrograms; reportCard.standardReportCardInputEncounterTypes = standardReportCardInputEncounterTypes; + reportCard.standardReportCardInputRecentDuration = standardReportCardInputRecentDuration; } class WebReportCard extends ReportCard { @@ -60,7 +62,10 @@ class WebReportCard extends ReportCard { static createNewReportCard() { const webReportCard = new WebReportCard(); - populateRecordCardFields(webReportCard, "", "", "", [], false, null, WebReportCard.MinimumNumberOfNestedCards, [], [], []); + populateRecordCardFields(webReportCard, "", "", "", [], false, null, WebReportCard.MinimumNumberOfNestedCards, [], [], [], { + value: "1", + unit: "days" + }); webReportCard.colour = "#ff0000"; return webReportCard; } @@ -78,7 +83,8 @@ class WebReportCard extends ReportCard { other.countOfCards, [...other.standardReportCardInputSubjectTypes], [...other.standardReportCardInputPrograms], - [...other.standardReportCardInputEncounterTypes] + [...other.standardReportCardInputEncounterTypes], + other.standardReportCardInputRecentDuration ); webReportCard.standardReportCardType = other.standardReportCardType; webReportCard.colour = other.colour; @@ -98,7 +104,8 @@ class WebReportCard extends ReportCard { resource.count, WebSubjectType.fromResources(resource.standardReportCardInputSubjectTypes), WebProgram.fromResources(resource.standardReportCardInputPrograms), - WebEncounterType.fromResources(resource.standardReportCardInputEncounterTypes) + WebEncounterType.fromResources(resource.standardReportCardInputEncounterTypes), + resource.standardReportCardInputRecentDuration ); webReportCard.colour = resource.color; if (!isNil(resource.standardReportCardType)) @@ -110,7 +117,7 @@ class WebReportCard extends ReportCard { return isNil(this.id); } - validate(isStandardReportCard) { + validateCard(isStandardReportCard) { const errors = []; if (isEmpty(this.name)) { errors.push({ key: "EMPTY_NAME", message: "Name cannot be empty" }); @@ -146,6 +153,19 @@ class WebReportCard extends ReportCard { message: "Nested Card count cannot be less than 1 or greater than 9" }); } + if (isStandardReportCard && this.isRecentType()) { + const recentDurationValueAsNumber = toNumber(this.standardReportCardInputRecentDuration.value); + if ( + !isInteger(recentDurationValueAsNumber) || + !(recentDurationValueAsNumber > 0) || + lowerCase(this.standardReportCardInputRecentDuration.value).indexOf("e") > -1 + ) { + errors.push({ + key: "INVALID_DURATION", + message: "Recent duration is mandatory and should be a positive number" + }); + } + } return errors; } @@ -162,7 +182,8 @@ class WebReportCard extends ReportCard { iconFileS3Key: this.iconFileS3Key, standardReportCardInputSubjectTypes: this.standardReportCardInputSubjectTypes.map(x => x.uuid), standardReportCardInputPrograms: this.standardReportCardInputPrograms.map(x => x.uuid), - standardReportCardInputEncounterTypes: this.standardReportCardInputEncounterTypes.map(x => x.uuid) + standardReportCardInputEncounterTypes: this.standardReportCardInputEncounterTypes.map(x => x.uuid), + standardReportCardInputRecentDuration: this.standardReportCardInputRecentDuration }; } } diff --git a/src/formDesigner/components/ReportCard/CreateEditReportCard.js b/src/formDesigner/components/ReportCard/CreateEditReportCard.js index b7a82defa..c833c6f1f 100644 --- a/src/formDesigner/components/ReportCard/CreateEditReportCard.js +++ b/src/formDesigner/components/ReportCard/CreateEditReportCard.js @@ -1,7 +1,7 @@ import React from "react"; import { ReportCardReducer, ReportCardReducerKeys } from "./ReportCardReducer"; import http from "../../../common/utils/httpClient"; -import { get, isNil } from "lodash"; +import { get, isNil, sortBy } from "lodash"; import Box from "@material-ui/core/Box"; import { DocumentationContainer } from "../../../common/components/DocumentationContainer"; import Grid from "@material-ui/core/Grid"; @@ -25,6 +25,8 @@ import { PopoverColorPicker } from "../../../common/components/PopoverColorPicke import WebReportCard from "../../../common/model/WebReportCard"; import DashboardService from "../../../common/service/DashboardService"; import FormMetaDataSelect from "../../../common/components/FormMetaDataSelect"; +import { StandardReportCardType } from "openchs-models"; +import { ValueTextUnitSelect } from "../../../common/components/ValueTextUnitSelect"; export const CreateEditReportCard = ({ edit, ...props }) => { const [card, dispatch] = React.useReducer(ReportCardReducer, WebReportCard.createNewReportCard()); @@ -62,8 +64,15 @@ export const CreateEditReportCard = ({ edit, ...props }) => { } }, [isStandardReportCard]); + React.useEffect(() => { + //to handle existing recent type cards without duration configured + if (card.isRecentType() && isNil(card.standardReportCardInputRecentDuration)) { + dispatch({ type: ReportCardReducerKeys.duration, payload: { value: "1", unit: "days" } }); + } + }, [card]); + const validateRequest = () => { - const errors = card.validate(isStandardReportCard); + const errors = card.validateCard(isStandardReportCard); console.log(errors); setError(errors); return errors.length === 0; @@ -144,18 +153,14 @@ export const CreateEditReportCard = ({ edit, ...props }) => { toolTipKey={"APP_DESIGNER_CARD_DESCRIPTION"} />

- {!isStandardReportCard && ( - - - dispatch({ type: ReportCardReducerKeys.color, payload: color })} - /> - {getErrorByKey(error, "EMPTY_COLOR")} - - )} + + dispatch({ type: ReportCardReducerKeys.color, payload: color })} + /> + {getErrorByKey(error, "EMPTY_COLOR")}

{ type: ReportCardReducerKeys.standardReportCardType, payload: standardReportCardTypes.find(x => event.target.value === x.name) }); + dispatch({ + type: ReportCardReducerKeys.duration, + payload: card.isRecentType() ? { value: "1", unit: "days" } : null + }); }} - style={{ width: "200px" }} + style={{ width: "250px" }} required - options={standardReportCardTypes.map((type, index) => ( + options={sortBy(standardReportCardTypes, ["name"]).map((type, index) => ( {type.name} @@ -230,6 +239,31 @@ export const CreateEditReportCard = ({ edit, ...props }) => { toolTipKey={"APP_DESIGNER_CARD_IS_STANDARD_TYPE"} /> )} + {isStandardReportCard && card.isRecentType() && ( + ( + + {unit} + + ))} + onValueChange={event => + dispatch({ + type: ReportCardReducerKeys.duration, + payload: { value: event.target.value, unit: card.standardReportCardInputRecentDuration.unit } + }) + } + onUnitChange={event => + dispatch({ + type: ReportCardReducerKeys.duration, + payload: { value: card.standardReportCardInputRecentDuration.value, unit: event.target.value } + }) + } + errorMsg={getErrorByKey(error, "INVALID_DURATION")} + /> + )} {card.isSubjectTypeFilterSupported() && ( <>

diff --git a/src/formDesigner/components/ReportCard/ReportCardReducer.js b/src/formDesigner/components/ReportCard/ReportCardReducer.js index f5588e8b1..0d77e1f4d 100644 --- a/src/formDesigner/components/ReportCard/ReportCardReducer.js +++ b/src/formDesigner/components/ReportCard/ReportCardReducer.js @@ -8,7 +8,8 @@ export const ReportCardReducerKeys = { nested: "nested", standardReportCardType: "standardReportCardType", setData: "setData", - cardFormMetaData: "cardFormMetaData" + cardFormMetaData: "cardFormMetaData", + duration: "duration" }; export const ReportCardReducer = (reportCard, action) => { @@ -40,6 +41,16 @@ export const ReportCardReducer = (reportCard, action) => { reportCard.standardReportCardInputPrograms = programs; reportCard.standardReportCardInputEncounterTypes = encounterTypes; break; + case ReportCardReducerKeys.duration: + if (action.payload) { + const { value, unit } = action.payload; + reportCard.standardReportCardInputRecentDuration = {}; + reportCard.standardReportCardInputRecentDuration.value = value; + reportCard.standardReportCardInputRecentDuration.unit = unit; + } else { + reportCard.standardReportCardInputRecentDuration = null; + } + break; default: break; } diff --git a/src/formDesigner/components/ReportCard/ReportCardShow.js b/src/formDesigner/components/ReportCard/ReportCardShow.js index e09fd108f..15f2d5571 100644 --- a/src/formDesigner/components/ReportCard/ReportCardShow.js +++ b/src/formDesigner/components/ReportCard/ReportCardShow.js @@ -60,6 +60,13 @@ function RenderCard({ reportCard }) { {reportCard.isStandardReportType() && ( )} +

+ {reportCard.isStandardReportType() && reportCard.isRecentType() && !_.isNil(reportCard.standardReportCardInputRecentDuration) && ( + + )} {reportCard.isSubjectTypeFilterSupported() && ( <>
diff --git a/yarn.lock b/yarn.lock index 330843e8f..dab259a42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7468,9 +7468,9 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000918, caniuse-lite@^1.0.30000929, can integrity sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg== caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001629: - version "1.0.30001636" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz#b15f52d2bdb95fad32c2f53c0b68032b85188a78" - integrity sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg== + version "1.0.30001638" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001638.tgz#598e1f0c2ac36f37ebc3f5b8887a32ca558e5d56" + integrity sha512-5SuJUJ7cZnhPpeLHaH0c/HPAnAHZvS6ElWyHK9GSIbVOQABLzowiI2pjmpvZ1WEbkyz46iFd4UXlOHR5SqgfMQ== capture-exit@^1.2.0: version "1.2.0" @@ -9439,9 +9439,9 @@ electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.621: integrity sha512-mPEG/52142po0XK1jQkZtbMmp38MZtQ3JDFItYxV65WXyhxDYEQ54tP4rb93m0RbMlZqQ+4zBw2N7UumSgGfbA== electron-to-chromium@^1.3.47, electron-to-chromium@^1.4.796: - version "1.4.806" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz#2cb046631cbabceb26fc72be68d273fa183e36bc" - integrity sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg== + version "1.4.814" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.814.tgz#176535a0b899c9c473464502ab77576aa8bb1cbe" + integrity sha512-GVulpHjFu1Y9ZvikvbArHmAhZXtm3wHlpjTMcXNGKl4IQ4jMQjlnz8yMQYYqdLHKi/jEL2+CBC2akWVCoIGUdw== elegant-spinner@^1.0.1: version "1.0.1" @@ -11665,7 +11665,7 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -12594,11 +12594,11 @@ is-color-stop@^1.0.0: rgba-regex "^1.0.0" is-core-module@^2.13.0: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + version "2.14.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1" + integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" is-data-descriptor@^0.1.4: version "0.1.4" @@ -14468,9 +14468,9 @@ lowlight@^1.14.0: highlight.js "~10.4.0" lru-cache@^10.2.0: - version "10.2.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" - integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== + version "10.3.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.3.0.tgz#4a4aaf10c84658ab70f79a85a9a3f1e1fb11196b" + integrity sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ== lru-cache@^4.0.1, lru-cache@^4.1.1: version "4.1.5" @@ -15476,9 +15476,9 @@ object-hash@^1.1.4: integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== object-inspect@^1.7.0, object-inspect@^1.8.0: version "1.8.0" @@ -15686,10 +15686,10 @@ open@^7.1.0: grunt "^1.0.3" webpack "^4.13.0" -openchs-models@1.31.79: - version "1.31.79" - resolved "https://registry.yarnpkg.com/openchs-models/-/openchs-models-1.31.79.tgz#58706743f73bdadef907eace9c1249a65bdb96a9" - integrity sha512-SMhnZbFqDsmXILMIGTM3dKaH8EU2+FljqLBa1IvfrfpdwVKdqksBTEhvFEJPlDHLlX06/eeeEvmxaNnmCmjCqg== +openchs-models@1.31.86: + version "1.31.86" + resolved "https://registry.yarnpkg.com/openchs-models/-/openchs-models-1.31.86.tgz#67c1fdfb4b6631b6f99b70559c010f435bec6068" + integrity sha512-Ye2f8tuTJO21wKfHsM8ZAnGbMUAceoffb0qnbN/zm6v8jLeznTkI71yFz6FbiV/dnG4p1PLWYrvYoXvKA4sQfg== dependencies: uuid "^9.0.1" @@ -19186,6 +19186,19 @@ rsvp@^4.8.4: "rules-config@github:avniproject/rules-config#fe552da405368bfd138e2f38e605c1d307e3ebe4": version "0.0.1" resolved "https://codeload.github.com/avniproject/rules-config/tar.gz/fe552da405368bfd138e2f38e605c1d307e3ebe4" + dependencies: + "@quasar/babel-preset-app" "^2.0.1" + babel-preset-env "^1.7.0" + babel-register "^6.26.0" + chai "^4.1.2" + lodash "^4.17.11" + moment "^2.29.4" + superagent "^3.8.3" + test "^0.6.0" + uglifyjs-webpack-plugin "^1.2.5" + webpack "^3.12.0" + webpack-cli "^3.0.3" + webpack-node-externals "1.6.0" run-async@^2.2.0, run-async@^2.4.0: version "2.4.1"