@tellescope/react-components 1.248.0 → 1.249.1
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 +2 -2
- package/lib/cjs/Forms/forms.d.ts.map +1 -1
- package/lib/cjs/Forms/forms.js +7 -7
- package/lib/cjs/Forms/forms.js.map +1 -1
- package/lib/cjs/Forms/forms.v2.d.ts +2 -2
- package/lib/cjs/Forms/forms.v2.d.ts.map +1 -1
- package/lib/cjs/Forms/forms.v2.js +7 -7
- package/lib/cjs/Forms/forms.v2.js.map +1 -1
- package/lib/cjs/Forms/hooks.d.ts +1 -0
- package/lib/cjs/Forms/hooks.d.ts.map +1 -1
- package/lib/cjs/Forms/hooks.js +53 -13
- package/lib/cjs/Forms/hooks.js.map +1 -1
- package/lib/cjs/Forms/inputs.d.ts +1 -1
- package/lib/cjs/Forms/inputs.d.ts.map +1 -1
- package/lib/cjs/Forms/inputs.js +6 -3
- package/lib/cjs/Forms/inputs.js.map +1 -1
- package/lib/cjs/Forms/inputs.v2.d.ts +1 -2
- package/lib/cjs/Forms/inputs.v2.d.ts.map +1 -1
- package/lib/cjs/Forms/inputs.v2.js +1 -44
- package/lib/cjs/Forms/inputs.v2.js.map +1 -1
- package/lib/cjs/Forms/types.d.ts +1 -0
- package/lib/cjs/Forms/types.d.ts.map +1 -1
- package/lib/esm/Forms/forms.d.ts +2 -2
- package/lib/esm/Forms/forms.d.ts.map +1 -1
- package/lib/esm/Forms/forms.js +7 -7
- package/lib/esm/Forms/forms.js.map +1 -1
- package/lib/esm/Forms/forms.v2.d.ts +2 -2
- package/lib/esm/Forms/forms.v2.d.ts.map +1 -1
- package/lib/esm/Forms/forms.v2.js +7 -7
- package/lib/esm/Forms/forms.v2.js.map +1 -1
- package/lib/esm/Forms/hooks.d.ts +1 -0
- package/lib/esm/Forms/hooks.d.ts.map +1 -1
- package/lib/esm/Forms/hooks.js +53 -13
- package/lib/esm/Forms/hooks.js.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 +6 -3
- package/lib/esm/Forms/inputs.js.map +1 -1
- package/lib/esm/Forms/inputs.v2.d.ts +1 -2
- package/lib/esm/Forms/inputs.v2.d.ts.map +1 -1
- package/lib/esm/Forms/inputs.v2.js +1 -44
- package/lib/esm/Forms/inputs.v2.js.map +1 -1
- package/lib/esm/Forms/types.d.ts +1 -0
- package/lib/esm/Forms/types.d.ts.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/Forms/forms.tsx +20 -14
- package/src/Forms/forms.v2.tsx +12 -6
- package/src/Forms/hooks.tsx +60 -11
- package/src/Forms/inputs.tsx +6 -3
- package/src/Forms/inputs.v2.tsx +1 -50
- package/src/Forms/types.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tellescope/react-components",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.249.1",
|
|
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.249.1",
|
|
55
|
+
"@tellescope/sdk": "1.249.1",
|
|
56
|
+
"@tellescope/types-client": "1.249.1",
|
|
57
|
+
"@tellescope/types-models": "1.249.1",
|
|
58
|
+
"@tellescope/types-utilities": "1.249.1",
|
|
59
|
+
"@tellescope/utilities": "1.249.1",
|
|
60
|
+
"@tellescope/validation": "1.249.1",
|
|
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": "23480776738c31e1d56244ce6c23d9abe032e15a",
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"access": "public"
|
|
90
90
|
}
|
package/src/Forms/forms.tsx
CHANGED
|
@@ -145,6 +145,7 @@ export const QuestionForField = ({
|
|
|
145
145
|
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
146
146
|
groupFields,
|
|
147
147
|
AddToDatabase,
|
|
148
|
+
lastNavigationDirectionRef,
|
|
148
149
|
} : {
|
|
149
150
|
spacing?: number,
|
|
150
151
|
form?: Form,
|
|
@@ -163,19 +164,19 @@ export const QuestionForField = ({
|
|
|
163
164
|
setUploadingFiles: React.Dispatch<React.SetStateAction<{ fieldId: string }[]>>,
|
|
164
165
|
groupFields?: FormField[],
|
|
165
166
|
AddToDatabase?: React.JSXElementConstructor<AddToDatabaseProps>,
|
|
166
|
-
} & Pick<TellescopeFormProps, "rootResponseId" | "goToNextField" | "groupId" | "groupInstance" | "submit" | "formResponseId" | 'enduserId' | 'isPreviousDisabled' | 'goToPreviousField' | 'enduser' | 'handleDatabaseSelect' | 'onAddFile' | 'onFieldChange' | 'fields' | 'customInputs' | 'responses' | 'selectedFiles' | 'validateField'>) => {
|
|
167
|
+
} & Pick<TellescopeFormProps, "rootResponseId" | "goToNextField" | "groupId" | "groupInstance" | "submit" | "formResponseId" | 'enduserId' | 'isPreviousDisabled' | 'goToPreviousField' | 'enduser' | 'handleDatabaseSelect' | 'onAddFile' | 'onFieldChange' | 'fields' | 'customInputs' | 'responses' | 'selectedFiles' | 'validateField' | 'lastNavigationDirectionRef'>) => {
|
|
167
168
|
const String = customInputs?.['string'] ?? StringInput
|
|
168
169
|
const StringLong = customInputs?.['stringLong'] ?? StringLongInput
|
|
169
170
|
const Email = customInputs?.['email'] ?? EmailInput
|
|
170
171
|
const Number = customInputs?.['number'] ?? NumberInput
|
|
171
|
-
const Phone = customInputs?.['phone'] ?? PhoneInput
|
|
172
|
-
const ResolvedDateInput = customInputs?.['date'] ?? DateInput
|
|
173
|
-
const Signature = customInputs?.['signature'] ?? SignatureInput
|
|
174
|
-
const MultipleChoice = customInputs?.['multiple_choice'] ?? MultipleChoiceInput
|
|
175
|
-
const Stripe = customInputs?.['Stripe'] ?? StripeInput
|
|
176
|
-
const Chargebee = customInputs?.['Chargebee'] ?? ChargeebeeInput
|
|
177
|
-
const File = customInputs?.['file'] ?? FileInput
|
|
178
|
-
const Files = customInputs?.['files'] ?? FilesInput
|
|
172
|
+
const Phone = customInputs?.['phone'] ?? PhoneInput
|
|
173
|
+
const ResolvedDateInput = customInputs?.['date'] ?? DateInput
|
|
174
|
+
const Signature = customInputs?.['signature'] ?? SignatureInput
|
|
175
|
+
const MultipleChoice = customInputs?.['multiple_choice'] ?? MultipleChoiceInput
|
|
176
|
+
const Stripe = customInputs?.['Stripe'] ?? StripeInput
|
|
177
|
+
const Chargebee = customInputs?.['Chargebee'] ?? ChargeebeeInput
|
|
178
|
+
const File = customInputs?.['file'] ?? FileInput
|
|
179
|
+
const Files = customInputs?.['files'] ?? FilesInput
|
|
179
180
|
const Ranking = customInputs?.['ranking'] ?? RankingInput
|
|
180
181
|
const Rating = customInputs?.['rating'] ?? RatingInput
|
|
181
182
|
const Address = customInputs?.['Address'] ?? AddressInput
|
|
@@ -293,7 +294,7 @@ export const QuestionForField = ({
|
|
|
293
294
|
<DateStringInput field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'string'>} form={form} />
|
|
294
295
|
)
|
|
295
296
|
: field.type === 'Hidden Value' ? (
|
|
296
|
-
<HiddenValue groupFields={groupFields} isSinglePage={isSinglePage} goToNextField={goToNextField} goToPreviousField={goToPreviousField} field={field} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<any>} form={form} />
|
|
297
|
+
<HiddenValue groupFields={groupFields} isSinglePage={isSinglePage} goToNextField={goToNextField} goToPreviousField={goToPreviousField} field={field} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<any>} form={form} lastNavigationDirectionRef={lastNavigationDirectionRef} />
|
|
297
298
|
)
|
|
298
299
|
: field.type === 'Address' ? (
|
|
299
300
|
<Address field={field} disabled={value.disabled} value={value.answer.value as any} onChange={onFieldChange as ChangeHandler<any>} form={form} />
|
|
@@ -428,13 +429,13 @@ export const QuestionForField = ({
|
|
|
428
429
|
enduser={enduser} goToPreviousField={goToPreviousField} isPreviousDisabled={isPreviousDisabled} goToNextField={goToNextField}
|
|
429
430
|
form={form} formResponseId={formResponseId} rootResponseId={rootResponseId} submit={submit}
|
|
430
431
|
repeats={repeats} onRepeatsChange={onRepeatsChange} setCustomerId={setCustomerId}
|
|
431
|
-
value={value} file={file}
|
|
432
|
+
value={value} file={file}
|
|
432
433
|
onAddFile={onAddFile} onFieldChange={onFieldChange}
|
|
433
434
|
responses={responses} selectedFiles={selectedFiles}
|
|
434
435
|
validateField={validateField} enduserId={enduserId}
|
|
435
436
|
spacing={field.options?.groupPadding}
|
|
436
437
|
logicOptions={logicOptions}
|
|
437
|
-
isInQuestionGroup
|
|
438
|
+
isInQuestionGroup
|
|
438
439
|
groupFields={
|
|
439
440
|
fields.filter(f => field.options?.subFields?.find(s => s.id === f.id))
|
|
440
441
|
}
|
|
@@ -442,6 +443,7 @@ export const QuestionForField = ({
|
|
|
442
443
|
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
443
444
|
handleFileUpload={handleFileUpload}
|
|
444
445
|
AddToDatabase={AddToDatabase}
|
|
446
|
+
lastNavigationDirectionRef={lastNavigationDirectionRef}
|
|
445
447
|
/>
|
|
446
448
|
</Flex>
|
|
447
449
|
)
|
|
@@ -529,6 +531,7 @@ export const TellescopeSingleQuestionFlow: typeof TellescopeForm = ({
|
|
|
529
531
|
groupInstance,
|
|
530
532
|
logicOptions,
|
|
531
533
|
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
534
|
+
lastNavigationDirectionRef,
|
|
532
535
|
}) => {
|
|
533
536
|
const beforeunloadHandler = React.useCallback((e: BeforeUnloadEvent) => {
|
|
534
537
|
try {
|
|
@@ -652,6 +655,7 @@ export const TellescopeSingleQuestionFlow: typeof TellescopeForm = ({
|
|
|
652
655
|
logicOptions={logicOptions}
|
|
653
656
|
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
654
657
|
handleFileUpload={handleFileUpload}
|
|
658
|
+
lastNavigationDirectionRef={lastNavigationDirectionRef}
|
|
655
659
|
/>
|
|
656
660
|
</Flex>
|
|
657
661
|
</Flex>
|
|
@@ -1295,7 +1299,8 @@ export const TellescopeSinglePageForm: React.JSXElementConstructor<TellescopeFor
|
|
|
1295
1299
|
groupInstance,
|
|
1296
1300
|
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
1297
1301
|
AddToDatabase,
|
|
1298
|
-
|
|
1302
|
+
lastNavigationDirectionRef,
|
|
1303
|
+
...props
|
|
1299
1304
|
}) => {
|
|
1300
1305
|
const list = useListForFormFields(fields, responses, { form: props.form, gender: enduser?.gender })
|
|
1301
1306
|
|
|
@@ -1424,7 +1429,7 @@ export const TellescopeSinglePageForm: React.JSXElementConstructor<TellescopeFor
|
|
|
1424
1429
|
enduserId={props.enduserId} formResponseId={props.formResponseId} rootResponseId={rootResponseId} submit={submit}
|
|
1425
1430
|
enduser={enduser} goToPreviousField={goToPreviousField} isPreviousDisabled={isPreviousDisabled} goToNextField={goToNextField}
|
|
1426
1431
|
repeats={repeats} onRepeatsChange={setRepeats} setCustomerId={setCustomerId}
|
|
1427
|
-
value={value} file={file}
|
|
1432
|
+
value={value} file={file}
|
|
1428
1433
|
customInputs={customInputs}
|
|
1429
1434
|
onAddFile={onAddFile} onFieldChange={onFieldChange}
|
|
1430
1435
|
responses={responses} selectedFiles={selectedFiles}
|
|
@@ -1433,6 +1438,7 @@ export const TellescopeSinglePageForm: React.JSXElementConstructor<TellescopeFor
|
|
|
1433
1438
|
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
1434
1439
|
handleFileUpload={handleFileUpload}
|
|
1435
1440
|
AddToDatabase={AddToDatabase}
|
|
1441
|
+
lastNavigationDirectionRef={lastNavigationDirectionRef}
|
|
1436
1442
|
/>
|
|
1437
1443
|
</Flex>
|
|
1438
1444
|
</Flex>
|
package/src/Forms/forms.v2.tsx
CHANGED
|
@@ -154,6 +154,7 @@ export const QuestionForField = ({
|
|
|
154
154
|
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
155
155
|
groupFields,
|
|
156
156
|
AddToDatabase,
|
|
157
|
+
lastNavigationDirectionRef,
|
|
157
158
|
} : {
|
|
158
159
|
spacing?: number,
|
|
159
160
|
form?: Form,
|
|
@@ -172,7 +173,7 @@ export const QuestionForField = ({
|
|
|
172
173
|
setUploadingFiles: React.Dispatch<React.SetStateAction<{ fieldId: string }[]>>,
|
|
173
174
|
groupFields?: FormField[],
|
|
174
175
|
AddToDatabase?: React.JSXElementConstructor<AddToDatabaseProps>,
|
|
175
|
-
} & Pick<TellescopeFormProps, "rootResponseId" | "goToNextField" | "groupId" | "groupInstance" | "submit" | "formResponseId" | 'enduserId' | 'isPreviousDisabled' | 'goToPreviousField' | 'enduser' | 'handleDatabaseSelect' | 'onAddFile' | 'onFieldChange' | 'fields' | 'customInputs' | 'responses' | 'selectedFiles' | 'validateField'>) => {
|
|
176
|
+
} & Pick<TellescopeFormProps, "rootResponseId" | "goToNextField" | "groupId" | "groupInstance" | "submit" | "formResponseId" | 'enduserId' | 'isPreviousDisabled' | 'goToPreviousField' | 'enduser' | 'handleDatabaseSelect' | 'onAddFile' | 'onFieldChange' | 'fields' | 'customInputs' | 'responses' | 'selectedFiles' | 'validateField' | 'lastNavigationDirectionRef'>) => {
|
|
176
177
|
const String = customInputs?.['string'] ?? StringInput
|
|
177
178
|
const StringLong = customInputs?.['stringLong'] ?? StringLongInput
|
|
178
179
|
const Email = customInputs?.['email'] ?? EmailInput
|
|
@@ -303,7 +304,7 @@ export const QuestionForField = ({
|
|
|
303
304
|
<DateStringInput field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'string'>} form={form} />
|
|
304
305
|
)
|
|
305
306
|
: field.type === 'Hidden Value' ? (
|
|
306
|
-
<HiddenValue groupFields={groupFields} isSinglePage={isSinglePage} goToNextField={goToNextField} goToPreviousField={goToPreviousField} field={field} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<any>} form={form} />
|
|
307
|
+
<HiddenValue groupFields={groupFields} isSinglePage={isSinglePage} goToNextField={goToNextField} goToPreviousField={goToPreviousField} field={field} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<any>} form={form} lastNavigationDirectionRef={lastNavigationDirectionRef} />
|
|
307
308
|
)
|
|
308
309
|
: field.type === 'Address' ? (
|
|
309
310
|
<Address field={field} disabled={value.disabled} value={value.answer.value as any} onChange={onFieldChange as ChangeHandler<any>} form={form} />
|
|
@@ -438,13 +439,13 @@ export const QuestionForField = ({
|
|
|
438
439
|
enduser={enduser} goToPreviousField={goToPreviousField} isPreviousDisabled={isPreviousDisabled} goToNextField={goToNextField}
|
|
439
440
|
form={form} formResponseId={formResponseId} rootResponseId={rootResponseId} submit={submit}
|
|
440
441
|
repeats={repeats} onRepeatsChange={onRepeatsChange} setCustomerId={setCustomerId}
|
|
441
|
-
value={value} file={file}
|
|
442
|
+
value={value} file={file}
|
|
442
443
|
onAddFile={onAddFile} onFieldChange={onFieldChange}
|
|
443
444
|
responses={responses} selectedFiles={selectedFiles}
|
|
444
445
|
validateField={validateField} enduserId={enduserId}
|
|
445
446
|
spacing={field.options?.groupPadding}
|
|
446
447
|
logicOptions={logicOptions}
|
|
447
|
-
isInQuestionGroup
|
|
448
|
+
isInQuestionGroup
|
|
448
449
|
groupFields={
|
|
449
450
|
fields.filter(f => field.options?.subFields?.find(s => s.id === f.id))
|
|
450
451
|
}
|
|
@@ -452,6 +453,7 @@ export const QuestionForField = ({
|
|
|
452
453
|
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
453
454
|
handleFileUpload={handleFileUpload}
|
|
454
455
|
AddToDatabase={AddToDatabase}
|
|
456
|
+
lastNavigationDirectionRef={lastNavigationDirectionRef}
|
|
455
457
|
/>
|
|
456
458
|
</Flex>
|
|
457
459
|
)
|
|
@@ -539,6 +541,7 @@ export const TellescopeSingleQuestionFlowV2: typeof TellescopeFormV2 = ({
|
|
|
539
541
|
groupInstance,
|
|
540
542
|
logicOptions,
|
|
541
543
|
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
544
|
+
lastNavigationDirectionRef,
|
|
542
545
|
}) => {
|
|
543
546
|
const beforeunloadHandler = React.useCallback((e: BeforeUnloadEvent) => {
|
|
544
547
|
try {
|
|
@@ -689,6 +692,7 @@ export const TellescopeSingleQuestionFlowV2: typeof TellescopeFormV2 = ({
|
|
|
689
692
|
logicOptions={logicOptions}
|
|
690
693
|
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
691
694
|
handleFileUpload={handleFileUpload}
|
|
695
|
+
lastNavigationDirectionRef={lastNavigationDirectionRef}
|
|
692
696
|
/>
|
|
693
697
|
</Flex>
|
|
694
698
|
</Flex>
|
|
@@ -1137,7 +1141,8 @@ export const TellescopeSinglePageForm: React.JSXElementConstructor<TellescopeFor
|
|
|
1137
1141
|
groupInstance,
|
|
1138
1142
|
uploadingFiles, setUploadingFiles, handleFileUpload,
|
|
1139
1143
|
AddToDatabase,
|
|
1140
|
-
|
|
1144
|
+
lastNavigationDirectionRef,
|
|
1145
|
+
...props
|
|
1141
1146
|
}) => {
|
|
1142
1147
|
const list = useListForFormFields(fields, responses, { form: props.form, gender: enduser?.gender })
|
|
1143
1148
|
|
|
@@ -1266,7 +1271,7 @@ export const TellescopeSinglePageForm: React.JSXElementConstructor<TellescopeFor
|
|
|
1266
1271
|
enduserId={props.enduserId} formResponseId={props.formResponseId} rootResponseId={rootResponseId} submit={submit}
|
|
1267
1272
|
enduser={enduser} goToPreviousField={goToPreviousField} isPreviousDisabled={isPreviousDisabled} goToNextField={goToNextField}
|
|
1268
1273
|
repeats={repeats} onRepeatsChange={setRepeats} setCustomerId={setCustomerId}
|
|
1269
|
-
value={value} file={file}
|
|
1274
|
+
value={value} file={file}
|
|
1270
1275
|
customInputs={customInputs}
|
|
1271
1276
|
onAddFile={onAddFile} onFieldChange={onFieldChange}
|
|
1272
1277
|
responses={responses} selectedFiles={selectedFiles}
|
|
@@ -1275,6 +1280,7 @@ export const TellescopeSinglePageForm: React.JSXElementConstructor<TellescopeFor
|
|
|
1275
1280
|
uploadingFiles={uploadingFiles} setUploadingFiles={setUploadingFiles}
|
|
1276
1281
|
handleFileUpload={handleFileUpload}
|
|
1277
1282
|
AddToDatabase={AddToDatabase}
|
|
1283
|
+
lastNavigationDirectionRef={lastNavigationDirectionRef}
|
|
1278
1284
|
/>
|
|
1279
1285
|
</Flex>
|
|
1280
1286
|
</Flex>
|
package/src/Forms/hooks.tsx
CHANGED
|
@@ -501,6 +501,41 @@ const existing_response_if_compatible = (existingResponses: FormResponseValue[]
|
|
|
501
501
|
return undefined // no valid match, write off as data loss due to incompatible type of new question
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
// Filter stale multiple-choice/dropdown selections whose options are now hidden by showCondition
|
|
505
|
+
const filter_stale_choices = (
|
|
506
|
+
value: string[] | undefined,
|
|
507
|
+
field: FormField,
|
|
508
|
+
responseContext: FormResponseValue[],
|
|
509
|
+
enduser?: Partial<Enduser>,
|
|
510
|
+
form?: Form,
|
|
511
|
+
): string[] | undefined => {
|
|
512
|
+
if (!value || !Array.isArray(value)) return value
|
|
513
|
+
if (field.type !== 'multiple_choice' && field.type !== 'Dropdown') return value
|
|
514
|
+
|
|
515
|
+
const options = field.options as { choices?: string[], optionDetails?: FormFieldOptionDetails[] } | undefined
|
|
516
|
+
if (!options?.optionDetails?.length) return value // no option-level conditions to check
|
|
517
|
+
|
|
518
|
+
const choices = options.choices ?? []
|
|
519
|
+
|
|
520
|
+
return value.filter(v => {
|
|
521
|
+
// preserve values not in the choices array (e.g. "other" free-text)
|
|
522
|
+
if (!choices.includes(v)) return true
|
|
523
|
+
|
|
524
|
+
const optionDetail = options.optionDetails?.find(d => d.option === v)
|
|
525
|
+
if (!optionDetail?.showCondition || object_is_empty(optionDetail.showCondition)) {
|
|
526
|
+
return true // no condition means always visible
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return responses_satisfy_conditions(responseContext, optionDetail.showCondition, {
|
|
530
|
+
dateOfBirth: enduser?.dateOfBirth,
|
|
531
|
+
gender: enduser?.gender,
|
|
532
|
+
state: enduser?.state,
|
|
533
|
+
form,
|
|
534
|
+
activeResponses: responseContext,
|
|
535
|
+
})
|
|
536
|
+
})
|
|
537
|
+
}
|
|
538
|
+
|
|
504
539
|
const shouldCallout = (field: FormField | undefined, value: FormResponseValueAnswer['value']) => {
|
|
505
540
|
if (!field) return false
|
|
506
541
|
if (!value) return false
|
|
@@ -546,6 +581,7 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
546
581
|
const [currentPageIndex, setCurrentPageIndex] = useState(0)
|
|
547
582
|
const [uploadingFiles, setUploadingFiles] = useState<{ fieldId: string }[]>([])
|
|
548
583
|
const prevFieldStackRef = useRef<typeof root[]>([])
|
|
584
|
+
const lastNavigationDirectionRef = useRef<'forward' | 'backward' | null>(null)
|
|
549
585
|
|
|
550
586
|
// Auto-advance state for form continuation
|
|
551
587
|
const [isAutoAdvancing, setIsAutoAdvancing] = useState(false)
|
|
@@ -654,14 +690,22 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
654
690
|
// placeholders for initial fields, reset when fields prop changes, since questions are now different (e.g. different form selected)
|
|
655
691
|
const fieldInitRef = useRef('')
|
|
656
692
|
const initializeFields = useCallback(() => (
|
|
657
|
-
fields.map(f =>
|
|
693
|
+
fields.map(f => {
|
|
694
|
+
const existingValue = existing_response_if_compatible(existingResponses, f)
|
|
695
|
+
const filteredValue = (
|
|
696
|
+
existingValue != null && Array.isArray(existingValue) && (f.type === 'multiple_choice' || f.type === 'Dropdown')
|
|
697
|
+
? filter_stale_choices(existingValue as string[], f, existingResponses ?? [], enduser, form)
|
|
698
|
+
: existingValue
|
|
699
|
+
)
|
|
700
|
+
|
|
701
|
+
return {
|
|
658
702
|
fieldId: f.id,
|
|
659
703
|
fieldTitle: f.title,
|
|
660
704
|
fieldDescription: f.description,
|
|
661
705
|
fieldHtmlDescription: f.htmlDescription,
|
|
662
706
|
externalId: f.externalId,
|
|
663
707
|
intakeField: f.intakeField || undefined,
|
|
664
|
-
touched: false,
|
|
708
|
+
touched: false,
|
|
665
709
|
includeInSubmit: false,
|
|
666
710
|
sharedWithEnduser: f.sharedWithEnduser,
|
|
667
711
|
isCalledOut: existingResponses?.find(r => r.fieldId === f.id)?.isCalledOut,
|
|
@@ -681,11 +725,11 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
681
725
|
: f?.intakeField === 'Address' && existingResponses?.find(r => r.fieldId === f.id && r.answer.type === 'Address')
|
|
682
726
|
? 'State'
|
|
683
727
|
: undefined
|
|
684
|
-
) as any,
|
|
685
|
-
answer: {
|
|
728
|
+
) as any,
|
|
729
|
+
answer: {
|
|
686
730
|
type: f.type,
|
|
687
731
|
value: (
|
|
688
|
-
|
|
732
|
+
filteredValue ?? (
|
|
689
733
|
(f.type === 'Insurance' || f.type === 'Address' || f.type === 'file' || f.type === 'signature' || f.type === 'multiple_choice' || f.type === 'Dropdown' || f.type === 'Table Input' || f.type === 'Database Select' || f.type === 'Medications' || f.type === 'Pharmacy Search')
|
|
690
734
|
? undefined
|
|
691
735
|
: f.type === 'Question Group'
|
|
@@ -711,8 +755,8 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
711
755
|
),
|
|
712
756
|
} as FormResponseValueAnswer,
|
|
713
757
|
field: f,
|
|
714
|
-
})
|
|
715
|
-
), [fields, existingResponses])
|
|
758
|
+
}})
|
|
759
|
+
), [fields, existingResponses, enduser, form])
|
|
716
760
|
|
|
717
761
|
const [responses, setResponses] = useState<(Response)[]>(initializeFields())
|
|
718
762
|
useEffect(() => {
|
|
@@ -734,12 +778,12 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
734
778
|
...response,
|
|
735
779
|
fieldTitle: replace_form_field_template_values(originalField.title || '', { enduser, responses }),
|
|
736
780
|
fieldDescription: replace_form_field_template_values(originalField.description || '', { enduser, responses }),
|
|
737
|
-
fieldHtmlDescription: replace_form_field_template_values(originalField.htmlDescription || '', { enduser, responses }),
|
|
781
|
+
fieldHtmlDescription: replace_form_field_template_values(originalField.htmlDescription || '', { enduser, responses, escapeNewlinesAsHTMLBreaks: true }),
|
|
738
782
|
field: {
|
|
739
783
|
...response.field,
|
|
740
784
|
title: replace_form_field_template_values(originalField.title || '', { enduser, responses }),
|
|
741
785
|
description: replace_form_field_template_values(originalField.description || '', { enduser, responses }),
|
|
742
|
-
htmlDescription: replace_form_field_template_values(originalField.htmlDescription || '', { enduser, responses }),
|
|
786
|
+
htmlDescription: replace_form_field_template_values(originalField.htmlDescription || '', { enduser, responses, escapeNewlinesAsHTMLBreaks: true }),
|
|
743
787
|
}
|
|
744
788
|
}
|
|
745
789
|
})
|
|
@@ -1447,12 +1491,14 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
1447
1491
|
responses: [
|
|
1448
1492
|
...responsesToSubmit,
|
|
1449
1493
|
// include existing responses in case previously saved as draft
|
|
1450
|
-
...(existingResponses ?? []).filter(r =>
|
|
1494
|
+
...(existingResponses ?? []).filter(r =>
|
|
1451
1495
|
!responsesToSubmit.find(_r => r.fieldId === _r.fieldId)
|
|
1452
1496
|
// but don't include responses which were populated from a patient field and not a prior response
|
|
1453
1497
|
// if these are edited, they would be included in responsesToSubmit
|
|
1454
1498
|
&& !r.isPrepopulatedFromEnduserField
|
|
1455
|
-
)
|
|
1499
|
+
)
|
|
1500
|
+
// initializeFields leverages filter_stale_choices to strip answers whose options are no longer visible in multiple choice type questions
|
|
1501
|
+
// existingResponses may still carry stale values for fields the user didn't interact with this session, but preserving them as-is avoids unexpected data loss
|
|
1456
1502
|
],
|
|
1457
1503
|
automationStepId,
|
|
1458
1504
|
customerId,
|
|
@@ -1549,6 +1595,7 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
1549
1595
|
if (!currentValue) return
|
|
1550
1596
|
if (isNextDisabled() && currentValue?.answer.type !== 'Hidden Value') return
|
|
1551
1597
|
|
|
1598
|
+
lastNavigationDirectionRef.current = 'forward'
|
|
1552
1599
|
console.log('going to next field')
|
|
1553
1600
|
if (currentValue.answer.type === 'Question Group') {
|
|
1554
1601
|
const responsesToSave = (
|
|
@@ -1613,6 +1660,7 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
1613
1660
|
const goToPreviousField = useCallback(() => {
|
|
1614
1661
|
if (isPreviousDisabled()) return
|
|
1615
1662
|
|
|
1663
|
+
lastNavigationDirectionRef.current = 'backward'
|
|
1616
1664
|
updateInclusion(false)
|
|
1617
1665
|
|
|
1618
1666
|
const previous = prevFieldStackRef.current.pop()
|
|
@@ -1749,6 +1797,7 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
|
|
|
1749
1797
|
uploadingFiles, setUploadingFiles,
|
|
1750
1798
|
handleFileUpload,
|
|
1751
1799
|
isAutoAdvancing,
|
|
1800
|
+
lastNavigationDirectionRef,
|
|
1752
1801
|
}
|
|
1753
1802
|
}
|
|
1754
1803
|
|
package/src/Forms/inputs.tsx
CHANGED
|
@@ -4895,7 +4895,7 @@ export const RedirectInput = ({ enduserId, groupId, groupInsance, rootResponseId
|
|
|
4895
4895
|
return null
|
|
4896
4896
|
}
|
|
4897
4897
|
|
|
4898
|
-
export const HiddenValueInput = ({ goToNextField, goToPreviousField, field, value, onChange, isSinglePage, groupFields }: FormInputProps<'email'>) => {
|
|
4898
|
+
export const HiddenValueInput = ({ goToNextField, goToPreviousField, field, value, onChange, isSinglePage, groupFields, lastNavigationDirectionRef }: FormInputProps<'email'>) => {
|
|
4899
4899
|
let lastRef = useRef(0)
|
|
4900
4900
|
let lastIdRef = useRef('')
|
|
4901
4901
|
|
|
@@ -4925,7 +4925,10 @@ export const HiddenValueInput = ({ goToNextField, goToPreviousField, field, valu
|
|
|
4925
4925
|
lastRef.current = Date.now()
|
|
4926
4926
|
lastIdRef.current = field.id
|
|
4927
4927
|
|
|
4928
|
-
|
|
4928
|
+
// Only collapse backward through a chain of hidden fields when actually navigating backward.
|
|
4929
|
+
// On forward nav (including form resume where existingResponses pre-populate the value),
|
|
4930
|
+
// fall through to the else branch so we re-set and advance instead of bouncing back.
|
|
4931
|
+
if (value && lastNavigationDirectionRef?.current === 'backward') {
|
|
4929
4932
|
if (isSinglePage) return
|
|
4930
4933
|
onChange('', field.id)
|
|
4931
4934
|
|
|
@@ -4939,7 +4942,7 @@ export const HiddenValueInput = ({ goToNextField, goToPreviousField, field, valu
|
|
|
4939
4942
|
// pass value that is set after above onChange
|
|
4940
4943
|
goToNextField?.({ type: 'Hidden Value', value: valueToSet })
|
|
4941
4944
|
}
|
|
4942
|
-
}, [value, onChange, field.id, valueToSet, goToNextField, goToPreviousField, isSinglePage, dontNavigate])
|
|
4945
|
+
}, [value, onChange, field.id, valueToSet, goToNextField, goToPreviousField, isSinglePage, dontNavigate, lastNavigationDirectionRef])
|
|
4943
4946
|
|
|
4944
4947
|
return <></>
|
|
4945
4948
|
}
|
package/src/Forms/inputs.v2.tsx
CHANGED
|
@@ -2371,56 +2371,7 @@ export const HeightInput = ({ field, value={} as any, onChange, form, ...props }
|
|
|
2371
2371
|
)
|
|
2372
2372
|
|
|
2373
2373
|
// Re-export from V1 to follow DRY principles
|
|
2374
|
-
export { RedirectInput } from './inputs'
|
|
2375
|
-
|
|
2376
|
-
export const HiddenValueInput = ({ goToNextField, goToPreviousField, field, value, onChange, isSinglePage, groupFields }: FormInputProps<'email'>) => {
|
|
2377
|
-
let lastRef = useRef(0)
|
|
2378
|
-
let lastIdRef = useRef('')
|
|
2379
|
-
|
|
2380
|
-
// in a Question Group, only the first Hidden Value should navigate
|
|
2381
|
-
// AND, it should only navigate if the group only contains hidden values
|
|
2382
|
-
const firstHiddenValue = groupFields?.find(v => v.type === 'Hidden Value')
|
|
2383
|
-
const dontNavigate = (
|
|
2384
|
-
(firstHiddenValue && firstHiddenValue?.id !== field.id) // is in a group, but not the first hidden value
|
|
2385
|
-
|| !!(groupFields?.find(v => v.type !== 'Hidden Value')) // group contains at least 1 non-hidden value
|
|
2386
|
-
)
|
|
2387
|
-
|
|
2388
|
-
const publicIdentifier = useMemo(() => {
|
|
2389
|
-
try {
|
|
2390
|
-
return new URL(window.location.href).searchParams.get('publicIdentifier') || ''
|
|
2391
|
-
} catch(err) {
|
|
2392
|
-
return ''
|
|
2393
|
-
}
|
|
2394
|
-
}, [])
|
|
2395
|
-
|
|
2396
|
-
const valueToSet = useMemo(() => (
|
|
2397
|
-
(field.title === "{{PUBLIC_IDENTIFIER}}" && publicIdentifier) ? publicIdentifier
|
|
2398
|
-
: field.title
|
|
2399
|
-
), [field.title, publicIdentifier])
|
|
2400
|
-
|
|
2401
|
-
useEffect(() => {
|
|
2402
|
-
if (lastRef.current > Date.now() - 1000 && lastIdRef.current === field.id) return
|
|
2403
|
-
lastRef.current = Date.now()
|
|
2404
|
-
lastIdRef.current = field.id
|
|
2405
|
-
|
|
2406
|
-
if (value) {
|
|
2407
|
-
if (isSinglePage) return
|
|
2408
|
-
onChange('', field.id)
|
|
2409
|
-
|
|
2410
|
-
if (dontNavigate) return
|
|
2411
|
-
goToPreviousField?.()
|
|
2412
|
-
} else {
|
|
2413
|
-
onChange(valueToSet, field.id)
|
|
2414
|
-
|
|
2415
|
-
if (dontNavigate) return
|
|
2416
|
-
|
|
2417
|
-
// pass value that is set after above onChange
|
|
2418
|
-
goToNextField?.({ type: 'Hidden Value', value: valueToSet })
|
|
2419
|
-
}
|
|
2420
|
-
}, [value, onChange, field.id, valueToSet, goToNextField, goToPreviousField, isSinglePage, dontNavigate])
|
|
2421
|
-
|
|
2422
|
-
return <></>
|
|
2423
|
-
}
|
|
2374
|
+
export { RedirectInput, HiddenValueInput } from './inputs'
|
|
2424
2375
|
|
|
2425
2376
|
export const EmotiiInput = ({ goToNextField, goToPreviousField, field, value, onChange, form, formResponseId, ...props }: FormInputProps<'email'>) => {
|
|
2426
2377
|
const session = useResolvedSession()
|
package/src/Forms/types.ts
CHANGED
|
@@ -39,6 +39,7 @@ export interface FormInputProps<K extends keyof AnswerForType> {
|
|
|
39
39
|
setUploadingFiles?: React.Dispatch<React.SetStateAction<{ fieldId: string }[]>>,
|
|
40
40
|
groupFields?: FormField[],
|
|
41
41
|
inputProps?: { sx: SxProps },
|
|
42
|
+
lastNavigationDirectionRef?: React.MutableRefObject<'forward' | 'backward' | null>,
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
export type FormInputs = {
|