@redneckz/wildless-cms-uni-blocks 0.14.1021 → 0.14.1023

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 (116) hide show
  1. package/bundle/api/sendUserSurvey.d.ts +1 -0
  2. package/bundle/blocks.schema.json +1 -1
  3. package/bundle/bundle.umd.js +786 -745
  4. package/bundle/bundle.umd.min.js +1 -1
  5. package/bundle/components/ApplicationForm/handlers.d.ts +4 -3
  6. package/bundle/model/AspectsProps.d.ts +7 -1
  7. package/bundle/ui-kit/UserSurveyDialog/UserSurveyDialogContent.d.ts +4 -2
  8. package/bundle/ui-kit/UserSurveyDialog/useUserSurveyDialog.d.ts +1 -1
  9. package/dist/api/sendUserSurvey.d.ts +1 -0
  10. package/dist/api/sendUserSurvey.js.map +1 -1
  11. package/dist/components/ApplicationForm/ApplicationForm.js +3 -0
  12. package/dist/components/ApplicationForm/ApplicationForm.js.map +1 -1
  13. package/dist/components/ApplicationForm/handlers.d.ts +4 -3
  14. package/dist/components/ApplicationForm/handlers.js +9 -3
  15. package/dist/components/ApplicationForm/handlers.js.map +1 -1
  16. package/dist/components/ApplicationLeadForm/getLeadFormTaskData.js +3 -0
  17. package/dist/components/ApplicationLeadForm/getLeadFormTaskData.js.map +1 -1
  18. package/dist/components/DebitForm/DebitFormStatus.js +5 -1
  19. package/dist/components/DebitForm/DebitFormStatus.js.map +1 -1
  20. package/dist/model/AspectsProps.d.ts +7 -1
  21. package/dist/ui-kit/UserSurveyDialog/FirstStep.js +2 -2
  22. package/dist/ui-kit/UserSurveyDialog/FirstStep.js.map +1 -1
  23. package/dist/ui-kit/UserSurveyDialog/UserSurveyDialog.js +17 -2
  24. package/dist/ui-kit/UserSurveyDialog/UserSurveyDialog.js.map +1 -1
  25. package/dist/ui-kit/UserSurveyDialog/UserSurveyDialogContent.d.ts +4 -2
  26. package/dist/ui-kit/UserSurveyDialog/useUserSurveyDialog.d.ts +1 -1
  27. package/dist/ui-kit/UserSurveyDialog/useUserSurveyDialog.js +23 -11
  28. package/dist/ui-kit/UserSurveyDialog/useUserSurveyDialog.js.map +1 -1
  29. package/lib/api/sendUserSurvey.d.ts +1 -0
  30. package/lib/api/sendUserSurvey.js.map +1 -1
  31. package/lib/components/ApplicationForm/ApplicationForm.js +3 -0
  32. package/lib/components/ApplicationForm/ApplicationForm.js.map +1 -1
  33. package/lib/components/ApplicationForm/handlers.d.ts +4 -3
  34. package/lib/components/ApplicationForm/handlers.js +9 -3
  35. package/lib/components/ApplicationForm/handlers.js.map +1 -1
  36. package/lib/components/ApplicationLeadForm/getLeadFormTaskData.js +3 -0
  37. package/lib/components/ApplicationLeadForm/getLeadFormTaskData.js.map +1 -1
  38. package/lib/components/DebitForm/DebitFormStatus.js +5 -1
  39. package/lib/components/DebitForm/DebitFormStatus.js.map +1 -1
  40. package/lib/model/AspectsProps.d.ts +7 -1
  41. package/lib/ui-kit/UserSurveyDialog/FirstStep.js +2 -2
  42. package/lib/ui-kit/UserSurveyDialog/FirstStep.js.map +1 -1
  43. package/lib/ui-kit/UserSurveyDialog/UserSurveyDialog.js +17 -2
  44. package/lib/ui-kit/UserSurveyDialog/UserSurveyDialog.js.map +1 -1
  45. package/lib/ui-kit/UserSurveyDialog/UserSurveyDialogContent.d.ts +4 -2
  46. package/lib/ui-kit/UserSurveyDialog/useUserSurveyDialog.d.ts +1 -1
  47. package/lib/ui-kit/UserSurveyDialog/useUserSurveyDialog.js +24 -12
  48. package/lib/ui-kit/UserSurveyDialog/useUserSurveyDialog.js.map +1 -1
  49. package/mobile/bundle/api/sendUserSurvey.d.ts +1 -0
  50. package/mobile/bundle/bundle.umd.js +786 -745
  51. package/mobile/bundle/bundle.umd.min.js +1 -1
  52. package/mobile/bundle/components/ApplicationForm/handlers.d.ts +4 -3
  53. package/mobile/bundle/model/AspectsProps.d.ts +7 -1
  54. package/mobile/bundle/ui-kit/UserSurveyDialog/UserSurveyDialogContent.d.ts +4 -2
  55. package/mobile/bundle/ui-kit/UserSurveyDialog/useUserSurveyDialog.d.ts +1 -1
  56. package/mobile/dist/api/sendUserSurvey.d.ts +1 -0
  57. package/mobile/dist/api/sendUserSurvey.js.map +1 -1
  58. package/mobile/dist/components/ApplicationForm/ApplicationForm.js +3 -0
  59. package/mobile/dist/components/ApplicationForm/ApplicationForm.js.map +1 -1
  60. package/mobile/dist/components/ApplicationForm/handlers.d.ts +4 -3
  61. package/mobile/dist/components/ApplicationForm/handlers.js +9 -3
  62. package/mobile/dist/components/ApplicationForm/handlers.js.map +1 -1
  63. package/mobile/dist/components/ApplicationLeadForm/getLeadFormTaskData.js +3 -0
  64. package/mobile/dist/components/ApplicationLeadForm/getLeadFormTaskData.js.map +1 -1
  65. package/mobile/dist/components/DebitForm/DebitFormStatus.js +5 -1
  66. package/mobile/dist/components/DebitForm/DebitFormStatus.js.map +1 -1
  67. package/mobile/dist/model/AspectsProps.d.ts +7 -1
  68. package/mobile/dist/ui-kit/UserSurveyDialog/FirstStep.js +2 -2
  69. package/mobile/dist/ui-kit/UserSurveyDialog/FirstStep.js.map +1 -1
  70. package/mobile/dist/ui-kit/UserSurveyDialog/UserSurveyDialog.js +17 -2
  71. package/mobile/dist/ui-kit/UserSurveyDialog/UserSurveyDialog.js.map +1 -1
  72. package/mobile/dist/ui-kit/UserSurveyDialog/UserSurveyDialogContent.d.ts +4 -2
  73. package/mobile/dist/ui-kit/UserSurveyDialog/useUserSurveyDialog.d.ts +1 -1
  74. package/mobile/dist/ui-kit/UserSurveyDialog/useUserSurveyDialog.js +23 -11
  75. package/mobile/dist/ui-kit/UserSurveyDialog/useUserSurveyDialog.js.map +1 -1
  76. package/mobile/lib/api/sendUserSurvey.d.ts +1 -0
  77. package/mobile/lib/api/sendUserSurvey.js.map +1 -1
  78. package/mobile/lib/components/ApplicationForm/ApplicationForm.js +3 -0
  79. package/mobile/lib/components/ApplicationForm/ApplicationForm.js.map +1 -1
  80. package/mobile/lib/components/ApplicationForm/handlers.d.ts +4 -3
  81. package/mobile/lib/components/ApplicationForm/handlers.js +9 -3
  82. package/mobile/lib/components/ApplicationForm/handlers.js.map +1 -1
  83. package/mobile/lib/components/ApplicationLeadForm/getLeadFormTaskData.js +3 -0
  84. package/mobile/lib/components/ApplicationLeadForm/getLeadFormTaskData.js.map +1 -1
  85. package/mobile/lib/components/DebitForm/DebitFormStatus.js +5 -1
  86. package/mobile/lib/components/DebitForm/DebitFormStatus.js.map +1 -1
  87. package/mobile/lib/model/AspectsProps.d.ts +7 -1
  88. package/mobile/lib/ui-kit/UserSurveyDialog/FirstStep.js +2 -2
  89. package/mobile/lib/ui-kit/UserSurveyDialog/FirstStep.js.map +1 -1
  90. package/mobile/lib/ui-kit/UserSurveyDialog/UserSurveyDialog.js +17 -2
  91. package/mobile/lib/ui-kit/UserSurveyDialog/UserSurveyDialog.js.map +1 -1
  92. package/mobile/lib/ui-kit/UserSurveyDialog/UserSurveyDialogContent.d.ts +4 -2
  93. package/mobile/lib/ui-kit/UserSurveyDialog/useUserSurveyDialog.d.ts +1 -1
  94. package/mobile/lib/ui-kit/UserSurveyDialog/useUserSurveyDialog.js +24 -12
  95. package/mobile/lib/ui-kit/UserSurveyDialog/useUserSurveyDialog.js.map +1 -1
  96. package/mobile/src/api/sendUserSurvey.ts +1 -0
  97. package/mobile/src/components/ApplicationForm/ApplicationForm.tsx +3 -0
  98. package/mobile/src/components/ApplicationForm/handlers.ts +11 -0
  99. package/mobile/src/components/ApplicationLeadForm/getLeadFormTaskData.ts +3 -0
  100. package/mobile/src/components/DebitForm/DebitFormStatus.tsx +11 -5
  101. package/mobile/src/model/AspectsProps.ts +9 -1
  102. package/mobile/src/ui-kit/UserSurveyDialog/FirstStep.tsx +6 -2
  103. package/mobile/src/ui-kit/UserSurveyDialog/UserSurveyDialog.tsx +21 -2
  104. package/mobile/src/ui-kit/UserSurveyDialog/UserSurveyDialogContent.ts +5 -2
  105. package/mobile/src/ui-kit/UserSurveyDialog/useUserSurveyDialog.ts +30 -13
  106. package/package.json +1 -1
  107. package/src/api/sendUserSurvey.ts +1 -0
  108. package/src/components/ApplicationForm/ApplicationForm.tsx +3 -0
  109. package/src/components/ApplicationForm/handlers.ts +11 -0
  110. package/src/components/ApplicationLeadForm/getLeadFormTaskData.ts +3 -0
  111. package/src/components/DebitForm/DebitFormStatus.tsx +11 -5
  112. package/src/model/AspectsProps.ts +9 -1
  113. package/src/ui-kit/UserSurveyDialog/FirstStep.tsx +6 -2
  114. package/src/ui-kit/UserSurveyDialog/UserSurveyDialog.tsx +21 -2
  115. package/src/ui-kit/UserSurveyDialog/UserSurveyDialogContent.ts +5 -2
  116. package/src/ui-kit/UserSurveyDialog/useUserSurveyDialog.ts +30 -13
