@eshal-bot/chat-widget 0.2.38 → 0.2.40
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/dist/{chat-widget-MarkdownRenderer-DBibTmXG.esm.js → chat-widget-MarkdownRenderer-H7vRRyDu.esm.js} +1 -1
- package/dist/chat-widget-index-BubaEkmK.esm.js +20 -0
- package/dist/chat-widget-markdown-chunk.js +102 -19
- package/dist/chat-widget-markdown-chunk.min.js +1 -1
- package/dist/chat-widget.esm.js +1 -1
- package/dist/chat-widget.js +23 -3
- package/dist/chat-widget.min.js +2 -2
- package/dist/chat-widget.umd.js +6 -6
- package/package.json +1 -1
- package/dist/chat-widget-index-nFrn-Uh5.esm.js +0 -20
|
@@ -88751,6 +88751,29 @@
|
|
|
88751
88751
|
function fill(text, values) {
|
|
88752
88752
|
return Object.entries(values).reduce((s, [k, v]) => s.replace(`{${k}}`, String(v)), String(text));
|
|
88753
88753
|
}
|
|
88754
|
+
|
|
88755
|
+
/** EV-4941: keep a masked address on one line ("+91 ••••• 6138"). */
|
|
88756
|
+
const noBreak = text => String(text ?? '').replace(/ /g, '\u00a0');
|
|
88757
|
+
|
|
88758
|
+
/**
|
|
88759
|
+
* EV-4939: a number whose calling code is not among the allowed ones, so the
|
|
88760
|
+
* card can say so before Send. Only numbers typed with +; a partial code that
|
|
88761
|
+
* could still become an allowed one is not flagged.
|
|
88762
|
+
*/
|
|
88763
|
+
function blockedByCountry(address, codes) {
|
|
88764
|
+
if (!Array.isArray(codes) || codes.length === 0 || !String(address).trim().startsWith('+')) return false;
|
|
88765
|
+
const digits = String(address).replace(/\D/g, '');
|
|
88766
|
+
if (!digits) return false;
|
|
88767
|
+
return !codes.some(c => digits.startsWith(c) || c.startsWith(digits));
|
|
88768
|
+
}
|
|
88769
|
+
|
|
88770
|
+
/** "14:59" for a lockout's time left. */
|
|
88771
|
+
function clock(seconds) {
|
|
88772
|
+
const s = Math.max(0, Math.ceil(seconds));
|
|
88773
|
+
// "4:59:59" past an hour (a daily limit).
|
|
88774
|
+
const mmss = `${String(Math.floor(s % 3600 / 60)).padStart(s >= 3600 ? 2 : 1, '0')}:${String(s % 60).padStart(2, '0')}`;
|
|
88775
|
+
return s >= 3600 ? `${Math.floor(s / 3600)}:${mmss}` : mmss;
|
|
88776
|
+
}
|
|
88754
88777
|
function boxStyle(isDark) {
|
|
88755
88778
|
return {
|
|
88756
88779
|
border: `1px solid ${BRAND_BLUE$1}`,
|
|
@@ -88824,6 +88847,13 @@
|
|
|
88824
88847
|
const [error, setError] = React.useState(null);
|
|
88825
88848
|
const [resendIn, setResendIn] = React.useState(0);
|
|
88826
88849
|
const [cancelled, setCancelled] = React.useState(false);
|
|
88850
|
+
// EV-4939: a lockout's end from the server, and the allowed calling codes.
|
|
88851
|
+
const [lockUntil, setLockUntil] = React.useState(null);
|
|
88852
|
+
const [lockIn, setLockIn] = React.useState(0);
|
|
88853
|
+
// EV-4939 item 8: the number a per-number limit holds; null holds every
|
|
88854
|
+
// number (a lockout is for the conversation).
|
|
88855
|
+
const [lockFor, setLockFor] = React.useState(null);
|
|
88856
|
+
const [callingCodes, setCallingCodes] = React.useState(null);
|
|
88827
88857
|
const resumedRef = React.useRef(false);
|
|
88828
88858
|
const pendingKey = React.useRef(Symbol('verify-card'));
|
|
88829
88859
|
// A card the conversation already moved past (a later visitor turn exists,
|
|
@@ -88871,6 +88901,31 @@
|
|
|
88871
88901
|
clearInterval(id);
|
|
88872
88902
|
};
|
|
88873
88903
|
}, [mode, step, ctx, t]);
|
|
88904
|
+
React.useEffect(() => {
|
|
88905
|
+
if (mode !== 'sms' || !ctx?.config) return undefined;
|
|
88906
|
+
let gone = false;
|
|
88907
|
+
ctx.config().then(res => {
|
|
88908
|
+
const codes = res?.body?.sms_calling_codes;
|
|
88909
|
+
if (!gone && Array.isArray(codes)) setCallingCodes(codes.map(String));
|
|
88910
|
+
}).catch(() => undefined);
|
|
88911
|
+
return () => {
|
|
88912
|
+
gone = true;
|
|
88913
|
+
};
|
|
88914
|
+
}, [mode, ctx]);
|
|
88915
|
+
React.useEffect(() => {
|
|
88916
|
+
if (!lockUntil) return undefined;
|
|
88917
|
+
const tick = () => {
|
|
88918
|
+
const left = (lockUntil - Date.now()) / 1000;
|
|
88919
|
+
if (left <= 0) {
|
|
88920
|
+
setLockUntil(null);
|
|
88921
|
+
setLockIn(0);
|
|
88922
|
+
setError(null);
|
|
88923
|
+
} else setLockIn(left);
|
|
88924
|
+
};
|
|
88925
|
+
tick();
|
|
88926
|
+
const id = setInterval(tick, 1000);
|
|
88927
|
+
return () => clearInterval(id);
|
|
88928
|
+
}, [lockUntil]);
|
|
88874
88929
|
React.useEffect(() => {
|
|
88875
88930
|
if (resendIn <= 0) return undefined;
|
|
88876
88931
|
const id = setTimeout(() => setResendIn(s => s - 1), 1000);
|
|
@@ -88908,12 +88963,22 @@
|
|
|
88908
88963
|
});
|
|
88909
88964
|
if (res.ok) {
|
|
88910
88965
|
setMasked(res.body?.masked || address.trim());
|
|
88966
|
+
setLockUntil(null);
|
|
88967
|
+
setLockFor(null);
|
|
88968
|
+
// EV-4941: if the card goes back to the number step (lockout, expiry,
|
|
88969
|
+
// a new number), the field reads "+91 90749 76138", not "+919074976138".
|
|
88970
|
+
if (res.body?.formatted) setAddress(String(res.body.formatted));
|
|
88911
88971
|
setResendIn(Number(res.body?.resend_after_s) || 60);
|
|
88912
88972
|
setCode('');
|
|
88913
88973
|
setStep('code');
|
|
88914
88974
|
} else {
|
|
88915
88975
|
setError(res.body?.error || t('verifyGenericError'));
|
|
88916
88976
|
if (res.body?.resendAfterS) setResendIn(Number(res.body.resendAfterS));
|
|
88977
|
+
if ((res.body?.code === 'locked' || res.body?.code === 'too_many') && res.body?.lockedUntil) {
|
|
88978
|
+
setLockUntil(Date.parse(res.body.lockedUntil));
|
|
88979
|
+
setLockFor(res.body.code === 'too_many' ? address.trim() : null);
|
|
88980
|
+
setResendIn(0);
|
|
88981
|
+
}
|
|
88917
88982
|
}
|
|
88918
88983
|
} catch {
|
|
88919
88984
|
setError(t('verifyGenericError'));
|
|
@@ -88948,13 +89013,19 @@
|
|
|
88948
89013
|
});
|
|
88949
89014
|
}
|
|
88950
89015
|
} else if (res.body?.code === 'wrong_code' && typeof res.body?.triesLeft === 'number') {
|
|
88951
|
-
setError(fill(t('verifyTriesLeft'), {
|
|
89016
|
+
setError(fill(t(res.body.triesLeft === 1 ? 'verifyTryLeft' : 'verifyTriesLeft'), {
|
|
88952
89017
|
count: res.body.triesLeft
|
|
88953
89018
|
}));
|
|
88954
89019
|
setCode('');
|
|
88955
89020
|
} else {
|
|
88956
89021
|
setError(res.body?.error || t('verifyGenericError'));
|
|
88957
89022
|
if (res.body?.code === 'expired' || res.body?.code === 'locked') setStep('address');
|
|
89023
|
+
// EV-4939: a lockout holds Send for its whole length, as a countdown.
|
|
89024
|
+
if (res.body?.code === 'locked' && res.body?.lockedUntil) {
|
|
89025
|
+
setLockUntil(Date.parse(res.body.lockedUntil));
|
|
89026
|
+
setLockFor(null);
|
|
89027
|
+
setResendIn(0);
|
|
89028
|
+
}
|
|
88958
89029
|
}
|
|
88959
89030
|
} catch {
|
|
88960
89031
|
setError(t('verifyGenericError'));
|
|
@@ -88972,11 +89043,22 @@
|
|
|
88972
89043
|
fontWeight: 600
|
|
88973
89044
|
},
|
|
88974
89045
|
children: ["\u2713 ", fill(t('verifyDone'), {
|
|
88975
|
-
target: masked
|
|
89046
|
+
target: noBreak(masked)
|
|
88976
89047
|
})]
|
|
88977
89048
|
})
|
|
88978
89049
|
});
|
|
88979
89050
|
}
|
|
89051
|
+
const countryBlocked = mode === 'sms' && blockedByCountry(address, callingCodes);
|
|
89052
|
+
const errorLine = text => text ? /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
89053
|
+
role: "alert",
|
|
89054
|
+
style: {
|
|
89055
|
+
color: '#b42318',
|
|
89056
|
+
fontSize: 13
|
|
89057
|
+
},
|
|
89058
|
+
children: text
|
|
89059
|
+
}) : null;
|
|
89060
|
+
const held = lockIn > 0 && (lockFor === null || lockFor === address.trim());
|
|
89061
|
+
const sendDisabled = busy || !address.trim() || resendIn > 0 || held || countryBlocked;
|
|
88980
89062
|
return /*#__PURE__*/jsxRuntimeExports.jsxs("div", {
|
|
88981
89063
|
style: boxStyle(isDark),
|
|
88982
89064
|
"data-testid": "verify-card",
|
|
@@ -89006,28 +89088,30 @@
|
|
|
89006
89088
|
value: address,
|
|
89007
89089
|
onChange: e => setAddress(e.target.value),
|
|
89008
89090
|
onKeyDown: e => {
|
|
89009
|
-
if (e.key === 'Enter') send();
|
|
89091
|
+
if (e.key === 'Enter' && !sendDisabled) send();
|
|
89010
89092
|
}
|
|
89011
89093
|
})]
|
|
89012
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
89094
|
+
}), errorLine(countryBlocked ? t('verifyCountryNotAllowed') : error), /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
89013
89095
|
type: "button",
|
|
89014
|
-
style: buttonStyle(
|
|
89015
|
-
disabled:
|
|
89096
|
+
style: buttonStyle(sendDisabled),
|
|
89097
|
+
disabled: sendDisabled,
|
|
89016
89098
|
onClick: send,
|
|
89017
|
-
children: busy ? t('verifySending') :
|
|
89099
|
+
children: busy ? t('verifySending') : held ? fill(t('verifyLockedFor'), {
|
|
89100
|
+
time: clock(lockIn)
|
|
89101
|
+
}) : resendIn > 0 ? fill(t('verifyResendIn'), {
|
|
89018
89102
|
seconds: resendIn
|
|
89019
89103
|
}) : t('verifySendCode')
|
|
89020
89104
|
})]
|
|
89021
89105
|
}) : /*#__PURE__*/jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
89022
89106
|
children: [/*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
89023
89107
|
children: fill(t('verifyEnterCode'), {
|
|
89024
|
-
target: masked
|
|
89108
|
+
target: noBreak(masked)
|
|
89025
89109
|
})
|
|
89026
89110
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("input", {
|
|
89111
|
+
// EV-4941: the widget's own font; spacing keeps the digits apart.
|
|
89027
89112
|
style: {
|
|
89028
89113
|
...inputStyle(isDark),
|
|
89029
89114
|
letterSpacing: '0.3em',
|
|
89030
|
-
fontFamily: 'monospace',
|
|
89031
89115
|
fontSize: 18
|
|
89032
89116
|
},
|
|
89033
89117
|
"aria-label": t('verifyCodeLabel'),
|
|
@@ -89039,7 +89123,7 @@
|
|
|
89039
89123
|
onKeyDown: e => {
|
|
89040
89124
|
if (e.key === 'Enter') confirm();
|
|
89041
89125
|
}
|
|
89042
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
89126
|
+
}), errorLine(error), /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
89043
89127
|
type: "button",
|
|
89044
89128
|
style: buttonStyle(busy || code.length !== 6),
|
|
89045
89129
|
disabled: busy || code.length !== 6,
|
|
@@ -89065,23 +89149,22 @@
|
|
|
89065
89149
|
onClick: () => {
|
|
89066
89150
|
setStep('address');
|
|
89067
89151
|
setError(null);
|
|
89152
|
+
// EV-4939: the wait was for the old address; a new one starts fresh.
|
|
89153
|
+
setResendIn(0);
|
|
89068
89154
|
},
|
|
89069
|
-
children: t('verifyDifferent')
|
|
89155
|
+
children: mode === 'sms' ? t('verifyDifferentNumber') : t('verifyDifferent')
|
|
89070
89156
|
})]
|
|
89071
|
-
}), error && /*#__PURE__*/jsxRuntimeExports.jsx("div", {
|
|
89072
|
-
role: "alert",
|
|
89073
|
-
style: {
|
|
89074
|
-
color: '#b42318',
|
|
89075
|
-
fontSize: 12
|
|
89076
|
-
},
|
|
89077
|
-
children: error
|
|
89078
89157
|
}), /*#__PURE__*/jsxRuntimeExports.jsx("button", {
|
|
89079
89158
|
type: "button",
|
|
89080
89159
|
style: {
|
|
89081
89160
|
...linkStyle,
|
|
89082
89161
|
color: isDark ? '#9ca3af' : '#6b7280'
|
|
89083
89162
|
},
|
|
89084
|
-
onClick: () =>
|
|
89163
|
+
onClick: () => {
|
|
89164
|
+
// EV-4942: tell the server, so the agent sees the cancel.
|
|
89165
|
+
if (ctx.cancel) Promise.resolve(ctx.cancel()).catch(() => undefined);
|
|
89166
|
+
setCancelled(true);
|
|
89167
|
+
},
|
|
89085
89168
|
disabled: busy,
|
|
89086
89169
|
children: t('verifyCancel')
|
|
89087
89170
|
})]
|