@tellescope/react-components 1.231.0 → 1.232.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.js +1 -1
- package/lib/cjs/Forms/forms.js.map +1 -1
- package/lib/cjs/Forms/forms.v2.d.ts +1 -1
- package/lib/cjs/Forms/forms.v2.js +1 -1
- package/lib/cjs/Forms/forms.v2.js.map +1 -1
- package/lib/cjs/Forms/hooks.d.ts.map +1 -1
- package/lib/cjs/Forms/hooks.js +24 -0
- package/lib/cjs/Forms/hooks.js.map +1 -1
- package/lib/cjs/Forms/inputs.d.ts +6 -3
- package/lib/cjs/Forms/inputs.d.ts.map +1 -1
- package/lib/cjs/Forms/inputs.js +171 -44
- package/lib/cjs/Forms/inputs.js.map +1 -1
- package/lib/cjs/Forms/inputs.v2.d.ts +7 -11
- package/lib/cjs/Forms/inputs.v2.d.ts.map +1 -1
- package/lib/cjs/Forms/inputs.v2.js +16 -445
- package/lib/cjs/Forms/inputs.v2.js.map +1 -1
- package/lib/esm/CMS/components.d.ts +0 -1
- package/lib/esm/CMS/components.d.ts.map +1 -1
- package/lib/esm/Forms/form_responses.d.ts +0 -1
- package/lib/esm/Forms/form_responses.d.ts.map +1 -1
- package/lib/esm/Forms/forms.d.ts +3 -3
- package/lib/esm/Forms/forms.js +1 -1
- package/lib/esm/Forms/forms.js.map +1 -1
- package/lib/esm/Forms/forms.v2.d.ts +4 -4
- package/lib/esm/Forms/forms.v2.js +1 -1
- package/lib/esm/Forms/forms.v2.js.map +1 -1
- package/lib/esm/Forms/hooks.d.ts +0 -1
- package/lib/esm/Forms/hooks.d.ts.map +1 -1
- package/lib/esm/Forms/hooks.js +24 -0
- package/lib/esm/Forms/hooks.js.map +1 -1
- package/lib/esm/Forms/inputs.d.ts +7 -4
- package/lib/esm/Forms/inputs.d.ts.map +1 -1
- package/lib/esm/Forms/inputs.js +173 -46
- package/lib/esm/Forms/inputs.js.map +1 -1
- package/lib/esm/Forms/inputs.v2.d.ts +8 -12
- package/lib/esm/Forms/inputs.v2.d.ts.map +1 -1
- package/lib/esm/Forms/inputs.v2.js +17 -446
- package/lib/esm/Forms/inputs.v2.js.map +1 -1
- package/lib/esm/controls.d.ts +2 -2
- package/lib/esm/inputs.d.ts +1 -1
- package/lib/esm/inputs.native.d.ts +0 -1
- package/lib/esm/inputs.native.d.ts.map +1 -1
- package/lib/esm/state.d.ts +315 -315
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/Forms/forms.tsx +1 -1
- package/src/Forms/forms.v2.tsx +1 -1
- package/src/Forms/hooks.tsx +33 -5
- package/src/Forms/inputs.tsx +224 -35
- package/src/Forms/inputs.v2.tsx +20 -639
package/lib/esm/Forms/inputs.js
CHANGED
|
@@ -72,10 +72,10 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
72
72
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
73
73
|
import React, { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
74
74
|
import axios from "axios";
|
|
75
|
-
import { Autocomplete, Box, Button, Checkbox, Chip, Collapse, Divider, FormControl, FormControlLabel, FormLabel, Grid, IconButton as MuiIconButton, InputLabel, MenuItem, Radio, RadioGroup, Select, TextField, Typography } from "@mui/material";
|
|
75
|
+
import { Autocomplete, Box, Button, Checkbox, Chip, CircularProgress, Collapse, Divider, FormControl, FormControlLabel, FormLabel, Grid, IconButton as MuiIconButton, InputLabel, MenuItem, Radio, RadioGroup, Select, TextField, Typography } from "@mui/material";
|
|
76
76
|
import { useDropzone } from "react-dropzone";
|
|
77
77
|
import { CANVAS_TITLE, EMOTII_TITLE, INSURANCE_RELATIONSHIPS, INSURANCE_RELATIONSHIPS_CANVAS, PRIMARY_HEX, RELATIONSHIP_TYPES, TELLESCOPE_GENDERS } from "@tellescope/constants";
|
|
78
|
-
import { MM_DD_YYYY_to_YYYY_MM_DD, capture_is_supported, downloadFile, emit_gtm_event, first_letter_capitalized, form_response_value_to_string, format_stripe_subscription_interval, getLocalTimezone, getPublicFileURL, mm_dd_yyyy, replace_enduser_template_values, truncate_string, update_local_storage, user_display_name } from "@tellescope/utilities";
|
|
78
|
+
import { MM_DD_YYYY_to_YYYY_MM_DD, capture_is_supported, downloadFile, emit_gtm_event, first_letter_capitalized, form_response_value_to_string, format_stripe_subscription_interval, getLocalTimezone, getPublicFileURL, mm_dd_yyyy, object_is_empty, replace_enduser_template_values, responses_satisfy_conditions, truncate_string, update_local_storage, user_display_name } from "@tellescope/utilities";
|
|
79
79
|
import { TIMEZONES_USA } from "@tellescope/types-models";
|
|
80
80
|
import { VALID_STATES, emailValidator, phoneValidator } from "@tellescope/validation";
|
|
81
81
|
import Slider from '@mui/material/Slider';
|
|
@@ -93,6 +93,15 @@ import { Elements, PaymentElement, useStripe, useElements, EmbeddedCheckout, Emb
|
|
|
93
93
|
import { loadStripe } from '@stripe/stripe-js';
|
|
94
94
|
import { CheckCircleOutline, Delete, Edit, ExpandMore } from "@mui/icons-material";
|
|
95
95
|
import { WYSIWYG } from "./wysiwyg";
|
|
96
|
+
// Debounce hook for search functionality
|
|
97
|
+
var useDebounce = function (value, delay) {
|
|
98
|
+
var _a = useState(value), debouncedValue = _a[0], setDebouncedValue = _a[1];
|
|
99
|
+
useEffect(function () {
|
|
100
|
+
var handler = setTimeout(function () { return setDebouncedValue(value); }, delay);
|
|
101
|
+
return function () { return clearTimeout(handler); };
|
|
102
|
+
}, [value, delay]);
|
|
103
|
+
return debouncedValue;
|
|
104
|
+
};
|
|
96
105
|
export var LanguageSelect = function (_a) {
|
|
97
106
|
var value = _a.value, props = __rest(_a, ["value"]);
|
|
98
107
|
return (_jsxs(Grid, __assign({ container: true, alignItems: "center", justifyContent: "center", wrap: "nowrap", spacing: 1 }, { children: [_jsx(Grid, __assign({ item: true }, { children: _jsx(LanguageIcon, { color: "primary" }) })), _jsx(Grid, __assign({ item: true, style: { width: 150 } }, { children: _jsx(StringSelector, __assign({}, props, { options: ["English", "Español"], size: "small", value: value === 'Spanish' ? 'Español' : value, label: (value === 'Español' || value === 'Spanish') ? 'Idioma'
|
|
@@ -808,20 +817,59 @@ export var MultipleChoiceInput = function (_a) {
|
|
|
808
817
|
? __spreadArray(__spreadArray([], (value !== null && value !== void 0 ? value : []).filter(function (v) { return v !== otherString; }), true), [e.target.value], false) : value === null || value === void 0 ? void 0 : value.filter(function (v) { return v !== otherString; }))), field.id);
|
|
809
818
|
} }) }))] })));
|
|
810
819
|
};
|
|
820
|
+
// Helper to emit GTM purchase event for Stripe payments (single source of truth)
|
|
821
|
+
var emitStripePurchaseEvent = function (field, cost) {
|
|
822
|
+
var _a;
|
|
823
|
+
emit_gtm_event({
|
|
824
|
+
event: 'form_purchase',
|
|
825
|
+
productIds: ((_a = field.options) === null || _a === void 0 ? void 0 : _a.productIds) || [],
|
|
826
|
+
fieldId: field.id,
|
|
827
|
+
value: cost / 100,
|
|
828
|
+
currency: 'USD',
|
|
829
|
+
});
|
|
830
|
+
};
|
|
811
831
|
export var StripeInput = function (_a) {
|
|
812
|
-
var _b, _d;
|
|
813
|
-
var field = _a.field, value = _a.value, onChange = _a.onChange, setCustomerId = _a.setCustomerId, enduserId = _a.enduserId;
|
|
832
|
+
var _b, _d, _e;
|
|
833
|
+
var field = _a.field, value = _a.value, onChange = _a.onChange, setCustomerId = _a.setCustomerId, enduserId = _a.enduserId, form = _a.form, responses = _a.responses, enduser = _a.enduser;
|
|
814
834
|
var session = useResolvedSession();
|
|
815
|
-
var
|
|
816
|
-
var
|
|
817
|
-
var
|
|
818
|
-
var
|
|
819
|
-
var
|
|
820
|
-
var
|
|
821
|
-
var
|
|
822
|
-
var
|
|
823
|
-
var
|
|
824
|
-
var
|
|
835
|
+
var _f = useState(''), clientSecret = _f[0], setClientSecret = _f[1];
|
|
836
|
+
var _g = useState(''), businessName = _g[0], setBusinessName = _g[1];
|
|
837
|
+
var _h = useState(false), isCheckout = _h[0], setIsCheckout = _h[1];
|
|
838
|
+
var _j = useState(), stripePromise = _j[0], setStripePromise = _j[1];
|
|
839
|
+
var _k = useState(''), answertext = _k[0], setAnswertext = _k[1];
|
|
840
|
+
var _l = useState(''), error = _l[0], setError = _l[1];
|
|
841
|
+
var _m = useState([]), selectedProducts = _m[0], setSelectedProducts = _m[1];
|
|
842
|
+
var _o = useState(false), showProductSelection = _o[0], setShowProductSelection = _o[1];
|
|
843
|
+
var _p = useState([]), availableProducts = _p[0], setAvailableProducts = _p[1];
|
|
844
|
+
var _q = useState(false), loadingProducts = _q[0], setLoadingProducts = _q[1];
|
|
845
|
+
// Compute visible products based on conditional logic
|
|
846
|
+
var visibleProducts = useMemo(function () {
|
|
847
|
+
if (!showProductSelection || availableProducts.length === 0) {
|
|
848
|
+
return availableProducts;
|
|
849
|
+
}
|
|
850
|
+
return availableProducts.filter(function (product) {
|
|
851
|
+
var _a, _b;
|
|
852
|
+
// Find condition for this product
|
|
853
|
+
var productCondition = (_b = (_a = field.options) === null || _a === void 0 ? void 0 : _a.productConditions) === null || _b === void 0 ? void 0 : _b.find(function (c) { return c.productId === product._id; });
|
|
854
|
+
// If no condition defined, show by default
|
|
855
|
+
if (!(productCondition === null || productCondition === void 0 ? void 0 : productCondition.showCondition) || object_is_empty(productCondition.showCondition)) {
|
|
856
|
+
return true;
|
|
857
|
+
}
|
|
858
|
+
// Evaluate condition against current form responses
|
|
859
|
+
return responses_satisfy_conditions(responses || [], productCondition.showCondition, {
|
|
860
|
+
dateOfBirth: enduser === null || enduser === void 0 ? void 0 : enduser.dateOfBirth,
|
|
861
|
+
gender: enduser === null || enduser === void 0 ? void 0 : enduser.gender,
|
|
862
|
+
state: enduser === null || enduser === void 0 ? void 0 : enduser.state,
|
|
863
|
+
form: form,
|
|
864
|
+
activeResponses: responses,
|
|
865
|
+
});
|
|
866
|
+
});
|
|
867
|
+
}, [availableProducts, (_b = field.options) === null || _b === void 0 ? void 0 : _b.productConditions, responses, showProductSelection, enduser, form]);
|
|
868
|
+
// Automatically deselect products that become hidden
|
|
869
|
+
useEffect(function () {
|
|
870
|
+
var visibleProductIds = visibleProducts.map(function (p) { return p._id; });
|
|
871
|
+
setSelectedProducts(function (prev) { return prev.filter(function (id) { return visibleProductIds.includes(id); }); });
|
|
872
|
+
}, [visibleProducts]);
|
|
825
873
|
var fetchRef = useRef(false);
|
|
826
874
|
useEffect(function () {
|
|
827
875
|
var _a, _b, _d;
|
|
@@ -887,6 +935,16 @@ export var StripeInput = function (_a) {
|
|
|
887
935
|
}, 0)
|
|
888
936
|
: 0 // Will be calculated by existing Stripe flow when not in selection mode
|
|
889
937
|
);
|
|
938
|
+
// Emit GTM purchase event once when success screen is displayed
|
|
939
|
+
var purchaseEmittedRef = useRef(false);
|
|
940
|
+
useEffect(function () {
|
|
941
|
+
var _a;
|
|
942
|
+
// Only emit for actual purchases (chargeImmediately), not for saving card details
|
|
943
|
+
if (value && ((_a = field.options) === null || _a === void 0 ? void 0 : _a.chargeImmediately) && !purchaseEmittedRef.current) {
|
|
944
|
+
emitStripePurchaseEvent(field, cost);
|
|
945
|
+
purchaseEmittedRef.current = true;
|
|
946
|
+
}
|
|
947
|
+
}, [value, field, cost]);
|
|
890
948
|
// Handle product selection step
|
|
891
949
|
if (showProductSelection) {
|
|
892
950
|
if (error) {
|
|
@@ -895,7 +953,11 @@ export var StripeInput = function (_a) {
|
|
|
895
953
|
if (loadingProducts) {
|
|
896
954
|
return (_jsxs(Grid, __assign({ container: true, direction: "column", spacing: 2, alignItems: "center" }, { children: [_jsx(Grid, __assign({ item: true }, { children: _jsx(LinearProgress, {}) })), _jsx(Grid, __assign({ item: true }, { children: _jsx(Typography, { children: "Loading product information..." }) }))] })));
|
|
897
955
|
}
|
|
898
|
-
|
|
956
|
+
// Check if all products are filtered out by conditional logic
|
|
957
|
+
if (visibleProducts.length === 0) {
|
|
958
|
+
return (_jsx(Grid, __assign({ container: true, direction: "column", spacing: 2, alignItems: "center" }, { children: _jsx(Grid, __assign({ item: true }, { children: _jsx(Typography, __assign({ color: "textSecondary" }, { children: "No products are available based on your previous answers." })) })) })));
|
|
959
|
+
}
|
|
960
|
+
var isSingleSelection_1 = ((_d = field.options) === null || _d === void 0 ? void 0 : _d.radio) === true;
|
|
899
961
|
var handleProductSelection_1 = function (productId) {
|
|
900
962
|
if (isSingleSelection_1) {
|
|
901
963
|
setSelectedProducts([productId]);
|
|
@@ -932,7 +994,7 @@ export var StripeInput = function (_a) {
|
|
|
932
994
|
}
|
|
933
995
|
});
|
|
934
996
|
};
|
|
935
|
-
return (_jsxs(Grid, __assign({ container: true, direction: "column", spacing: 2 }, { children: [_jsx(Grid, __assign({ item: true }, { children: _jsxs(Typography, __assign({ variant: "h6" }, { children: ["Select Product", isSingleSelection_1 ? '' : 's'] })) })),
|
|
997
|
+
return (_jsxs(Grid, __assign({ container: true, direction: "column", spacing: 2 }, { children: [_jsx(Grid, __assign({ item: true }, { children: _jsxs(Typography, __assign({ variant: "h6" }, { children: ["Select Product", isSingleSelection_1 ? '' : 's'] })) })), visibleProducts.map(function (product) {
|
|
936
998
|
var _a, _b, _d;
|
|
937
999
|
// Use real-time Stripe pricing if available, fallback to Tellescope pricing
|
|
938
1000
|
var price = product.currentPrice || product.cost;
|
|
@@ -945,7 +1007,7 @@ export var StripeInput = function (_a) {
|
|
|
945
1007
|
return (_jsx(Typography, __assign({ color: "error" }, { children: error })));
|
|
946
1008
|
}
|
|
947
1009
|
if (value) {
|
|
948
|
-
return (_jsxs(Grid, __assign({ container: true, alignItems: "center", wrap: "nowrap" }, { children: [_jsx(CheckCircleOutline, { color: "success" }), _jsx(Typography, __assign({ sx: { ml: 1, fontSize: 20 } }, { children: ((
|
|
1010
|
+
return (_jsxs(Grid, __assign({ container: true, alignItems: "center", wrap: "nowrap" }, { children: [_jsx(CheckCircleOutline, { color: "success" }), _jsx(Typography, __assign({ sx: { ml: 1, fontSize: 20 } }, { children: ((_e = field.options) === null || _e === void 0 ? void 0 : _e.chargeImmediately) ? 'Your purchase was successful' : "Your payment details have been saved!" }))] })));
|
|
949
1011
|
}
|
|
950
1012
|
if (!(clientSecret && stripePromise))
|
|
951
1013
|
return _jsx(LinearProgress, {});
|
|
@@ -1050,26 +1112,30 @@ export var DropdownInput = function (_a) {
|
|
|
1050
1112
|
var choicesForDatabase = {};
|
|
1051
1113
|
var preventRefetch = {};
|
|
1052
1114
|
var LOAD_CHOICES_LIMIT = 500;
|
|
1115
|
+
var MIN_SEARCH_CHARS = 3;
|
|
1116
|
+
var SEARCH_DEBOUNCE_MS = 300;
|
|
1053
1117
|
var useDatabaseChoices = function (_a) {
|
|
1054
|
-
var _b, _d
|
|
1055
|
-
var
|
|
1118
|
+
var _b, _d;
|
|
1119
|
+
var _e = _a.databaseId, databaseId = _e === void 0 ? '' : _e, field = _a.field, otherAnswers = _a.otherAnswers, _f = _a.searchQuery, searchQuery = _f === void 0 ? '' : _f;
|
|
1056
1120
|
var session = useResolvedSession();
|
|
1057
|
-
var
|
|
1058
|
-
|
|
1121
|
+
var _g = useState(false), isSearching = _g[0], setIsSearching = _g[1];
|
|
1122
|
+
var _h = useState([]), searchResults = _h[0], setSearchResults = _h[1];
|
|
1123
|
+
var _j = useState(false), initialLoadComplete = _j[0], setInitialLoadComplete = _j[1];
|
|
1124
|
+
var debouncedSearch = useDebounce(searchQuery, SEARCH_DEBOUNCE_MS);
|
|
1125
|
+
// Load initial page on mount (only once, not recursively)
|
|
1126
|
+
var initialLoadRef = useRef(false);
|
|
1059
1127
|
useEffect(function () {
|
|
1060
|
-
var _a, _b, _d
|
|
1061
|
-
if (
|
|
1128
|
+
var _a, _b, _d;
|
|
1129
|
+
if (initialLoadRef.current)
|
|
1062
1130
|
return;
|
|
1063
|
-
if (
|
|
1064
|
-
|
|
1065
|
-
var choices = (_d = (_b = choicesForDatabase[databaseId]) === null || _b === void 0 ? void 0 : _b.records) !== null && _d !== void 0 ? _d : [];
|
|
1066
|
-
var lastId = (_e = choicesForDatabase[databaseId]) === null || _e === void 0 ? void 0 : _e.lastId;
|
|
1067
|
-
if (preventRefetch[databaseId + field.id + lastId])
|
|
1131
|
+
if (((_a = choicesForDatabase[databaseId]) === null || _a === void 0 ? void 0 : _a.done) || ((_d = (_b = choicesForDatabase[databaseId]) === null || _b === void 0 ? void 0 : _b.records) === null || _d === void 0 ? void 0 : _d.length)) {
|
|
1132
|
+
setInitialLoadComplete(true);
|
|
1068
1133
|
return;
|
|
1069
|
-
|
|
1134
|
+
}
|
|
1135
|
+
initialLoadRef.current = true;
|
|
1136
|
+
preventRefetch[databaseId + field.id] = true;
|
|
1070
1137
|
session.api.form_fields.load_choices_from_database({
|
|
1071
1138
|
fieldId: field.id,
|
|
1072
|
-
lastId: lastId,
|
|
1073
1139
|
limit: LOAD_CHOICES_LIMIT,
|
|
1074
1140
|
databaseId: databaseId,
|
|
1075
1141
|
})
|
|
@@ -1078,17 +1144,67 @@ var useDatabaseChoices = function (_a) {
|
|
|
1078
1144
|
var newChoices = _a.choices;
|
|
1079
1145
|
choicesForDatabase[databaseId] = {
|
|
1080
1146
|
lastId: (_b = newChoices === null || newChoices === void 0 ? void 0 : newChoices[newChoices.length - 1]) === null || _b === void 0 ? void 0 : _b.id,
|
|
1081
|
-
records:
|
|
1147
|
+
records: newChoices.sort(function (c1, c2) { return (label_for_database_record(field, c1)
|
|
1082
1148
|
.localeCompare(label_for_database_record(field, c2))); }),
|
|
1083
|
-
done:
|
|
1149
|
+
done: true, // Don't load more pages automatically
|
|
1084
1150
|
};
|
|
1085
|
-
|
|
1151
|
+
setInitialLoadComplete(true);
|
|
1152
|
+
})
|
|
1153
|
+
.catch(function (err) {
|
|
1154
|
+
console.error(err);
|
|
1155
|
+
preventRefetch[databaseId + field.id] = false;
|
|
1156
|
+
setInitialLoadComplete(true); // Mark as complete even on error to avoid infinite loading
|
|
1157
|
+
});
|
|
1158
|
+
}, [session, field, databaseId]);
|
|
1159
|
+
// Handle debounced search
|
|
1160
|
+
var searchRef = useRef(debouncedSearch);
|
|
1161
|
+
useEffect(function () {
|
|
1162
|
+
var trimmed = debouncedSearch.trim();
|
|
1163
|
+
// If search is cleared, return to initial results
|
|
1164
|
+
if (!trimmed) {
|
|
1165
|
+
setSearchResults([]);
|
|
1166
|
+
setIsSearching(false);
|
|
1167
|
+
searchRef.current = debouncedSearch;
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
// Only search if meets minimum character requirement
|
|
1171
|
+
if (trimmed.length < MIN_SEARCH_CHARS) {
|
|
1172
|
+
setSearchResults([]);
|
|
1173
|
+
setIsSearching(false);
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
// Avoid duplicate searches
|
|
1177
|
+
if (searchRef.current === debouncedSearch)
|
|
1178
|
+
return;
|
|
1179
|
+
searchRef.current = debouncedSearch;
|
|
1180
|
+
setIsSearching(true);
|
|
1181
|
+
session.api.form_fields.load_choices_from_database({
|
|
1182
|
+
fieldId: field.id,
|
|
1183
|
+
limit: LOAD_CHOICES_LIMIT,
|
|
1184
|
+
databaseId: databaseId,
|
|
1185
|
+
search: trimmed,
|
|
1186
|
+
})
|
|
1187
|
+
.then(function (_a) {
|
|
1188
|
+
var _b, _d;
|
|
1189
|
+
var newChoices = _a.choices;
|
|
1190
|
+
// Add search results to the same cache as initial load
|
|
1191
|
+
// This ensures selected search results persist even after search is cleared
|
|
1192
|
+
var existingRecords = (_d = (_b = choicesForDatabase[databaseId]) === null || _b === void 0 ? void 0 : _b.records) !== null && _d !== void 0 ? _d : [];
|
|
1193
|
+
var existingIds = new Set(existingRecords.map(function (r) { return r.id; }));
|
|
1194
|
+
var uniqueNewChoices = newChoices.filter(function (c) { return !existingIds.has(c.id); });
|
|
1195
|
+
if (uniqueNewChoices.length > 0) {
|
|
1196
|
+
choicesForDatabase[databaseId] = __assign(__assign({}, choicesForDatabase[databaseId]), { records: __spreadArray(__spreadArray([], existingRecords, true), uniqueNewChoices, true).sort(function (c1, c2) { return (label_for_database_record(field, c1)
|
|
1197
|
+
.localeCompare(label_for_database_record(field, c2))); }), done: true });
|
|
1198
|
+
}
|
|
1199
|
+
setSearchResults(newChoices.sort(function (c1, c2) { return (label_for_database_record(field, c1)
|
|
1200
|
+
.localeCompare(label_for_database_record(field, c2))); }));
|
|
1201
|
+
setIsSearching(false);
|
|
1086
1202
|
})
|
|
1087
1203
|
.catch(function (err) {
|
|
1088
1204
|
console.error(err);
|
|
1089
|
-
|
|
1205
|
+
setIsSearching(false);
|
|
1090
1206
|
});
|
|
1091
|
-
}, [session, field, databaseId,
|
|
1207
|
+
}, [session, field, databaseId, debouncedSearch]);
|
|
1092
1208
|
var addChoice = useCallback(function (record) {
|
|
1093
1209
|
if (!choicesForDatabase[databaseId]) {
|
|
1094
1210
|
choicesForDatabase[databaseId] = {
|
|
@@ -1098,10 +1214,15 @@ var useDatabaseChoices = function (_a) {
|
|
|
1098
1214
|
}
|
|
1099
1215
|
choicesForDatabase[databaseId].records.push(record);
|
|
1100
1216
|
}, [choicesForDatabase, databaseId]);
|
|
1217
|
+
// Use search results if searching, otherwise use cached initial results
|
|
1218
|
+
var activeChoices = debouncedSearch.trim().length >= MIN_SEARCH_CHARS
|
|
1219
|
+
? searchResults
|
|
1220
|
+
: ((_d = (_b = choicesForDatabase[databaseId]) === null || _b === void 0 ? void 0 : _b.records) !== null && _d !== void 0 ? _d : []);
|
|
1101
1221
|
return {
|
|
1102
1222
|
addChoice: addChoice,
|
|
1103
|
-
doneLoading:
|
|
1104
|
-
|
|
1223
|
+
doneLoading: initialLoadComplete,
|
|
1224
|
+
isSearching: isSearching,
|
|
1225
|
+
choices: __spreadArray(__spreadArray([], activeChoices, true), (otherAnswers || []).map(function (v) {
|
|
1105
1226
|
var _a;
|
|
1106
1227
|
return ({
|
|
1107
1228
|
id: v.text,
|
|
@@ -1109,7 +1230,7 @@ var useDatabaseChoices = function (_a) {
|
|
|
1109
1230
|
values: [{ label: ((_a = field.options) === null || _a === void 0 ? void 0 : _a.databaseLabel) || '', type: 'Text', value: v.text }],
|
|
1110
1231
|
});
|
|
1111
1232
|
}), true),
|
|
1112
|
-
|
|
1233
|
+
minSearchChars: MIN_SEARCH_CHARS,
|
|
1113
1234
|
};
|
|
1114
1235
|
};
|
|
1115
1236
|
var label_for_database_record = function (field, record) {
|
|
@@ -1141,13 +1262,15 @@ var get_other_answers = function (_value, typing) {
|
|
|
1141
1262
|
};
|
|
1142
1263
|
export var DatabaseSelectInput = function (_a) {
|
|
1143
1264
|
var _b, _d, _e, _f, _g, _h, _j, _k;
|
|
1144
|
-
var AddToDatabase = _a.AddToDatabase, field = _a.field, _value = _a.value, onChange = _a.onChange, onDatabaseSelect = _a.onDatabaseSelect, responses = _a.responses, size = _a.size, disabled = _a.disabled, enduser = _a.enduser;
|
|
1265
|
+
var AddToDatabase = _a.AddToDatabase, field = _a.field, _value = _a.value, onChange = _a.onChange, onDatabaseSelect = _a.onDatabaseSelect, responses = _a.responses, size = _a.size, disabled = _a.disabled, enduser = _a.enduser, inputProps = _a.inputProps;
|
|
1145
1266
|
var _l = useState(''), typing = _l[0], setTyping = _l[1];
|
|
1146
|
-
var _m =
|
|
1267
|
+
var _m = useState(false), open = _m[0], setOpen = _m[1];
|
|
1268
|
+
var _o = useDatabaseChoices({
|
|
1147
1269
|
databaseId: (_b = field.options) === null || _b === void 0 ? void 0 : _b.databaseId,
|
|
1148
1270
|
field: field,
|
|
1149
1271
|
otherAnswers: get_other_answers(_value, ((_d = field === null || field === void 0 ? void 0 : field.options) === null || _d === void 0 ? void 0 : _d.other) ? typing : undefined),
|
|
1150
|
-
|
|
1272
|
+
searchQuery: typing,
|
|
1273
|
+
}), addChoice = _o.addChoice, choices = _o.choices, doneLoading = _o.doneLoading, isSearching = _o.isSearching, minSearchChars = _o.minSearchChars;
|
|
1151
1274
|
var value = React.useMemo(function () {
|
|
1152
1275
|
var _a, _b;
|
|
1153
1276
|
try {
|
|
@@ -1251,9 +1374,13 @@ export var DatabaseSelectInput = function (_a) {
|
|
|
1251
1374
|
}
|
|
1252
1375
|
return filtered;
|
|
1253
1376
|
}, [field, stateFilteredChoices]);
|
|
1377
|
+
// Show placeholder when typing but below minimum search characters
|
|
1378
|
+
var charsNeeded = typing.trim().length > 0 && typing.trim().length < minSearchChars
|
|
1379
|
+
? minSearchChars - typing.trim().length
|
|
1380
|
+
: 0;
|
|
1254
1381
|
if (!doneLoading)
|
|
1255
1382
|
return _jsx(LinearProgress, {});
|
|
1256
|
-
return (_jsxs(_Fragment, { children: [_jsx(Autocomplete, { id: field.id, freeSolo: false, size: size, componentsProps: { popper: { sx: { wordBreak: "break-word" } } }, options: filteredChoices, multiple: true, getOptionLabel: function (o) { return (Array.isArray(o) // edge case
|
|
1383
|
+
return (_jsxs(_Fragment, { children: [_jsx(Autocomplete, { id: field.id, freeSolo: false, size: size, componentsProps: { popper: { sx: { wordBreak: "break-word" } } }, options: filteredChoices, multiple: true, loading: isSearching, open: open, onOpen: function () { return setOpen(true); }, onClose: function () { return setOpen(false); }, getOptionLabel: function (o) { return (Array.isArray(o) // edge case
|
|
1257
1384
|
? ''
|
|
1258
1385
|
: label_for_database_record(field, o)); }, value: value, disabled: disabled, onChange: function (_, v) {
|
|
1259
1386
|
var _a, _b, _d, _e, _f;
|
|
@@ -1276,7 +1403,7 @@ export var DatabaseSelectInput = function (_a) {
|
|
|
1276
1403
|
recordId: (_f = (_e = v[v.length - 1]) === null || _e === void 0 ? void 0 : _e.id) !== null && _f !== void 0 ? _f : '',
|
|
1277
1404
|
text: label_for_database_record(field, v[v.length - 1]),
|
|
1278
1405
|
}]), field.id);
|
|
1279
|
-
}, inputValue: typing, onInputChange: function (e, v) { return e && setTyping(v); }, renderInput: function (params) { return _jsx(TextField, __assign({}, params, { InputProps: __assign(__assign({}, params.InputProps), { sx: defaultInputProps.sx }) })); },
|
|
1406
|
+
}, inputValue: typing, onInputChange: function (e, v) { return e && setTyping(v); }, renderInput: function (params) { return (_jsx(TextField, __assign({}, params, { InputProps: __assign(__assign({}, params.InputProps), { sx: (inputProps || defaultInputProps).sx, endAdornment: (_jsxs(_Fragment, { children: [isSearching ? _jsx(CircularProgress, { color: "inherit", size: 20 }) : null, params.InputProps.endAdornment] })) }), placeholder: charsNeeded > 0 ? "Type ".concat(charsNeeded, " more character").concat(charsNeeded > 1 ? 's' : '', " to search...") : undefined, helperText: charsNeeded > 0 ? "Type ".concat(charsNeeded, " more character").concat(charsNeeded > 1 ? 's' : '', " to search") : undefined }))); },
|
|
1280
1407
|
// use custom Chip to ensure very long entries break properly (whitespace: normal)
|
|
1281
1408
|
renderTags: function (value, getTagProps) {
|
|
1282
1409
|
return value.map(function (value, index) { return (_jsx(Chip, __assign({ label: _jsx(Typography, __assign({ style: { whiteSpace: 'normal' } }, { children: Array.isArray(value) ? '' : label_for_database_record(field, value) })) }, getTagProps({ index: index }), { sx: { height: "100%", py: 0.5 } }))); });
|
|
@@ -1652,7 +1779,7 @@ export var contact_is_valid = function (e) {
|
|
|
1652
1779
|
};
|
|
1653
1780
|
export var RelatedContactsInput = function (_a) {
|
|
1654
1781
|
var _b, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _w, _x;
|
|
1655
|
-
var field = _a.field, _value = _a.value, onChange = _a.onChange, props = __rest(_a, ["field", "value", "onChange"]);
|
|
1782
|
+
var field = _a.field, _value = _a.value, onChange = _a.onChange, parentError = _a.error, props = __rest(_a, ["field", "value", "onChange", "error"]);
|
|
1656
1783
|
// safeguard against any rogue values like empty string
|
|
1657
1784
|
var value = Array.isArray(_value) ? _value : [];
|
|
1658
1785
|
var _y = useState(value.length === 1 ? 0 : -1), editing = _y[0], setEditing = _y[1];
|
|
@@ -1671,7 +1798,7 @@ export var RelatedContactsInput = function (_a) {
|
|
|
1671
1798
|
_jsx(Grid, __assign({ item: true, xs: 4 }, { children: _jsx(TextField, { label: "Last Name", size: "small", fullWidth: true, InputProps: defaultInputProps, value: lname, onChange: function (e) { return onChange(value.map(function (v, i) { return i === editing ? __assign(__assign({}, v), { lname: e.target.value }) : v; }), field.id); } }) })), _jsx(Grid, __assign({ item: true, xs: 4 }, { children: _jsx(StringSelector, { options: ((_j = (_h = field.options) === null || _h === void 0 ? void 0 : _h.relatedContactTypes) === null || _j === void 0 ? void 0 : _j.length) ? field.options.relatedContactTypes : RELATIONSHIP_TYPES, label: "Relationship", size: "small", disabled: ((_l = (_k = field === null || field === void 0 ? void 0 : field.options) === null || _k === void 0 ? void 0 : _k.relatedContactTypes) === null || _l === void 0 ? void 0 : _l.length) === 1, value: (_o = (_m = relationships === null || relationships === void 0 ? void 0 : relationships[0]) === null || _m === void 0 ? void 0 : _m.type) !== null && _o !== void 0 ? _o : '', onChange: function (type) { return onChange(value.map(function (v, i) { return i === editing ? __assign(__assign({}, v), { relationships: [{ type: type, id: '' /* to be filled on server-side */ }] }) : v; }), field.id); } }) }))] })) })), _jsx(Grid, __assign({ item: true }, { children: _jsxs(Grid, __assign({ container: true, alignItems: "center", wrap: "nowrap", spacing: 1 }, { children: [!((_q = (_p = field.options) === null || _p === void 0 ? void 0 : _p.hiddenDefaultFields) === null || _q === void 0 ? void 0 : _q.includes('Date of Birth')) &&
|
|
1672
1799
|
_jsx(Grid, __assign({ item: true, xs: 4 }, { children: _jsx(DateStringInput, { value: dateOfBirth, field: __assign(__assign({}, field), { isOptional: true }), size: "small", label: "Date of Birth (MM-DD-YYYY)", onChange: function (dateOfBirth) { return onChange(value.map(function (v, i) { return i === editing ? __assign(__assign({}, v), { dateOfBirth: dateOfBirth }) : v; }), field.id); } }) })), !((_s = (_r = field.options) === null || _r === void 0 ? void 0 : _r.hiddenDefaultFields) === null || _s === void 0 ? void 0 : _s.includes('Email')) &&
|
|
1673
1800
|
_jsx(Grid, __assign({ item: true, xs: 4 }, { children: _jsx(TextField, { label: "Email", size: "small", fullWidth: true, type: "email", InputProps: defaultInputProps, value: email, onChange: function (e) { return onChange(value.map(function (v, i) { return i === editing ? __assign(__assign({}, v), { email: e.target.value }) : v; }), field.id); } }) })), !((_u = (_t = field.options) === null || _t === void 0 ? void 0 : _t.hiddenDefaultFields) === null || _u === void 0 ? void 0 : _u.includes('Phone Number')) &&
|
|
1674
|
-
_jsx(Grid, __assign({ item: true, xs: 4 }, { children: _jsx(TextField, { label: "Phone Number", size: "small", fullWidth: true, InputProps: defaultInputProps, value: phone, onChange: function (e) { return onChange(value.map(function (v, i) { return i === editing ? __assign(__assign({}, v), { phone: e.target.value }) : v; }), field.id); } }) }))] })) })), (((_w = field.options) === null || _w === void 0 ? void 0 : _w.tableChoices) || []).length > 0 &&
|
|
1801
|
+
_jsx(Grid, __assign({ item: true, xs: 4 }, { children: _jsx(TextField, { label: "Phone Number", size: "small", fullWidth: true, InputProps: defaultInputProps, value: phone, onChange: function (e) { return onChange(value.map(function (v, i) { return i === editing ? __assign(__assign({}, v), { phone: e.target.value.trim() }) : v; }), field.id); } }) }))] })) })), (((_w = field.options) === null || _w === void 0 ? void 0 : _w.tableChoices) || []).length > 0 &&
|
|
1675
1802
|
_jsx(Grid, __assign({ item: true }, { children: _jsx(Grid, __assign({ container: true, spacing: 1 }, { children: (((_x = field.options) === null || _x === void 0 ? void 0 : _x.tableChoices) || []).map(function (_a, i) {
|
|
1676
1803
|
var info = _a.info, label = _a.label, type = _a.type;
|
|
1677
1804
|
return (_jsx(Grid, __assign({ item: true, xs: 6 }, { children: type === 'Text'
|
|
@@ -1691,7 +1818,7 @@ export var RelatedContactsInput = function (_a) {
|
|
|
1691
1818
|
return i === editing ? __assign(__assign({}, v), { fields: __assign(__assign({}, fields_1), (_a = {}, _a[label] = e.target.value, _a)) }) : v;
|
|
1692
1819
|
}), field.id); } }, { children: [_jsx(MenuItem, __assign({ value: "" }, { children: _jsx("em", { children: "None" }) })), info.choices.map(function (c) { return (_jsx(MenuItem, __assign({ value: c }, { children: c }), c)); })] }))] })))
|
|
1693
1820
|
: null }), i));
|
|
1694
|
-
}) })) })), _jsx(Grid, __assign({ item: true, sx: { my: 0.75 } }, { children: _jsx(Button, __assign({ variant: "outlined", onClick: function () { return setEditing(-1); }, size: "small" }, { children: "Save Contact" })) })), errorMessage &&
|
|
1821
|
+
}) })) })), _jsx(Grid, __assign({ item: true, sx: { my: 0.75 } }, { children: _jsx(Button, __assign({ variant: "outlined", onClick: function () { return setEditing(-1); }, size: "small", disabled: !!errorMessage || !!parentError }, { children: "Save Contact" })) })), errorMessage &&
|
|
1695
1822
|
_jsx(Grid, __assign({ item: true }, { children: _jsx(Typography, __assign({ color: "error" }, { children: errorMessage })) }))] })));
|
|
1696
1823
|
}
|
|
1697
1824
|
return (_jsxs(Grid, __assign({ container: true, direction: "column", spacing: 1 }, { children: [_jsx(Grid, __assign({ item: true }, { children: value.map(function (contact, i) { return (_jsx(Grid, __assign({ item: true }, { children: _jsxs(Grid, __assign({ container: true, alignItems: "center", justifyContent: "space-between", wrap: "nowrap", spacing: 1 }, { children: [_jsx(Grid, __assign({ item: true }, { children: _jsxs(Grid, __assign({ container: true, alignItems: "center" }, { children: [_jsx(IconButton, __assign({ onClick: function () { return setEditing(i); }, color: "primary", size: "small" }, { children: _jsx(Edit, {}) })), _jsx(Typography, __assign({ noWrap: true }, { children: user_display_name(contact) || "Unnamed Contact ".concat(i + 1) }))] })) })), _jsx(Grid, __assign({ item: true }, { children: _jsx(LabeledIconButton, { Icon: Delete, label: "Remove", onClick: function () { return onChange(value.filter(function (v, _i) { return i !== _i; }), field.id); } }) }))] })) }), i)); }) })), _jsx(Grid, __assign({ item: true }, { children: _jsx(Button, __assign({ variant: "contained", onClick: handleAddContact }, { children: "Add Contact" })) }))] })));
|