@redneckz/wildless-cms-uni-blocks 0.14.249 → 0.14.251
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/bundle/blocks.schema.json +1 -1
- package/bundle/bundle.umd.js +96 -46
- package/bundle/bundle.umd.min.js +1 -1
- package/bundle/components/Header/HeaderChatBotButton.d.ts +4 -1
- package/bundle/components/Header/HeaderSecondaryMenuButton.d.ts +4 -1
- package/bundle/components/Header/useChatBot.d.ts +4 -1
- package/bundle/hooks/useExternalNS.d.ts +2 -1
- package/bundle/hooks/useNavigateHandler.d.ts +1 -0
- package/bundle/model/LinkProps.d.ts +2 -0
- package/dist/components/Header/HeaderChatBotButton.d.ts +4 -1
- package/dist/components/Header/HeaderChatBotButton.js +3 -11
- package/dist/components/Header/HeaderChatBotButton.js.map +1 -1
- package/dist/components/Header/HeaderSecondaryMenuButton.d.ts +4 -1
- package/dist/components/Header/HeaderSecondaryMenuButton.js.map +1 -1
- package/dist/components/Header/useChatBot.d.ts +4 -1
- package/dist/components/Header/useChatBot.js +24 -3
- package/dist/components/Header/useChatBot.js.map +1 -1
- package/dist/hooks/useExternalNS.d.ts +2 -1
- package/dist/hooks/useExternalNS.js +49 -23
- package/dist/hooks/useExternalNS.js.map +1 -1
- package/dist/hooks/useNavigateHandler.d.ts +1 -0
- package/dist/hooks/useNavigateHandler.js +19 -8
- package/dist/hooks/useNavigateHandler.js.map +1 -1
- package/dist/model/LinkProps.d.ts +2 -0
- package/dist/ui-kit/Select/Select.js +1 -1
- package/dist/ui-kit/Select/Select.js.map +1 -1
- package/dist/ui-kit/Select/SelectPopup.js +1 -1
- package/dist/ui-kit/Select/SelectPopup.js.map +1 -1
- package/dist/ui-kit/YandexMap/useYandexMaps.js +1 -1
- package/dist/ui-kit/YandexMap/useYandexMaps.js.map +1 -1
- package/lib/common.css +1 -1
- package/lib/components/Header/HeaderChatBotButton.d.ts +4 -1
- package/lib/components/Header/HeaderChatBotButton.js +3 -11
- package/lib/components/Header/HeaderChatBotButton.js.map +1 -1
- package/lib/components/Header/HeaderSecondaryMenuButton.d.ts +4 -1
- package/lib/components/Header/HeaderSecondaryMenuButton.js.map +1 -1
- package/lib/components/Header/useChatBot.d.ts +4 -1
- package/lib/components/Header/useChatBot.js +25 -4
- package/lib/components/Header/useChatBot.js.map +1 -1
- package/lib/hooks/useExternalNS.d.ts +2 -1
- package/lib/hooks/useExternalNS.js +48 -23
- package/lib/hooks/useExternalNS.js.map +1 -1
- package/lib/hooks/useNavigateHandler.d.ts +1 -0
- package/lib/hooks/useNavigateHandler.js +19 -8
- package/lib/hooks/useNavigateHandler.js.map +1 -1
- package/lib/model/LinkProps.d.ts +2 -0
- package/lib/ui-kit/Select/Select.js +1 -1
- package/lib/ui-kit/Select/Select.js.map +1 -1
- package/lib/ui-kit/Select/SelectPopup.js +1 -1
- package/lib/ui-kit/Select/SelectPopup.js.map +1 -1
- package/lib/ui-kit/YandexMap/useYandexMaps.js +1 -1
- package/lib/ui-kit/YandexMap/useYandexMaps.js.map +1 -1
- package/mobile/bundle/bundle.umd.js +100 -34
- package/mobile/bundle/bundle.umd.min.js +1 -1
- package/mobile/bundle/components/Header/HeaderChatBotButton.d.ts +4 -1
- package/mobile/bundle/components/Header/HeaderSecondaryMenuButton.d.ts +4 -1
- package/mobile/bundle/components/Header/useChatBot.d.ts +4 -1
- package/mobile/bundle/hooks/useExternalNS.d.ts +2 -1
- package/mobile/bundle/hooks/useNavigateHandler.d.ts +1 -0
- package/mobile/bundle/model/LinkProps.d.ts +2 -0
- package/mobile/dist/components/Header/HeaderChatBotButton.d.ts +4 -1
- package/mobile/dist/components/Header/HeaderChatBotButton.js +3 -11
- package/mobile/dist/components/Header/HeaderChatBotButton.js.map +1 -1
- package/mobile/dist/components/Header/HeaderSecondaryMenuButton.d.ts +4 -1
- package/mobile/dist/components/Header/HeaderSecondaryMenuButton.js.map +1 -1
- package/mobile/dist/components/Header/useChatBot.d.ts +4 -1
- package/mobile/dist/components/Header/useChatBot.js +24 -3
- package/mobile/dist/components/Header/useChatBot.js.map +1 -1
- package/mobile/dist/hooks/useExternalNS.d.ts +2 -1
- package/mobile/dist/hooks/useExternalNS.js +49 -23
- package/mobile/dist/hooks/useExternalNS.js.map +1 -1
- package/mobile/dist/hooks/useNavigateHandler.d.ts +1 -0
- package/mobile/dist/hooks/useNavigateHandler.js +19 -8
- package/mobile/dist/hooks/useNavigateHandler.js.map +1 -1
- package/mobile/dist/model/LinkProps.d.ts +2 -0
- package/mobile/dist/ui-kit/Select/Select.js +1 -1
- package/mobile/dist/ui-kit/Select/Select.js.map +1 -1
- package/mobile/dist/ui-kit/Select/SelectPopup.js +1 -1
- package/mobile/dist/ui-kit/Select/SelectPopup.js.map +1 -1
- package/mobile/dist/ui-kit/YandexMap/useYandexMaps.js +1 -1
- package/mobile/dist/ui-kit/YandexMap/useYandexMaps.js.map +1 -1
- package/mobile/lib/common.css +1 -1
- package/mobile/lib/components/Header/HeaderChatBotButton.d.ts +4 -1
- package/mobile/lib/components/Header/HeaderChatBotButton.js +3 -11
- package/mobile/lib/components/Header/HeaderChatBotButton.js.map +1 -1
- package/mobile/lib/components/Header/HeaderSecondaryMenuButton.d.ts +4 -1
- package/mobile/lib/components/Header/HeaderSecondaryMenuButton.js.map +1 -1
- package/mobile/lib/components/Header/useChatBot.d.ts +4 -1
- package/mobile/lib/components/Header/useChatBot.js +25 -4
- package/mobile/lib/components/Header/useChatBot.js.map +1 -1
- package/mobile/lib/hooks/useExternalNS.d.ts +2 -1
- package/mobile/lib/hooks/useExternalNS.js +48 -23
- package/mobile/lib/hooks/useExternalNS.js.map +1 -1
- package/mobile/lib/hooks/useNavigateHandler.d.ts +1 -0
- package/mobile/lib/hooks/useNavigateHandler.js +19 -8
- package/mobile/lib/hooks/useNavigateHandler.js.map +1 -1
- package/mobile/lib/model/LinkProps.d.ts +2 -0
- package/mobile/lib/ui-kit/Select/Select.js +1 -1
- package/mobile/lib/ui-kit/Select/Select.js.map +1 -1
- package/mobile/lib/ui-kit/Select/SelectPopup.js +1 -1
- package/mobile/lib/ui-kit/Select/SelectPopup.js.map +1 -1
- package/mobile/lib/ui-kit/YandexMap/useYandexMaps.js +1 -1
- package/mobile/lib/ui-kit/YandexMap/useYandexMaps.js.map +1 -1
- package/mobile/src/components/Header/HeaderChatBotButton.tsx +15 -30
- package/mobile/src/components/Header/HeaderSecondaryMenuButton.tsx +2 -1
- package/mobile/src/components/Header/useChatBot.ts +29 -5
- package/mobile/src/hooks/useExternalNS.ts +55 -25
- package/mobile/src/hooks/useNavigateHandler.ts +34 -18
- package/mobile/src/model/LinkProps.ts +2 -0
- package/mobile/src/ui-kit/Select/Select.tsx +1 -1
- package/mobile/src/ui-kit/Select/SelectPopup.tsx +1 -1
- package/mobile/src/ui-kit/YandexMap/useYandexMaps.ts +1 -1
- package/package.json +1 -1
- package/src/components/Header/HeaderChatBotButton.tsx +15 -30
- package/src/components/Header/HeaderSecondaryMenuButton.tsx +2 -1
- package/src/components/Header/useChatBot.ts +29 -5
- package/src/hooks/useExternalNS.ts +55 -25
- package/src/hooks/useNavigateHandler.ts +34 -18
- package/src/model/LinkProps.ts +2 -0
- package/src/ui-kit/Select/Select.tsx +1 -1
- package/src/ui-kit/Select/SelectPopup.tsx +1 -1
- package/src/ui-kit/YandexMap/useYandexMaps.ts +1 -1
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { JSX } from '@redneckz/uni-jsx';
|
|
2
|
-
import { useBool } from '@redneckz/uni-jsx/lib/hooks/useBool';
|
|
3
2
|
import { type IconVersion } from '../../model/IconVersion';
|
|
4
|
-
import {
|
|
3
|
+
import { type PreventableEvent } from '../../ui-kit/PreventableEvent';
|
|
5
4
|
import { HeaderSecondaryMenuButton } from './HeaderSecondaryMenuButton';
|
|
6
5
|
import { useChatBot } from './useChatBot';
|
|
7
6
|
|
|
@@ -9,36 +8,22 @@ interface HeaderChatBotButtonProps {
|
|
|
9
8
|
className?: string;
|
|
10
9
|
iconVersion?: IconVersion;
|
|
11
10
|
chat?: string;
|
|
12
|
-
onClick?: () => void;
|
|
11
|
+
onClick?: (ev: PreventableEvent & { target: EventTarget | null }) => void;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
const
|
|
14
|
+
export const HeaderChatBotButton = JSX<HeaderChatBotButtonProps>(
|
|
15
|
+
({ chat = 'personal', iconVersion, className }) => {
|
|
16
|
+
const load = useChatBot(chat);
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const HeaderChatBotButtonWithLoader = JSX<HeaderChatBotButtonProps>(
|
|
28
|
-
({ chat = 'personal', ...rest }) => {
|
|
29
|
-
useChatBot(chat);
|
|
30
|
-
|
|
31
|
-
return renderChatBotButton(rest);
|
|
18
|
+
return (
|
|
19
|
+
<HeaderSecondaryMenuButton
|
|
20
|
+
className={className}
|
|
21
|
+
image={{ icon: 'HeadphonesIcon', iconVersion }}
|
|
22
|
+
ariaLabel="Чат"
|
|
23
|
+
onClick={load}
|
|
24
|
+
buttonSize="large"
|
|
25
|
+
isGrayBg={true}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
32
28
|
},
|
|
33
29
|
);
|
|
34
|
-
|
|
35
|
-
const renderChatBotButton = ({ className, iconVersion, onClick }: HeaderChatBotButtonProps) => (
|
|
36
|
-
<HeaderSecondaryMenuButton
|
|
37
|
-
className={style(CHAT_BUTTON_EXTERNAL_NAME, className)}
|
|
38
|
-
image={{ icon: 'HeadphonesIcon', iconVersion }}
|
|
39
|
-
ariaLabel="Чат"
|
|
40
|
-
onClick={onClick}
|
|
41
|
-
buttonSize="large"
|
|
42
|
-
isGrayBg={true}
|
|
43
|
-
/>
|
|
44
|
-
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { JSX } from '@redneckz/uni-jsx';
|
|
2
2
|
import { Img } from '../../ui-kit/Img/Img';
|
|
3
3
|
import { type ImageContent } from '../../ui-kit/Img/ImgProps';
|
|
4
|
+
import { type PreventableEvent } from '../../ui-kit/PreventableEvent';
|
|
4
5
|
import { style } from '../../utils/style';
|
|
5
6
|
|
|
6
7
|
export interface HeaderSecondaryMenuButtonProps extends ImageContent {
|
|
@@ -10,7 +11,7 @@ export interface HeaderSecondaryMenuButtonProps extends ImageContent {
|
|
|
10
11
|
isGrayBg?: boolean;
|
|
11
12
|
disabled?: boolean;
|
|
12
13
|
ariaLabel?: string;
|
|
13
|
-
onClick?: () => void;
|
|
14
|
+
onClick?: (ev: PreventableEvent & { target: EventTarget | null }) => void;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
const BUTTON_SIZE_STYLE = {
|
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
import { useEffect } from '@redneckz/uni-jsx/lib/hooks';
|
|
2
|
-
import {
|
|
2
|
+
import { initializeExternalNS } from '../../hooks/useExternalNS';
|
|
3
|
+
import { type PreventableEvent } from '../../ui-kit/PreventableEvent';
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
+
const CHAT_NAMESPACE = 'chatbot';
|
|
6
|
+
const CHAT_BUTTON_EXTERNAL_NAME = 'text-page__btn-chat';
|
|
7
|
+
const CHAT_FRAME_ID = 'webchat-js-container:webchat_rshb';
|
|
8
|
+
const CHAT_STORAGE_NAME = 'webchat-keep-open';
|
|
5
9
|
|
|
6
10
|
const CHATBOT_URL: Record<string, string> = {
|
|
7
11
|
personal: '//chat.mes.rshb.ru/assets/js/webchat_rshb',
|
|
8
12
|
business: '', //TODO: add url business chat
|
|
9
13
|
};
|
|
10
14
|
|
|
11
|
-
export const useChatBot = (chat
|
|
12
|
-
useEffect(() => globalThis.localStorage?.setItem(
|
|
15
|
+
export const useChatBot = (chat?: string) => {
|
|
16
|
+
useEffect(() => globalThis.localStorage?.setItem(CHAT_STORAGE_NAME, String(Date.now())), []);
|
|
17
|
+
const chatUrl = CHATBOT_URL[chat ?? ''];
|
|
13
18
|
|
|
14
|
-
return
|
|
19
|
+
return (ev: PreventableEvent & { target: EventTarget | null }) => {
|
|
20
|
+
if (!chatUrl) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (chat !== 'personal') {
|
|
25
|
+
initializeExternalNS(CHAT_NAMESPACE, chatUrl);
|
|
26
|
+
} else {
|
|
27
|
+
const target = ev.target as HTMLElement;
|
|
28
|
+
|
|
29
|
+
if (!target?.classList.contains(CHAT_BUTTON_EXTERNAL_NAME)) {
|
|
30
|
+
target?.classList.add(CHAT_BUTTON_EXTERNAL_NAME);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const chatFrame = document.getElementById(CHAT_FRAME_ID);
|
|
34
|
+
if (!chatFrame) {
|
|
35
|
+
initializeExternalNS(CHAT_NAMESPACE, chatUrl);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
15
39
|
};
|
|
@@ -1,44 +1,74 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from '@redneckz/uni-jsx/lib/hooks';
|
|
2
2
|
|
|
3
3
|
export const getNS = <NS>(_: string): NS | undefined => (globalThis as any)[_];
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
const
|
|
5
|
+
export const initializeExternalNS = <NS>(namespaceName: string, url: string) => {
|
|
6
|
+
const script = document.getElementById(url);
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
if (script) {
|
|
9
|
+
const ns = getNS<NS>(namespaceName);
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (script) {
|
|
14
|
-
if (getNS<NS>(namespaceName)) {
|
|
15
|
-
setNS();
|
|
16
|
-
} else {
|
|
17
|
-
script.addEventListener('load', setNS);
|
|
18
|
-
|
|
19
|
-
return () => {
|
|
20
|
-
script.removeEventListener('load', setNS);
|
|
21
|
-
};
|
|
22
|
-
}
|
|
11
|
+
if (ns) {
|
|
12
|
+
return Promise.resolve(ns);
|
|
23
13
|
} else {
|
|
14
|
+
return new Promise<NS | undefined>((resolve) => {
|
|
15
|
+
script.addEventListener('load', () => {
|
|
16
|
+
resolve(getNS<NS>(namespaceName));
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
return new Promise<NS | undefined>((resolve, reject) => {
|
|
24
22
|
const newScript = document.createElement('script');
|
|
25
23
|
|
|
26
24
|
newScript.src = url;
|
|
27
25
|
newScript.async = true;
|
|
28
26
|
newScript.id = url;
|
|
29
|
-
newScript.addEventListener('load',
|
|
27
|
+
newScript.addEventListener('load', () => {
|
|
28
|
+
resolve(getNS<NS>(namespaceName));
|
|
29
|
+
});
|
|
30
|
+
newScript.addEventListener('error', (error) => {
|
|
31
|
+
reject(error);
|
|
32
|
+
});
|
|
30
33
|
|
|
31
34
|
document.head.appendChild(newScript);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
export function useExternalNS<NS>(
|
|
40
|
+
namespaceName: string,
|
|
41
|
+
url: string,
|
|
42
|
+
unmountNS = true,
|
|
43
|
+
): NS | undefined {
|
|
44
|
+
const [externalNS, setExternalNS] = useState<NS | undefined>(undefined);
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
let isMounted = true;
|
|
48
|
+
|
|
49
|
+
initializeExternalNS<NS>(namespaceName, url)
|
|
50
|
+
.then((ns) => {
|
|
51
|
+
if (isMounted) {
|
|
52
|
+
setExternalNS(ns);
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
.catch((error) => {
|
|
56
|
+
console.error(`Failed to initialize external namespace: ${error}`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
isMounted = false;
|
|
39
61
|
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
if (unmountNS) {
|
|
63
|
+
const script = document.getElementById(url);
|
|
64
|
+
if (script) {
|
|
65
|
+
document.head.removeChild(script);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
setExternalNS(undefined);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}, [namespaceName, url, unmountNS]);
|
|
42
72
|
|
|
43
73
|
return externalNS;
|
|
44
74
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect } from '@redneckz/uni-jsx/lib/hooks';
|
|
2
2
|
import { useEventListener } from '@redneckz/uni-jsx/lib/hooks/useEventListener';
|
|
3
|
+
import { useChatBot } from '../components/Header/useChatBot';
|
|
3
4
|
import { type Target } from '../model/LinkProps';
|
|
4
5
|
import { projectSettings } from '../ProjectSettings';
|
|
5
6
|
import { type PreventableEvent } from '../ui-kit/PreventableEvent';
|
|
@@ -10,35 +11,45 @@ import { isURL } from '../utils/url';
|
|
|
10
11
|
import { handlerDecorator } from './handlerDecorator';
|
|
11
12
|
|
|
12
13
|
export type NavigateElement = Element | null;
|
|
14
|
+
export type MethodsMap = Record<string, (params: any) => any>;
|
|
13
15
|
|
|
14
16
|
export const useNavigateHandler = handlerDecorator(() => {
|
|
15
17
|
useEffect(() => {
|
|
16
18
|
getSessionQuery(); //? Call first time for save query in sessionStorage
|
|
17
19
|
}, []);
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
+
const loadBot = useChatBot(projectSettings.CHAT_BOT);
|
|
21
22
|
|
|
22
|
-
const
|
|
23
|
-
|
|
23
|
+
const reachGoalYM = (targetName?: string) => {
|
|
24
|
+
const [ymID] = projectSettings.YANDEX_METRIKA_ID?.split(',').reverse() ?? [];
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
if ([ymID, targetName, globalThis.ym].every(Boolean)) {
|
|
27
|
+
globalThis.ym(ymID, 'reachGoal', targetName);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
+
useEventListener(globalThis, 'click', navigationHandler({ loadBot, reachGoalYM }));
|
|
32
|
+
});
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
ev.
|
|
34
|
+
const navigationHandler =
|
|
35
|
+
(methods: MethodsMap) => (ev: PreventableEvent & { target: EventTarget | null }) => {
|
|
36
|
+
const element = getAnchorElement(ev.target as NavigateElement);
|
|
35
37
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
goTransition(element?.target as Target)?.(url);
|
|
38
|
+
for (const key in element?.dataset) {
|
|
39
|
+
getScenario(key)?.(element as HTMLElement, methods);
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
if (isURL(element?.href) && !element?.href?.startsWith(globalThis.location?.origin)) {
|
|
43
|
+
ev.preventDefault();
|
|
44
|
+
ev.stopPropagation();
|
|
45
|
+
|
|
46
|
+
const url = adjustSessionQuery(element?.href) || element?.href;
|
|
47
|
+
if (url) {
|
|
48
|
+
const transition = getTransition(element?.target as Target);
|
|
49
|
+
transition?.(url);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
42
53
|
|
|
43
54
|
const getAnchorElement = (target: NavigateElement) => {
|
|
44
55
|
let _target = target;
|
|
@@ -49,7 +60,7 @@ const getAnchorElement = (target: NavigateElement) => {
|
|
|
49
60
|
return _target as HTMLAnchorElement | null;
|
|
50
61
|
};
|
|
51
62
|
|
|
52
|
-
const
|
|
63
|
+
const getTransition = tableFunc<Target, (url: string) => void>([
|
|
53
64
|
[(_) => _ === '_blank', (url) => globalThis.open(url, '_blank')],
|
|
54
65
|
[(_) => _ === '_parent', (url) => globalThis.parent && (globalThis.parent.location.href = url)],
|
|
55
66
|
[
|
|
@@ -60,3 +71,8 @@ const goTransition = tableFunc<Target, (url: string) => void>([
|
|
|
60
71
|
],
|
|
61
72
|
[() => true, (url) => globalThis.location && (globalThis.location.href = url)],
|
|
62
73
|
]);
|
|
74
|
+
|
|
75
|
+
const getScenario = tableFunc<string, (target: HTMLElement | null, methods: MethodsMap) => void>([
|
|
76
|
+
[(_) => _ === 'ymtarget', (target, methods) => methods?.reachGoalYM(target?.dataset?.ymtarget)],
|
|
77
|
+
[(_) => _ === 'chatbot', (target, methods) => methods?.loadBot({ target })],
|
|
78
|
+
]);
|
|
@@ -14,6 +14,8 @@ export type Target = '' | '_self' | '_blank' | '_parent' | '_top';
|
|
|
14
14
|
export type DataAttributes = {
|
|
15
15
|
/** @title Имя цели для Яндекс Метрики */
|
|
16
16
|
ymTarget?: string;
|
|
17
|
+
/** @title Открыть чат бот */
|
|
18
|
+
chatbot?: boolean;
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
export interface LinkCommonProps {
|
|
@@ -19,7 +19,7 @@ export const SelectPopup = JSX<SelectPopupProps>(
|
|
|
19
19
|
({ popupRef, options, value, query, onChange, iconVersion }) =>
|
|
20
20
|
options?.length ? (
|
|
21
21
|
<div
|
|
22
|
-
className="bg-white text-l max-h-64 overflow-y-auto overflow-x-hidden rounded-md"
|
|
22
|
+
className="bg-white text-l max-h-64 overflow-y-auto overflow-x-hidden rounded-md shadow-2xl"
|
|
23
23
|
role="list"
|
|
24
24
|
ref={popupRef}
|
|
25
25
|
>
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { JSX } from '@redneckz/uni-jsx';
|
|
2
|
-
import { useBool } from '@redneckz/uni-jsx/lib/hooks/useBool';
|
|
3
2
|
import { type IconVersion } from '../../model/IconVersion';
|
|
4
|
-
import {
|
|
3
|
+
import { type PreventableEvent } from '../../ui-kit/PreventableEvent';
|
|
5
4
|
import { HeaderSecondaryMenuButton } from './HeaderSecondaryMenuButton';
|
|
6
5
|
import { useChatBot } from './useChatBot';
|
|
7
6
|
|
|
@@ -9,36 +8,22 @@ interface HeaderChatBotButtonProps {
|
|
|
9
8
|
className?: string;
|
|
10
9
|
iconVersion?: IconVersion;
|
|
11
10
|
chat?: string;
|
|
12
|
-
onClick?: () => void;
|
|
11
|
+
onClick?: (ev: PreventableEvent & { target: EventTarget | null }) => void;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
const
|
|
14
|
+
export const HeaderChatBotButton = JSX<HeaderChatBotButtonProps>(
|
|
15
|
+
({ chat = 'personal', iconVersion, className }) => {
|
|
16
|
+
const load = useChatBot(chat);
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const HeaderChatBotButtonWithLoader = JSX<HeaderChatBotButtonProps>(
|
|
28
|
-
({ chat = 'personal', ...rest }) => {
|
|
29
|
-
useChatBot(chat);
|
|
30
|
-
|
|
31
|
-
return renderChatBotButton(rest);
|
|
18
|
+
return (
|
|
19
|
+
<HeaderSecondaryMenuButton
|
|
20
|
+
className={className}
|
|
21
|
+
image={{ icon: 'HeadphonesIcon', iconVersion }}
|
|
22
|
+
ariaLabel="Чат"
|
|
23
|
+
onClick={load}
|
|
24
|
+
buttonSize="large"
|
|
25
|
+
isGrayBg={true}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
32
28
|
},
|
|
33
29
|
);
|
|
34
|
-
|
|
35
|
-
const renderChatBotButton = ({ className, iconVersion, onClick }: HeaderChatBotButtonProps) => (
|
|
36
|
-
<HeaderSecondaryMenuButton
|
|
37
|
-
className={style(CHAT_BUTTON_EXTERNAL_NAME, className)}
|
|
38
|
-
image={{ icon: 'HeadphonesIcon', iconVersion }}
|
|
39
|
-
ariaLabel="Чат"
|
|
40
|
-
onClick={onClick}
|
|
41
|
-
buttonSize="large"
|
|
42
|
-
isGrayBg={true}
|
|
43
|
-
/>
|
|
44
|
-
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { JSX } from '@redneckz/uni-jsx';
|
|
2
2
|
import { Img } from '../../ui-kit/Img/Img';
|
|
3
3
|
import { type ImageContent } from '../../ui-kit/Img/ImgProps';
|
|
4
|
+
import { type PreventableEvent } from '../../ui-kit/PreventableEvent';
|
|
4
5
|
import { style } from '../../utils/style';
|
|
5
6
|
|
|
6
7
|
export interface HeaderSecondaryMenuButtonProps extends ImageContent {
|
|
@@ -10,7 +11,7 @@ export interface HeaderSecondaryMenuButtonProps extends ImageContent {
|
|
|
10
11
|
isGrayBg?: boolean;
|
|
11
12
|
disabled?: boolean;
|
|
12
13
|
ariaLabel?: string;
|
|
13
|
-
onClick?: () => void;
|
|
14
|
+
onClick?: (ev: PreventableEvent & { target: EventTarget | null }) => void;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
const BUTTON_SIZE_STYLE = {
|
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
import { useEffect } from '@redneckz/uni-jsx/lib/hooks';
|
|
2
|
-
import {
|
|
2
|
+
import { initializeExternalNS } from '../../hooks/useExternalNS';
|
|
3
|
+
import { type PreventableEvent } from '../../ui-kit/PreventableEvent';
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
+
const CHAT_NAMESPACE = 'chatbot';
|
|
6
|
+
const CHAT_BUTTON_EXTERNAL_NAME = 'text-page__btn-chat';
|
|
7
|
+
const CHAT_FRAME_ID = 'webchat-js-container:webchat_rshb';
|
|
8
|
+
const CHAT_STORAGE_NAME = 'webchat-keep-open';
|
|
5
9
|
|
|
6
10
|
const CHATBOT_URL: Record<string, string> = {
|
|
7
11
|
personal: '//chat.mes.rshb.ru/assets/js/webchat_rshb',
|
|
8
12
|
business: '', //TODO: add url business chat
|
|
9
13
|
};
|
|
10
14
|
|
|
11
|
-
export const useChatBot = (chat
|
|
12
|
-
useEffect(() => globalThis.localStorage?.setItem(
|
|
15
|
+
export const useChatBot = (chat?: string) => {
|
|
16
|
+
useEffect(() => globalThis.localStorage?.setItem(CHAT_STORAGE_NAME, String(Date.now())), []);
|
|
17
|
+
const chatUrl = CHATBOT_URL[chat ?? ''];
|
|
13
18
|
|
|
14
|
-
return
|
|
19
|
+
return (ev: PreventableEvent & { target: EventTarget | null }) => {
|
|
20
|
+
if (!chatUrl) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (chat !== 'personal') {
|
|
25
|
+
initializeExternalNS(CHAT_NAMESPACE, chatUrl);
|
|
26
|
+
} else {
|
|
27
|
+
const target = ev.target as HTMLElement;
|
|
28
|
+
|
|
29
|
+
if (!target?.classList.contains(CHAT_BUTTON_EXTERNAL_NAME)) {
|
|
30
|
+
target?.classList.add(CHAT_BUTTON_EXTERNAL_NAME);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const chatFrame = document.getElementById(CHAT_FRAME_ID);
|
|
34
|
+
if (!chatFrame) {
|
|
35
|
+
initializeExternalNS(CHAT_NAMESPACE, chatUrl);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
15
39
|
};
|
|
@@ -1,44 +1,74 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from '@redneckz/uni-jsx/lib/hooks';
|
|
2
2
|
|
|
3
3
|
export const getNS = <NS>(_: string): NS | undefined => (globalThis as any)[_];
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
const
|
|
5
|
+
export const initializeExternalNS = <NS>(namespaceName: string, url: string) => {
|
|
6
|
+
const script = document.getElementById(url);
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
if (script) {
|
|
9
|
+
const ns = getNS<NS>(namespaceName);
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (script) {
|
|
14
|
-
if (getNS<NS>(namespaceName)) {
|
|
15
|
-
setNS();
|
|
16
|
-
} else {
|
|
17
|
-
script.addEventListener('load', setNS);
|
|
18
|
-
|
|
19
|
-
return () => {
|
|
20
|
-
script.removeEventListener('load', setNS);
|
|
21
|
-
};
|
|
22
|
-
}
|
|
11
|
+
if (ns) {
|
|
12
|
+
return Promise.resolve(ns);
|
|
23
13
|
} else {
|
|
14
|
+
return new Promise<NS | undefined>((resolve) => {
|
|
15
|
+
script.addEventListener('load', () => {
|
|
16
|
+
resolve(getNS<NS>(namespaceName));
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
return new Promise<NS | undefined>((resolve, reject) => {
|
|
24
22
|
const newScript = document.createElement('script');
|
|
25
23
|
|
|
26
24
|
newScript.src = url;
|
|
27
25
|
newScript.async = true;
|
|
28
26
|
newScript.id = url;
|
|
29
|
-
newScript.addEventListener('load',
|
|
27
|
+
newScript.addEventListener('load', () => {
|
|
28
|
+
resolve(getNS<NS>(namespaceName));
|
|
29
|
+
});
|
|
30
|
+
newScript.addEventListener('error', (error) => {
|
|
31
|
+
reject(error);
|
|
32
|
+
});
|
|
30
33
|
|
|
31
34
|
document.head.appendChild(newScript);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
export function useExternalNS<NS>(
|
|
40
|
+
namespaceName: string,
|
|
41
|
+
url: string,
|
|
42
|
+
unmountNS = true,
|
|
43
|
+
): NS | undefined {
|
|
44
|
+
const [externalNS, setExternalNS] = useState<NS | undefined>(undefined);
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
let isMounted = true;
|
|
48
|
+
|
|
49
|
+
initializeExternalNS<NS>(namespaceName, url)
|
|
50
|
+
.then((ns) => {
|
|
51
|
+
if (isMounted) {
|
|
52
|
+
setExternalNS(ns);
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
.catch((error) => {
|
|
56
|
+
console.error(`Failed to initialize external namespace: ${error}`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return () => {
|
|
60
|
+
isMounted = false;
|
|
39
61
|
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
if (unmountNS) {
|
|
63
|
+
const script = document.getElementById(url);
|
|
64
|
+
if (script) {
|
|
65
|
+
document.head.removeChild(script);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
setExternalNS(undefined);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}, [namespaceName, url, unmountNS]);
|
|
42
72
|
|
|
43
73
|
return externalNS;
|
|
44
74
|
}
|