@tellescope/react-components 1.230.1 → 1.231.0

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 (48) hide show
  1. package/lib/cjs/Forms/forms.d.ts.map +1 -1
  2. package/lib/cjs/Forms/forms.js +30 -28
  3. package/lib/cjs/Forms/forms.js.map +1 -1
  4. package/lib/cjs/Forms/forms.v2.d.ts.map +1 -1
  5. package/lib/cjs/Forms/forms.v2.js +32 -30
  6. package/lib/cjs/Forms/forms.v2.js.map +1 -1
  7. package/lib/cjs/Forms/hooks.d.ts +111 -3
  8. package/lib/cjs/Forms/hooks.d.ts.map +1 -1
  9. package/lib/cjs/Forms/hooks.js +26 -8
  10. package/lib/cjs/Forms/hooks.js.map +1 -1
  11. package/lib/cjs/Forms/inputs.d.ts +1 -0
  12. package/lib/cjs/Forms/inputs.d.ts.map +1 -1
  13. package/lib/cjs/Forms/inputs.js +28 -1
  14. package/lib/cjs/Forms/inputs.js.map +1 -1
  15. package/lib/cjs/Forms/inputs.v2.d.ts +1 -0
  16. package/lib/cjs/Forms/inputs.v2.d.ts.map +1 -1
  17. package/lib/cjs/Forms/inputs.v2.js +32 -32
  18. package/lib/cjs/Forms/inputs.v2.js.map +1 -1
  19. package/lib/esm/Forms/forms.d.ts +3 -3
  20. package/lib/esm/Forms/forms.d.ts.map +1 -1
  21. package/lib/esm/Forms/forms.js +31 -29
  22. package/lib/esm/Forms/forms.js.map +1 -1
  23. package/lib/esm/Forms/forms.v2.d.ts +3 -3
  24. package/lib/esm/Forms/forms.v2.d.ts.map +1 -1
  25. package/lib/esm/Forms/forms.v2.js +33 -31
  26. package/lib/esm/Forms/forms.v2.js.map +1 -1
  27. package/lib/esm/Forms/hooks.d.ts +111 -3
  28. package/lib/esm/Forms/hooks.d.ts.map +1 -1
  29. package/lib/esm/Forms/hooks.js +28 -10
  30. package/lib/esm/Forms/hooks.js.map +1 -1
  31. package/lib/esm/Forms/inputs.d.ts +2 -1
  32. package/lib/esm/Forms/inputs.d.ts.map +1 -1
  33. package/lib/esm/Forms/inputs.js +26 -0
  34. package/lib/esm/Forms/inputs.js.map +1 -1
  35. package/lib/esm/Forms/inputs.v2.d.ts +2 -1
  36. package/lib/esm/Forms/inputs.v2.d.ts.map +1 -1
  37. package/lib/esm/Forms/inputs.v2.js +32 -33
  38. package/lib/esm/Forms/inputs.v2.js.map +1 -1
  39. package/lib/esm/controls.d.ts +2 -2
  40. package/lib/esm/inputs.d.ts +1 -1
  41. package/lib/esm/state.d.ts +319 -319
  42. package/lib/tsconfig.tsbuildinfo +1 -1
  43. package/package.json +9 -9
  44. package/src/Forms/forms.tsx +6 -2
  45. package/src/Forms/forms.v2.tsx +16 -12
  46. package/src/Forms/hooks.tsx +46 -12
  47. package/src/Forms/inputs.tsx +158 -0
  48. package/src/Forms/inputs.v2.tsx +179 -65
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellescope/react-components",
3
- "version": "1.230.1",
3
+ "version": "1.231.0",
4
4
  "description": "",
5
5
  "main": "./lib/cjs/index.js",
6
6
  "module": "./lib/esm/index.js",
@@ -47,13 +47,13 @@
47
47
  "@reduxjs/toolkit": "^1.6.2",
48
48
  "@stripe/react-stripe-js": "^2.9.0",
49
49
  "@stripe/stripe-js": "^1.52.1",
