@tellescope/react-components 1.245.1 → 1.246.2
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/lib/cjs/Forms/forms.d.ts +3 -2
- package/lib/cjs/Forms/forms.d.ts.map +1 -1
- package/lib/cjs/Forms/forms.js +86 -9
- package/lib/cjs/Forms/forms.js.map +1 -1
- package/lib/esm/Forms/forms.d.ts +3 -2
- package/lib/esm/Forms/forms.d.ts.map +1 -1
- package/lib/esm/Forms/forms.js +86 -9
- package/lib/esm/Forms/forms.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/Forms/forms.tsx +185 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tellescope/react-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.246.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/cjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
"@reduxjs/toolkit": "1.9.0",
|
|
52
52
|
"@stripe/react-stripe-js": "2.9.0",
|
|
53
53
|
"@stripe/stripe-js": "1.52.1",
|
|
54
|
-
"@tellescope/constants": "1.
|
|
55
|
-
"@tellescope/sdk": "1.
|
|
56
|
-
"@tellescope/types-client": "1.
|
|
57
|
-
"@tellescope/types-models": "1.
|
|
58
|
-
"@tellescope/types-utilities": "1.
|
|
59
|
-
"@tellescope/utilities": "1.
|
|
60
|
-
"@tellescope/validation": "1.
|
|
54
|
+
"@tellescope/constants": "1.246.2",
|
|
55
|
+
"@tellescope/sdk": "1.246.2",
|
|
56
|
+
"@tellescope/types-client": "1.246.2",
|
|
57
|
+
"@tellescope/types-models": "1.246.2",
|
|
58
|
+
"@tellescope/types-utilities": "1.246.2",
|
|
59
|
+
"@tellescope/utilities": "1.246.2",
|
|
60
|
+
"@tellescope/validation": "1.246.2",
|
|
61
61
|
"css-to-react-native": "3.0.0",
|
|
62
62
|
"draft-js": "0.11.7",
|
|
63
63
|
"draftjs-to-html": "0.9.1",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
85
85
|
"react-native": "^0.65.0 || ^0.66.0 || ^0.67.0 || ^0.68.0 || ^0.71.0"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "a9167f6d732de999cf012ffba3004f0d62ae8c14",
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"access": "public"
|
|
90
90
|
}
|
package/src/Forms/forms.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import { ChangeHandler, FormInputs } from "./types"
|
|
|
5
5
|
import { AddToDatabaseProps, AddressInput, AllergiesInput, AppointmentBookingInput, BelugaPatientPreferenceInput, BridgeEligibilityInput, CandidEligibilityInput, ChargeebeeInput, ConditionsInput, DatabaseSelectInput, DateInput, DateStringInput, DropdownInput, EmailInput, EmotiiInput, FileInput, FilesInput, HeightInput, HiddenValueInput, InsuranceInput, LanguageSelect, MedicationsInput, MultipleChoiceInput, NumberInput, PharmacySearchInput, PhoneInput, Progress, RankingInput, RatingInput, RedirectInput, RelatedContactsInput, RichTextInput, SignatureInput, StringInput, StringLongInput, StripeInput, TableInput, TimeInput, TimezoneInput, defaultButtonStyles } from "./inputs"
|
|
6
6
|
import { PRIMARY_HEX } from "@tellescope/constants"
|
|
7
7
|
import { FormResponse, FormField, Form, Enduser } from "@tellescope/types-client"
|
|
8
|
-
import { FormResponseAnswerFileValue, OrganizationTheme } from "@tellescope/types-models"
|
|
8
|
+
import { FormResponseAnswerFileValue, OrganizationTheme, HistoricalDataSource } from "@tellescope/types-models"
|
|
9
9
|
import { calculate_form_scoring, field_can_autosubmit, form_response_value_to_string, formatted_date, object_is_empty, objects_equivalent, read_local_storage, remove_script_tags, responses_satisfy_conditions, truncate_string } from "@tellescope/utilities"
|
|
10
10
|
import { Divider } from "@mui/material"
|
|
11
11
|
|
|
@@ -236,7 +236,7 @@ export const QuestionForField = ({
|
|
|
236
236
|
<div style={{ marginTop: 15 }}></div>
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
<Description field={field} style={{ fontSize: 16 }} />
|
|
239
|
+
<Description field={field} style={{ fontSize: 16 }} enduserId={enduserId} />
|
|
240
240
|
|
|
241
241
|
{feedback.length > 0 &&
|
|
242
242
|
<Flex column style={{ marginBottom: 11, marginTop: 3, }}>
|
|
@@ -1017,20 +1017,195 @@ export const UpdateResponse = ({
|
|
|
1017
1017
|
)
|
|
1018
1018
|
}
|
|
1019
1019
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1020
|
+
const HistoricalDataSection = ({ sources, enduserId } : { sources: HistoricalDataSource[], enduserId: string }) => {
|
|
1021
|
+
const session = useSession({ throwIfMissingContext: false })
|
|
1022
|
+
const [observations, setObservations] = useState<any[]>([])
|
|
1023
|
+
const [medications, setMedications] = useState<any[]>([])
|
|
1024
|
+
const [loading, setLoading] = useState(true)
|
|
1025
|
+
const [error, setError] = useState('')
|
|
1026
|
+
|
|
1027
|
+
const loadedKeyRef = useRef('')
|
|
1028
|
+
|
|
1029
|
+
useEffect(() => {
|
|
1030
|
+
if (!session) return
|
|
1031
|
+
|
|
1032
|
+
// Build a stable key from enduserId + sources to avoid re-fetching on object reference changes
|
|
1033
|
+
const key = enduserId + ':' + JSON.stringify(sources)
|
|
1034
|
+
if (loadedKeyRef.current === key) return
|
|
1035
|
+
loadedKeyRef.current = key
|
|
1036
|
+
|
|
1037
|
+
const loadData = async () => {
|
|
1038
|
+
setLoading(true)
|
|
1039
|
+
setError('')
|
|
1040
|
+
try {
|
|
1041
|
+
const promises: Promise<void>[] = []
|
|
1042
|
+
|
|
1043
|
+
for (const source of sources) {
|
|
1044
|
+
if (source.type === 'Observations') {
|
|
1045
|
+
promises.push(
|
|
1046
|
+
session.api.enduser_observations.getSome({
|
|
1047
|
+
filter: { enduserId, ...source.filter },
|
|
1048
|
+
limit: source.limit,
|
|
1049
|
+
})
|
|
1050
|
+
.then((obs: any[]) => setObservations(obs))
|
|
1051
|
+
)
|
|
1052
|
+
} else if (source.type === 'Medications') {
|
|
1053
|
+
promises.push(
|
|
1054
|
+
session.api.enduser_medications.getSome({
|
|
1055
|
+
filter: { enduserId, status: { _ne: 'draft' }, ...source.filter },
|
|
1056
|
+
limit: source.limit,
|
|
1057
|
+
})
|
|
1058
|
+
.then((meds: any[]) => setMedications(meds))
|
|
1059
|
+
)
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
await Promise.all(promises)
|
|
1064
|
+
} catch (err: any) {
|
|
1065
|
+
setError(err?.message || 'Failed to load historical data')
|
|
1066
|
+
} finally {
|
|
1067
|
+
setLoading(false)
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
loadData()
|
|
1072
|
+
}, [session, enduserId, sources])
|
|
1073
|
+
|
|
1074
|
+
if (!session) return null
|
|
1075
|
+
|
|
1076
|
+
if (loading) {
|
|
1022
1077
|
return (
|
|
1078
|
+
<Flex style={{ padding: 10, justifyContent: 'center' }}>
|
|
1079
|
+
<CircularProgress size={24} />
|
|
1080
|
+
</Flex>
|
|
1081
|
+
)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
if (error) {
|
|
1085
|
+
return (
|
|
1086
|
+
<Typography color="error" style={{ padding: 10 }}>
|
|
1087
|
+
{error}
|
|
1088
|
+
</Typography>
|
|
1089
|
+
)
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
const hasObservations = sources.some(s => s.type === 'Observations')
|
|
1093
|
+
const hasMedications = sources.some(s => s.type === 'Medications')
|
|
1094
|
+
|
|
1095
|
+
return (
|
|
1096
|
+
<div style={{ marginTop: 10 }}>
|
|
1097
|
+
{hasObservations && (
|
|
1098
|
+
<div style={{ marginBottom: 15 }}>
|
|
1099
|
+
<Typography style={{ fontWeight: 'bold', marginBottom: 5 }}>Observations</Typography>
|
|
1100
|
+
{observations.length === 0 ? (
|
|
1101
|
+
<Typography style={{ fontStyle: 'italic', color: '#888' }}>No observations found</Typography>
|
|
1102
|
+
) : (
|
|
1103
|
+
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 14 }}>
|
|
1104
|
+
<thead>
|
|
1105
|
+
<tr style={{ borderBottom: '2px solid #ccc', textAlign: 'left' }}>
|
|
1106
|
+
<th style={{ padding: '6px 8px' }}>Date</th>
|
|
1107
|
+
<th style={{ padding: '6px 8px' }}>Type</th>
|
|
1108
|
+
<th style={{ padding: '6px 8px' }}>Value</th>
|
|
1109
|
+
<th style={{ padding: '6px 8px' }}>Category</th>
|
|
1110
|
+
<th style={{ padding: '6px 8px' }}>Status</th>
|
|
1111
|
+
</tr>
|
|
1112
|
+
</thead>
|
|
1113
|
+
<tbody>
|
|
1114
|
+
{observations.map((obs: any) => (
|
|
1115
|
+
<tr key={obs.id} style={{ borderBottom: '1px solid #eee' }}>
|
|
1116
|
+
<td style={{ padding: '6px 8px' }}>{obs.timestamp ? formatted_date(new Date(obs.timestamp)) : '-'}</td>
|
|
1117
|
+
<td style={{ padding: '6px 8px' }}>{obs.type || obs.code || '-'}</td>
|
|
1118
|
+
<td style={{ padding: '6px 8px' }}>
|
|
1119
|
+
{obs.measurement ? `${obs.measurement.value} ${obs.measurement.unit}` : obs.qualitativeResult || '-'}
|
|
1120
|
+
</td>
|
|
1121
|
+
<td style={{ padding: '6px 8px' }}>{obs.category || '-'}</td>
|
|
1122
|
+
<td style={{ padding: '6px 8px' }}>{obs.status || '-'}</td>
|
|
1123
|
+
</tr>
|
|
1124
|
+
))}
|
|
1125
|
+
</tbody>
|
|
1126
|
+
</table>
|
|
1127
|
+
)}
|
|
1128
|
+
</div>
|
|
1129
|
+
)}
|
|
1130
|
+
|
|
1131
|
+
{hasMedications && (
|
|
1132
|
+
<div style={{ marginBottom: 15 }}>
|
|
1133
|
+
<Typography style={{ fontWeight: 'bold', marginBottom: 5 }}>Medications</Typography>
|
|
1134
|
+
{medications.length === 0 ? (
|
|
1135
|
+
<Typography style={{ fontStyle: 'italic', color: '#888' }}>No medications found</Typography>
|
|
1136
|
+
) : (
|
|
1137
|
+
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 14 }}>
|
|
1138
|
+
<thead>
|
|
1139
|
+
<tr style={{ borderBottom: '2px solid #ccc', textAlign: 'left' }}>
|
|
1140
|
+
<th style={{ padding: '6px 8px' }}>Medication</th>
|
|
1141
|
+
<th style={{ padding: '6px 8px' }}>Dosage</th>
|
|
1142
|
+
<th style={{ padding: '6px 8px' }}>Dispensing</th>
|
|
1143
|
+
<th style={{ padding: '6px 8px' }}>Pharmacy</th>
|
|
1144
|
+
<th style={{ padding: '6px 8px' }}>Prescriber</th>
|
|
1145
|
+
<th style={{ padding: '6px 8px' }}>Date</th>
|
|
1146
|
+
</tr>
|
|
1147
|
+
</thead>
|
|
1148
|
+
<tbody>
|
|
1149
|
+
{medications.map((med: any) => (
|
|
1150
|
+
<tr key={med.id} style={{ borderBottom: '1px solid #eee' }}>
|
|
1151
|
+
<td style={{ padding: '6px 8px' }}>
|
|
1152
|
+
{med.title || '-'}
|
|
1153
|
+
{med.allergyNote ? <div style={{ color: 'red', fontSize: 12 }}>Allergies: {med.allergyNote}</div> : null}
|
|
1154
|
+
{med.directions ? <div style={{ color: '#888', fontSize: 12 }}>Directions: {med.directions}</div> : null}
|
|
1155
|
+
</td>
|
|
1156
|
+
<td style={{ padding: '6px 8px' }}>
|
|
1157
|
+
{med.dosage
|
|
1158
|
+
? med.dosage.description
|
|
1159
|
+
? med.dosage.description
|
|
1160
|
+
: `${med.dosage.value || ''}${med.dosage.unit ? ` ${med.dosage.unit}` : ''}${med.dosage.quantity ? ` ${med.dosage.quantity} units` : ''}${med.dosage.frequency ? ` ${!isNaN(parseInt(med.dosage.frequency)) ? `${med.dosage.frequency}x ${med.dosage?.frequencyDescriptor ? `Per ${med.dosage.frequencyDescriptor}` : 'daily'}` : med.dosage.frequency}` : ''}`
|
|
1161
|
+
: '-'}
|
|
1162
|
+
</td>
|
|
1163
|
+
<td style={{ padding: '6px 8px' }}>
|
|
1164
|
+
{med.dispensing ? `${med.dispensing.quantity || ''} ${med.dispensing.unit || ''}`.trim() || '-' : '-'}
|
|
1165
|
+
</td>
|
|
1166
|
+
<td style={{ padding: '6px 8px' }}>{med.pharmacyName || med.pharmacyId || '-'}</td>
|
|
1167
|
+
<td style={{ padding: '6px 8px' }}>
|
|
1168
|
+
{med.prescriberName || '-'}
|
|
1169
|
+
{med.source ? <div style={{ fontStyle: 'italic', fontSize: 12 }}>{med.source}</div> : null}
|
|
1170
|
+
{med.notes ? <div style={{ fontSize: 12 }}>{med.notes}</div> : null}
|
|
1171
|
+
</td>
|
|
1172
|
+
<td style={{ padding: '6px 8px' }}>
|
|
1173
|
+
{formatted_date(new Date(med.startedTakingAt || med.prescribedAt || med.createdAt))}
|
|
1174
|
+
</td>
|
|
1175
|
+
</tr>
|
|
1176
|
+
))}
|
|
1177
|
+
</tbody>
|
|
1178
|
+
</table>
|
|
1179
|
+
)}
|
|
1180
|
+
</div>
|
|
1181
|
+
)}
|
|
1182
|
+
</div>
|
|
1183
|
+
)
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
export const Description = ({ field, color="primary", style, enduserId } : { field: FormField, color?: string, enduserId?: string } & Styled) => {
|
|
1187
|
+
const existingContent = (
|
|
1188
|
+
!field.htmlDescription && field.description ? (
|
|
1023
1189
|
<Typography color={color as any} style={style}>
|
|
1024
1190
|
{field.description}
|
|
1025
1191
|
</Typography>
|
|
1026
|
-
)
|
|
1027
|
-
|
|
1028
|
-
|
|
1192
|
+
) : field.htmlDescription ? (
|
|
1193
|
+
<span dangerouslySetInnerHTML={{
|
|
1194
|
+
__html: remove_script_tags(field.htmlDescription)
|
|
1195
|
+
}} />
|
|
1196
|
+
) : null
|
|
1197
|
+
)
|
|
1029
1198
|
|
|
1030
1199
|
return (
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1200
|
+
<>
|
|
1201
|
+
{existingContent}
|
|
1202
|
+
{field.type === 'description' && field.options?.historicalDataSources?.length && enduserId ? (
|
|
1203
|
+
<HistoricalDataSection
|
|
1204
|
+
sources={field.options.historicalDataSources}
|
|
1205
|
+
enduserId={enduserId}
|
|
1206
|
+
/>
|
|
1207
|
+
) : null}
|
|
1208
|
+
</>
|
|
1034
1209
|
)
|
|
1035
1210
|
}
|
|
1036
1211
|
|