@tellescope/react-components 1.230.1 → 1.230.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.
Files changed (53) hide show
  1. package/lib/cjs/Forms/forms.d.ts.map +1 -1
  2. package/lib/cjs/Forms/forms.js +29 -27
  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 +29 -27
  6. package/lib/cjs/Forms/forms.v2.js.map +1 -1
  7. package/lib/cjs/Forms/hooks.d.ts.map +1 -1
  8. package/lib/cjs/Forms/hooks.js +30 -4
  9. package/lib/cjs/Forms/hooks.js.map +1 -1
  10. package/lib/cjs/Forms/inputs.d.ts +1 -0
  11. package/lib/cjs/Forms/inputs.d.ts.map +1 -1
  12. package/lib/cjs/Forms/inputs.js +28 -1
  13. package/lib/cjs/Forms/inputs.js.map +1 -1
  14. package/lib/cjs/Forms/inputs.v2.d.ts +1 -0
  15. package/lib/cjs/Forms/inputs.v2.d.ts.map +1 -1
  16. package/lib/cjs/Forms/inputs.v2.js +28 -1
  17. package/lib/cjs/Forms/inputs.v2.js.map +1 -1
  18. package/lib/esm/CMS/components.d.ts +0 -1
  19. package/lib/esm/CMS/components.d.ts.map +1 -1
  20. package/lib/esm/Forms/form_responses.d.ts +0 -1
  21. package/lib/esm/Forms/form_responses.d.ts.map +1 -1
  22. package/lib/esm/Forms/forms.d.ts +3 -3
  23. package/lib/esm/Forms/forms.d.ts.map +1 -1
  24. package/lib/esm/Forms/forms.js +30 -28
  25. package/lib/esm/Forms/forms.js.map +1 -1
  26. package/lib/esm/Forms/forms.v2.d.ts +3 -3
  27. package/lib/esm/Forms/forms.v2.d.ts.map +1 -1
  28. package/lib/esm/Forms/forms.v2.js +30 -28
  29. package/lib/esm/Forms/forms.v2.js.map +1 -1
  30. package/lib/esm/Forms/hooks.d.ts +0 -1
  31. package/lib/esm/Forms/hooks.d.ts.map +1 -1
  32. package/lib/esm/Forms/hooks.js +31 -5
  33. package/lib/esm/Forms/hooks.js.map +1 -1
  34. package/lib/esm/Forms/inputs.d.ts +1 -0
  35. package/lib/esm/Forms/inputs.d.ts.map +1 -1
  36. package/lib/esm/Forms/inputs.js +26 -0
  37. package/lib/esm/Forms/inputs.js.map +1 -1
  38. package/lib/esm/Forms/inputs.v2.d.ts +1 -0
  39. package/lib/esm/Forms/inputs.v2.d.ts.map +1 -1
  40. package/lib/esm/Forms/inputs.v2.js +26 -0
  41. package/lib/esm/Forms/inputs.v2.js.map +1 -1
  42. package/lib/esm/controls.d.ts +2 -2
  43. package/lib/esm/inputs.d.ts +1 -1
  44. package/lib/esm/inputs.native.d.ts +0 -1
  45. package/lib/esm/inputs.native.d.ts.map +1 -1
  46. package/lib/esm/state.d.ts +40 -40
  47. package/lib/tsconfig.tsbuildinfo +1 -1
  48. package/package.json +9 -9
  49. package/src/Forms/forms.tsx +5 -1
  50. package/src/Forms/forms.v2.tsx +5 -1
  51. package/src/Forms/hooks.tsx +55 -8
  52. package/src/Forms/inputs.tsx +158 -0
  53. package/src/Forms/inputs.v2.tsx +166 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellescope/react-components",
3
- "version": "1.230.1",
3
+ "version": "1.230.2",
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.230.2",
51
+ "@tellescope/sdk": "1.230.2",
52
+ "@tellescope/types-client": "1.230.2",
53
+ "@tellescope/types-models": "1.230.2",
54
+ "@tellescope/types-utilities": "1.230.2",
55
+ "@tellescope/utilities": "1.230.2",
56
+ "@tellescope/validation": "1.230.2",
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": "0bc1e80c698398e1c62c4f026fa76475883f2396",
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
 
@@ -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
 
