@tellescope/react-components 1.157.1 → 1.159.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 (54) hide show
  1. package/lib/cjs/CMS/components.d.ts +1 -0
  2. package/lib/cjs/CMS/components.d.ts.map +1 -1
  3. package/lib/cjs/Forms/form_responses.d.ts +1 -0
  4. package/lib/cjs/Forms/form_responses.d.ts.map +1 -1
  5. package/lib/cjs/Forms/forms.js +1 -1
  6. package/lib/cjs/Forms/forms.js.map +1 -1
  7. package/lib/cjs/Forms/hooks.d.ts +2 -0
  8. package/lib/cjs/Forms/hooks.d.ts.map +1 -1
  9. package/lib/cjs/Forms/hooks.js +11 -3
  10. package/lib/cjs/Forms/hooks.js.map +1 -1
  11. package/lib/cjs/Forms/inputs.d.ts.map +1 -1
  12. package/lib/cjs/Forms/inputs.js +78 -28
  13. package/lib/cjs/Forms/inputs.js.map +1 -1
  14. package/lib/cjs/controls.d.ts +2 -2
  15. package/lib/cjs/inputs.native.d.ts +1 -0
  16. package/lib/cjs/inputs.native.d.ts.map +1 -1
  17. package/lib/cjs/mui.d.ts +2 -1
  18. package/lib/cjs/mui.d.ts.map +1 -1
  19. package/lib/cjs/mui.js +2 -2
  20. package/lib/cjs/mui.js.map +1 -1
  21. package/lib/cjs/state.js +1 -1
  22. package/lib/cjs/state.js.map +1 -1
  23. package/lib/esm/CMS/components.d.ts +1 -0
  24. package/lib/esm/CMS/components.d.ts.map +1 -1
  25. package/lib/esm/Forms/forms.d.ts +3 -3
  26. package/lib/esm/Forms/forms.js +1 -1
  27. package/lib/esm/Forms/forms.js.map +1 -1
  28. package/lib/esm/Forms/hooks.d.ts +1 -0
  29. package/lib/esm/Forms/hooks.d.ts.map +1 -1
  30. package/lib/esm/Forms/hooks.js +11 -3
  31. package/lib/esm/Forms/hooks.js.map +1 -1
  32. package/lib/esm/Forms/inputs.d.ts +1 -1
  33. package/lib/esm/Forms/inputs.d.ts.map +1 -1
  34. package/lib/esm/Forms/inputs.js +78 -28
  35. package/lib/esm/Forms/inputs.js.map +1 -1
  36. package/lib/esm/Forms/inputs.native.d.ts +1 -0
  37. package/lib/esm/Forms/inputs.native.d.ts.map +1 -1
  38. package/lib/esm/controls.d.ts +2 -2
  39. package/lib/esm/inputs.d.ts +1 -1
  40. package/lib/esm/layout.d.ts +1 -1
  41. package/lib/esm/mui.d.ts +2 -1
  42. package/lib/esm/mui.d.ts.map +1 -1
  43. package/lib/esm/mui.js +2 -2
  44. package/lib/esm/mui.js.map +1 -1
  45. package/lib/esm/state.d.ts +256 -256
  46. package/lib/esm/state.js +1 -1
  47. package/lib/esm/state.js.map +1 -1
  48. package/lib/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +9 -9
  50. package/src/Forms/forms.tsx +1 -1
  51. package/src/Forms/hooks.tsx +8 -0
  52. package/src/Forms/inputs.tsx +109 -37
  53. package/src/mui.tsx +3 -2
  54. package/src/state.tsx +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tellescope/react-components",
3
- "version": "1.157.1",
3
+ "version": "1.159.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.157.1",
51
- "@tellescope/sdk": "^1.157.1",
52
- "@tellescope/types-client": "^1.157.1",
53
- "@tellescope/types-models": "^1.157.1",
54
- "@tellescope/types-utilities": "^1.157.1",
55
- "@tellescope/utilities": "^1.157.1",
56
- "@tellescope/validation": "^1.157.1",
50
+ "@tellescope/constants": "^1.159.0",
51
+ "@tellescope/sdk": "^1.159.0",
52
+ "@tellescope/types-client": "^1.159.0",
53
+ "@tellescope/types-models": "^1.159.0",
54
+ "@tellescope/types-utilities": "^1.159.0",
55
+ "@tellescope/utilities": "^1.159.0",
56
+ "@tellescope/validation": "^1.159.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",
@@ -80,7 +80,7 @@
80
80
  "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
81
81
  "react-native": "^0.65.0 || ^0.66.0 || ^0.67.0 || ^0.68.0 || ^0.71.0"
