@cxpinsight/react-native 0.21.0 → 0.23.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.
- package/CHANGELOG.md +37 -0
- package/lib/CXPinsight.d.ts +7 -2
- package/lib/CXPinsight.d.ts.map +1 -1
- package/lib/CXPinsight.js +32 -2
- package/lib/CXPinsight.js.map +1 -1
- package/lib/CXPinsightProvider.d.ts.map +1 -1
- package/lib/CXPinsightProvider.js +3 -0
- package/lib/CXPinsightProvider.js.map +1 -1
- package/lib/core/firebaseBridge.d.ts +49 -0
- package/lib/core/firebaseBridge.d.ts.map +1 -0
- package/lib/core/firebaseBridge.js +158 -0
- package/lib/core/firebaseBridge.js.map +1 -0
- package/lib/core/mobileRecorder.d.ts.map +1 -1
- package/lib/core/mobileRecorder.js +23 -1
- package/lib/core/mobileRecorder.js.map +1 -1
- package/lib/core/networkCapture.d.ts.map +1 -1
- package/lib/core/networkCapture.js +9 -4
- package/lib/core/networkCapture.js.map +1 -1
- package/lib/core/triggerEngine.d.ts.map +1 -1
- package/lib/core/triggerEngine.js +10 -3
- package/lib/core/triggerEngine.js.map +1 -1
- package/lib/survey/SurveyModal.d.ts +4 -1
- package/lib/survey/SurveyModal.d.ts.map +1 -1
- package/lib/survey/SurveyModal.js +36 -15
- package/lib/survey/SurveyModal.js.map +1 -1
- package/lib/survey/questions/CSATQuestion.js +1 -1
- package/lib/survey/questions/CSATQuestion.js.map +1 -1
- package/lib/survey/questions/MultipleChoiceQuestion.d.ts +14 -2
- package/lib/survey/questions/MultipleChoiceQuestion.d.ts.map +1 -1
- package/lib/survey/questions/MultipleChoiceQuestion.js +67 -7
- package/lib/survey/questions/MultipleChoiceQuestion.js.map +1 -1
- package/lib/survey/questions/RatingQuestion.d.ts +30 -2
- package/lib/survey/questions/RatingQuestion.d.ts.map +1 -1
- package/lib/survey/questions/RatingQuestion.js +127 -16
- package/lib/survey/questions/RatingQuestion.js.map +1 -1
- package/lib/survey/styleContract.d.ts +25 -0
- package/lib/survey/styleContract.d.ts.map +1 -1
- package/lib/survey/styleContract.js +37 -0
- package/lib/survey/styleContract.js.map +1 -1
- package/lib/survey/validate.d.ts +2 -1
- package/lib/survey/validate.d.ts.map +1 -1
- package/lib/survey/validate.js +3 -2
- package/lib/survey/validate.js.map +1 -1
- package/lib/types.d.ts +16 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +7 -3
|
@@ -49,7 +49,6 @@ const react_native_1 = require("react-native");
|
|
|
49
49
|
const types_1 = require("../types");
|
|
50
50
|
const storage = __importStar(require("../core/storage"));
|
|
51
51
|
const NPSQuestion_1 = require("./questions/NPSQuestion");
|
|
52
|
-
const CSATQuestion_1 = require("./questions/CSATQuestion");
|
|
53
52
|
const TextQuestion_1 = require("./questions/TextQuestion");
|
|
54
53
|
const MultipleChoiceQuestion_1 = require("./questions/MultipleChoiceQuestion");
|
|
55
54
|
const RankingQuestion_1 = require("./questions/RankingQuestion");
|
|
@@ -59,6 +58,7 @@ const ImagePickerQuestion_1 = require("./questions/ImagePickerQuestion");
|
|
|
59
58
|
const MatrixDropdownQuestion_1 = require("./questions/MatrixDropdownQuestion");
|
|
60
59
|
const MatrixDynamicQuestion_1 = require("./questions/MatrixDynamicQuestion");
|
|
61
60
|
const PanelDynamicQuestion_1 = require("./questions/PanelDynamicQuestion");
|
|
61
|
+
const RatingQuestion_1 = require("./questions/RatingQuestion");
|
|
62
62
|
const DateQuestion_1 = require("./questions/DateQuestion");
|
|
63
63
|
const survey_spec_1 = require("@cxpinsight/survey-spec");
|
|
64
64
|
const mobileRecorder_1 = require("../core/mobileRecorder");
|
|
@@ -502,7 +502,7 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
502
502
|
if (!q)
|
|
503
503
|
return prev;
|
|
504
504
|
// Same rule as the page pass: a locked question raises no error.
|
|
505
|
-
const err = isEnabled(q) ? (0, validate_1.validateAnswer)(forValidation(q), value) : null;
|
|
505
|
+
const err = isEnabled(q) ? (0, validate_1.validateAnswer)(forValidation(q), value, currentLanguage) : null;
|
|
506
506
|
if (err)
|
|
507
507
|
return prev; // still invalid → keep the error
|
|
508
508
|
const { [name]: _dropped, ...rest } = prev;
|
|
@@ -598,7 +598,7 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
598
598
|
if (!isEnabled(q))
|
|
599
599
|
continue;
|
|
600
600
|
const k = q.id || q.name;
|
|
601
|
-
const err = (0, validate_1.validateAnswer)(forValidation(q), responses[k]);
|
|
601
|
+
const err = (0, validate_1.validateAnswer)(forValidation(q), responses[k], currentLanguage);
|
|
602
602
|
if (err)
|
|
603
603
|
out[k] = err;
|
|
604
604
|
}
|
|
@@ -609,7 +609,7 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
609
609
|
// server rejection (survey deactivated, cap hit) surfaces a retry
|
|
610
610
|
// message instead of a false thank-you.
|
|
611
611
|
const submitAndReset = async () => {
|
|
612
|
-
const ok = await onSubmit(buildSubmitPayload(), { via: viaRef.current });
|
|
612
|
+
const ok = await onSubmit(buildSubmitPayload(), { via: viaRef.current, language: currentLanguage || survey.defaultLanguage || undefined });
|
|
613
613
|
if (ok === false) {
|
|
614
614
|
setSubmitError('We couldn’t submit your response. Please try again.');
|
|
615
615
|
return; // keep the survey open for a retry
|
|
@@ -949,7 +949,18 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
949
949
|
return ((0, jsx_runtime_1.jsx)(NPSQuestion_1.NPSQuestion, { value: val ?? null, onChange: (v) => updateResponse(key, v), contract: contract }));
|
|
950
950
|
},
|
|
951
951
|
'rating': () => {
|
|
952
|
-
|
|
952
|
+
// ONE scale for every ratingType. This drew CSATQuestion — stars only,
|
|
953
|
+
// always from 1 — so a number, smiley or thumb scale, a 0-based range
|
|
954
|
+
// and the end captions all rendered as five stars on the phone. The
|
|
955
|
+
// keys and the aliases are the web SDK's (_cxpQ_rating): minValue /
|
|
956
|
+
// maxValue (v1.1, also what render.props min/max become above), then
|
|
957
|
+
// the SurveyJS-era rateMin / rateMax; rateLabels' ends win as captions.
|
|
958
|
+
const qx = question;
|
|
959
|
+
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : (typeof v === 'string' && v.trim() !== '' && Number.isFinite(Number(v)) ? Number(v) : undefined));
|
|
960
|
+
const labels = Array.isArray(qx.rateLabels) ? qx.rateLabels : [];
|
|
961
|
+
return ((0, jsx_runtime_1.jsx)(RatingQuestion_1.RatingQuestion, { value: val ?? null, onChange: (v) => updateResponse(key, v), rateMin: num(qx.minValue) ?? num(qx.rateMin) ?? 1, rateMax: num(qx.maxValue) ?? num(qx.rateMax) ?? 5,
|
|
962
|
+
// Unset is a star — the web SDK's default, and what this always drew.
|
|
963
|
+
ratingType: typeof qx.ratingType === 'string' && qx.ratingType ? qx.ratingType : 'star', minLabel: labels.length ? labels[0] : (qx.minLabel || qx.minRateDescription), maxLabel: labels.length ? labels[labels.length - 1] : (qx.maxLabel || qx.maxRateDescription), contract: contract, explicit: explicitFields }));
|
|
953
964
|
},
|
|
954
965
|
'csat': () => RENDERERS['rating'](),
|
|
955
966
|
'ces': () => RENDERERS['rating'](),
|
|
@@ -968,18 +979,18 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
968
979
|
'email': () => RENDERERS['text'](),
|
|
969
980
|
'number': () => RENDERERS['text'](),
|
|
970
981
|
'radio': () => {
|
|
971
|
-
return ((0, jsx_runtime_1.jsx)(MultipleChoiceQuestion_1.MultipleChoiceQuestion, { choices: normalizeChoices(question), value: val ?? '', onChange: (v) => updateResponse(key, v), mode: "radiogroup", isRtl: isRtl, contract: contract }));
|
|
982
|
+
return ((0, jsx_runtime_1.jsx)(MultipleChoiceQuestion_1.MultipleChoiceQuestion, { choices: normalizeChoices(question), value: val ?? '', onChange: (v) => updateResponse(key, v), mode: "radiogroup", isRtl: isRtl, contract: contract, optionLayout: question.optionLayout, explicit: explicitFields }));
|
|
972
983
|
},
|
|
973
984
|
'radiogroup': () => RENDERERS['radio'](),
|
|
974
985
|
'dropdown': () => RENDERERS['radio'](),
|
|
975
986
|
'checkbox': () => {
|
|
976
|
-
return ((0, jsx_runtime_1.jsx)(MultipleChoiceQuestion_1.MultipleChoiceQuestion, { choices: normalizeChoices(question), value: val ?? [], onChange: (v) => updateResponse(key, v), mode: "checkbox", isRtl: isRtl, contract: contract }));
|
|
987
|
+
return ((0, jsx_runtime_1.jsx)(MultipleChoiceQuestion_1.MultipleChoiceQuestion, { choices: normalizeChoices(question), value: val ?? [], onChange: (v) => updateResponse(key, v), mode: "checkbox", isRtl: isRtl, contract: contract, optionLayout: question.optionLayout, explicit: explicitFields }));
|
|
977
988
|
},
|
|
978
989
|
'binary': () => {
|
|
979
990
|
return ((0, jsx_runtime_1.jsx)(MultipleChoiceQuestion_1.MultipleChoiceQuestion, { choices: [
|
|
980
|
-
{ value: 'true', text: question.yesLabel || '
|
|
981
|
-
{ value: 'false', text: question.noLabel || '
|
|
982
|
-
], value: val ?? '', onChange: (v) => updateResponse(key, v), mode: "radiogroup", isRtl: isRtl, contract: contract }));
|
|
991
|
+
{ value: 'true', text: question.yesLabel || (0, survey_spec_1.chromeWord)('yes', currentLanguage) },
|
|
992
|
+
{ value: 'false', text: question.noLabel || (0, survey_spec_1.chromeWord)('no', currentLanguage) },
|
|
993
|
+
], value: val ?? '', onChange: (v) => updateResponse(key, v), mode: "radiogroup", isRtl: isRtl, contract: contract, hideIndicator: !(0, survey_spec_1.showsYesNoIndicator)(display) }));
|
|
983
994
|
},
|
|
984
995
|
'boolean': () => RENDERERS['binary'](),
|
|
985
996
|
'yesno': () => RENDERERS['binary'](),
|
|
@@ -1561,6 +1572,12 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
1561
1572
|
[resolvedTheme, primaryColor,
|
|
1562
1573
|
JSON.stringify(surveyPaletteOverride), JSON.stringify(initPaletteOverride),
|
|
1563
1574
|
JSON.stringify(survey.branding?.style)]);
|
|
1575
|
+
// The fields set BY NAME, same layers and order as the contract above
|
|
1576
|
+
// (palette < style slice < host init). Answer surfaces that had no box or
|
|
1577
|
+
// shape before — a bare star, a chip — read these, so a value the contract
|
|
1578
|
+
// only holds as a default cannot redraw them.
|
|
1579
|
+
const explicitFields = (0, react_2.useMemo)(() => (0, styleContract_1.explicitContractFields)(surveyPaletteOverride, stylePlatformSlice(survey.branding?.style), initPaletteOverride), [JSON.stringify(surveyPaletteOverride), JSON.stringify(initPaletteOverride),
|
|
1580
|
+
JSON.stringify(survey.branding?.style)]);
|
|
1564
1581
|
const styles = (0, react_2.useMemo)(() => makeStyles(contract), [contract]);
|
|
1565
1582
|
// A picture band outside the header keeps the CARD'S padding. padBand exists only when a density
|
|
1566
1583
|
// is set; without one the band had no horizontal padding at all and ran edge to edge, like
|
|
@@ -2103,6 +2120,10 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
2103
2120
|
// plain merge that leaves the value undefined — never enabled the swipe
|
|
2104
2121
|
// either. One authored survey, dismissable two different ways depending on
|
|
2105
2122
|
// which screen you were looking at.
|
|
2123
|
+
// The headline and body switches — the same rule the web card and the link
|
|
2124
|
+
// page ask (survey-spec showsTitle / showsDescription).
|
|
2125
|
+
const titleShown = (0, survey_spec_1.showsTitle)(display);
|
|
2126
|
+
const descriptionShown = (0, survey_spec_1.showsDescription)(display);
|
|
2106
2127
|
const closeShown = (0, survey_spec_1.showsClose)(display, interactionKind, survey.delivery);
|
|
2107
2128
|
const closeReserve = !closeShown ? null : {
|
|
2108
2129
|
[isRtl ? 'paddingLeft' : 'paddingRight']: contract.closeSize + contract.closeInset + 8,
|
|
@@ -2885,13 +2906,13 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
2885
2906
|
// it belongs to unless the author says otherwise.
|
|
2886
2907
|
alignSelf: imgD.align === 'start' ? 'flex-start'
|
|
2887
2908
|
: imgD.align === 'end' ? 'flex-end' : 'center',
|
|
2888
|
-
}, resizeMode: imgD.fit })) : null, (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: (besideImage || notifyBeside) ? { flex: 1, minWidth: 0 } : undefined, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.title, dirText, fontStyle, themeTextPrimary, titleFS, notifyTitleFS,
|
|
2909
|
+
}, resizeMode: imgD.fit })) : null, (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: (besideImage || notifyBeside) ? { flex: 1, minWidth: 0 } : undefined, children: [titleShown ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.title, dirText, fontStyle, themeTextPrimary, titleFS, notifyTitleFS,
|
|
2889
2910
|
closeReserve,
|
|
2890
2911
|
{ textAlign: cardTitleAlign }], children: (0, interpolate_1.interpolatePlain)(
|
|
2891
2912
|
// Title is plain text; strip any stray rich-text markup +
|
|
2892
2913
|
// decode so it never shows literal HTML on native.
|
|
2893
2914
|
String((0, translationLookup_1.surveyText)(survey, currentLanguage, 'title', survey.title) || '')
|
|
2894
|
-
.replace(/<[^>]*>/g, '').replace(/ /gi, ' '), evalCtx) }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: notifyBeside ? {
|
|
2915
|
+
.replace(/<[^>]*>/g, '').replace(/ /gi, ' '), evalCtx) })) : null, (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: notifyBeside ? {
|
|
2895
2916
|
flexDirection: 'row',
|
|
2896
2917
|
alignItems: 'center',
|
|
2897
2918
|
justifyContent: 'space-between',
|
|
@@ -2900,7 +2921,7 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
2900
2921
|
// markup, so strip tags + decode to plain text.
|
|
2901
2922
|
const descRaw = (0, translationLookup_1.surveyText)(survey, currentLanguage, 'description', survey.description);
|
|
2902
2923
|
const desc = String(descRaw || '').replace(/<[^>]*>/g, '').replace(/ /gi, ' ').trim();
|
|
2903
|
-
return desc ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.description, dirText, fontStyle, themeTextSecondary, descFS, notifyDescFS,
|
|
2924
|
+
return desc && descriptionShown ? ((0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.description, dirText, fontStyle, themeTextSecondary, descFS, notifyDescFS,
|
|
2904
2925
|
{ textAlign: cardDescAlign },
|
|
2905
2926
|
// Takes the width the button leaves, and no more.
|
|
2906
2927
|
notifyBeside && { flex: 1, minWidth: 0, marginTop: 2 }], children: (0, interpolate_1.interpolatePlain)(desc, evalCtx) })) : null;
|
|
@@ -2996,7 +3017,7 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
2996
3017
|
// Right-align parity with web: Back hugs the left edge while
|
|
2997
3018
|
// Next/Submit sits on the right (web uses margin-right:auto).
|
|
2998
3019
|
buttonAlign === 'right' && { marginRight: 'auto' },
|
|
2999
|
-
], onPress: handleBack, activeOpacity: 0.7, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.backButtonText, fontStyle, themeTextSecondary, buttonFS], children:
|
|
3020
|
+
], onPress: handleBack, activeOpacity: 0.7, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.backButtonText, fontStyle, themeTextSecondary, buttonFS], children: (0, survey_spec_1.chromeWord)('back', currentLanguage) }) })), impliedNow.length > 0 || !(0, survey_spec_1.drawsOwnSubmit)(survey.interactionType) ? null : (() => {
|
|
3000
3021
|
// Reflect the actual outcome of pressing Next: if a
|
|
3001
3022
|
// branch resolves to __end__ we're submitting even
|
|
3002
3023
|
// when we're not on the last page. Cheap to evaluate
|
|
@@ -3014,7 +3035,7 @@ function SurveyModal({ survey, visible, onSubmit, onDismiss, reply = null }) {
|
|
|
3014
3035
|
// explicitly 'full'. When the author picked right/center/left,
|
|
3015
3036
|
// respect it even on the first page (was forced full-width,
|
|
3016
3037
|
// so mobile ignored the setting on page 1 — unlike web).
|
|
3017
|
-
style: [styles.nextButton, ((isSingleButton && !alignsAuto) || buttonAlign === 'full') && styles.nextButtonFull, btnAutoWidth, { backgroundColor: primaryColor }], onPress: handleNext, activeOpacity: 0.7, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.nextButtonText, fontStyle, buttonFS], children: willSubmit ? '
|
|
3038
|
+
style: [styles.nextButton, ((isSingleButton && !alignsAuto) || buttonAlign === 'full') && styles.nextButtonFull, btnAutoWidth, { backgroundColor: primaryColor }], onPress: handleNext, activeOpacity: 0.7, children: (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.nextButtonText, fontStyle, buttonFS], children: willSubmit ? (0, survey_spec_1.chromeWord)('submit', currentLanguage) : (0, survey_spec_1.chromeWord)('next', currentLanguage) }) }));
|
|
3018
3039
|
})()] })] })] }))] }), (0, jsx_runtime_1.jsx)(handsFreeVoice_1.VoiceOverlay, { visible: voiceActive, phase: voicePhase, transcript: voiceTranscript, onStop: () => (0, handsFreeVoice_1.stopVoice)() })] }) }));
|
|
3019
3040
|
}
|
|
3020
3041
|
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = react_native_1.Dimensions.get('window');
|