@tellescope/react-components 1.235.0 → 1.235.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/CMS/ContentViewer.d.ts.map +1 -1
- package/lib/cjs/CMS/ContentViewer.js +26 -22
- package/lib/cjs/CMS/ContentViewer.js.map +1 -1
- package/lib/cjs/Forms/inputs.d.ts.map +1 -1
- package/lib/cjs/Forms/inputs.js +220 -100
- package/lib/cjs/Forms/inputs.js.map +1 -1
- package/lib/cjs/Forms/inputs.v2.js +1 -1
- package/lib/esm/CMS/ContentViewer.d.ts.map +1 -1
- package/lib/esm/CMS/ContentViewer.js +27 -23
- package/lib/esm/CMS/ContentViewer.js.map +1 -1
- package/lib/esm/CMS/components.d.ts +1 -0
- package/lib/esm/CMS/components.d.ts.map +1 -1
- package/lib/esm/Forms/form_responses.d.ts +1 -0
- package/lib/esm/Forms/form_responses.d.ts.map +1 -1
- package/lib/esm/Forms/forms.d.ts +3 -3
- package/lib/esm/Forms/forms.v2.d.ts +3 -3
- package/lib/esm/Forms/hooks.d.ts +1 -0
- package/lib/esm/Forms/hooks.d.ts.map +1 -1
- package/lib/esm/Forms/inputs.d.ts +1 -1
- package/lib/esm/Forms/inputs.d.ts.map +1 -1
- package/lib/esm/Forms/inputs.js +220 -100
- package/lib/esm/Forms/inputs.js.map +1 -1
- package/lib/esm/Forms/inputs.v2.d.ts +1 -1
- package/lib/esm/Forms/inputs.v2.js +1 -1
- package/lib/esm/controls.d.ts +2 -2
- package/lib/esm/inputs.d.ts +1 -1
- package/lib/esm/inputs.native.d.ts +1 -0
- package/lib/esm/inputs.native.d.ts.map +1 -1
- package/lib/esm/state.d.ts +315 -315
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +44 -44
- package/src/CMS/ContentViewer.tsx +16 -2
- package/src/Forms/inputs.tsx +189 -76
- package/src/Forms/inputs.v2.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tellescope/react-components",
|
|
3
|
-
"version": "1.235.
|
|
3
|
+
"version": "1.235.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/cjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -30,60 +30,60 @@
|
|
|
30
30
|
"homepage": "https://github.com/tellescope-os/enduser-authentication#readme",
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@babel/core": "7.28.5",
|
|
33
|
-
"@types/css-to-react-native": "
|
|
34
|
-
"@types/react": "
|
|
35
|
-
"@types/react-beautiful-dnd": "
|
|
36
|
-
"@types/react-dom": "
|
|
37
|
-
"@types/react-native": "
|
|
38
|
-
"@types/react-window": "
|
|
33
|
+
"@types/css-to-react-native": "3.0.0",
|
|
34
|
+
"@types/react": "17.0.52",
|
|
35
|
+
"@types/react-beautiful-dnd": "13.1.2",
|
|
36
|
+
"@types/react-dom": "17.0.18",
|
|
37
|
+
"@types/react-native": "0.65.27",
|
|
38
|
+
"@types/react-window": "1.8.5",
|
|
39
39
|
"babel-loader": "8.4.1",
|
|
40
40
|
"react-native": "0.68.0",
|
|
41
41
|
"typescript": "4.9.3"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@emotion/css": "
|
|
45
|
-
"@mui/icons-material": "
|
|
46
|
-
"@mui/material": "
|
|
47
|
-
"@reduxjs/toolkit": "
|
|
48
|
-
"@stripe/react-stripe-js": "
|
|
49
|
-
"@stripe/stripe-js": "
|
|
50
|
-
"@tellescope/constants": "1.235.
|
|
51
|
-
"@tellescope/sdk": "1.235.
|
|
52
|
-
"@tellescope/types-client": "1.235.
|
|
53
|
-
"@tellescope/types-models": "1.235.
|
|
54
|
-
"@tellescope/types-utilities": "1.235.
|
|
55
|
-
"@tellescope/utilities": "1.235.
|
|
56
|
-
"@tellescope/validation": "1.235.
|
|
57
|
-
"@typescript-eslint/eslint-plugin": "
|
|
58
|
-
"@typescript-eslint/parser": "
|
|
59
|
-
"css-to-react-native": "
|
|
60
|
-
"draft-js": "
|
|
61
|
-
"draftjs-to-html": "
|
|
62
|
-
"eslint": "
|
|
63
|
-
"eslint-plugin-react": "
|
|
64
|
-
"formik": "
|
|
65
|
-
"heic2any": "
|
|
66
|
-
"html-to-draftjs": "
|
|
67
|
-
"react-beautiful-dnd": "
|
|
68
|
-
"react-datepicker": "
|
|
69
|
-
"react-draft-wysiwyg": "
|
|
70
|
-
"react-draggable": "
|
|
71
|
-
"react-dropzone": "
|
|
72
|
-
"react-ga4": "
|
|
73
|
-
"react-native-paper": "
|
|
74
|
-
"react-native-render-html": "
|
|
75
|
-
"react-native-vector-icons": "
|
|
76
|
-
"react-native-video": "
|
|
77
|
-
"react-redux": "
|
|
78
|
-
"react-window": "
|
|
79
|
-
"yup": "
|
|
44
|
+
"@emotion/css": "11.10.5",
|
|
45
|
+
"@mui/icons-material": "5.10.15",
|
|
46
|
+
"@mui/material": "5.10.15",
|
|
47
|
+
"@reduxjs/toolkit": "1.9.0",
|
|
48
|
+
"@stripe/react-stripe-js": "2.9.0",
|
|
49
|
+
"@stripe/stripe-js": "1.52.1",
|
|
50
|
+
"@tellescope/constants": "1.235.2",
|
|
51
|
+
"@tellescope/sdk": "1.235.2",
|
|
52
|
+
"@tellescope/types-client": "1.235.2",
|
|
53
|
+
"@tellescope/types-models": "1.235.2",
|
|
54
|
+
"@tellescope/types-utilities": "1.235.2",
|
|
55
|
+
"@tellescope/utilities": "1.235.2",
|
|
56
|
+
"@tellescope/validation": "1.235.2",
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "4.33.0",
|
|
58
|
+
"@typescript-eslint/parser": "4.33.0",
|
|
59
|
+
"css-to-react-native": "3.0.0",
|
|
60
|
+
"draft-js": "0.11.7",
|
|
61
|
+
"draftjs-to-html": "0.9.1",
|
|
62
|
+
"eslint": "7.32.0",
|
|
63
|
+
"eslint-plugin-react": "7.31.11",
|
|
64
|
+
"formik": "2.2.9",
|
|
65
|
+
"heic2any": "0.0.4",
|
|
66
|
+
"html-to-draftjs": "1.5.0",
|
|
67
|
+
"react-beautiful-dnd": "13.1.1",
|
|
68
|
+
"react-datepicker": "3.8.0",
|
|
69
|
+
"react-draft-wysiwyg": "1.15.0",
|
|
70
|
+
"react-draggable": "4.4.6",
|
|
71
|
+
"react-dropzone": "11.7.1",
|
|
72
|
+
"react-ga4": "1.4.1",
|
|
73
|
+
"react-native-paper": "4.12.5",
|
|
74
|
+
"react-native-render-html": "6.3.4",
|
|
75
|
+
"react-native-vector-icons": "9.2.0",
|
|
76
|
+
"react-native-video": "5.2.1",
|
|
77
|
+
"react-redux": "7.2.9",
|
|
78
|
+
"react-window": "1.8.9",
|
|
79
|
+
"yup": "0.32.11"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
82
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
83
83
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
|
84
84
|
"react-native": "^0.65.0 || ^0.66.0 || ^0.67.0 || ^0.68.0 || ^0.71.0"
|
|
85
85
|
},
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "2ed60803588d8f6e1318f31a916f416aaeef57c5",
|
|
87
87
|
"publishConfig": {
|
|
88
88
|
"access": "public"
|
|
89
89
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useLayoutEffect, useRef, useState } from "react"
|
|
2
2
|
import { ManagedContentRecord } from "@tellescope/types-client"
|
|
3
|
-
import { remove_script_tags } from "@tellescope/utilities"
|
|
3
|
+
import { remove_script_tags, sanitize_html_for_cms } from "@tellescope/utilities"
|
|
4
4
|
import { Button, Grid, Typography } from "@mui/material"
|
|
5
5
|
import { PDFBlockUI } from "./components"
|
|
6
6
|
import { css } from "@emotion/css"
|
|
@@ -229,7 +229,18 @@ export const ArticleViewer = ({
|
|
|
229
229
|
)
|
|
230
230
|
}}
|
|
231
231
|
/>
|
|
232
|
-
)
|
|
232
|
+
)
|
|
233
|
+
: block.type === 'raw-html' ? (
|
|
234
|
+
<div style={{
|
|
235
|
+
fontSize: 18,
|
|
236
|
+
lineHeight: '25pt',
|
|
237
|
+
...blockStyleToCSS(block.style)
|
|
238
|
+
}}
|
|
239
|
+
dangerouslySetInnerHTML={{
|
|
240
|
+
__html: sanitize_html_for_cms(block.info.html)
|
|
241
|
+
}}
|
|
242
|
+
/>
|
|
243
|
+
)
|
|
233
244
|
: block.type === 'image' ? (
|
|
234
245
|
<img src={block.info.link} alt={block.info.alt || ''} style={{
|
|
235
246
|
maxWidth: block.info.maxWidth || '100%',
|
|
@@ -297,6 +308,9 @@ export const html_for_article = (article: ManagedContentRecord, options?: { root
|
|
|
297
308
|
: block.type === 'html' ? (
|
|
298
309
|
`<div>${remove_script_tags(remove_script_tags(block.info.html))}</div>`
|
|
299
310
|
)
|
|
311
|
+
: block.type === 'raw-html' ? (
|
|
312
|
+
`<div>${sanitize_html_for_cms(block.info.html)}</div>`
|
|
313
|
+
)
|
|
300
314
|
: block.type === 'image' ? (
|
|
301
315
|
// wrap with div to supporting centering later
|
|
302
316
|
`<div style="">
|
package/src/Forms/inputs.tsx
CHANGED
|
@@ -579,6 +579,7 @@ export const InsuranceInput = ({ field, onDatabaseSelect, value, onChange, form,
|
|
|
579
579
|
(addressQuestion?.answer?.type === 'Address' ? addressQuestion?.answer?.value?.state : undefined) || enduser?.state
|
|
580
580
|
), [enduser?.state, addressQuestion])
|
|
581
581
|
|
|
582
|
+
// load from database
|
|
582
583
|
const loadRef = useRef(false) // so session changes don't cause
|
|
583
584
|
useEffect(() => {
|
|
584
585
|
if (field?.options?.dataSource === CANVAS_TITLE) return // instead, look-up while typing against Canvas Search API
|
|
@@ -602,6 +603,7 @@ export const InsuranceInput = ({ field, onDatabaseSelect, value, onChange, form,
|
|
|
602
603
|
.catch(console.error)
|
|
603
604
|
}, [session, state, field?.options?.dataSource])
|
|
604
605
|
|
|
606
|
+
// load from 3rd-party on search only
|
|
605
607
|
const searchRef = useRef(query)
|
|
606
608
|
useEffect(() => {
|
|
607
609
|
if (field?.options?.dataSource !== CANVAS_TITLE && field?.options?.dataSource !== BRIDGE_TITLE) { return }
|
|
@@ -654,10 +656,11 @@ export const InsuranceInput = ({ field, onDatabaseSelect, value, onChange, form,
|
|
|
654
656
|
onDatabaseSelect?.([databaseRecord])
|
|
655
657
|
}
|
|
656
658
|
|
|
659
|
+
// don't lose existing payerId on back-and-forth navigation
|
|
657
660
|
onChange({
|
|
658
661
|
...value,
|
|
659
662
|
payerName: v || '',
|
|
660
|
-
payerId: payers.find(p => p.name === v)?.id || '',
|
|
663
|
+
payerId: (value?.payerName === v && value?.payerId ? value.payerId : '') || payers.find(p => p.name === v)?.id || '',
|
|
661
664
|
payerType: payers.find(p => p.name === v)?.type || '',
|
|
662
665
|
}, field.id)
|
|
663
666
|
}
|
|
@@ -997,12 +1000,12 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
997
1000
|
// enduser state is automatically resolved on the backend as default
|
|
998
1001
|
}, [responses])
|
|
999
1002
|
|
|
1000
|
-
// Soft eligibility check function
|
|
1003
|
+
// Soft eligibility check function - supports multiple service type IDs
|
|
1001
1004
|
const checkProviderEligibility = useCallback(async () => {
|
|
1002
|
-
const
|
|
1005
|
+
const serviceTypeIds = field.options?.bridgeServiceTypeIds
|
|
1003
1006
|
|
|
1004
|
-
if (!
|
|
1005
|
-
setError('Bridge Service Type
|
|
1007
|
+
if (!serviceTypeIds || serviceTypeIds.length === 0) {
|
|
1008
|
+
setError('Bridge Service Type IDs not configured')
|
|
1006
1009
|
return
|
|
1007
1010
|
}
|
|
1008
1011
|
// payerId and state can be automatically resolved on the backend, if already saved on Enduser, so not required here
|
|
@@ -1011,25 +1014,54 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1011
1014
|
setError(undefined)
|
|
1012
1015
|
|
|
1013
1016
|
try {
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1017
|
+
// Fire parallel requests for each service type ID
|
|
1018
|
+
const results = await Promise.all(
|
|
1019
|
+
serviceTypeIds.map(async (serviceTypeId) => {
|
|
1020
|
+
try {
|
|
1021
|
+
const { data } = await session.api.integrations.proxy_read({
|
|
1022
|
+
id: enduserId,
|
|
1023
|
+
integration: BRIDGE_TITLE,
|
|
1024
|
+
type: 'provider-eligibility',
|
|
1025
|
+
query: JSON.stringify({
|
|
1026
|
+
serviceTypeId,
|
|
1027
|
+
payerId,
|
|
1028
|
+
state,
|
|
1029
|
+
}),
|
|
1030
|
+
})
|
|
1031
|
+
return {
|
|
1032
|
+
serviceTypeId,
|
|
1033
|
+
status: data?.status || 'unknown',
|
|
1034
|
+
userIds: data?.userIds || [],
|
|
1035
|
+
}
|
|
1036
|
+
} catch (err: any) {
|
|
1037
|
+
console.error(`Provider eligibility check failed for ${serviceTypeId}:`, err)
|
|
1038
|
+
return {
|
|
1039
|
+
serviceTypeId,
|
|
1040
|
+
status: 'error',
|
|
1041
|
+
userIds: [],
|
|
1042
|
+
error: err?.message,
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
})
|
|
1046
|
+
)
|
|
1024
1047
|
|
|
1025
|
-
//
|
|
1026
|
-
const
|
|
1027
|
-
|
|
1048
|
+
// Aggregate results - union of userIds across all service types
|
|
1049
|
+
const allUserIds = results.flatMap(r => r.userIds)
|
|
1050
|
+
const uniqueUserIds = Array.from(new Set(allUserIds))
|
|
1028
1051
|
|
|
1029
|
-
//
|
|
1052
|
+
// Determine aggregated status (ELIGIBLE if any are eligible, otherwise first non-error status)
|
|
1053
|
+
const aggregatedStatus = results.some(r => r.status === 'ELIGIBLE')
|
|
1054
|
+
? 'ELIGIBLE'
|
|
1055
|
+
: results.find(r => r.status !== 'error')?.status || 'unknown'
|
|
1056
|
+
|
|
1057
|
+
// Store aggregated userIds in shared variable for Appointment Booking to use
|
|
1058
|
+
setBridgeEligibilityUserIds(uniqueUserIds)
|
|
1059
|
+
|
|
1060
|
+
// Update the answer with aggregated results
|
|
1030
1061
|
onChange({
|
|
1031
|
-
|
|
1032
|
-
|
|
1062
|
+
payerId, // Store payerId to detect changes on remount
|
|
1063
|
+
status: aggregatedStatus,
|
|
1064
|
+
userIds: uniqueUserIds,
|
|
1033
1065
|
}, field.id)
|
|
1034
1066
|
} catch (err: any) {
|
|
1035
1067
|
setError(err?.message || 'Failed to check eligibility')
|
|
@@ -1039,12 +1071,12 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1039
1071
|
}
|
|
1040
1072
|
}, [session, field, payerId, state, onChange, enduserId])
|
|
1041
1073
|
|
|
1042
|
-
// Hard eligibility check function with polling
|
|
1074
|
+
// Hard eligibility check function with polling - supports multiple service type IDs
|
|
1043
1075
|
const checkServiceEligibility = useCallback(async () => {
|
|
1044
|
-
const
|
|
1076
|
+
const serviceTypeIds = field.options?.bridgeServiceTypeIds
|
|
1045
1077
|
|
|
1046
|
-
if (!
|
|
1047
|
-
setError('Bridge Service Type
|
|
1078
|
+
if (!serviceTypeIds || serviceTypeIds.length === 0) {
|
|
1079
|
+
setError('Bridge Service Type IDs not configured')
|
|
1048
1080
|
return
|
|
1049
1081
|
}
|
|
1050
1082
|
|
|
@@ -1052,33 +1084,65 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1052
1084
|
setError(undefined)
|
|
1053
1085
|
|
|
1054
1086
|
try {
|
|
1055
|
-
// Initiate service eligibility
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1087
|
+
// Initiate service eligibility checks for all service type IDs in parallel
|
|
1088
|
+
const initiatedChecks = await Promise.all(
|
|
1089
|
+
serviceTypeIds.map(async (serviceTypeId) => {
|
|
1090
|
+
try {
|
|
1091
|
+
const { data } = await session.api.integrations.proxy_read({
|
|
1092
|
+
id: enduserId,
|
|
1093
|
+
integration: BRIDGE_TITLE,
|
|
1094
|
+
type: 'service-eligibility',
|
|
1095
|
+
query: JSON.stringify({
|
|
1096
|
+
serviceTypeId,
|
|
1097
|
+
payerId,
|
|
1098
|
+
memberId,
|
|
1099
|
+
state,
|
|
1100
|
+
}),
|
|
1101
|
+
})
|
|
1067
1102
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1103
|
+
const serviceEligibilityId = data?.id
|
|
1104
|
+
if (!serviceEligibilityId) {
|
|
1105
|
+
throw new Error('No service eligibility ID returned')
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
return {
|
|
1109
|
+
serviceTypeId,
|
|
1110
|
+
serviceEligibilityId,
|
|
1111
|
+
error: undefined,
|
|
1112
|
+
}
|
|
1113
|
+
} catch (err: any) {
|
|
1114
|
+
console.error(`Service eligibility check initiation failed for ${serviceTypeId}:`, err)
|
|
1115
|
+
return {
|
|
1116
|
+
serviceTypeId,
|
|
1117
|
+
serviceEligibilityId: null,
|
|
1118
|
+
error: err?.message,
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
})
|
|
1122
|
+
)
|
|
1072
1123
|
|
|
1073
1124
|
setLoading(false)
|
|
1074
1125
|
setPolling(true)
|
|
1075
1126
|
|
|
1076
|
-
// Poll for results
|
|
1077
|
-
const
|
|
1127
|
+
// Poll for results from all checks in parallel
|
|
1128
|
+
const pollForAllResults = async () => {
|
|
1078
1129
|
const maxAttempts = 60 // Poll for up to 60 attempts (2 minutes at 2s intervals)
|
|
1130
|
+
|
|
1131
|
+
// Track completion status for each check
|
|
1132
|
+
const checkStatuses = new Map(
|
|
1133
|
+
initiatedChecks.map(check => [
|
|
1134
|
+
check.serviceTypeId,
|
|
1135
|
+
{
|
|
1136
|
+
completed: check.error !== undefined || check.serviceEligibilityId === null,
|
|
1137
|
+
result: check.error ? { status: 'error', userIds: [], error: check.error } : null,
|
|
1138
|
+
serviceEligibilityId: check.serviceEligibilityId,
|
|
1139
|
+
}
|
|
1140
|
+
])
|
|
1141
|
+
)
|
|
1142
|
+
|
|
1079
1143
|
let attempts = 0
|
|
1080
1144
|
|
|
1081
|
-
const
|
|
1145
|
+
const pollAll = async (): Promise<void> => {
|
|
1082
1146
|
if (attempts >= maxAttempts) {
|
|
1083
1147
|
setError('Eligibility check timed out. Please try again.')
|
|
1084
1148
|
setPolling(false)
|
|
@@ -1087,44 +1151,87 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1087
1151
|
|
|
1088
1152
|
attempts++
|
|
1089
1153
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1154
|
+
// Poll all incomplete checks in parallel
|
|
1155
|
+
const pollPromises = initiatedChecks
|
|
1156
|
+
.filter(check => {
|
|
1157
|
+
const status = checkStatuses.get(check.serviceTypeId)
|
|
1158
|
+
return check.serviceEligibilityId && status && !status.completed
|
|
1159
|
+
})
|
|
1160
|
+
.map(async (check) => {
|
|
1161
|
+
try {
|
|
1162
|
+
const { data: pollData } = await session.api.integrations.proxy_read({
|
|
1163
|
+
id: check.serviceEligibilityId!,
|
|
1164
|
+
integration: BRIDGE_TITLE,
|
|
1165
|
+
type: 'service-eligibility-poll',
|
|
1166
|
+
})
|
|
1167
|
+
|
|
1168
|
+
const status = pollData?.status
|
|
1169
|
+
|
|
1170
|
+
// Check if we're in a terminal state
|
|
1171
|
+
if (status && status !== 'PENDING') {
|
|
1172
|
+
const checkStatus = checkStatuses.get(check.serviceTypeId)!
|
|
1173
|
+
checkStatus.completed = true
|
|
1174
|
+
checkStatus.result = {
|
|
1175
|
+
status: status || 'unknown',
|
|
1176
|
+
userIds: pollData?.userIds || [],
|
|
1177
|
+
error: undefined,
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
} catch (err: any) {
|
|
1181
|
+
console.error(`Service eligibility polling failed for ${check.serviceTypeId}:`, err)
|
|
1182
|
+
const checkStatus = checkStatuses.get(check.serviceTypeId)!
|
|
1183
|
+
checkStatus.completed = true
|
|
1184
|
+
checkStatus.result = {
|
|
1185
|
+
status: 'error',
|
|
1186
|
+
userIds: [],
|
|
1187
|
+
error: err?.message,
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1095
1190
|
})
|
|
1096
1191
|
|
|
1097
|
-
|
|
1192
|
+
await Promise.all(pollPromises)
|
|
1098
1193
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
// Store userIds in shared variable for Appointment Booking to use
|
|
1102
|
-
const userIds = pollData?.userIds || []
|
|
1103
|
-
setBridgeEligibilityUserIds(userIds)
|
|
1194
|
+
// Check if all checks are completed
|
|
1195
|
+
const allCompleted = Array.from(checkStatuses.values()).every(s => s.completed)
|
|
1104
1196
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1197
|
+
if (allCompleted) {
|
|
1198
|
+
// Aggregate results - union of userIds across all service types
|
|
1199
|
+
const results = Array.from(checkStatuses.entries()).map(([serviceTypeId, status]) => ({
|
|
1200
|
+
serviceTypeId,
|
|
1201
|
+
status: status.result?.status || 'unknown',
|
|
1202
|
+
userIds: status.result?.userIds || [],
|
|
1203
|
+
}))
|
|
1110
1204
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1205
|
+
const allUserIds = results.flatMap(r => r.userIds)
|
|
1206
|
+
const uniqueUserIds = Array.from(new Set(allUserIds))
|
|
1207
|
+
|
|
1208
|
+
// Determine aggregated status (ELIGIBLE if any are eligible, otherwise first non-error status)
|
|
1209
|
+
const aggregatedStatus = results.some(r => r.status === 'ELIGIBLE')
|
|
1210
|
+
? 'ELIGIBLE'
|
|
1211
|
+
: results.find(r => r.status !== 'error')?.status || 'unknown'
|
|
1212
|
+
|
|
1213
|
+
// Store aggregated userIds in shared variable for Appointment Booking to use
|
|
1214
|
+
setBridgeEligibilityUserIds(uniqueUserIds)
|
|
1215
|
+
|
|
1216
|
+
// Update the answer with aggregated results
|
|
1217
|
+
onChange({
|
|
1218
|
+
payerId, // Store payerId to detect changes on remount
|
|
1219
|
+
status: aggregatedStatus,
|
|
1220
|
+
userIds: uniqueUserIds,
|
|
1221
|
+
}, field.id)
|
|
1114
1222
|
|
|
1115
|
-
// Still pending, poll again after delay
|
|
1116
|
-
setTimeout(poll, 2000) // Poll every 2 seconds
|
|
1117
|
-
} catch (err: any) {
|
|
1118
|
-
setError(err?.message || 'Failed to poll eligibility status')
|
|
1119
|
-
console.error('Service eligibility polling failed:', err)
|
|
1120
1223
|
setPolling(false)
|
|
1224
|
+
return
|
|
1121
1225
|
}
|
|
1226
|
+
|
|
1227
|
+
// Still have pending checks, poll again after delay
|
|
1228
|
+
setTimeout(pollAll, 2000) // Poll every 2 seconds
|
|
1122
1229
|
}
|
|
1123
1230
|
|
|
1124
|
-
|
|
1231
|
+
pollAll()
|
|
1125
1232
|
}
|
|
1126
1233
|
|
|
1127
|
-
|
|
1234
|
+
pollForAllResults()
|
|
1128
1235
|
} catch (err: any) {
|
|
1129
1236
|
setError(err?.message || 'Failed to check service eligibility')
|
|
1130
1237
|
console.error('Service eligibility check failed:', err)
|
|
@@ -1137,6 +1244,12 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1137
1244
|
const autoCheckRef = useRef(false)
|
|
1138
1245
|
useEffect(() => {
|
|
1139
1246
|
if (!isEnduserSession) return
|
|
1247
|
+
|
|
1248
|
+
// If we already have a result and the payer hasn't changed, use the cached result
|
|
1249
|
+
if (value?.status && value?.payerId === payerId) {
|
|
1250
|
+
return
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1140
1253
|
if (autoCheckRef.current) return
|
|
1141
1254
|
autoCheckRef.current = true
|
|
1142
1255
|
|
|
@@ -1145,7 +1258,7 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1145
1258
|
} else {
|
|
1146
1259
|
checkProviderEligibility()
|
|
1147
1260
|
}
|
|
1148
|
-
}, [isEnduserSession, eligibilityType, checkProviderEligibility, checkServiceEligibility])
|
|
1261
|
+
}, [isEnduserSession, eligibilityType, checkProviderEligibility, checkServiceEligibility, value, payerId])
|
|
1149
1262
|
|
|
1150
1263
|
const errorComponent = useMemo(() => (
|
|
1151
1264
|
<Grid container spacing={2} direction="column" alignItems="center" style={{ padding: '20px 0' }}>
|
|
@@ -1224,7 +1337,7 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1224
1337
|
</Grid>
|
|
1225
1338
|
</Grid>
|
|
1226
1339
|
)
|
|
1227
|
-
}, [value])
|
|
1340
|
+
}, [value, payerName])
|
|
1228
1341
|
|
|
1229
1342
|
// Loading/polling state for enduser sessions
|
|
1230
1343
|
if (isEnduserSession) {
|
|
@@ -1246,7 +1359,7 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1246
1359
|
Eligibility Type: {eligibilityType}
|
|
1247
1360
|
</Typography>
|
|
1248
1361
|
<Typography variant="body2" color="textSecondary">
|
|
1249
|
-
Service Type: {field.options?.
|
|
1362
|
+
Service Type IDs: {field.options?.bridgeServiceTypeIds?.join(', ') || 'Not configured'}
|
|
1250
1363
|
</Typography>
|
|
1251
1364
|
{state && <Typography variant="body2" color="textSecondary">State: {state}</Typography>}
|
|
1252
1365
|
{payerId && <Typography variant="body2" color="textSecondary">Payer ID: {payerId}</Typography>}
|
|
@@ -1275,7 +1388,7 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1275
1388
|
submitText="Check Provider Eligibility (Free)"
|
|
1276
1389
|
submittingText="Checking..."
|
|
1277
1390
|
submitting={loading && !polling}
|
|
1278
|
-
disabled={!field.options?.
|
|
1391
|
+
disabled={!field.options?.bridgeServiceTypeIds?.length || loading || polling}
|
|
1279
1392
|
/>
|
|
1280
1393
|
</Grid>
|
|
1281
1394
|
<Grid item>
|
|
@@ -1285,7 +1398,7 @@ export const BridgeEligibilityInput = ({ field, value, onChange, responses, endu
|
|
|
1285
1398
|
submitText="Check Service Eligibility (Paid)"
|
|
1286
1399
|
submittingText={polling ? "Polling..." : "Initiating..."}
|
|
1287
1400
|
submitting={loading || polling}
|
|
1288
|
-
disabled={!field.options?.
|
|
1401
|
+
disabled={!field.options?.bridgeServiceTypeIds?.length || loading || polling}
|
|
1289
1402
|
/>
|
|
1290
1403
|
</Grid>
|
|
1291
1404
|
</Grid>
|
|
@@ -2290,7 +2403,7 @@ export const StripeInput = ({ field, value, onChange, setCustomerId, enduserId,
|
|
|
2290
2403
|
fieldId: field.id,
|
|
2291
2404
|
enduserId,
|
|
2292
2405
|
...(selectedProducts.length > 0 && { selectedProductIds: selectedProducts }) // Pass selected products to Stripe checkout
|
|
2293
|
-
}
|
|
2406
|
+
})
|
|
2294
2407
|
.then(({ clientSecret, publishableKey, stripeAccount, businessName, customerId, isCheckout, answerText }) => {
|
|
2295
2408
|
setAnswertext(answerText || '')
|
|
2296
2409
|
setIsCheckout(!!isCheckout)
|
package/src/Forms/inputs.v2.tsx
CHANGED
|
@@ -1192,7 +1192,7 @@ export const MultipleChoiceInput = ({ field, form, value: _value, onChange }: Fo
|
|
|
1192
1192
|
display: 'flex',
|
|
1193
1193
|
alignItems: 'center',
|
|
1194
1194
|
width: '100%',
|
|
1195
|
-
border: isSelected ? '
|
|
1195
|
+
border: isSelected ? '3px solid' : '1px solid',
|
|
1196
1196
|
borderColor: 'primary.main',
|
|
1197
1197
|
borderRadius: 1,
|
|
1198
1198
|
padding: '16px 16px',
|