@@ -2,9 +2,11 @@ import { type JSONRefObject } from '../../data/JSONRefObject';
2
2
  import { type OnCloseProps } from '../../model/OnCloseProps';
3
3
  import { type UniBlockContent } from '../../UniBlock/UniBlockProps';
4
4
 
5
+ export type UserSurveyType = 'NPS' | 'CSI';
6
+
5
7
  export type UserSurveyStoreSlice = {
6
8
  userSurvey: {
7
- lastShownType: 'NPS' | 'CSI';
9
+ lastShownType: UserSurveyType;
8
10
  nextDueAt: number;
9
11
  };
10
12
  };
@@ -18,7 +20,7 @@ export type StepProps = {
18
20
  currentRating?: number;
19
21
  currentReason?: Reason;
20
22
  reasons?: Reason[];
21
- surveyType: 'NPS' | 'CSI';
23
+ surveyType: UserSurveyType;
22
24
  isSending: boolean;
23
25
  setCurrentReason: (value: Reason) => void;
24
26
  setCurrentRating: (value: number) => void;
@@ -28,4 +30,5 @@ export type StepProps = {
28
30
 
29
31
  export interface UserSurveyDialogContent extends OnCloseProps, UniBlockContent {
30
32
  reasonsSource?: { reasons: Reason[] } | JSONRefObject;
33
+ isAfterTargetAction?: boolean;
31
34
  }
@@ -1,4 +1,4 @@
1
- import { useEffect } from '@redneckz/uni-jsx/lib/hooks';
1
+ import { useCallback, useEffect } from '@redneckz/uni-jsx/lib/hooks';
2
2
  import { useLocalStore } from '@redneckz/uni-jsx/lib/Store/useLocalStore';
3
3
  import { useSessionStore } from '@redneckz/uni-jsx/lib/Store/useSessionStore';
4
4
  import { noop } from '../../utils/noop';
@@ -10,47 +10,64 @@ const DELAY = 5 * 60 * 1000;
10
10
 
11
11
  type SurveyTimerStore = {
12
12
  surveyTimerStart: string;
13
+ surveyTimerId: NodeJS.Timeout;
14
+ isSurveySkipped: boolean;
13
15
  };
14
16
 
15
17
  // Хук отвечает за показ пользователю опроса
16
- export const useUserSurveyDialog = () => {
18
+ export const useUserSurveyDialog = (withoutTimer?: boolean) => {
17
19
  const userSurveyDialog = useDialog(UserSurveyDialog);
18
20
  const userSurveyStore = useLocalStore<UserSurveyStoreSlice>();
19
21
  const sessionStore = useSessionStore<SurveyTimerStore>();
22
+ const surveyTimer = sessionStore.surveyTimerId;
23
+ const isSurveySkipped = sessionStore.isSurveySkipped;
20
24
  const elapsedTime = sessionStore.surveyTimerStart
21
25
  ? Date.now() - Number.parseInt(sessionStore.surveyTimerStart)
22
26
  : 0;
27
+ const isShowSurvey =
28
+ !isSurveySkipped &&
29
+ (!userSurveyStore.userSurvey || userSurveyStore.userSurvey?.nextDueAt <= Date.now());
23
30
 
24
- const openUserSurveyDialog = () => {
25
- userSurveyStore.userSurvey = {
26
- lastShownType: userSurveyStore.userSurvey?.lastShownType === 'NPS' ? 'CSI' : 'NPS',
27
- nextDueAt: getTimeAfter30days(),
28
- };
31
+ const handleCloseSurvey = useCallback(() => {
32
+ sessionStore.isSurveySkipped = true;
33
+ }, []);
34
+
35
+ const openUserSurveyDialog = useCallback((isAfterTargetAction?: boolean) => {
29
36
  userSurveyDialog.open({
30
37
  reasonsSource: {
31
38
  $ref: '/wcms-resources/user-survey-reasons.json',
32
39
  },
40
+ isAfterTargetAction,
41
+ onClose: handleCloseSurvey,
33
42
  });
34
- };
43
+ }, []);
44
+
45
+ const handleOpenSurveyAction = useCallback(() => {
46
+ if (isShowSurvey) {
47
+ surveyTimer && clearTimeout(surveyTimer);
48
+ openUserSurveyDialog(true);
49
+ }
50
+ }, [surveyTimer, isShowSurvey]);
35
51
 
36
52
  useEffect(() => {
37
53
  // Опрос показывается только если ранее пользоваютелю не показывался опрос или с того момента прошел месяц
38
- if (!userSurveyStore.userSurvey || userSurveyStore.userSurvey?.nextDueAt <= Date.now()) {
54
+ if (!withoutTimer && isShowSurvey) {
39
55
  // начинаем отсчитывать время от первого захода на сайт
40
56
  if (!sessionStore.surveyTimerStart) {
41
57
  sessionStore.surveyTimerStart = Date.now().toString();
42
58
  }
43
59
  // Опрос показывается спустя 5 минут нахождения на сайте
44
60
  const timeout = setTimeout(openUserSurveyDialog, DELAY - elapsedTime);
61
+ sessionStore.surveyTimerId = timeout;
45
62
 
46
63
  return () => {
47
64
  clearTimeout(timeout);
65
+ sessionStore.surveyTimerId = null;
48
66
  };
49
67
  }
50
68
 
51
69
  return noop;
52
- }, []);
53
- };
70
+ }, [isShowSurvey]);
54
71
 
55
- // Отсчитываем месяц с текущей даты
56
- const getTimeAfter30days = () => Date.now() + 30 * 24 * 60 * 60 * 1000;
72
+ return handleOpenSurveyAction;
73
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redneckz/wildless-cms-uni-blocks",
3
- "version": "0.14.1021",
3
+ "version": "0.14.1023",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "ЦК",
@@ -7,6 +7,7 @@ export type UserSurveyRequest = {
7
7
  message?: string;
8
8
  url: string;
9
9
  type: string;
10
+ ip: string;
10
11
  };
11
12
 
12
13
  export const sendUserSurvey = async (body: UserSurveyRequest) => {
@@ -8,6 +8,7 @@ import { getConsentDataProcessing } from '../../ui-kit/FormField/getConsentDataP
8
8
  import { getFormValidator } from '../../ui-kit/FormField/getObjectValidator';
9
9
  import { type PreventableEventWithTarget } from '../../ui-kit/PreventableEvent';
10
10
  import { ResponseTypeDialog } from '../../ui-kit/ResponseTypeDialog/ResponseTypeDialog';
11
+ import { useUserSurveyDialog } from '../../ui-kit/UserSurveyDialog/useUserSurveyDialog';
11
12
  import { UniBlock } from '../../UniBlock/UniBlock';
12
13
  import { type UniBlockProps } from '../../UniBlock/UniBlockProps';
13
14
  import { style } from '../../utils/style';
@@ -71,6 +72,7 @@ export const ApplicationForm = UniBlock<ApplicationFormProps>(
71
72
  const formValidator = useMemo(() => getFormValidator(inputs), [inputs]);
72
73
  const responseTypeDialog = useDialog(ResponseTypeDialog);
73
74
  const verifyPhoneDialog = useDialog(VerifyPhoneDialog);
75
+ const openUserSurvey = useUserSurveyDialog(true);
74
76
 
75
77
  const handleSubmit = useCallback(
76
78
  async (formData: FormState, ev: PreventableEventWithTarget) => {
@@ -88,6 +90,7 @@ export const ApplicationForm = UniBlock<ApplicationFormProps>(
88
90
  verifyPhoneDialog,
89
91
  onSuccess,
90
92
  withSnowplow,
93
+ openUserSurvey,
91
94
  },
92
95
  endpoint,
93
96
  );
@@ -19,6 +19,7 @@ export type HandlerProps = {
19
19
  verifyPhoneDialog?: any;
20
20
  responseTypeDialog?: any;
21
21
  onSuccess?: () => void;
22
+ openUserSurvey?: () => void;
22
23
  withSnowplow?: boolean;
23
24
  };
24
25
 
@@ -32,8 +33,10 @@ export const handleInitCorporateLead = async ({
32
33
  data = [],
33
34
  aspects = {},
34
35
  ev,
36
+ openUserSurvey,
35
37
  }: HandlerProps) => {
36
38
  const { phone } = formatData;
39
+ const hasSurveyAspect = data?.find((_) => _.aspectName === 'openUserSurvey');
37
40
 
38
41
  const response = await API.sendCode({ phone: String(phone) });
39
42
 
@@ -56,6 +59,7 @@ export const handleInitCorporateLead = async ({
56
59
  id,
57
60
  });
58
61
 
62
+ hasSurveyAspect && openUserSurvey?.();
59
63
  handleAspects({
60
64
  aspectsAttributes: getAspectsWithInclude(data, snowplowParams),
61
65
  aspects,
@@ -74,13 +78,16 @@ export const handleCallback = async ({
74
78
  responseTypeDialog,
75
79
  onSuccess = noop,
76
80
  endpoint,
81
+ openUserSurvey,
77
82
  }: HandlerProps) => {
83
+ const hasSurveyAspect = data?.find((_) => _.aspectName === 'openUserSurvey');
78
84
  const response = await API.sendPhoneCallRequest(formatData, endpoint);
79
85
 
80
86
  onSuccess();
81
87
 
82
88
  if (response?.status === 'success') {
83
89
  responseTypeDialog.open({ ok: true, typeForm });
90
+ hasSurveyAspect && openUserSurvey?.();
84
91
  handleAspects({ aspectsAttributes: data, aspects, ev });
85
92
  } else if (response?.status === 'error') {
86
93
  responseTypeDialog.open({
@@ -104,12 +111,16 @@ export const handleDefault = async ({
104
111
  responseTypeDialog,
105
112
  endpoint,
106
113
  withSnowplow,
114
+ openUserSurvey,
107
115
  }: HandlerProps) => {
116
+ const hasSurveyAspect = data?.find((_) => _.aspectName === 'openUserSurvey');
108
117
  const response = await API.send({ body: formatData, router, endpoint });
109
118
  const ok = Boolean(response);
110
119
 
111
120
  responseTypeDialog.open({ ok });
121
+
112
122
  if (ok) {
123
+ hasSurveyAspect && openUserSurvey?.();
113
124
  const { requestId } = response;
114
125
  const { phone } = formatData;
115
126
  const utms = router.pathname.split('?')[1];
@@ -127,6 +127,9 @@ export const getDebitLeadFormTaskData = ({
127
127
 
128
128
  const getTaskSource = (source: Nullable<string>) => {
129
129
  switch (source) {
130
+ case 'banki_ru': {
131
+ return 'banki_ru';
132
+ }
130
133
  case 'referal_sf': {
131
134
  return 'ReferalSF';
132
135
  }
@@ -1,6 +1,7 @@
1
1
  import { JSX } from '@redneckz/uni-jsx';
2
2
  import type { DescriptionProps, LabelProps, TitleProps } from '../../model/HeadlineType';
3
3
  import { BlockWrapper } from '../../ui-kit/BlockWrapper';
4
+ import { Button } from '../../ui-kit/Button/Button';
4
5
  import { LinkButton } from '../../ui-kit/LinkButton/LinkButton';
5
6
  import { Text } from '../../ui-kit/Text/Text';
6
7
  import { type UniBlockProps } from '../../UniBlock/UniBlockProps';
@@ -19,6 +20,10 @@ type DebitFormStatusProps = UniBlockProps &
19
20
  const INTERNET_BANK_LINK = 'https://online.rshb.ru/d?l=dcNqSvOE';
20
21
  const PRELOGIN_LINK = 'https://online.rshb.ru/rshb-mbfl/webmodules/prelogin-zone';
21
22
 
23
+ const openLink = (url: string) => {
24
+ window.location.href = url;
25
+ };
26
+
22
27
  export const DebitFormStatus = JSX<DebitFormStatusProps>(
23
28
  ({ title, description: dsc, sectionInfo, buttonText, isDboClient, isOffice, ...props }) => {
24
29
  return (
@@ -36,12 +41,13 @@ export const DebitFormStatus = JSX<DebitFormStatusProps>(
36
41
  <SectionInfo items={sectionInfo} />
37
42
  {isOffice ? (
38
43
  <div className="flex flex-col md:flex-row md:gap-lg">
39
- <LinkButton
40
- href={PRELOGIN_LINK}
41
- text="Узнать статус заявки"
42
- version="primary"
44
+ <Button
45
+ onClick={() => openLink(PRELOGIN_LINK)}
43
46
  className="w-full mt-lg"
44
- />
47
+ version="primary"
48
+ >
49
+ Узнать статус заявки
50
+ </Button>
45
51
  <LinkButton
46
52
  href="/natural"
47
53
  text="Вернуться на главную"
@@ -35,6 +35,13 @@ export type ChatBotAspect = {
35
35
  aspectName: 'openChatBot';
36
36
  };
37
37
 
38
+ /**
39
+ * @title Отправить опрос пользователю
40
+ */
41
+ export type UserSurveyAspect = {
42
+ aspectName: 'openUserSurvey';
43
+ };
44
+
38
45
  /**
39
46
  * @title Отправить событие партнёру
40
47
  * @default {"aspectName": "partnersEvent", "params": {"partner": "", "typeAction": "targetaction"}}
@@ -62,7 +69,8 @@ export type AspectsDef =
62
69
  | YandexReachGoalAspect
63
70
  | MindboxEventAspect
64
71
  | SnowplowEventAspect
65
- | PartnersEventAspect;
72
+ | PartnersEventAspect
73
+ | UserSurveyAspect;
66
74
 
67
75
  export type AspectsProps = {
68
76
  /** @title Дополнительные атрибуты */
@@ -8,7 +8,7 @@ import { type StepProps } from './UserSurveyDialogContent';
8
8
  const stars = new Array(5).fill(Star);
9
9
 
10
10
  const TITLE = {
11
- NPS: 'Оцените, пожалуйста, от 1 до 5 насколько вероятно, что вы порекомендуете Россельхозбанк коллегам, друзьям и знакомым?',
11
+ NPS: 'Оцените, пожалуйста, от 1 до 5,\nнасколько вероятно, что вы порекомендуете Россельхозбанк коллегам, друзьям и знакомым?',
12
12
  CSI: 'Оцените, пожалуйста, удовлетворённость пользования сайтом',
13
13
  };
14
14
 
@@ -25,7 +25,11 @@ export const FirstStep = JSX<StepProps>(
25
25
 
26
26
  return (
27
27
  <div className="flex flex-col gap-xl items-center">
28
- <Heading className="text-center" headingType="h5" title={TITLE[surveyType]} />
28
+ <Heading
29
+ className="text-center whitespace-pre-line"
30
+ headingType="h5"
31
+ title={TITLE[surveyType]}
32
+ />
29
33
  <div className="flex justify-center">
30
34
  {stars.map((StarItem, index) => (
31
35
  <StarItem
@@ -12,6 +12,7 @@ import {
12
12
  type Reason,
13
13
  type UserSurveyDialogContent,
14
14
  type UserSurveyStoreSlice,
15
+ type UserSurveyType,
15
16
  } from './UserSurveyDialogContent';
16
17
 
17
18
  export type UserSurveyDialogProps = UserSurveyDialogContent;
@@ -20,13 +21,13 @@ const STEPS = [FirstStep, SecondStep, FinalStep];
20
21
  const LAST_STEP_INDEX = 2;
21
22
 
22
23
  export const UserSurveyDialog = UniBlock<UserSurveyDialogProps>(
23
- ({ onClose = noop, reasonsSource = {} }) => {
24
+ ({ onClose = noop, isAfterTargetAction = false, reasonsSource = {} }) => {
24
25
  const [isSending, { setTrue: startSending, setFalse: endSending }] = useBool(false);
25
26
  const [currentRating, setCurrentRating] = useState<number>(0);
26
27
  const [currentReason, setCurrentReason] = useState<Reason>();
27
28
  const [step, setStep] = useState<number>(0);
28
29
  const userSurveyStore = useLocalStore<UserSurveyStoreSlice>();
29
- const surveyType = userSurveyStore.userSurvey?.lastShownType ?? 'NPS';
30
+ const surveyType = getUserSurveyType(userSurveyStore.userSurvey?.lastShownType);
30
31
 
31
32
  const { reasons } = reasonsSource as { reasons: Reason[] };
32
33
 
@@ -46,8 +47,13 @@ export const UserSurveyDialog = UniBlock<UserSurveyDialogProps>(
46
47
  message: getMessage(currentReason, message),
47
48
  url: globalThis.location.href,
48
49
  type: surveyType,
50
+ ip: isAfterTargetAction ? 'after_target_action' : 'time_on_site',
49
51
  });
50
52
  endSending();
53
+ userSurveyStore.userSurvey = {
54
+ lastShownType: surveyType,
55
+ nextDueAt: getTimeAfter30days(),
56
+ };
51
57
  setStep(LAST_STEP_INDEX);
52
58
  },
53
59
  [currentRating, currentReason],
@@ -78,3 +84,16 @@ const getMessage = (currentReason?: Reason, message?: string) => {
78
84
 
79
85
  return message?.length ? message : 'Другое. Клиент не оставил комментариев';
80
86
  };
87
+
88
+ // Отсчитываем месяц с текущей даты
89
+ const getTimeAfter30days = () => Date.now() + 30 * 24 * 60 * 60 * 1000;
90
+
91
+ // Если пользователь проходил опрос то показываем другой, иначе показываем случайный тип опроса
92
+ const getUserSurveyType = (lastShownType?: UserSurveyType) => {
93
+ console.log('Расчитал');
94
+ if (lastShownType) {
95
+ return lastShownType === 'NPS' ? 'CSI' : 'NPS';
96
+ }
97
+
98
+ return ['NPS', 'CSI'][Date.now() % 2] as UserSurveyType;
99
+ };
@@ -2,9 +2,11 @@ import { type JSONRefObject } from '../../data/JSONRefObject';
2
2
  import { type OnCloseProps } from '../../model/OnCloseProps';
3
3
  import { type UniBlockContent } from '../../UniBlock/UniBlockProps';
4
4
 
5
+ export type UserSurveyType = 'NPS' | 'CSI';
6
+
5
7
  export type UserSurveyStoreSlice = {
6
8
  userSurvey: {
7
- lastShownType: 'NPS' | 'CSI';
9
+ lastShownType: UserSurveyType;
8
10
  nextDueAt: number;
9
11
  };
10
12
  };
@@ -18,7 +20,7 @@ export type StepProps = {
18
20
  currentRating?: number;
19
21
  currentReason?: Reason;
20
22
  reasons?: Reason[];
21
- surveyType: 'NPS' | 'CSI';
23
+ surveyType: UserSurveyType;
22
24
  isSending: boolean;
23
25
  setCurrentReason: (value: Reason) => void;
24
26
  setCurrentRating: (value: number) => void;
@@ -28,4 +30,5 @@ export type StepProps = {
28
30
 
29
31
  export interface UserSurveyDialogContent extends OnCloseProps, UniBlockContent {
30
32
  reasonsSource?: { reasons: Reason[] } | JSONRefObject;
33
+ isAfterTargetAction?: boolean;
31
34
  }
@@ -1,4 +1,4 @@
1
- import { useEffect } from '@redneckz/uni-jsx/lib/hooks';
1
+ import { useCallback, useEffect } from '@redneckz/uni-jsx/lib/hooks';
2
2
  import { useLocalStore } from '@redneckz/uni-jsx/lib/Store/useLocalStore';
3
3
  import { useSessionStore } from '@redneckz/uni-jsx/lib/Store/useSessionStore';
4
4
  import { noop } from '../../utils/noop';
@@ -10,47 +10,64 @@ const DELAY = 5 * 60 * 1000;
10
10
 
11
11
  type SurveyTimerStore = {
12
12
  surveyTimerStart: string;
13
+ surveyTimerId: NodeJS.Timeout;
14
+ isSurveySkipped: boolean;
13
15
  };
14
16
 
15
17
  // Хук отвечает за показ пользователю опроса
16
- export const useUserSurveyDialog = () => {
18
+ export const useUserSurveyDialog = (withoutTimer?: boolean) => {
17
19
  const userSurveyDialog = useDialog(UserSurveyDialog);
18
20
  const userSurveyStore = useLocalStore<UserSurveyStoreSlice>();
19
21
  const sessionStore = useSessionStore<SurveyTimerStore>();
22
+ const surveyTimer = sessionStore.surveyTimerId;
23
+ const isSurveySkipped = sessionStore.isSurveySkipped;
20
24
  const elapsedTime = sessionStore.surveyTimerStart
21
25
  ? Date.now() - Number.parseInt(sessionStore.surveyTimerStart)
22
26
  : 0;
27
+ const isShowSurvey =
28
+ !isSurveySkipped &&
29
+ (!userSurveyStore.userSurvey || userSurveyStore.userSurvey?.nextDueAt <= Date.now());
23
30
 
24
- const openUserSurveyDialog = () => {
25
- userSurveyStore.userSurvey = {
26
- lastShownType: userSurveyStore.userSurvey?.lastShownType === 'NPS' ? 'CSI' : 'NPS',
27
- nextDueAt: getTimeAfter30days(),
28
- };
31
+ const handleCloseSurvey = useCallback(() => {
32
+ sessionStore.isSurveySkipped = true;
33
+ }, []);
34
+
35
+ const openUserSurveyDialog = useCallback((isAfterTargetAction?: boolean) => {
29
36
  userSurveyDialog.open({
30
37
  reasonsSource: {
31
38
  $ref: '/wcms-resources/user-survey-reasons.json',
32
39
  },
40
+ isAfterTargetAction,
41
+ onClose: handleCloseSurvey,
33
42
  });
34
- };
43
+ }, []);
44
+
45
+ const handleOpenSurveyAction = useCallback(() => {
46
+ if (isShowSurvey) {
47
+ surveyTimer && clearTimeout(surveyTimer);
48
+ openUserSurveyDialog(true);
49
+ }
50
+ }, [surveyTimer, isShowSurvey]);
35
51
 
36
52
  useEffect(() => {
37
53
  // Опрос показывается только если ранее пользоваютелю не показывался опрос или с того момента прошел месяц
38
- if (!userSurveyStore.userSurvey || userSurveyStore.userSurvey?.nextDueAt <= Date.now()) {
54
+ if (!withoutTimer && isShowSurvey) {
39
55
  // начинаем отсчитывать время от первого захода на сайт
40
56
  if (!sessionStore.surveyTimerStart) {
41
57
  sessionStore.surveyTimerStart = Date.now().toString();
42
58
  }
43
59
  // Опрос показывается спустя 5 минут нахождения на сайте
44
60
  const timeout = setTimeout(openUserSurveyDialog, DELAY - elapsedTime);
61
+ sessionStore.surveyTimerId = timeout;
45
62
 
46
63
  return () => {
47
64
  clearTimeout(timeout);
65
+ sessionStore.surveyTimerId = null;
48
66
  };
49
67
  }
50
68
 
51
69
  return noop;
52
- }, []);
53
- };
70
+ }, [isShowSurvey]);
54
71
 
55
- // Отсчитываем месяц с текущей даты
56
- const getTimeAfter30days = () => Date.now() + 30 * 24 * 60 * 60 * 1000;
72
+ return handleOpenSurveyAction;
73
+ };