50
- "@tellescope/constants": "1.230.1",
51
- "@tellescope/sdk": "1.230.1",
52
- "@tellescope/types-client": "1.230.1",
53
- "@tellescope/types-models": "1.230.1",
54
- "@tellescope/types-utilities": "1.230.1",
55
- "@tellescope/utilities": "1.230.1",
56
- "@tellescope/validation": "1.230.1",
50
+ "@tellescope/constants": "1.231.0",
51
+ "@tellescope/sdk": "1.231.0",
52
+ "@tellescope/types-client": "1.231.0",
53
+ "@tellescope/types-models": "1.231.0",
54
+ "@tellescope/types-utilities": "1.231.0",
55
+ "@tellescope/utilities": "1.231.0",
56
+ "@tellescope/validation": "1.231.0",
57
57
  "@typescript-eslint/eslint-plugin": "^4.33.0",
58
58
  "@typescript-eslint/parser": "^4.33.0",
59
59
  "css-to-react-native": "^3.0.0",
@@ -83,7 +83,7 @@
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": "0dca02b5fe32a3244d8e0a5a31ed1dd6652341c8",
86
+ "gitHead": "55bd4ea4e0ef23c03fee4eeff595f42bc501a0f9",
87
87
  "publishConfig": {
88
88
  "access": "public"
89
89
  }
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
2
2
  import { Button, CircularProgress, FileBlob, FileUploadHandler, Flex, LinearProgress, LoadingButton, Modal, Paper, Styled, Typography, form_display_text_for_language, useFileUpload, useFormResponses, useSession } from "../index"
3
3
  import { useListForFormFields, useOrganizationTheme, useTellescopeForm, WithOrganizationTheme, Response, FileResponse, NextFieldLogicOptions } from "./hooks"
4
4
  import { ChangeHandler, FormInputs } from "./types"
