@ltht-react/plan-definition-editor 2.0.3 → 2.0.5

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.
Files changed (2) hide show
  1. package/package.json +8 -7
  2. package/src/index.tsx +237 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ltht-react/plan-definition-editor",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "ltht-react component for selecting problems from a PlanDefinition.",
5
5
  "author": "LTHT",
6
6
  "homepage": "",
@@ -8,7 +8,8 @@
8
8
  "main": "lib/index.js",
9
9
  "typings": "lib/index.d.ts",
10
10
  "files": [
11
- "lib"
11
+ "lib",
12
+ "src"
12
13
  ],
13
14
  "directories": {
14
15
  "lib": "lib"
@@ -27,11 +28,11 @@
27
28
  "dependencies": {
28
29
  "@emotion/react": "^11.0.0",
29
30
  "@emotion/styled": "^11.0.0",
30
- "@ltht-react/icon": "^2.0.3",
31
- "@ltht-react/input": "^2.0.3",
32
- "@ltht-react/styles": "^2.0.3",
33
- "@ltht-react/types": "^2.0.3",
31
+ "@ltht-react/icon": "^2.0.5",
32
+ "@ltht-react/input": "^2.0.5",
33
+ "@ltht-react/styles": "^2.0.5",
34
+ "@ltht-react/types": "^2.0.5",
34
35
  "react": "^18.2.0"
35
36
  },
36
- "gitHead": "6f18742bbf2f44123b6478257e52fbbdd291a25b"
37
+ "gitHead": "5d14d78829abb529afe382226925f4793a2c8257"
37
38
  }