82
82
  },
83
- "gitHead": "5019608eaa05afae077c4bf4551306a31f60cb73",
83
+ "gitHead": "105154b2072ee3c52f066e163aec77441d7e6c7d",
84
84
  "publishConfig": {
85
85
  "access": "public"
86
86
  }
@@ -372,7 +372,7 @@ export const QuestionForField = ({
372
372
 
373
373
  {field.type !== 'Question Group' &&
374
374
  <Typography color="error" style={{ marginTop: 3, height: 10, fontSize: 14, marginBottom: -10 }}>
375
- {(validationMessage === 'A response is required' || validationMessage === 'A value must be checked' || validationMessage === 'A file is required')
375
+ {(validationMessage === 'A response is required' || validationMessage === 'A value must be checked' || validationMessage === 'A file is required' || 'Enter a valid phone number' || 'Insurer is required')
376
376
  ? value.touched
377
377
  ? form_display_text_for_language(form, validationMessage)
378
378
  : null
@@ -198,6 +198,7 @@ export const getNextField = (activeField: FormFieldNode, currentValue: Response,
198
198
  urlLogicValue?: string,
199
199
  dateOfBirth?: string,
200
200
  gender?: string,
201
+ state?: string,
201
202
  form?: Form,
202
203
  activeResponses?: FormResponseValue[], // current and previous answers (not future answers)
203
204
  }) => {
@@ -600,6 +601,7 @@ export const useTellescopeForm = ({ form, urlLogicValue, customization, carePlan
600
601
  disabled: !!(existingResponses?.find(r => r.fieldId === f.id)?.answer?.value && f.disabledWhenPrepopulated),
601
602
  // keep consistent with onFieldChange
602
603
  computedValueKey: (
604
+ // the height typeof is unnecessary (no actual type comparison), but don't change without testing both number and height question types
603
605
  f?.intakeField === 'height' && typeof existingResponses?.find(r => r.fieldId === f.id)?.answer?.value
604
606
  ? 'Height'
605
607
  : f?.intakeField === 'weight' && typeof existingResponses?.find(r => r.fieldId === f.id)?.answer?.value === 'number'
@@ -608,6 +610,8 @@ export const useTellescopeForm = ({ form, urlLogicValue, customization, carePlan
608
610
  ? 'Date of Birth'
609
611
  : f?.intakeField === 'gender' && ['multiple_choice', 'Dropdown'].includes(existingResponses?.find(r => r.fieldId === f.id)?.answer?.type || '')
610
612
  ? 'Gender'
613
+ : f?.intakeField === 'Address' && existingResponses?.find(r => r.fieldId === f.id && r.answer.type === 'Address')
614
+ ? 'State'
611
615
  : undefined
612
616
  ) as any,
613
617
  answer: {
@@ -1060,6 +1064,7 @@ export const useTellescopeForm = ({ form, urlLogicValue, customization, carePlan
1060
1064
  activeResponses: responses.filter(r => r.includeInSubmit),
1061
1065
  dateOfBirth: enduser?.dateOfBirth,
1062
1066
  gender: enduser?.gender,
1067
+ state: enduser?.state,
1063
1068
  })
1064
1069
  )
1065
1070
  )
@@ -1275,6 +1280,7 @@ export const useTellescopeForm = ({ form, urlLogicValue, customization, carePlan
1275
1280
  activeResponses: responses.filter(r => r.includeInSubmit),
1276
1281
  dateOfBirth: enduser?.dateOfBirth,
1277
1282
  gender: enduser?.gender,
1283
+ state: enduser?.state,
1278
1284
  })
1279
1285
 
1280
1286
  // when autoadvancing, prevent adding duplicates by checking whether already on stack
@@ -1341,6 +1347,8 @@ export const useTellescopeForm = ({ form, urlLogicValue, customization, carePlan
1341
1347
  ? 'Date of Birth'
1342
1348
  : field?.intakeField === 'gender' && (r.answer.type === 'Dropdown' || r.answer.type === 'multiple_choice')
1343
1349
  ? 'Gender'
1350
+ : field?.intakeField === 'Address' && r.answer.type === 'Address'
1351
+ ? 'State'
1344
1352
  : undefined
1345
1353
  )
1346
1354
  })))
@@ -13,7 +13,7 @@ import LinearProgress from '@mui/material/LinearProgress';
13
13
  import DatePicker from "react-datepicker";
14
14
  import { datepickerCSS } from "./css/react-datepicker" // avoids build issue with RN
15
15
  import { CancelIcon, FileBlob, IconButton, LabeledIconButton, LoadingButton, Styled, form_display_text_for_language, isDateString, useProducts, useResolvedSession } from ".."
16
- import { CalendarEvent, DatabaseRecord, FormField } from "@tellescope/types-client"
16
+ import { AllergyCode, CalendarEvent, DatabaseRecord, FormField } from "@tellescope/types-client"
17
17
  import { css } from '@emotion/css'
18
18
  import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
19
19
  import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
@@ -492,6 +492,7 @@ export const InsuranceInput = ({ field, value, onChange, form, responses, enduse
492
492
  const session = useResolvedSession()
493
493
 
494
494
  const [payers, setPayers] = useState<{ id: string, name: string, type?: string, state?: string }[]>([])
495
+ const [query, setQuery] = useState('')
495
496
 
496
497
  const addressQuestion = useMemo(() => responses?.find(r => {
497
498
  if (r.answer.type !== 'Address') return false
@@ -509,6 +510,7 @@ export const InsuranceInput = ({ field, value, onChange, form, responses, enduse
509
510
 
510
511
  const loadRef = useRef(false) // so session changes don't cause
511
512
  useEffect(() => {
513
+ if (field?.options?.dataSource === CANVAS_TITLE) return // instead, look-up while typing against Canvas Search API
512
514
  if (loadRef.current) return
513
515
  loadRef.current = true
514
516
 
@@ -525,7 +527,30 @@ export const InsuranceInput = ({ field, value, onChange, form, responses, enduse
525
527
  .filter(c => !c.state || !state || (c.state === state))
526
528
  ))
527
529
  .catch(console.error)
528
- }, [session, state])
530
+ }, [session, state, field?.options?.dataSource])
531
+
532
+ const searchRef = useRef(query)
533
+ useEffect(() => {
534
+ if (field?.options?.dataSource !== CANVAS_TITLE) { return }
535
+ if (!query) return
536
+ if (searchRef.current === query) return
537
+ searchRef.current = query
538
+
539
+ session.api.integrations.proxy_read({
540
+ integration: CANVAS_TITLE,
541
+ query,
542
+ type: 'organizations',
543
+ })
544
+ .then(({ data }) => {
545
+ try {
546
+ setPayers(data.map((d: any) => ({
547
+ id: d.resource.id,
548
+ name: d.resource.name,
549
+ })))
550
+ } catch(err) { console.error }
551
+ })
552
+ .catch(console.error)
553
+ }, [session, field?.options?.dataSource, query])
529
554
 
530
555
  return (
531
556
  <Grid container spacing={2} sx={{ mt: '0' }}>
@@ -538,12 +563,20 @@ export const InsuranceInput = ({ field, value, onChange, form, responses, enduse
538
563
  payerId: payers.find(p => p.name === v)?.id || '',
539
564
  payerType: payers.find(p => p.name === v)?.type || '',
540
565
  }, field.id)}
541
- onInputChange={field.options?.requirePredefinedInsurer ? undefined : (e, v) => onChange({
542
- ...value,
543
- payerName: v || '',
544
- payerId: payers.find(p => p.name === v)?.id || '',
545
- payerType: payers.find(p => p.name === v)?.type || '',
546
- }, field.id)}
566
+ onInputChange={
567
+ field.options?.requirePredefinedInsurer
568
+ ? (e, v) => { if (v) { setQuery(v) } }
569
+ : (e, v) => {
570
+ if (v) { setQuery(v) }
571
+
572
+ onChange({
573
+ ...value,
574
+ payerName: v || '',
575
+ payerId: payers.find(p => p.name === v)?.id || '',
576
+ payerType: payers.find(p => p.name === v)?.type || '',
577
+ }, field.id)
578
+ }
579
+ }
547
580
  renderInput={(params) => (
548
581
  <TextField {...params} InputProps={{ ...params.InputProps, sx: defaultInputProps.sx }}
549
582
  required={!field.isOptional} size="small" label="Insurer"
@@ -596,7 +629,11 @@ export const InsuranceInput = ({ field, value, onChange, form, responses, enduse
596
629
  <Grid item xs={12}>
597
630
  <StringSelector size="small" label="Relationship to Policy Owner"
598
631
  options={
599
- (field.options?.billingProvider === 'Canvas' ? INSURANCE_RELATIONSHIPS_CANVAS : INSURANCE_RELATIONSHIPS)
632
+ (
633
+ (field.options?.billingProvider === CANVAS_TITLE || field.options?.dataSource === CANVAS_TITLE )
634
+ ? INSURANCE_RELATIONSHIPS_CANVAS
635
+ : INSURANCE_RELATIONSHIPS
636
+ )
600
637
  .sort((x, y) => x.localeCompare(y))
601
638
  }
602
639
  value={value?.relationship || 'Self'}
@@ -809,13 +846,14 @@ export const InsuranceInput = ({ field, value, onChange, form, responses, enduse
809
846
  }
810
847
 
811
848
 
812
- const StringSelector = ({ options, value, onChange, required, ...props } : {
849
+ const StringSelector = ({ options, value, onChange, required, getDisplayValue, ...props } : {
813
850
  options: string[]
814
851
  value: string,
815
852
  onChange: (v: string) => void,
816
853
  label?: string,
817
854
  size?: "small",
818
855
  required?: boolean,
856
+ getDisplayValue?: (v: string) => string,
819
857
  }) => (
820
858
  <FormControl fullWidth size={props.size} required={required}>
821
859
  <InputLabel>{props.label}</InputLabel>
@@ -823,7 +861,7 @@ const StringSelector = ({ options, value, onChange, required, ...props } : {
823
861
  sx={defaultInputProps.sx}
824
862
  >
825
863
  {options.map((o, i) => (
826
- <MenuItem value={o} key={o || i}>{o}</MenuItem>
864
+ <MenuItem value={o} key={o || i}>{getDisplayValue?.(o) ?? o}</MenuItem>
827
865
  ))}
828
866
  </Select>
829
867
  </FormControl>
@@ -886,7 +924,9 @@ export const AddressInput = ({ field, form, value, onChange, ...props }: FormInp
886
924
  )}
887
925
  renderInput={(params) => (
888
926
  <TextField {...params} InputProps={{ ...params.InputProps, sx: defaultInputProps.sx }}
889
- size={'small'} required={!field.isOptional}
927
+ required={!field.isOptional}
928
+ // don't use 'small' so as to be consistent with other text fields, in case this is used in a group
929
+ // size={'small'}
890
930
  label={form_display_text_for_language(form, "State")}
891
931
  />
892
932
  )}
@@ -2966,32 +3006,64 @@ export const AllergiesInput = ({ goToNextField, goToPreviousField, field, value,
2966
3006
  }, [session, query, field?.options?.dataSource])
2967
3007
 
2968
3008
  return (
2969
- <Autocomplete multiple value={value || []} options={results} style={{ marginTop: 5 }}
2970
- noOptionsText={query.length ? 'No results found' : 'Type to start search'}
2971
- onChange={(e, v) => {
2972
- if (!v) { return }
2973
- onChange(v, field.id)
2974
- setResults([])
2975
- }}
2976
- getOptionLabel={v => first_letter_capitalized(v.display)} filterOptions={o => o}
2977
- inputValue={query} onInputChange={(e, v) => e && setQuery(v) }
2978
- renderInput={(params) => (
2979
- <TextField {...params} InputProps={{ ...params.InputProps, sx: defaultInputProps.sx }}
2980
- required={!field.isOptional} size="small" label="" placeholder="Search allergies..."
2981
- />
2982
- )}
2983
- renderTags={(value, getTagProps) =>
2984
- value.map((value, index) => (
2985
- <Chip
2986
- label={<Typography style={{whiteSpace: 'normal'}}>{value.display}</Typography>}
2987
- {...getTagProps({ index })}
2988
- sx={{height:"100%", py: 0.5 }}
3009
+ <Grid container direction="column" spacing={1}>
3010
+ <Grid item>
3011
+ <Autocomplete multiple value={value || []} options={results} style={{ marginTop: 5 }}
3012
+ noOptionsText={query.length ? 'No results found' : 'Type to start search'}
3013
+ onChange={(e, v) => {
3014
+ if (!v) { return }
3015
+ onChange(v, field.id)
3016
+ setResults([])
3017
+ }}
3018
+ getOptionLabel={v => first_letter_capitalized(v.display)} filterOptions={o => o}
3019
+ inputValue={query} onInputChange={(e, v) => e && setQuery(v) }
3020
+ renderInput={(params) => (
3021
+ <TextField {...params} InputProps={{ ...params.InputProps, sx: defaultInputProps.sx }}
3022
+ required={!field.isOptional} size="small" label="" placeholder="Search allergies..."
2989
3023
  />
2990
- ))
2991
- }
2992
- />
3024
+ )}
3025
+ renderTags={(value, getTagProps) =>
3026
+ value.map((value, index) => (
3027
+ <Chip
3028
+ label={<Typography style={{whiteSpace: 'normal'}}>{value.display}</Typography>}
3029
+ {...getTagProps({ index })}
3030
+ sx={{height:"100%", py: 0.5 }}
3031
+ />
3032
+ ))
3033
+ }
3034
+ />
3035
+ </Grid>
3036
+
3037
+ {(value || []).map((allergy, i) => (
3038
+ <Grid item key={i}>
3039
+ <Grid container alignItems="center" wrap="nowrap" columnGap={0.5} justifyContent={"space-between"}>
3040
+ <Grid item>
3041
+ <Typography noWrap sx={{ width: 85, fontSize: 14 }}>
3042
+ {allergy.display}
3043
+ </Typography>
3044
+ </Grid>
3045
+
3046
+ <Grid item sx={{ width: 140 }}>
3047
+ <StringSelector options={['mild', 'moderate', 'severe']} size="small" label="Severity"
3048
+ value={allergy.severity || ''}
3049
+ onChange={severity => onChange((value || []).map((v, _i) => i === _i ? { ...v, severity } : v), field.id)}
3050
+ getDisplayValue={first_letter_capitalized}
3051
+ />
3052
+ </Grid>
3053
+
3054
+ <Grid item sx={{ width: "50%" }}>
3055
+ <TextField InputProps={{ sx: defaultInputProps.sx }} fullWidth size="small" label="Note"
3056
+ value={allergy.note || ''}
3057
+ onChange={e => onChange((value || []).map((v, _i) => i === _i ? { ...v, note: e.target.value } : v), field.id)}
3058
+ />
3059
+ </Grid>
3060
+ </Grid>
3061
+ </Grid>
3062
+ ))}
3063
+ </Grid>
2993
3064
  )
2994
3065
  }
3066
+ const display_with_code = (v: { code: string, display: string }) => `${v.code}: ${first_letter_capitalized(v.display)}`
2995
3067
 
2996
3068
  export const ConditionsInput = ({ goToNextField, goToPreviousField, field, value, onChange, form, formResponseId, ...props }: FormInputProps<'Conditions'>) => {
2997
3069
  const session = useResolvedSession()
@@ -3029,7 +3101,7 @@ export const ConditionsInput = ({ goToNextField, goToPreviousField, field, value
3029
3101
  onChange(v, field.id)
3030
3102
  setResults([])
3031
3103
  }}
3032
- getOptionLabel={v => first_letter_capitalized(v.display)} filterOptions={o => o}
3104
+ getOptionLabel={display_with_code} filterOptions={o => o}
3033
3105
  inputValue={query} onInputChange={(e, v) => e && setQuery(v) }
3034
3106
  renderInput={(params) => (
3035
3107
  <TextField {...params} InputProps={{ ...params.InputProps, sx: defaultInputProps.sx }}
@@ -3039,7 +3111,7 @@ export const ConditionsInput = ({ goToNextField, goToPreviousField, field, value
3039
3111
  renderTags={(value, getTagProps) =>
3040
3112
  value.map((value, index) => (
3041
3113
  <Chip
3042
- label={<Typography style={{whiteSpace: 'normal'}}>{value.display}</Typography>}
3114
+ label={<Typography style={{whiteSpace: 'normal'}}>{display_with_code(value)}</Typography>}
3043
3115
  {...getTagProps({ index })}
3044
3116
  sx={{height:"100%", py: 0.5 }}
3045
3117
  />
package/src/mui.tsx CHANGED
@@ -340,9 +340,10 @@ export interface ModalProps extends Styled {
340
340
  setOpen: (b: boolean) => void,
341
341
  onClick?: () => void,
342
342
  ref?: any,
343
+ zIndex?: number,
343
344
  }
344
- export const Modal = ({ children, onClick, open, setOpen, style=defaultModalStyle }: ModalProps) => (
345
- <MuiModal open={open} onClick={onClick} onClose={() => setOpen(false)}>
345
+ export const Modal = ({ children, onClick, open, setOpen, style=defaultModalStyle, zIndex }: ModalProps) => (
346
+ <MuiModal open={open} onClick={onClick} onClose={() => setOpen(false)} style={{ zIndex }}>
346
347
  <Grid container style={style}>
347
348
  {children}
348
349
  </Grid>
package/src/state.tsx CHANGED
@@ -1985,7 +1985,7 @@ export const useTemplates = (options={} as HookOptions<Template>) => {
1985
1985
  )
1986
1986
  }
1987
1987
  export const useForms = (options={} as HookOptions<Form>) => {
1988
- const session = useSession()
1988
+ const session = useResolvedSession()
1989
1989
  return useListStateHook(
1990
1990
  'forms', useTypedSelector(s => s.forms), session, formsSlice,
1991
1991
  {