@@ -349,6 +350,9 @@ export const QuestionForField = ({
349
350
  : field.type === 'Medications' ? (
350
351
  <Medications field={field} value={value.answer.value as any} onChange={onFieldChange as ChangeHandler<'Medications'>} form={form}/>
351
352
  )
353
+ : field.type === 'Beluga Patient Preference' ? (
354
+ <BelugaPatientPreference field={field} value={value.answer.value as any} onChange={onFieldChange as ChangeHandler<'Beluga Patient Preference'>} form={form}/>
355
+ )
352
356
  : field.type === 'Insurance' ? (
353
357
  <Insurance field={field} value={value.answer.value as any} form={form}
354
358
  onDatabaseSelect={handleDatabaseSelect}
@@ -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[] = []
@@ -1419,6 +1419,30 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
1419
1419
  return false
1420
1420
  }, [activeField, validateField, uploadingFiles])
1421
1421
 
1422
+ // Helper function to apply templating to responses
1423
+ // Templates field titles/descriptions with current enduser data and form response values
1424
+ // Can be called whenever we need to update templates (e.g., on "next" button click)
1425
+ const applyTemplatingToResponses = useCallback((
1426
+ currentResponses: Response[]
1427
+ ): Response[] => {
1428
+ return currentResponses.map(response => {
1429
+ const originalField = fields.find(f => f.id === response.fieldId) || response.field
1430
+
1431
+ return {
1432
+ ...response,
1433
+ fieldTitle: replace_form_field_template_values(originalField.title || '', { enduser, responses: currentResponses }),
1434
+ fieldDescription: replace_form_field_template_values(originalField.description || '', { enduser, responses: currentResponses }),
1435
+ fieldHtmlDescription: replace_form_field_template_values(originalField.htmlDescription || '', { enduser, responses: currentResponses }),
1436
+ field: {
1437
+ ...response.field,
1438
+ title: replace_form_field_template_values(originalField.title || '', { enduser, responses: currentResponses }),
1439
+ description: replace_form_field_template_values(originalField.description || '', { enduser, responses: currentResponses }),
1440
+ htmlDescription: replace_form_field_template_values(originalField.htmlDescription || '', { enduser, responses: currentResponses }),
1441
+ }
1442
+ }
1443
+ })
1444
+ }, [fields, enduser])
1445
+
1422
1446
  const autoAdvanceRef = useRef(false)
1423
1447
  // don't make option, to avoid user passing invalid data, like an onclick event
1424
1448
  const goToNextField = useCallback((answer: FormResponseValue['answer'] | undefined) => {
@@ -1426,10 +1450,24 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
1426
1450
  if (isNextDisabled() && currentValue?.answer.type !== 'Hidden Value') return
1427
1451
 
1428
1452
  console.log('going to next field')
1453
+
1454
+ // If an answer is provided (e.g., from Hidden Value), update responses first
1455
+ const responsesWithAnswer = answer
1456
+ ? responses.map(r =>
1457
+ r.fieldId === currentValue.fieldId
1458
+ ? { ...r, answer }
1459
+ : r
1460
+ )
1461
+ : responses
1462
+
1463
+ // Apply templating to all responses including the newly updated answer
1464
+ const templatedResponses = applyTemplatingToResponses(responsesWithAnswer)
1465
+ setResponses(templatedResponses)
1466
+
1429
1467
  if (currentValue.answer.type === 'Question Group') {
1430
1468
  const responsesToSave = (
1431
1469
  (currentValue.field.options?.subFields || [])
1432
- .map(({ id }) => responses.find(f => f.fieldId === id)!)
1470
+ .map(({ id }) => templatedResponses.find(f => f.fieldId === id)!)
1433
1471
  .filter(f => f && f?.answer.type !== 'file' && f?.answer.type !== 'files')
1434
1472
  )
1435
1473
  if (responsesToSave.length) {
@@ -1440,7 +1478,7 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
1440
1478
  })
1441
1479
  .catch(console.error)
1442
1480
  }
1443
- }
1481
+ }
1444
1482
  else if (currentValue?.answer?.type !== 'file' && currentValue?.answer?.type !== 'files' && (formResponseId || accessCode)) {
1445
1483
  session.api.form_responses.save_field_response({
1446
1484
  accessCode,
@@ -1455,17 +1493,26 @@ export const useTellescopeForm = ({ dontAutoadvance, isPublicForm, form, urlLogi
1455
1493
 
1456
1494
  try { window.scrollTo({ top: 0 }) } catch(err) {} // scroll to top if needed
1457
1495
  setActiveField(activeField => {
1458
- let newField = getNextField(activeField, currentValue, responses, logicOptions)
1496
+ let newField = getNextField(activeField, currentValue, templatedResponses, logicOptions)
1459
1497
 
1460
1498
  // when autoadvancing, prevent adding duplicates by checking whether already on stack
1461
1499
  if (newField !== undefined && !prevFieldStackRef.current.find(v => v.value.id === activeField?.value.id)) {
1462
1500
  prevFieldStackRef.current.push(activeField)
1463
1501
  setCurrentPageIndex(i => i + 1)
1464
1502
  }
1465
-
1466
- return newField || activeField
1503
+
1504
+ const fieldToReturn = newField || activeField
1505
+
1506
+ // Apply templating to the active field by pulling from the templated responses
1507
+ // This ensures the UI displays templated titles/descriptions immediately
1508
+ const templatedResponse = templatedResponses.find(r => r.fieldId === fieldToReturn.value.id)
1509
+ if (templatedResponse) {
1510
+ fieldToReturn.value = templatedResponse.field
1511
+ }
1512
+
1513
+ return fieldToReturn
1467
1514
  })
1468
- }, [prevFieldStackRef, currentValue, isNextDisabled, updateFormResponse, session, responses, logicOptions, accessCode, formResponseId, setActiveField, setCurrentPageIndex])
1515
+ }, [prevFieldStackRef, currentValue, isNextDisabled, updateFormResponse, session, responses, logicOptions, accessCode, formResponseId, setActiveField, setCurrentPageIndex, applyTemplatingToResponses])
1469
1516
 
1470
1517
  useEffect(() => {
1471
1518
  if (dontAutoadvance) return
@@ -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 {
@@ -2973,6 +2973,172 @@ export const MedicationsInput = ({ field, value, onChange, ...props }: FormInput
2973
2973
  )
2974
2974
  }
2975
2975
 
2976
+ export const BelugaPatientPreferenceInput = ({ field, value: _value, onChange }: FormInputProps<'Beluga Patient Preference'>) => {
2977
+ const value = Array.isArray(_value) ? _value : []
2978
+
2979
+ return (
2980
+ <Grid container direction="column" sx={{ mt: 2 }}>
2981
+ {value.map((v, i) => (
2982
+ <>
2983
+ <Grid item key={i}>
2984
+ <Grid container alignItems="center" wrap="nowrap">
2985
+ <Grid item sx={{ width: '100%'}}>
2986
+ <Grid container direction="column" spacing={1.5}>
2987
+ <Grid item>
2988
+ <TextField label="Medication Name" size="small" fullWidth required
2989
+ InputProps={defaultInputProps}
2990
+ value={v.name ?? ''}
2991
+ onChange={e =>
2992
+ onChange(
2993
+ value.map((_v, _i) => (
2994
+ i === _i ? { ..._v, name: e.target.value } : _v
2995
+ )),
2996
+ field.id,
2997
+ )
2998
+ }
2999
+ />
3000
+ </Grid>
3001
+
3002
+ <Grid item>
3003
+ <Grid container spacing={1}>
3004
+ <Grid item xs={12} md={6}>
3005
+ <TextField label="Strength" size="small" fullWidth required
3006
+ InputProps={defaultInputProps}
3007
+ value={v.strength ?? ''}
3008
+ onChange={e =>
3009
+ onChange(
3010
+ value.map((_v, _i) => (
3011
+ i === _i ? { ..._v, strength: e.target.value } : _v
3012
+ )),
3013
+ field.id,
3014
+ )
3015
+ }
3016
+ />
3017
+ </Grid>
3018
+ <Grid item xs={12} md={6}>
3019
+ <TextField label="Dispense Unit" size="small" fullWidth required
3020
+ InputProps={defaultInputProps}
3021
+ value={v.dispenseUnit ?? ''}
3022
+ onChange={e =>
3023
+ onChange(
3024
+ value.map((_v, _i) => (
3025
+ i === _i ? { ..._v, dispenseUnit: e.target.value } : _v
3026
+ )),
3027
+ field.id,
3028
+ )
3029
+ }
3030
+ />
3031
+ </Grid>
3032
+ </Grid>
3033
+ </Grid>
3034
+
3035
+ <Grid item>
3036
+ <Grid container spacing={1}>
3037
+ <Grid item xs={12} md={4}>
3038
+ <TextField label="Quantity" size="small" fullWidth required
3039
+ InputProps={defaultInputProps}
3040
+ value={v.quantity ?? ''}
3041
+ onChange={e =>
3042
+ onChange(
3043
+ value.map((_v, _i) => (
3044
+ i === _i ? { ..._v, quantity: e.target.value } : _v
3045
+ )),
3046
+ field.id,
3047
+ )
3048
+ }
3049
+ />
3050
+ </Grid>
3051
+ <Grid item xs={12} md={4}>
3052
+ <TextField label="Refills" size="small" fullWidth required
3053
+ InputProps={defaultInputProps}
3054
+ value={v.refills ?? ''}
3055
+ onChange={e =>
3056
+ onChange(
3057
+ value.map((_v, _i) => (
3058
+ i === _i ? { ..._v, refills: e.target.value } : _v
3059
+ )),
3060
+ field.id,
3061
+ )
3062
+ }
3063
+ />
3064
+ </Grid>
3065
+ <Grid item xs={12} md={4}>
3066
+ <TextField label="Days Supply" size="small" fullWidth required
3067
+ InputProps={defaultInputProps}
3068
+ value={v.daysSupply ?? ''}
3069
+ onChange={e =>
3070
+ onChange(
3071
+ value.map((_v, _i) => (
3072
+ i === _i ? { ..._v, daysSupply: e.target.value } : _v
3073
+ )),
3074
+ field.id,
3075
+ )
3076
+ }
3077
+ />
3078
+ </Grid>
3079
+ </Grid>
3080
+ </Grid>
3081
+
3082
+ <Grid item>
3083
+ <TextField label="Sig (Instructions)" size="small" fullWidth required multiline rows={2}
3084
+ InputProps={defaultInputProps}
3085
+ value={v.sig ?? ''}
3086
+ onChange={e =>
3087
+ onChange(
3088
+ value.map((_v, _i) => (
3089
+ i === _i ? { ..._v, sig: e.target.value } : _v
3090
+ )),
3091
+ field.id,
3092
+ )
3093
+ }
3094
+ />
3095
+ </Grid>
3096
+
3097
+ <Grid item>
3098
+ <TextField label="Med ID (NDC11)" size="small" fullWidth required
3099
+ InputProps={defaultInputProps}
3100
+ value={v.medId ?? ''}
3101
+ onChange={e =>
3102
+ onChange(
3103
+ value.map((_v, _i) => (
3104
+ i === _i ? { ..._v, medId: e.target.value } : _v
3105
+ )),
3106
+ field.id,
3107
+ )
3108
+ }
3109
+ />
3110
+ </Grid>
3111
+
3112
+ <Grid item>
3113
+ <Typography color="primary" sx={{ textDecoration: 'underline', cursor: 'pointer' }}
3114
+ onClick={() => onChange(value.filter((_, _i) => i !== _i), field.id)}
3115
+ >
3116
+ Remove medication
3117
+ </Typography>
3118
+ </Grid>
3119
+ </Grid>
3120
+ </Grid>
3121
+ </Grid>
3122
+ </Grid>
3123
+
3124
+ <Grid item><Divider flexItem sx={{ my: 1 }} /></Grid>
3125
+ </>
3126
+ ))}
3127
+
3128
+ <Grid item>
3129
+ <Button color="primary" variant="outlined"
3130
+ onClick={() => onChange([
3131
+ ...value,
3132
+ { name: '', strength: '', quantity: '', refills: '', daysSupply: '', sig: '', dispenseUnit: '', medId: '' }
3133
+ ], field.id)}
3134
+ >
3135
+ Add Medication
3136
+ </Button>
3137
+ </Grid>
3138
+ </Grid>
3139
+ )
3140
+ }
3141
+
2976
3142
  export const contact_is_valid = (e: Partial<Enduser>) => {
2977
3143
  if (e.email) {
2978
3144
  try {