@openmrs/esm-fast-data-entry-app 1.0.0-pre.59 → 1.0.1-pre.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.husky/pre-push +0 -0
- package/.yarn/plugins/@yarnpkg/plugin-version.cjs +550 -0
- package/.yarn/versions/7ee3eceb.yml +0 -0
- package/dist/openmrs-esm-fast-data-entry-app.js +1 -1
- package/jest.config.json +20 -18
- package/package.json +31 -38
- package/src/FormBootstrap.tsx +9 -2
- package/src/Root.tsx +12 -5
- package/src/add-group-modal/AddGroupModal.tsx +209 -0
- package/src/add-group-modal/styles.scss +35 -0
- package/src/context/FormWorkflowContext.tsx +1 -1
- package/src/context/FormWorkflowReducer.ts +1 -1
- package/src/context/GroupFormWorkflowContext.tsx +141 -0
- package/src/context/GroupFormWorkflowReducer.ts +272 -0
- package/src/empty-state/EmptyState.tsx +12 -8
- package/src/form-entry-workflow/FormEntryWorkflow.tsx +23 -13
- package/src/{form-review-card → form-entry-workflow/form-review-card}/FormReviewCard.tsx +3 -3
- package/src/{form-review-card → form-entry-workflow/form-review-card}/index.ts +0 -0
- package/src/form-entry-workflow/form-review-card/styles.scss +39 -0
- package/src/{patient-banner → form-entry-workflow/patient-banner}/PatientBanner.test.tsx +0 -0
- package/src/{patient-banner → form-entry-workflow/patient-banner}/PatientBanner.tsx +3 -3
- package/src/{patient-banner → form-entry-workflow/patient-banner}/index.ts +0 -0
- package/src/{patient-banner → form-entry-workflow/patient-banner}/styles.scss +8 -7
- package/src/{patient-search-header → form-entry-workflow/patient-search-header}/PatientSearchHeader.tsx +13 -11
- package/src/{patient-search-header → form-entry-workflow/patient-search-header}/index.ts +0 -0
- package/src/form-entry-workflow/patient-search-header/styles.scss +22 -0
- package/src/form-entry-workflow/styles.scss +14 -13
- package/src/{workflow-review → form-entry-workflow/workflow-review}/WorkflowReview.tsx +6 -6
- package/src/{workflow-review → form-entry-workflow/workflow-review}/index.ts +0 -0
- package/src/{workflow-review → form-entry-workflow/workflow-review}/styles.scss +0 -0
- package/src/forms-app-menu-link.tsx +2 -2
- package/src/forms-page/FormsPage.tsx +55 -21
- package/src/{forms-table → forms-page/forms-table}/FormsTable.tsx +14 -6
- package/src/{forms-table → forms-page/forms-table}/index.ts +0 -0
- package/src/{forms-table → forms-page/forms-table}/styles.scss +0 -0
- package/src/forms-page/styles.scss +5 -5
- package/src/group-form-entry-workflow/GroupFormEntryWorkflow.tsx +413 -0
- package/src/group-form-entry-workflow/group-banner/GroupBanner.test.tsx +9 -0
- package/src/group-form-entry-workflow/group-banner/GroupBanner.tsx +45 -0
- package/src/group-form-entry-workflow/group-banner/index.ts +3 -0
- package/src/group-form-entry-workflow/group-banner/styles.scss +60 -0
- package/src/group-form-entry-workflow/group-search/CompactGroupResults.tsx +106 -0
- package/src/group-form-entry-workflow/group-search/CompactGroupSearch.tsx +63 -0
- package/src/group-form-entry-workflow/group-search/GroupSearch.tsx +93 -0
- package/src/group-form-entry-workflow/group-search/compact-group-result.scss +64 -0
- package/src/group-form-entry-workflow/group-search/compact-group-search.scss +35 -0
- package/src/group-form-entry-workflow/group-search/group-search.scss +94 -0
- package/src/group-form-entry-workflow/group-search/mock-group-data.ts +79 -0
- package/src/group-form-entry-workflow/group-search/useGroupSearch.ts +14 -0
- package/src/group-form-entry-workflow/group-search-header/GroupSearchHeader.tsx +42 -0
- package/src/group-form-entry-workflow/group-search-header/index.ts +3 -0
- package/src/{patient-search-header → group-form-entry-workflow/group-search-header}/styles.scss +5 -6
- package/src/group-form-entry-workflow/index.ts +3 -0
- package/src/group-form-entry-workflow/styles.scss +86 -0
- package/src/hooks/useKeyPress.ts +31 -0
- package/src/hooks/usePostCohort.ts +18 -0
- package/src/index.ts +5 -1
- package/src/patient-card/PatientCard.tsx +11 -9
- package/src/patient-card/styles.scss +9 -8
- package/translations/en.json +30 -1
- package/.github/pull_request_template.md +0 -18
- package/.github/workflows/node.js.yml +0 -121
- package/dist/132.js +0 -1
- package/dist/187.js +0 -1
- package/dist/247.js +0 -1
- package/dist/294.js +0 -2
- package/dist/294.js.LICENSE.txt +0 -14
- package/dist/312.js +0 -1
- package/dist/412.js +0 -1
- package/dist/536.js +0 -2
- package/dist/536.js.LICENSE.txt +0 -8
- package/dist/574.js +0 -1
- package/dist/592.js +0 -1
- package/dist/595.js +0 -2
- package/dist/595.js.LICENSE.txt +0 -1
- package/dist/776.js +0 -1
- package/dist/804.js +0 -1
- package/dist/880.js +0 -2
- package/dist/880.js.LICENSE.txt +0 -20
- package/dist/906.js +0 -1
- package/dist/935.js +0 -2
- package/dist/935.js.LICENSE.txt +0 -23
- package/dist/990.js +0 -1
- package/dist/openmrs-esm-fast-data-entry-app.js.buildmanifest.json +0 -433
- package/dist/openmrs-esm-fast-data-entry-app.old +0 -1
- package/src/form-review-card/styles.scss +0 -38
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
var _openmrs_esm_fast_data_entry_app;(()=>{function b(a){var c=h[a];if(void 0!==c)return c.exports;var d=h[a]={id:a,loaded:!1,exports:{}};return G[a].call(d.exports,d,d.exports,b),d.loaded=!0,d.exports}var j,k,q,v,w,x,y,z,A,B,C,D,E,F,G={7140:(b,c,d)=>{var f={"./start":()=>d.e(132).then(()=>()=>d(8132))},e=(a,b)=>(d.R=b,b=d.o(f,a)?f[a]():Promise.resolve().then(()=>{throw new Error("Module \""+a+"\" does not exist in container.")}),d.R=void 0,b),a=(b,c)=>{if(d.S){var e=d.S["default"];if(e&&e!==b)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return d.S["default"]=b,d.I("default",c)}};d.d(c,{get:()=>e,init:()=>a})}},h={};b.m=G,b.c=h,b.n=a=>{var c=a&&a.__esModule?()=>a.default:()=>a;return b.d(c,{a:c}),c},b.d=(a,c)=>{for(var d in c)b.o(c,d)&&!b.o(a,d)&&Object.defineProperty(a,d,{enumerable:!0,get:c[d]})},b.f={},b.e=a=>Promise.all(Object.keys(b.f).reduce((c,d)=>(b.f[d](a,c),c),[])),b.u=a=>a+".js",b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(a){if("object"==typeof window)return window}}(),b.o=(a,b)=>Object.prototype.hasOwnProperty.call(a,b),j={},k="@openmrs/esm-fast-data-entry-app:",b.l=(c,e,g)=>{if(j[c])j[c].push(e);else{var h,a;if(void 0!==g)for(var m,n=document.getElementsByTagName("script"),o=0;o<n.length;o++)if(m=n[o],m.getAttribute("src")==c||m.getAttribute("data-webpack")==k+g){h=m;break}h||(a=!0,(h=document.createElement("script")).charset="utf-8",h.timeout=120,b.nc&&h.setAttribute("nonce",b.nc),h.setAttribute("data-webpack",k+g),h.src=c),j[c]=[e];var q=(b,f)=>{h.onerror=h.onload=null,clearTimeout(d);var e=j[c];if(delete j[c],h.parentNode&&h.parentNode.removeChild(h),e&&e.forEach(a=>a(f)),b)return b(f)},d=setTimeout(q.bind(null,void 0,{type:"timeout",target:h}),12e4);h.onerror=q.bind(null,h.onerror),h.onload=q.bind(null,h.onload),a&&document.head.appendChild(h)}},b.r=a=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(a,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(a,"__esModule",{value:!0})},b.nmd=a=>(a.paths=[],a.children||(a.children=[]),a),(()=>{b.S={};var c={},d={};b.I=(e,f)=>{f||(f=[]);var g=d[e];if(g||(g=d[e]={}),!(0<=f.indexOf(g))){if(f.push(g),c[e])return c[e];b.o(b.S,e)||(b.S[e]={});var h=b.S[e],i=(b,c,d,e)=>{var f=h[b]=h[b]||{},a=f[c];a&&(a.loaded||(!e==!a.eager?!("@openmrs/esm-fast-data-entry-app">a.from):!e))||(f[c]={get:d,from:"@openmrs/esm-fast-data-entry-app",eager:!!e})},j=[];return"default"===e&&(i("@carbon/react","1.11.0",()=>Promise.all([b.e(820),b.e(327),b.e(569),b.e(672),b.e(183)]).then(()=>()=>b(8569))),i("@openmrs/esm-framework","4.0.2-pre.275",()=>Promise.all([b.e(595),b.e(672)]).then(()=>()=>b(595))),i("react-dom","18.2.0",()=>Promise.all([b.e(935),b.e(672)]).then(()=>()=>b(3935))),i("react-i18next","11.18.5",()=>Promise.all([b.e(247),b.e(672)]).then(()=>()=>b(8247))),i("react-router-dom","6.3.0",()=>Promise.all([b.e(68),b.e(672)]).then(()=>()=>b(6068))),i("react","18.2.0",()=>b.e(294).then(()=>()=>b(7294)))),c[e]=j.length?Promise.all(j).then(()=>c[e]=1):1}}})(),(()=>{var a;b.g.importScripts&&(a=b.g.location+"");var c=b.g.document;if(!a&&c&&(c.currentScript&&(a=c.currentScript.src),!a)){var d=c.getElementsByTagName("script");d.length&&(a=d[d.length-1].src)}if(!a)throw new Error("Automatic publicPath is not supported in this browser");a=a.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),b.p=a})(),q=a=>{var b=a=>a.split(".").map(a=>+a==a?+a:a),c=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(a),d=c[1]?b(c[1]):[];return c[2]&&(d.length++,d.push.apply(d,b(c[2]))),c[3]&&(d.push([]),d.push.apply(d,b(c[3]))),d},v=(b,c)=>{b=q(b),c=q(c);for(var d=0;;){if(d>=b.length)return d<c.length&&"u"!=(typeof c[d])[0];var f=b[d],a=(typeof f)[0];if(d>=c.length)return"u"==a;var g=c[d],h=(typeof g)[0];if(a!=h)return"o"==a&&"n"==h||"s"==h||"u"==a;if("o"!=a&&"u"!=a&&f!=g)return f<g;d++}},w=a=>{function b(){return g.pop().replace(/^\((.+)\)$/,"$1")}var c=a[0],d="";if(1===a.length)return"*";if(c+.5){d+=0==c?">=":-1==c?"<":1==c?"^":2==c?"~":0<c?"=":"!=";for(var e=1,f=1;f<a.length;f++)e--,d+="u"==(typeof(h=a[f]))[0]?"-":(0<e?".":"")+(e=2,h);return d}var g=[];for(f=1;f<a.length;f++){var h=a[f];g.push(0===h?"not("+b()+")":1===h?"("+b()+" || "+b()+")":2===h?g.pop()+" "+g.pop():w(h))}return b()},x=(b,e)=>{if(0 in b){e=q(e);var g=b[0],j=0>g;j&&(g=-g-1);for(var a=0,k=1,m=!0;;k++,a++){var o,t,v=k<b.length?(typeof b[k])[0]:"";if(a>=e.length||"o"==(t=(typeof(o=e[a]))[0]))return!m||("u"==v?k>g&&!j:""==v!=j);if("u"==t){if(!m||"u"!=v)return!1;}else if(!m)"s"!=v&&"n"!=v&&(m=!1,k--);else if(v==t){if(!(k<=g)){if(j?o>b[k]:o<b[k])return!1;o!=b[k]&&(m=!1)}else if(o!=b[k])return!1;}else if("s"!=v&&"n"!=v){if(j||k<=g)return!1;m=!1,k--}else{if(k<=g||t<v!=j)return!1;m=!1}}}var d=[],p=d.pop.bind(d);for(a=1;a<b.length;a++){var c=b[a];d.push(1==c?p()|p():2==c?p()&p():c?x(c,e):!p())}return!!p()},y=(a,b)=>{var c=a[b];return Object.keys(c).reduce((a,b)=>a&&(c[a].loaded||!v(a,b))?a:b,0)},z=(a,b,c,d)=>"Unsatisfied version "+c+" from "+(c&&a[b][c].from)+" of shared singleton module "+b+" (required "+w(d)+")",A=(b,c,d,e)=>{var f=y(b,d);return x(e,f)||"undefined"!=typeof console&&console.warn&&console.warn(z(b,d,f,e)),B(b[d][f])},B=a=>(a.loaded=1,a.get()),C=(c=>function(d,e,f,g){var a=b.I(d);return a&&a.then?a.then(c.bind(c,d,b.S[d],e,f,g)):c(0,b.S[d],e,f,g)})((c,d,e,f,g)=>d&&b.o(d,e)?A(d,0,e,f):g()),D={},E={1672:()=>C("default","react",[1,18],()=>b.e(294).then(()=>()=>b(7294))),5183:()=>C("default","react-dom",[1,18],()=>b.e(935).then(()=>()=>b(3935))),1132:()=>C("default","@openmrs/esm-framework",[0],()=>Promise.all([b.e(595),b.e(672)]).then(()=>()=>b(595))),1338:()=>C("default","react-router-dom",[1,6],()=>b.e(68).then(()=>()=>b(6068))),3397:()=>C("default","react-i18next",[1,11],()=>b.e(247).then(()=>()=>b(8247))),4422:()=>C("default","@carbon/react",[1,1,9,0],()=>Promise.all([b.e(820),b.e(327),b.e(569),b.e(183)]).then(()=>()=>b(8569)))},F={132:[1132],183:[5183],397:[3397],672:[1672],804:[1338],877:[4422]},b.f.consumes=(a,c)=>{b.o(F,a)&&F[a].forEach(d=>{if(b.o(D,d))return c.push(D[d]);var e=a=>{D[d]=0,b.m[d]=c=>{delete b.c[d],c.exports=a()}},f=a=>{delete D[d],b.m[d]=()=>{throw delete b.c[d],a}};try{var g=E[d]();g.then?c.push(D[d]=g.then(e).catch(f)):e(g)}catch(a){f(a)}})},(()=>{var c={447:0};b.f.j=(d,e)=>{var f=b.o(c,d)?c[d]:void 0;if(0!==f)if(f)e.push(f[2]);else if(/^(183|397|672)$/.test(d))c[d]=0;else{var g=new Promise((b,e)=>f=c[d]=[b,e]);e.push(f[2]=g);var a=b.p+b.u(d),h=new Error;b.l(a,e=>{if(b.o(c,d)&&(0!==(f=c[d])&&(c[d]=void 0),f)){var g=e&&("load"===e.type?"missing":e.type),a=e&&e.target&&e.target.src;h.message="Loading chunk "+d+" failed.\n("+g+": "+a+")",h.name="ChunkLoadError",h.type=g,h.request=a,f[1](h)}},"chunk-"+d,d)}};var a=(d,e)=>{var f,g,[h,j,i]=e,k=0;if(h.some(a=>0!==c[a])){for(f in j)b.o(j,f)&&(b.m[f]=j[f]);i&&i(b)}for(d&&d(e);k<h.length;k++)g=h[k],b.o(c,g)&&c[g]&&c[g][0](),c[g]=0},d=self.webpackChunk_openmrs_esm_fast_data_entry_app=self.webpackChunk_openmrs_esm_fast_data_entry_app||[];d.forEach(a.bind(null,0)),d.push=a.bind(null,d.push.bind(d))})(),b.nc=void 0;var m=b(7140);_openmrs_esm_fast_data_entry_app=m})();
|
package/jest.config.json
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"^
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
1
|
+
|
|
2
|
+
{
|
|
3
|
+
"transform": {
|
|
4
|
+
"^.+\\.tsx?$": "@swc/jest"
|
|
5
|
+
},
|
|
6
|
+
"transformIgnorePatterns": ["/node_modules/(?!@openmrs)"],
|
|
7
|
+
"moduleNameMapper": {
|
|
8
|
+
"\\.(s?css)$": "identity-obj-proxy",
|
|
9
|
+
"@openmrs/esm-framework": "@openmrs/esm-framework/mock",
|
|
10
|
+
"^lodash-es/(.*)$": "lodash/$1",
|
|
11
|
+
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"setupFilesAfterEnv": [
|
|
14
|
+
"<rootDir>/src/setup-tests.ts"
|
|
15
|
+
],
|
|
16
|
+
"testEnvironment": "jsdom",
|
|
17
|
+
"testEnvironmentOptions": {
|
|
18
|
+
"url": "http://localhost/"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-fast-data-entry-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-pre.8",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "An OpenMRS 3.x microfrontend",
|
|
6
6
|
"browser": "dist/openmrs-esm-fast-data-entry-app.js",
|
|
@@ -42,43 +42,29 @@
|
|
|
42
42
|
"bugs": {
|
|
43
43
|
"url": "https://github.com/openmrs/openmrs-esm-fast-data-entry-app/issues"
|
|
44
44
|
},
|
|
45
|
-
"resolutions": {
|
|
46
|
-
"**/@types/react": "^16.14.5"
|
|
47
|
-
},
|
|
48
|
-
"dependencies": {},
|
|
49
45
|
"peerDependencies": {
|
|
50
|
-
"@
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"react": "
|
|
54
|
-
"react-dom": "^16.0",
|
|
46
|
+
"@carbon/react": "^1.9.0",
|
|
47
|
+
"@openmrs/esm-framework": "*",
|
|
48
|
+
"react": "18.x",
|
|
49
|
+
"react-dom": "18.x",
|
|
55
50
|
"react-i18next": "11.x",
|
|
56
|
-
"react-router-dom": "
|
|
51
|
+
"react-router-dom": "6.x"
|
|
57
52
|
},
|
|
58
53
|
"devDependencies": {
|
|
59
|
-
"@
|
|
60
|
-
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
|
61
|
-
"@babel/preset-env": "^7.14.4",
|
|
62
|
-
"@babel/preset-react": "^7.13.13",
|
|
63
|
-
"@babel/preset-typescript": "^7.13.0",
|
|
64
|
-
"@babel/runtime": "^7.14.0",
|
|
54
|
+
"@carbon/react": "^1.9.0",
|
|
65
55
|
"@openmrs/esm-framework": "next",
|
|
56
|
+
"@swc/core": "^1.2.245",
|
|
57
|
+
"@swc/jest": "^0.2.22",
|
|
66
58
|
"@testing-library/dom": "^7.20.0",
|
|
67
|
-
"@testing-library/jest-dom": "^5.
|
|
68
|
-
"@testing-library/react": "^
|
|
69
|
-
"@testing-library/user-event": "^
|
|
70
|
-
"@types/
|
|
71
|
-
"@types/
|
|
72
|
-
"@types/
|
|
73
|
-
"@types/
|
|
74
|
-
"@types/react-dom": "^16.9.12",
|
|
75
|
-
"@types/react-router-dom": "^5.1.7",
|
|
76
|
-
"@types/testing-library__jest-dom": "^5.14.1",
|
|
59
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
60
|
+
"@testing-library/react": "^13.3.0",
|
|
61
|
+
"@testing-library/user-event": "^14.4.3",
|
|
62
|
+
"@types/jest": "^28.1.7",
|
|
63
|
+
"@types/react-dom": "^18.0.6",
|
|
64
|
+
"@types/react-router-dom": "^5.3.3",
|
|
65
|
+
"@types/testing-library__jest-dom": "^5.14.5",
|
|
77
66
|
"@types/webpack-env": "^1.16.0",
|
|
78
67
|
"@typescript-eslint/parser": "^5.14.0",
|
|
79
|
-
"babel-eslint": "^10.1.0",
|
|
80
|
-
"babel-jest": "^27.0.2",
|
|
81
|
-
"babel-preset-minify": "^0.5.1",
|
|
82
68
|
"concurrently": "^6.2.0",
|
|
83
69
|
"eslint": "^8.20.0",
|
|
84
70
|
"eslint-config-prettier": "^8.3.0",
|
|
@@ -87,18 +73,25 @@
|
|
|
87
73
|
"eslint-plugin-prettier": "^4.2.1",
|
|
88
74
|
"husky": "^8.0.1",
|
|
89
75
|
"identity-obj-proxy": "^3.0.0",
|
|
90
|
-
"jest": "^
|
|
91
|
-
"jest-cli": "^
|
|
76
|
+
"jest": "^28.1.3",
|
|
77
|
+
"jest-cli": "^28.1.3",
|
|
78
|
+
"jest-environment-jsdom": "^28.1.3",
|
|
92
79
|
"openmrs": "next",
|
|
93
80
|
"prettier": "^2.3.0",
|
|
94
81
|
"pretty-quick": "^3.1.0",
|
|
95
|
-
"react": "^
|
|
96
|
-
"react-dom": "^
|
|
97
|
-
"react-i18next": "^11.
|
|
98
|
-
"react-router-dom": "^
|
|
82
|
+
"react": "^18.2.0",
|
|
83
|
+
"react-dom": "^18.2.0",
|
|
84
|
+
"react-i18next": "^11.18.4",
|
|
85
|
+
"react-router-dom": "^6.3.0",
|
|
86
|
+
"semver": "^7.3.7",
|
|
99
87
|
"swc-loader": "^0.2.3",
|
|
100
88
|
"swr": "^1.3.0",
|
|
101
89
|
"typescript": "^4.7.3",
|
|
102
90
|
"webpack": "^5.73.0"
|
|
103
|
-
}
|
|
104
|
-
|
|
91
|
+
},
|
|
92
|
+
"packageManager": "yarn@3.2.2",
|
|
93
|
+
"dependencies": {
|
|
94
|
+
"react-hook-form": "^7.34.2"
|
|
95
|
+
},
|
|
96
|
+
"stableVersion": "1.0.0"
|
|
97
|
+
}
|
package/src/FormBootstrap.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { ExtensionSlot } from "@openmrs/esm-framework";
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { detach, ExtensionSlot } from "@openmrs/esm-framework";
|
|
3
3
|
import useGetPatient from "./hooks/useGetPatient";
|
|
4
4
|
|
|
5
5
|
export interface Order {
|
|
@@ -106,6 +106,7 @@ interface FormParams {
|
|
|
106
106
|
encounterUuid?: string;
|
|
107
107
|
showDiscardSubmitButtons?: boolean;
|
|
108
108
|
handlePostResponse?: (Encounter) => void;
|
|
109
|
+
handleEncounterCreate?: (Object) => void;
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
const FormBootstrap = ({
|
|
@@ -115,9 +116,14 @@ const FormBootstrap = ({
|
|
|
115
116
|
visitTypeUuid,
|
|
116
117
|
encounterUuid,
|
|
117
118
|
handlePostResponse,
|
|
119
|
+
handleEncounterCreate,
|
|
118
120
|
}: FormParams) => {
|
|
119
121
|
const patient = useGetPatient(patientUuid);
|
|
120
122
|
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
return () => detach("form-widget-slot", "form-widget-slot");
|
|
125
|
+
});
|
|
126
|
+
|
|
121
127
|
return (
|
|
122
128
|
<div>
|
|
123
129
|
{formUuid && patientUuid && patient && (
|
|
@@ -133,6 +139,7 @@ const FormBootstrap = ({
|
|
|
133
139
|
encounterUuid: encounterUuid ?? "",
|
|
134
140
|
closeWorkspace: () => undefined,
|
|
135
141
|
handlePostResponse,
|
|
142
|
+
handleEncounterCreate,
|
|
136
143
|
showDiscardSubmitButtons: false,
|
|
137
144
|
}}
|
|
138
145
|
/>
|
package/src/Root.tsx
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { BrowserRouter, Route,
|
|
2
|
+
import { BrowserRouter, Route, Routes } from "react-router-dom";
|
|
3
3
|
import { appPath } from "./constant";
|
|
4
4
|
const FormsPage = React.lazy(() => import("./forms-page"));
|
|
5
5
|
const FormEntryWorkflow = React.lazy(() => import("./form-entry-workflow"));
|
|
6
|
+
const GroupFormEntryWorkflow = React.lazy(
|
|
7
|
+
() => import("./group-form-entry-workflow")
|
|
8
|
+
);
|
|
6
9
|
|
|
7
10
|
const Root = () => {
|
|
8
11
|
return (
|
|
9
12
|
<main>
|
|
10
13
|
<BrowserRouter basename={appPath}>
|
|
11
|
-
<
|
|
12
|
-
<Route
|
|
13
|
-
<Route path="/:formUuid
|
|
14
|
-
|
|
14
|
+
<Routes>
|
|
15
|
+
<Route path="/" element={<FormsPage />} />
|
|
16
|
+
<Route path="/form/:formUuid" element={<FormEntryWorkflow />} />
|
|
17
|
+
<Route
|
|
18
|
+
path="/groupform/:formUuid"
|
|
19
|
+
element={<GroupFormEntryWorkflow />}
|
|
20
|
+
/>
|
|
21
|
+
</Routes>
|
|
15
22
|
</BrowserRouter>
|
|
16
23
|
</main>
|
|
17
24
|
);
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import React, { useCallback, useContext, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ComposedModal,
|
|
4
|
+
Button,
|
|
5
|
+
ModalHeader,
|
|
6
|
+
ModalFooter,
|
|
7
|
+
ModalBody,
|
|
8
|
+
TextInput,
|
|
9
|
+
FormLabel,
|
|
10
|
+
} from "@carbon/react";
|
|
11
|
+
import { Add, Close } from "@carbon/react/icons";
|
|
12
|
+
import { useTranslation } from "react-i18next";
|
|
13
|
+
import { ExtensionSlot } from "@openmrs/esm-framework";
|
|
14
|
+
import styles from "./styles.scss";
|
|
15
|
+
import GroupFormWorkflowContext from "../context/GroupFormWorkflowContext";
|
|
16
|
+
|
|
17
|
+
const MemExtension = React.memo(ExtensionSlot);
|
|
18
|
+
|
|
19
|
+
const PatientRow = ({ patient, removePatient }) => {
|
|
20
|
+
const { t } = useTranslation();
|
|
21
|
+
return (
|
|
22
|
+
<li key={patient.uuid} className={styles.patientRow}>
|
|
23
|
+
<span className={styles.patientName}>{patient?.display}</span>
|
|
24
|
+
<span>
|
|
25
|
+
<Button
|
|
26
|
+
kind="tertiary"
|
|
27
|
+
size="sm"
|
|
28
|
+
onClick={() => removePatient(patient.uuid)}
|
|
29
|
+
renderIcon={Close}
|
|
30
|
+
tooltipPosition="right"
|
|
31
|
+
>
|
|
32
|
+
{t("remove", "Remove")}
|
|
33
|
+
</Button>
|
|
34
|
+
</span>
|
|
35
|
+
</li>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const NewGroupForm = (props) => {
|
|
40
|
+
const {
|
|
41
|
+
name,
|
|
42
|
+
setName,
|
|
43
|
+
patientList,
|
|
44
|
+
updatePatientList,
|
|
45
|
+
errors,
|
|
46
|
+
validate,
|
|
47
|
+
removePatient,
|
|
48
|
+
} = props;
|
|
49
|
+
const { t } = useTranslation();
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
style={{
|
|
54
|
+
display: "flex",
|
|
55
|
+
flexDirection: "column",
|
|
56
|
+
rowGap: "1rem",
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
<TextInput
|
|
60
|
+
labelText={t("newGroupName", "New Group Name")}
|
|
61
|
+
value={name}
|
|
62
|
+
onChange={(e) => setName(e.target.value)}
|
|
63
|
+
onBlur={() => validate("name")}
|
|
64
|
+
/>
|
|
65
|
+
{errors?.name && (
|
|
66
|
+
<p className={styles.formError}>
|
|
67
|
+
{t("groupNameError", "Please enter a group name.")}
|
|
68
|
+
</p>
|
|
69
|
+
)}
|
|
70
|
+
<FormLabel>Patients in group</FormLabel>
|
|
71
|
+
{errors?.patientList && (
|
|
72
|
+
<p className={styles.formError}>
|
|
73
|
+
{t("noPatientError", "Please enter at least one patient.")}
|
|
74
|
+
</p>
|
|
75
|
+
)}
|
|
76
|
+
{!errors?.patientList && (
|
|
77
|
+
<ul>
|
|
78
|
+
{patientList?.map((patient, index) => (
|
|
79
|
+
<PatientRow
|
|
80
|
+
patient={patient}
|
|
81
|
+
removePatient={removePatient}
|
|
82
|
+
key={index}
|
|
83
|
+
/>
|
|
84
|
+
))}
|
|
85
|
+
</ul>
|
|
86
|
+
)}
|
|
87
|
+
|
|
88
|
+
<FormLabel>Search for patients to add to group</FormLabel>
|
|
89
|
+
<div className={styles.searchBar}>
|
|
90
|
+
<MemExtension
|
|
91
|
+
extensionSlotName="patient-search-bar-slot"
|
|
92
|
+
state={{
|
|
93
|
+
selectPatientAction: updatePatientList,
|
|
94
|
+
buttonProps: {
|
|
95
|
+
kind: "primary",
|
|
96
|
+
},
|
|
97
|
+
}}
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const AddGroupModal = () => {
|
|
105
|
+
const { setGroup } = useContext(GroupFormWorkflowContext);
|
|
106
|
+
const { t } = useTranslation();
|
|
107
|
+
const [open, setOpen] = useState(false);
|
|
108
|
+
const [errors, setErrors] = useState({});
|
|
109
|
+
const [name, setName] = useState("");
|
|
110
|
+
const [patientList, setPatientList] = useState([]);
|
|
111
|
+
|
|
112
|
+
const handleCancel = () => {
|
|
113
|
+
setOpen(false);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const removePatient = useCallback(
|
|
117
|
+
(patientUuid: string) =>
|
|
118
|
+
setPatientList((patientList) =>
|
|
119
|
+
patientList.filter((patient) => patient.uuid !== patientUuid)
|
|
120
|
+
),
|
|
121
|
+
[setPatientList]
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const validate = useCallback(
|
|
125
|
+
(field?: string | undefined) => {
|
|
126
|
+
let valid = true;
|
|
127
|
+
if (field) {
|
|
128
|
+
valid = field === "name" ? !!name : !!patientList.length;
|
|
129
|
+
setErrors((errors) => ({
|
|
130
|
+
...errors,
|
|
131
|
+
[field]: valid ? null : "required",
|
|
132
|
+
}));
|
|
133
|
+
} else {
|
|
134
|
+
if (!name) {
|
|
135
|
+
setErrors((errors) => ({ ...errors, name: "required" }));
|
|
136
|
+
valid = false;
|
|
137
|
+
} else {
|
|
138
|
+
setErrors((errors) => ({ ...errors, name: null }));
|
|
139
|
+
}
|
|
140
|
+
if (!patientList.length) {
|
|
141
|
+
setErrors((errors) => ({ ...errors, patientList: "required" }));
|
|
142
|
+
valid = false;
|
|
143
|
+
} else {
|
|
144
|
+
setErrors((errors) => ({ ...errors, patientList: null }));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return valid;
|
|
148
|
+
},
|
|
149
|
+
[name, patientList.length]
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const updatePatientList = useCallback(
|
|
153
|
+
(patient) => {
|
|
154
|
+
setPatientList((patientList) => {
|
|
155
|
+
if (!patientList.find((p) => p.uuid === patient.uuid)) {
|
|
156
|
+
return [...patientList, patient];
|
|
157
|
+
} else {
|
|
158
|
+
return patientList;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
setErrors((errors) => ({ ...errors, patientList: null }));
|
|
162
|
+
},
|
|
163
|
+
[setPatientList]
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const handleSubmit = () => {
|
|
167
|
+
if (validate()) {
|
|
168
|
+
setGroup({ id: "1234", name: name, members: patientList });
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<div className={styles.modal}>
|
|
174
|
+
<Button
|
|
175
|
+
onClick={() => setOpen(true)}
|
|
176
|
+
renderIcon={Add}
|
|
177
|
+
iconDescription="Add"
|
|
178
|
+
>
|
|
179
|
+
{t("createNewGroup", "Create New Group")}
|
|
180
|
+
</Button>
|
|
181
|
+
<ComposedModal open={open} onClose={() => setOpen(false)}>
|
|
182
|
+
<ModalHeader>{t("createNewGroup", "Create New Group")}</ModalHeader>
|
|
183
|
+
<ModalBody>
|
|
184
|
+
<NewGroupForm
|
|
185
|
+
{...{
|
|
186
|
+
name,
|
|
187
|
+
setName,
|
|
188
|
+
patientList,
|
|
189
|
+
updatePatientList,
|
|
190
|
+
errors,
|
|
191
|
+
validate,
|
|
192
|
+
removePatient,
|
|
193
|
+
}}
|
|
194
|
+
/>
|
|
195
|
+
</ModalBody>
|
|
196
|
+
<ModalFooter>
|
|
197
|
+
<Button kind="secondary" onClick={handleCancel}>
|
|
198
|
+
{t("cancel", "Cancel")}
|
|
199
|
+
</Button>
|
|
200
|
+
<Button kind="primary" onClick={handleSubmit}>
|
|
201
|
+
{t("createGroup", "Create Group")}
|
|
202
|
+
</Button>
|
|
203
|
+
</ModalFooter>
|
|
204
|
+
</ComposedModal>
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export default AddGroupModal;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
@use '@carbon/styles/scss/spacing';
|
|
2
|
+
@use '@carbon/colors';
|
|
3
|
+
|
|
4
|
+
.modal {
|
|
5
|
+
:global(.cds--modal) {
|
|
6
|
+
z-index: 90;
|
|
7
|
+
}
|
|
8
|
+
:global(.cds--modal-container) {
|
|
9
|
+
height: 600px;
|
|
10
|
+
}
|
|
11
|
+
:global(.cds--modal-content) {
|
|
12
|
+
height: 100%;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.searchBar > div > div > div {
|
|
17
|
+
width: 100%
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.formError {
|
|
21
|
+
color: red;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.patientRow {
|
|
25
|
+
display: flex;
|
|
26
|
+
width: "100%";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.patientName {
|
|
30
|
+
flex-grow: 1;
|
|
31
|
+
padding: spacing.$spacing-02;
|
|
32
|
+
&:hover {
|
|
33
|
+
background-color: colors.$gray-20;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useReducer } from "react";
|
|
|
2
2
|
import reducer from "./FormWorkflowReducer";
|
|
3
3
|
import { useParams, useLocation } from "react-router-dom";
|
|
4
4
|
interface ParamTypes {
|
|
5
|
-
formUuid
|
|
5
|
+
formUuid?: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
const initialActions = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { navigate } from "@openmrs/esm-framework";
|
|
2
2
|
import { initialWorkflowState } from "./FormWorkflowContext";
|
|
3
3
|
|
|
4
|
-
export const fdeWorkflowStorageVersion = "1.0.
|
|
4
|
+
export const fdeWorkflowStorageVersion = "1.0.13";
|
|
5
5
|
export const fdeWorkflowStorageName = "openmrs:fastDataEntryWorkflowState";
|
|
6
6
|
const persistData = (data) => {
|
|
7
7
|
localStorage.setItem(fdeWorkflowStorageName, JSON.stringify(data));
|