5
- import { AddToDatabaseProps, AddressInput, AllergiesInput, AppointmentBookingInput, ChargeebeeInput, ConditionsInput, DatabaseSelectInput, DateInput, DateStringInput, DropdownInput, EmailInput, EmotiiInput, FileInput, FilesInput, HeightInput, HiddenValueInput, InsuranceInput, LanguageSelect, MedicationsInput, MultipleChoiceInput, NumberInput, PhoneInput, Progress, RankingInput, RatingInput, RedirectInput, RelatedContactsInput, RichTextInput, SignatureInput, StringInput, StringLongInput, StripeInput, TableInput, TimeInput, TimezoneInput, defaultButtonStyles } from "./inputs"
5
+ import { AddToDatabaseProps, AddressInput, AllergiesInput, AppointmentBookingInput, BelugaPatientPreferenceInput, ChargeebeeInput, ConditionsInput, DatabaseSelectInput, DateInput, DateStringInput, DropdownInput, EmailInput, EmotiiInput, FileInput, FilesInput, HeightInput, HiddenValueInput, InsuranceInput, LanguageSelect, MedicationsInput, MultipleChoiceInput, NumberInput, 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
8
  import { FormResponseAnswerFileValue, OrganizationTheme } from "@tellescope/types-models"
@@ -190,6 +190,7 @@ export const QuestionForField = ({
190
190
  const Allergies = customInputs?.['Allergies'] ?? AllergiesInput
191
191
  const Conditions = customInputs?.['Conditions'] ?? ConditionsInput
192
192
  const RichText = customInputs?.['Rich Text'] ?? RichTextInput
193
+ const BelugaPatientPreference = customInputs?.['Beluga Patient Preference'] ?? BelugaPatientPreferenceInput
193
194
 
194
195
  const validationMessage = validateField(field)
195
196
 
@@ -324,7 +325,7 @@ export const QuestionForField = ({
324
325
  <StringLong field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'string' | 'stringLong'>} form={form} />
325
326
  )
326
327
  : field.type === 'Rich Text' ? (
327
- <RichText field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'Rich Text'>} form={form} />
328
+ <RichText key={field.id} field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'Rich Text'>} form={form} />
328
329
  )
329
330
  : field.type === 'email' ? (
330
331
  <Email field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'email'>} form={form} />
@@ -357,6 +358,9 @@ export const QuestionForField = ({
357
358
  : field.type === 'Medications' ? (
358
359
  <Medications field={field} value={value.answer.value as any} onChange={onFieldChange as ChangeHandler<'Medications'>} form={form}/>
359
360
  )
361
+ : field.type === 'Beluga Patient Preference' ? (
362
+ <BelugaPatientPreference field={field} value={value.answer.value as any} onChange={onFieldChange as ChangeHandler<'Beluga Patient Preference'>} form={form}/>
363
+ )
360
364
  : field.type === 'Insurance' ? (
361
365
  <Insurance field={field} value={value.answer.value as any} form={form}
362
366
  onDatabaseSelect={handleDatabaseSelect}
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
2
2
  import { Button, CircularProgress, FileBlob, FileUploadHandler, Flex, LinearProgress, LoadingButton, Modal, Paper, Styled, Typography, WithTheme, form_display_text_for_language, useFileUpload, useFormResponses, useSession } from "../index"
3
3
  import { useListForFormFields, useOrganizationTheme, useTellescopeForm, WithOrganizationTheme, Response, FileResponse, NextFieldLogicOptions } from "./hooks"
4
4
  import { ChangeHandler, FormInputs } from "./types"
5
- import { AddToDatabaseProps, AddressInput, AllergiesInput, AppointmentBookingInput, ChargeebeeInput, ConditionsInput, DatabaseSelectInput, DateInput, DateStringInput, DropdownInput, EmailInput, EmotiiInput, FileInput, FilesInput, HeightInput, HiddenValueInput, InsuranceInput, LanguageSelect, MedicationsInput, MultipleChoiceInput, NumberInput, PhoneInput, Progress, RankingInput, RatingInput, RedirectInput, RelatedContactsInput, RichTextInput, SignatureInput, StringInput, StringLongInput, StripeInput, TableInput, TimeInput, TimezoneInput, defaultButtonStyles } from "./inputs.v2"
5
+ import { AddToDatabaseProps, AddressInput, AllergiesInput, AppointmentBookingInput, BelugaPatientPreferenceInput, ChargeebeeInput, ConditionsInput, DatabaseSelectInput, DateInput, DateStringInput, DropdownInput, EmailInput, EmotiiInput, FileInput, FilesInput, HeightInput, HiddenValueInput, InsuranceInput, LanguageSelect, MedicationsInput, MultipleChoiceInput, NumberInput, PhoneInput, Progress, RankingInput, RatingInput, RedirectInput, RelatedContactsInput, RichTextInput, SignatureInput, StringInput, StringLongInput, StripeInput, TableInput, TimeInput, TimezoneInput, defaultButtonStyles } from "./inputs.v2"
6
6
  import { PRIMARY_HEX } from "@tellescope/constants"
7
7
  import { FormResponse, FormField, Form, Enduser } from "@tellescope/types-client"
8
8
  import { FormResponseAnswerFileValue, OrganizationTheme } from "@tellescope/types-models"
@@ -183,6 +183,7 @@ export const QuestionForField = ({
183
183
  const Allergies = customInputs?.['Allergies'] ?? AllergiesInput
184
184
  const Conditions = customInputs?.['Conditions'] ?? ConditionsInput
185
185
  const RichText = customInputs?.['Rich Text'] ?? RichTextInput
186
+ const BelugaPatientPreference = customInputs?.['Beluga Patient Preference'] ?? BelugaPatientPreferenceInput
186
187
 
187
188
  const validationMessage = validateField(field)
188
189
 
@@ -203,9 +204,9 @@ export const QuestionForField = ({
203
204
  ) {
204
205
  return null
205
206
  }
206
- return (
207
+ return (
207
208
  // margin leaves room for error message in Question Group
208
- <Flex column flex={1} style={{ marginBottom: spacing ?? 25 }} id={field.id}>
209
+ <Flex column flex={1} style={{ marginBottom: spacing ?? 25 }} id={field.id}>
209
210
  {field.type !== 'Redirect' && field.title &&
210
211
  <Typography component="h4" style={{
211
212
  marginTop: 15, // ensures PDF display doesn't push description into overlap with logo / title at top of form
@@ -222,13 +223,15 @@ export const QuestionForField = ({
222
223
  <div style={{ marginTop: 15 }}></div>
223
224
  }
224
225
 
225
- {feedback.length > 0 &&
226
+ <Description field={field} style={{ fontSize: 14, color: '#00000099', marginBottom: 11 }} />
227
+
228
+ {feedback.length > 0 &&
226
229
  <Flex column style={{ marginBottom: 11, marginTop: 3, }}>
227
230
  {feedback.map((f, i) => (
228
231
  <Typography key={i} color="error" style={{ fontSize: 20 }}>
229
232
  {f}
230
233
  </Typography>
231
- ))}
234
+ ))}
232
235
  </Flex>
233
236
  }
234
237
 
@@ -316,7 +319,7 @@ export const QuestionForField = ({
316
319
  <StringLong field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'string' | 'stringLong'>} form={form} error={!!validationMessage && (!['A response is required', 'A value must be checked', 'A file is required', 'Enter a valid phone number', 'Insurer is required'].includes(validationMessage) || value.touched)} />
317
320
  )
318
321
  : field.type === 'Rich Text' ? (
319
- <RichText field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'Rich Text'>} form={form} />
322
+ <RichText key={field.id} field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'Rich Text'>} form={form} />
320
323
  )
321
324
  : field.type === 'email' ? (
322
325
  <Email field={field} disabled={value.disabled} value={value.answer.value as string} onChange={onFieldChange as ChangeHandler<'email'>} form={form} error={!!validationMessage && (!['A response is required', 'A value must be checked', 'A file is required', 'Enter a valid phone number', 'Insurer is required'].includes(validationMessage) || value.touched)} />
@@ -349,6 +352,9 @@ export const QuestionForField = ({
349
352
  : field.type === 'Medications' ? (
350
353
  <Medications field={field} value={value.answer.value as any} onChange={onFieldChange as ChangeHandler<'Medications'>} form={form}/>
351
354
  )
355
+ : field.type === 'Beluga Patient Preference' ? (
356
+ <BelugaPatientPreference field={field} value={value.answer.value as any} onChange={onFieldChange as ChangeHandler<'Beluga Patient Preference'>} form={form}/>
357
+ )
352
358
  : field.type === 'Insurance' ? (
353
359
  <Insurance field={field} value={value.answer.value as any} form={form}
354
360
  onDatabaseSelect={handleDatabaseSelect}
@@ -431,17 +437,15 @@ export const QuestionForField = ({
431
437
  </Flex>
432
438
  )}
433
439
 
434
- <Description field={field} style={{ fontSize: 14, color: '#00000099', marginTop: 4 }} />
435
-
436
440
  {field.type !== 'Question Group' &&
437
- <Typography color="error" style={{ marginTop: 3, height: 10, fontSize: 14, marginBottom: -10 }}>
441
+ <Typography color="error" style={{ marginTop: 3, height: 10, fontSize: 14, marginBottom: -10 }}>
438
442
  {(validationMessage === 'A response is required' || validationMessage === 'A value must be checked' || validationMessage === 'A file is required' || 'Enter a valid phone number' || 'Insurer is required')
439
- ? value.touched
443
+ ? value.touched
440
444
  ? form_display_text_for_language(form, validationMessage)
441
- : null
445
+ : null
442
446
  : form_display_text_for_language(form, validationMessage)
443
447
  }
444
- </Typography>
448
+ </Typography>
445
449
  }
446
450
  </Flex>
447
451
  )
@@ -1,4 +1,4 @@
1
- import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react"
1
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"
2
2
  import { Session } from "@tellescope/sdk"
3
3
  import { ChangeHandler, FormFieldNode } from "./types"
4
4
  import { DatabaseRecord, Enduser, Form, FormField, FormResponse } from "@tellescope/types-client"
@@ -9,7 +9,7 @@ import { WithTheme, contact_is_valid, useAddGTMTag, useFileUpload, useFormFields
9
9
  import ReactGA from "react-ga4";
10
10
 
11
11
  import isEmail from "validator/lib/isEmail"
12
- import { append_current_utm_params, emit_gtm_event, field_can_autoadvance, getLocalTimezone, get_time_values, get_utm_params, is_object, object_is_empty, read_local_storage, responses_satisfy_conditions, update_local_storage } from "@tellescope/utilities"
12
+ import { append_current_utm_params, emit_gtm_event, field_can_autoadvance, getLocalTimezone, get_time_values, get_utm_params, is_object, object_is_empty, read_local_storage, replace_form_field_template_values, responses_satisfy_conditions, update_local_storage } from "@tellescope/utilities"
13
13
 
14
14
  export const useFlattenedTree = (root?: FormFieldNode) => {
15
15
  const flat: FormField[] = []
@@ -684,7 +684,27 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
684
684
  setResponses(initializeFields())
685
685
  }, [formId, initializeFields])
686
686
 
687
-
687
+ // Create templated versions of responses for UI display
688
+ // This applies template value replacements (e.g., {{enduser.BMI}}) to field titles/descriptions
689
+ // The templated responses are used ONLY for display and submission, not for navigation logic
690
+ const templatedResponses = useMemo(() => {
691
+ return responses.map(response => {
692
+ const originalField = fields.find(f => f.id === response.fieldId) || response.field
693
+
694
+ return {
695
+ ...response,
696
+ fieldTitle: replace_form_field_template_values(originalField.title || '', { enduser, responses }),
697
+ fieldDescription: replace_form_field_template_values(originalField.description || '', { enduser, responses }),
698
+ fieldHtmlDescription: replace_form_field_template_values(originalField.htmlDescription || '', { enduser, responses }),
699
+ field: {
700
+ ...response.field,
701
+ title: replace_form_field_template_values(originalField.title || '', { enduser, responses }),
702
+ description: replace_form_field_template_values(originalField.description || '', { enduser, responses }),
703
+ htmlDescription: replace_form_field_template_values(originalField.htmlDescription || '', { enduser, responses }),
704
+ }
705
+ }
706
+ })
707
+ }, [responses, fields, enduser])
688
708
 
689
709
  // placeholders for initial files, reset when fields prop changes, since questions are now different (e.g. different form selected)
690
710
  const fileInitRef = useRef('')
@@ -706,15 +726,28 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
706
726
  }, [formId, initializeFiles])
707
727
 
708
728
  const currentValue = (
709
- responses.find(f => f.fieldId === activeField.value.id)
729
+ templatedResponses.find(f => f.fieldId === activeField.value.id)
710
730
  )
711
731
  const currentFileValue = (
712
732
  selectedFiles.find(f => f.fieldId === activeField.value.id)
713
733
  )
714
734
 
735
+ // Create templated version of activeField for UI display
736
+ // This applies template replacements to the field's title/description
737
+ const templatedActiveField = useMemo(() => {
738
+ const templatedResponse = templatedResponses.find(r => r.fieldId === activeField.value.id)
739
+ if (templatedResponse) {
740
+ return {
741
+ ...activeField,
742
+ value: templatedResponse.field
743
+ }
744
+ }
745
+ return activeField
746
+ }, [activeField, templatedResponses])
747
+
715
748
  const logicOptions: NextFieldLogicOptions = {
716
749
  urlLogicValue,
717
- activeResponses: responses.filter(r => r.includeInSubmit),
750
+ activeResponses: templatedResponses.filter(r => r.includeInSubmit),
718
751
  dateOfBirth: enduser?.dateOfBirth,
719
752
  gender: enduser?.gender,
720
753
  state: enduser?.state,
@@ -1274,10 +1307,11 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
1274
1307
 
1275
1308
  if (!accessCode && session.type === 'enduser') throw new Error('enduser session without accessCode')
1276
1309
  try {
1310
+ // Use templatedResponses for submission to ensure template values are resolved
1277
1311
  const responsesToSubmit = (
1278
- options?.includedFieldIds
1279
- ? options.includedFieldIds.map(id => responses.find(r => r.fieldId === id)!)
1280
- : responses.filter(r => r.includeInSubmit)
1312
+ options?.includedFieldIds
1313
+ ? options.includedFieldIds.map(id => templatedResponses.find(r => r.fieldId === id)!)
1314
+ : templatedResponses.filter(r => r.includeInSubmit)
1281
1315
  )
1282
1316
 
1283
1317
  // ensure Question Group responses are included
@@ -1286,7 +1320,7 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
1286
1320
  if (r.answer.type !== 'Question Group') continue
1287
1321
 
1288
1322
  for (const f of r.answer.value ?? []) {
1289
- const match = responses.find(r => r.fieldId === f?.id)
1323
+ const match = templatedResponses.find(r => r.fieldId === f?.id)
1290
1324
  if (!match || responsesToSubmit.find(r => r.fieldId === match.fieldId)) continue
1291
1325
 
1292
1326
  // hidden in group by conditional logic
@@ -1403,7 +1437,7 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
1403
1437
  } finally {
1404
1438
  setSubmittingStatus(undefined)
1405
1439
  }
1406
- }, [accessCode, automationStepId, enduserId, responses, selectedFiles, session, handleUpload, existingResponses, ga4measurementId, rootResponseId, parentResponseId, calendarEventId, goBackURL, logicOptions, handleFileUpload])
1440
+ }, [accessCode, automationStepId, enduserId, responses, templatedResponses, selectedFiles, session, handleUpload, existingResponses, ga4measurementId, rootResponseId, parentResponseId, calendarEventId, goBackURL, logicOptions, handleFileUpload])
1407
1441
 
1408
1442
  const isNextDisabled = useCallback(() => {
1409
1443
  if (uploadingFiles.length) { return true }
@@ -1589,12 +1623,12 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
1589
1623
  return {
1590
1624
  enduserId,
1591
1625
  formResponseId,
1592
- activeField,
1626
+ activeField: templatedActiveField, // Use templated activeField for UI display
1593
1627
  currentValue,
1594
1628
  currentFileValue,
1595
1629
  getResponsesWithQuestionGroupAnswers,
1596
1630
  fields,
1597
- responses,
1631
+ responses: templatedResponses, // Use templated responses - only display fields differ, answer values unchanged
1598
1632
  selectedFiles,
1599
1633
  onFieldChange,
1600
1634
  onAddFile,
@@ -2948,6 +2948,164 @@ export const MedicationsInput = ({ field, value, onChange, ...props }: FormInput
2948
2948
  )
2949
2949
  }
2950
2950
 
2951
+ export const BelugaPatientPreferenceInput = ({ field, value: _value, onChange }: FormInputProps<'Beluga Patient Preference'>) => {
2952
+ const value = Array.isArray(_value) ? _value : []
2953
+
2954
+ return (
2955
+ <Grid container direction="column" sx={{ mt: 2 }}>
2956
+ {value.map((v, i) => (
2957
+ <>
2958
+ <Grid item key={i}>
2959
+ <Grid container alignItems="center" wrap="nowrap">
2960
+ <Grid item sx={{ width: '100%'}}>
2961
+ <Grid container direction="column" spacing={1.5}>
2962
+ <Grid item>
2963
+ <TextField label="Medication Name" size="small" fullWidth required
2964
+ value={v.name ?? ''}
2965
+ onChange={e =>
2966
+ onChange(
2967
+ value.map((_v, _i) => (
2968
+ i === _i ? { ..._v, name: e.target.value } : _v
2969
+ )),
2970
+ field.id,
2971
+ )
2972
+ }
2973
+ />
2974
+ </Grid>
2975
+
2976
+ <Grid item>
2977
+ <Grid container spacing={1}>
2978
+ <Grid item xs={12} md={6}>
2979
+ <TextField label="Strength" size="small" fullWidth required
2980
+ value={v.strength ?? ''}
2981
+ onChange={e =>
2982
+ onChange(
2983
+ value.map((_v, _i) => (
2984
+ i === _i ? { ..._v, strength: e.target.value } : _v
2985
+ )),
2986
+ field.id,
2987
+ )
2988
+ }
2989
+ />
2990
+ </Grid>
2991
+ <Grid item xs={12} md={6}>
2992
+ <TextField label="Dispense Unit" size="small" fullWidth required
2993
+ value={v.dispenseUnit ?? ''}
2994
+ onChange={e =>
2995
+ onChange(
2996
+ value.map((_v, _i) => (
2997
+ i === _i ? { ..._v, dispenseUnit: e.target.value } : _v
2998
+ )),
2999
+ field.id,
3000
+ )
3001
+ }
3002
+ />
3003
+ </Grid>
3004
+ </Grid>
3005
+ </Grid>
3006
+
3007
+ <Grid item>
3008
+ <Grid container spacing={1}>
3009
+ <Grid item xs={12} md={4}>
3010
+ <TextField label="Quantity" size="small" fullWidth required
3011
+ value={v.quantity ?? ''}
3012
+ onChange={e =>
3013
+ onChange(
3014
+ value.map((_v, _i) => (
3015
+ i === _i ? { ..._v, quantity: e.target.value } : _v
3016
+ )),
3017
+ field.id,
3018
+ )
3019
+ }
3020
+ />
3021
+ </Grid>
3022
+ <Grid item xs={12} md={4}>
3023
+ <TextField label="Refills" size="small" fullWidth required
3024
+ value={v.refills ?? ''}
3025
+ onChange={e =>
3026
+ onChange(
3027
+ value.map((_v, _i) => (
3028
+ i === _i ? { ..._v, refills: e.target.value } : _v
3029
+ )),
3030
+ field.id,
3031
+ )
3032
+ }
3033
+ />
3034
+ </Grid>
3035
+ <Grid item xs={12} md={4}>
3036
+ <TextField label="Days Supply" size="small" fullWidth required
3037
+ value={v.daysSupply ?? ''}
3038
+ onChange={e =>
3039
+ onChange(
3040
+ value.map((_v, _i) => (
3041
+ i === _i ? { ..._v, daysSupply: e.target.value } : _v
3042
+ )),
3043
+ field.id,
3044
+ )
3045
+ }
3046
+ />
3047
+ </Grid>
3048
+ </Grid>
3049
+ </Grid>
3050
+
3051
+ <Grid item>
3052
+ <TextField label="Sig (Instructions)" size="small" fullWidth required multiline rows={2}
3053
+ value={v.sig ?? ''}
3054
+ onChange={e =>
3055
+ onChange(
3056
+ value.map((_v, _i) => (
3057
+ i === _i ? { ..._v, sig: e.target.value } : _v
3058
+ )),
3059
+ field.id,
3060
+ )
3061
+ }
3062
+ />
3063
+ </Grid>
3064
+
3065
+ <Grid item>
3066
+ <TextField label="Med ID (NDC11)" size="small" fullWidth required
3067
+ value={v.medId ?? ''}
3068
+ onChange={e =>
3069
+ onChange(
3070
+ value.map((_v, _i) => (
3071
+ i === _i ? { ..._v, medId: e.target.value } : _v
3072
+ )),
3073
+ field.id,
3074
+ )
3075
+ }
3076
+ />
3077
+ </Grid>
3078
+
3079
+ <Grid item>
3080
+ <Typography color="primary" sx={{ textDecoration: 'underline', cursor: 'pointer' }}
3081
+ onClick={() => onChange(value.filter((_, _i) => i !== _i), field.id)}
3082
+ >
3083
+ Remove medication
3084
+ </Typography>
3085
+ </Grid>
3086
+ </Grid>
3087
+ </Grid>
3088
+ </Grid>
3089
+ </Grid>
3090
+
3091
+ <Grid item><Divider flexItem sx={{ my: 1 }} /></Grid>
3092
+ </>
3093
+ ))}
3094
+
3095
+ <Grid item>
3096
+ <Button color="primary" variant="outlined"
3097
+ onClick={() => onChange([
3098
+ ...value,
3099
+ { name: '', strength: '', quantity: '', refills: '', daysSupply: '', sig: '', dispenseUnit: '', medId: '' }
3100
+ ], field.id)}
3101
+ >
3102
+ Add Medication
3103
+ </Button>
3104
+ </Grid>
3105
+ </Grid>
3106
+ )
3107
+ }
3108
+
2951
3109
  export const contact_is_valid = (e: Partial<Enduser>) => {
2952
3110
  if (e.email) {
2953
3111
  try {