package/src/index.tsx ADDED
@@ -0,0 +1,237 @@
1
+ import { css } from '@emotion/react'
2
+ import styled from '@emotion/styled'
3
+ import { PlanDefinition } from '@ltht-react/types'
4
+ import { BANNER_COLOURS, WIDESCREEN_MINIMUM_MEDIA_QUERY } from '@ltht-react/styles'
5
+ import Icon from '@ltht-react/icon'
6
+ import { Toggle as ToggleInput } from '@ltht-react/input'
7
+ import { ChangeEvent, FC, useMemo } from 'react'
8
+
9
+ const toggleRowWidth = '3.5rem'
10
+
11
+ const toggleInputMixin = css`
12
+ > div:first-of-type {
13
+ text-align: right;
14
+ width: ${toggleRowWidth};
15
+ padding-right: 1rem;
16
+ }
17
+ `
18
+
19
+ const StyledProblemToggleRow = styled.div`
20
+ display: flex;
21
+ font-weight: bold;
22
+ align-items: center;
23
+ ${toggleInputMixin}
24
+ margin-bottom: 0.25rem;
25
+ `
26
+
27
+ const StyledEducationToggleRow = styled.div`
28
+ display: flex;
29
+ align-items: center;
30
+ ${toggleInputMixin}
31
+ margin-bottom: 0.25rem;
32
+
33
+ > label svg {
34
+ margin-right: 0.5rem;
35
+ }
36
+ `
37
+
38
+ const StyledTargetRow = styled.div`
39
+ display: flex;
40
+ align-items: center;
41
+ ${toggleInputMixin}
42
+
43
+ svg {
44
+ align: right;
45
+ margin-right: 1rem;
46
+ }
47
+
48
+ > span:first-of-type {
49
+ text-align: right;
50
+ display: block;
51
+ width: ${toggleRowWidth};
52
+ }
53
+
54
+ > div:first-of-type {
55
+ flex: 1;
56
+ text-align: left;
57
+ }
58
+ `
59
+
60
+ const StyledListItem = styled.li`
61
+ margin-bottom: 1rem;
62
+
63
+ ${WIDESCREEN_MINIMUM_MEDIA_QUERY} {
64
+ }
65
+ `
66
+
67
+ const StyledSectionToggle = styled.div`
68
+ background-color: ${BANNER_COLOURS.INFO.BACKGROUND};
69
+ font-weight: bold;
70
+ color: black;
71
+ display: flex;
72
+ align-items: center;
73
+ padding: 0.5rem 0.25rem;
74
+ ${toggleInputMixin}
75
+ `
76
+
77
+ const StyledProblemSection = styled.ul`
78
+ list-style: none;
79
+ padding: 0.25rem 0.25rem;
80
+ margin-bottom: 1rem;
81
+ `
82
+
83
+ export const SelectedPlanDetail: FC<ISelectedPlanDetailProps> = ({
84
+ planDefinition,
85
+ selectedProblemIds,
86
+ onProblemChange,
87
+ }) => {
88
+ // Split actions from plan definition into clinical problem based and education based
89
+ const { problemActions, educationActions } = useMemo(() => {
90
+ const problemActions = planDefinition.action?.filter(
91
+ (action) =>
92
+ action?.code && action?.code[0] && action?.code[0].coding && action?.code[0].coding[0]?.code === 'problem'
93
+ )
94
+ const educationActions = planDefinition.action?.filter(
95
+ (action) =>
96
+ action?.code && action?.code[0] && action?.code[0].coding && action?.code[0].coding[0]?.code === 'education'
97
+ )
98
+
99
+ return {
100
+ problemActions,
101
+ educationActions,
102
+ }
103
+ }, [planDefinition.action])
104
+
105
+ // Calculate whether all problems in the given categories are enabled
106
+ const { allProblemsOn, allEducationOn } = useMemo(
107
+ () => ({
108
+ allProblemsOn:
109
+ problemActions?.map((pa) => pa?.elementId as string).every((id) => selectedProblemIds.includes(id)) ?? false,
110
+ allEducationOn:
111
+ educationActions?.map((ea) => ea?.elementId as string).every((id) => selectedProblemIds.includes(id)) ?? false,
112
+ }),
113
+ [educationActions, problemActions, selectedProblemIds]
114
+ )
115
+
116
+ const handleSingleActionChange: OnProblemChange = (e) => {
117
+ onProblemChange(e)
118
+ }
119
+
120
+ const handleToggleAllProblemsClick = (e: ChangeEvent<HTMLInputElement>) => {
121
+ const newState = problemActions?.map((p) => ({ problemId: p?.elementId as string, state: e.target.checked }))
122
+ newState && onProblemChange(newState)
123
+ }
124
+
125
+ const handleToggleAllEducationClick = (e: ChangeEvent<HTMLInputElement>) => {
126
+ const newState = educationActions?.map((p) => ({ problemId: p?.elementId as string, state: e.target.checked }))
127
+
128
+ newState && onProblemChange(newState)
129
+ }
130
+
131
+ return (
132
+ <>
133
+ <StyledSectionToggle>
134
+ <div>
135
+ <ToggleInput
136
+ checked={allProblemsOn}
137
+ onChange={(e: ChangeEvent<HTMLInputElement>) => handleToggleAllProblemsClick(e)}
138
+ id="problem-toggle-all"
139
+ />
140
+ </div>
141
+ <label htmlFor="problem-toggle-all">Patient Problems</label>
142
+ </StyledSectionToggle>
143
+ <StyledProblemSection>
144
+ {problemActions?.map((problem, pidx) => {
145
+ const goal = planDefinition.goal?.find(
146
+ (g) => problem?.goalId && problem.goalId.length > 0 && g?.elementId?.includes(problem.goalId[0] as string)
147
+ )
148
+ return (
149
+ <StyledListItem key={`problem-${pidx}`}>
150
+ <StyledProblemToggleRow>
151
+ <div>
152
+ <ToggleInput
153
+ checked={selectedProblemIds.includes(problem?.elementId as string)}
154
+ onChange={(e: ChangeEvent<HTMLInputElement>) =>
155
+ handleSingleActionChange([{ problemId: problem?.elementId as string, state: e.target.checked }])
156
+ }
157
+ id={`problem-${pidx}`}
158
+ />
159
+ </div>
160
+ <label htmlFor={`problem-${pidx}`}>{problem?.description}</label>
161
+ </StyledProblemToggleRow>
162
+ <div>
163
+ <StyledTargetRow>
164
+ <span>
165
+ <Icon type="bullseye" size="large" />
166
+ </span>
167
+ <div>{goal?.description?.text}</div>
168
+ </StyledTargetRow>
169
+
170
+ {problem?.action?.map((interventionPlan, ipidx) => (
171
+ <StyledTargetRow key={`intervention-plan-${ipidx}`}>
172
+ <div>
173
+ <p>{interventionPlan?.description}</p>
174
+ <ul>
175
+ {interventionPlan?.action?.map((intervention, idx) => (
176
+ <li key={`intervention-${idx}`}>{intervention?.description}</li>
177
+ ))}
178
+ </ul>
179
+ </div>
180
+ </StyledTargetRow>
181
+ ))}
182
+ </div>
183
+ </StyledListItem>
184
+ )
185
+ })}
186
+ </StyledProblemSection>
187
+ <StyledSectionToggle>
188
+ <div>
189
+ <ToggleInput
190
+ checked={allEducationOn}
191
+ onChange={(e: ChangeEvent<HTMLInputElement>) => handleToggleAllEducationClick(e)}
192
+ id="education-toggle-all"
193
+ />
194
+ </div>
195
+ <label htmlFor="education-toggle-all">Patient Education</label>
196
+ </StyledSectionToggle>
197
+ <StyledProblemSection>
198
+ <StyledListItem>
199
+ <div>
200
+ {educationActions?.map((g, eaidx) => (
201
+ <StyledEducationToggleRow key={`education-${eaidx}`}>
202
+ <div>
203
+ <ToggleInput
204
+ checked={selectedProblemIds.includes(g?.elementId as string)}
205
+ onChange={(e: ChangeEvent<HTMLInputElement>) =>
206
+ handleSingleActionChange([{ problemId: g?.elementId as string, state: e.target.checked }])
207
+ }
208
+ id={`education-${eaidx}`}
209
+ />
210
+ </div>
211
+ <label htmlFor={`education-${eaidx}`}>
212
+ <Icon type="bullseye" size="large" />
213
+ {g?.description}
214
+ </label>
215
+ </StyledEducationToggleRow>
216
+ ))}
217
+ </div>
218
+ </StyledListItem>
219
+ </StyledProblemSection>
220
+ </>
221
+ )
222
+ }
223
+
224
+ export interface ProblemState {
225
+ problemId: string
226
+ state: boolean
227
+ }
228
+
229
+ export type OnProblemChange = (e: ProblemState[]) => void
230
+
231
+ export interface ISelectedPlanDetailProps {
232
+ planDefinition: PlanDefinition
233
+ selectedProblemIds: string[]
234
+ onProblemChange: OnProblemChange
235
+ }
236
+
237
+ export default SelectedPlanDetail