@pushwoosh/smart-components-kit 1.0.23 → 1.0.25

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.
@@ -2,7 +2,7 @@ import React, { useEffect } from 'react';
2
2
  import { FieldBox, NativeInput, Select, Spinner } from '@pushwoosh/dumb-components';
3
3
  import { Horizontal, Vertical } from '@pushwoosh/kit-helpers';
4
4
  import { useDynamicContentTags } from './hooks';
5
- import { TagPickerDiv } from './styled';
5
+ import { SimpleTagPickerDiv } from './styled';
6
6
  const defaultDynamicContent = {
7
7
  tagName: '',
8
8
  modifier: 'regular',
@@ -21,7 +21,7 @@ export const SimpleDynamicContentPickerFormSmart = ({
21
21
  }
22
22
  }, [asyncResult.loading, update]);
23
23
  if (asyncResult.loading) {
24
- return React.createElement(TagPickerDiv, null, React.createElement(Horizontal, {
24
+ return React.createElement(SimpleTagPickerDiv, null, React.createElement(Horizontal, {
25
25
  "$placeItems": "center",
26
26
  "$padding": 36
27
27
  }, React.createElement(Spinner, {
@@ -33,7 +33,7 @@ export const SimpleDynamicContentPickerFormSmart = ({
33
33
  name: '',
34
34
  modifiers: ['regular']
35
35
  };
36
- return React.createElement(TagPickerDiv, null, React.createElement(FieldBox, {
36
+ return React.createElement(SimpleTagPickerDiv, null, React.createElement(FieldBox, {
37
37
  title: "Tag"
38
38
  }, React.createElement(Vertical, {
39
39
  "$gap": 8
@@ -5,7 +5,7 @@ import { DynamicContentCustomPickerForm } from './DynamicContentCustomPickerForm
5
5
  import { DynamicContentEventPickerForm } from './DynamicContentEventPickerForm';
6
6
  import { DynamicContentTagPickerForm } from './DynamicContentTagPickerForm';
7
7
  import { useVariedDynamicContentTags } from './hooks';
8
- import { TagPickerDiv } from './styled';
8
+ import { VariedTagPickerDiv } from './styled';
9
9
  import { createDefaultDynamicContent } from './utils';
10
10
  const defaultVariedDynamicContent = {
11
11
  kind: 'tag',
@@ -39,7 +39,7 @@ export const VariedDynamicContentPickerFormSmart = ({
39
39
  update();
40
40
  }, [asyncResult.loading, update]);
41
41
  if (asyncResult.loading) {
42
- return React.createElement(TagPickerDiv, null, React.createElement(Horizontal, {
42
+ return React.createElement(VariedTagPickerDiv, null, React.createElement(Horizontal, {
43
43
  "$placeItems": "center",
44
44
  "$padding": 36
45
45
  }, React.createElement(Spinner, {
@@ -47,7 +47,7 @@ export const VariedDynamicContentPickerFormSmart = ({
47
47
  })));
48
48
  }
49
49
  const isValidDc = vdc.kind === 'tag' && vdc.dc.tagName !== '' && vdc.dc.modifier !== '' || vdc.kind === 'event' && vdc.dc.eventName !== '' && vdc.dc.attribute !== '' || vdc.kind === 'customText' && vdc.dc.text !== '';
50
- return React.createElement(TagPickerDiv, null, React.createElement(Vertical, {
50
+ return React.createElement(VariedTagPickerDiv, null, React.createElement(Vertical, {
51
51
  "$gap": 8
52
52
  }, React.createElement(FieldBox, {
53
53
  title: "Variable Type"
@@ -1,5 +1,5 @@
1
1
  import { Color, Shadow, ShapeRadius } from '@pushwoosh/kit-constants';
2
- export declare const TagPickerDiv: import("styled-components").StyledComponent<"div", any, {
2
+ export declare const SimpleTagPickerDiv: import("styled-components").StyledComponent<"div", any, {
3
3
  $alignContent?: "end" | "start" | "center" | "space-between" | "space-around" | "space-evenly" | "stretch" | undefined;
4
4
  $alignItems?: "end" | "start" | "center" | "stretch" | "baseline" | undefined;
5
5
  $bgColor?: string | undefined;
@@ -58,6 +58,67 @@ export declare const TagPickerDiv: import("styled-components").StyledComponent<"
58
58
  $gap: number;
59
59
  $padding: number;
60
60
  $borderRadius: ShapeRadius;
61
+ }, "$gridAutoFlow" | "$borderRadius" | "$gap" | "$padding">;
62
+ export declare const VariedTagPickerDiv: import("styled-components").StyledComponent<"div", any, {
63
+ $alignContent?: "end" | "start" | "center" | "space-between" | "space-around" | "space-evenly" | "stretch" | undefined;
64
+ $alignItems?: "end" | "start" | "center" | "stretch" | "baseline" | undefined;
65
+ $bgColor?: string | undefined;
66
+ $border?: string | ({
67
+ top?: string | undefined;
68
+ right?: string | undefined;
69
+ bottom?: string | undefined;
70
+ left?: string | undefined;
71
+ } | {
72
+ horizontal: string;
73
+ top?: string | undefined;
74
+ bottom?: string | undefined;
75
+ } | {
76
+ vertical: string;
77
+ right?: string | undefined;
78
+ left?: string | undefined;
79
+ }) | undefined;
80
+ $borderRadius?: (string | number) | undefined;
81
+ $boxShadow?: string | undefined;
82
+ $gap?: (string | number) | undefined;
83
+ $gridAutoFlow?: "row" | "column" | "dense" | "row dense" | "column dense" | undefined;
84
+ $justifyContent?: "end" | "start" | "center" | "space-between" | "space-around" | "space-evenly" | "stretch" | undefined;
85
+ $justifyItems?: "end" | "start" | "center" | "stretch" | "baseline" | undefined;
86
+ $margin?: (string | number) | ({
87
+ top?: (string | number) | undefined;
88
+ right?: (string | number) | undefined;
89
+ bottom?: (string | number) | undefined;
90
+ left?: (string | number) | undefined;
91
+ } | {
92
+ horizontal: string | number;
93
+ top?: (string | number) | undefined;
94
+ bottom?: (string | number) | undefined;
95
+ } | {
96
+ vertical: string | number;
97
+ right?: (string | number) | undefined;
98
+ left?: (string | number) | undefined;
99
+ }) | undefined;
100
+ $padding?: (string | number) | ({
101
+ top?: (string | number) | undefined;
102
+ right?: (string | number) | undefined;
103
+ bottom?: (string | number) | undefined;
104
+ left?: (string | number) | undefined;
105
+ } | {
106
+ horizontal: string | number;
107
+ top?: (string | number) | undefined;
108
+ bottom?: (string | number) | undefined;
109
+ } | {
110
+ vertical: string | number;
111
+ right?: (string | number) | undefined;
112
+ left?: (string | number) | undefined;
113
+ }) | undefined;
114
+ $placeItems?: "end" | "start" | "center" | "stretch" | undefined;
115
+ } & {
116
+ $gridAutoFlow: string;
117
+ } & {
118
+ $gap: number;
119
+ $padding: number;
120
+ $borderRadius: ShapeRadius;
121
+ } & {
61
122
  $border: string;
62
123
  $bgColor: Color;
63
124
  $boxShadow: Shadow;
@@ -1,14 +1,19 @@
1
1
  import styled from 'styled-components';
2
2
  import { Color, Shadow, ShapeRadius } from '@pushwoosh/kit-constants';
3
3
  import { Vertical } from '@pushwoosh/kit-helpers';
4
- export const TagPickerDiv = styled(Vertical).attrs({
4
+ export const SimpleTagPickerDiv = styled(Vertical).attrs({
5
5
  $gap: 16,
6
6
  $padding: 16,
7
- $borderRadius: ShapeRadius.CONTROL,
7
+ $borderRadius: ShapeRadius.CONTROL
8
+ }).withConfig({
9
+ displayName: "SimpleTagPickerDiv",
10
+ componentId: "sc-17kpm8h-0"
11
+ })(["width:240px;"]);
12
+ export const VariedTagPickerDiv = styled(SimpleTagPickerDiv).attrs({
8
13
  $border: `1px solid ${Color.FORM}`,
9
14
  $bgColor: Color.FROZEN,
10
15
  $boxShadow: Shadow.REGULAR
11
16
  }).withConfig({
12
- displayName: "TagPickerDiv",
13
- componentId: "sc-17kpm8h-0"
14
- })(["width:240px;"]);
17
+ displayName: "VariedTagPickerDiv",
18
+ componentId: "sc-17kpm8h-1"
19
+ })([""]);
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { type TaskInfo_args, type GetLastTasksRequest, type Status } from '@pushwoosh/rpc-v2-http-api-data/pushwoosh_export_messages_v2';
3
+ export type ExportTask = {
4
+ id: number;
5
+ status: Status;
6
+ filename?: string;
7
+ args?: TaskInfo_args;
8
+ progressTitle: string;
9
+ resultSubTitle: string;
10
+ };
11
+ type ExportCsvBannerProps = {
12
+ exportTask: ExportTask | undefined;
13
+ updateExportTask: (exportTask: Partial<ExportTask>) => void;
14
+ showLastExportLocalStorageKey: string;
15
+ lastTasksParams?: GetLastTasksRequest;
16
+ };
17
+ export declare const ExportCsvBanner: ({ exportTask, updateExportTask, showLastExportLocalStorageKey, lastTasksParams, }: ExportCsvBannerProps) => React.JSX.Element | null;
18
+ export {};
@@ -0,0 +1,121 @@
1
+ import React, { useEffect } from 'react';
2
+ import { ExportResult, ProgressBar, Button } from '@pushwoosh/dumb-components';
3
+ import { Color, ShapeRadius } from '@pushwoosh/kit-constants';
4
+ import { Horizontal } from '@pushwoosh/kit-helpers';
5
+ import { DangerTriangleIcon, DownloadIcon } from '@pushwoosh/kit-icons';
6
+ import { useExportService } from '../useExportService';
7
+ import { useExportVisibility } from './hooks/useExportVisibility';
8
+ export const ExportCsvBanner = ({
9
+ exportTask,
10
+ updateExportTask,
11
+ showLastExportLocalStorageKey,
12
+ lastTasksParams
13
+ }) => {
14
+ const {
15
+ getLastTasks,
16
+ getStatus,
17
+ clearExport,
18
+ taskResult,
19
+ progress,
20
+ error
21
+ } = useExportService();
22
+ const {
23
+ isHidden,
24
+ hide,
25
+ show
26
+ } = useExportVisibility(showLastExportLocalStorageKey);
27
+ useEffect(() => {
28
+ if (!exportTask) {
29
+ return;
30
+ }
31
+ if (exportTask.id && (exportTask.status === 'STATUS_PENDING' || exportTask.status === 'STATUS_UNSPECIFIED')) {
32
+ clearExport();
33
+ getStatus({
34
+ uid: exportTask.id
35
+ });
36
+ show();
37
+ }
38
+ }, [clearExport, exportTask, getStatus, show]);
39
+ useEffect(() => {
40
+ if (taskResult) {
41
+ updateExportTask({
42
+ status: 'STATUS_SUCCESS',
43
+ filename: taskResult.data.file
44
+ });
45
+ }
46
+ }, [taskResult, updateExportTask]);
47
+ useEffect(() => {
48
+ if (error) {
49
+ updateExportTask({
50
+ status: 'STATUS_FAILED'
51
+ });
52
+ }
53
+ }, [error, updateExportTask]);
54
+ useEffect(() => {
55
+ if (lastTasksParams && !isHidden) {
56
+ getLastTasks(lastTasksParams).then(res => {
57
+ if (res.length > 0) {
58
+ const {
59
+ id,
60
+ result,
61
+ status,
62
+ args
63
+ } = res[0];
64
+ const {
65
+ data
66
+ } = result;
67
+ updateExportTask({
68
+ id,
69
+ status,
70
+ filename: data.file,
71
+ args,
72
+ progressTitle: 'Exporting list:',
73
+ resultSubTitle: 'Result:'
74
+ });
75
+ }
76
+ });
77
+ }
78
+ }, [getLastTasks, isHidden, lastTasksParams, updateExportTask]);
79
+ if (!exportTask || isHidden) return null;
80
+ const {
81
+ filename,
82
+ status,
83
+ resultSubTitle,
84
+ progressTitle
85
+ } = exportTask;
86
+ return React.createElement(Horizontal, {
87
+ "$padding": 8,
88
+ "$alignItems": "center",
89
+ "$border": `1px solid ${Color.DIVIDER}`,
90
+ "$borderRadius": ShapeRadius.SECTION,
91
+ "$bgColor": Color.CLEAR
92
+ }, status === 'STATUS_SUCCESS' && React.createElement(ExportResult, {
93
+ type: "success",
94
+ title: "Exporting complete",
95
+ subtitle: `${resultSubTitle} ${filename}`,
96
+ handleClose: hide,
97
+ rightSlot: React.createElement("a", {
98
+ href: `/api/v2/statistics/exportMessagesStatistics/download/${filename}`,
99
+ download: filename
100
+ }, React.createElement(Button, {
101
+ color: "secondary",
102
+ size: "compact",
103
+ icon: React.createElement(DownloadIcon, {
104
+ size: "small",
105
+ view: "filled"
106
+ })
107
+ }, "Download CSV"))
108
+ }), status === 'STATUS_PENDING' && React.createElement(ProgressBar, {
109
+ title: progressTitle,
110
+ percentValue: progress
111
+ }), status === 'STATUS_FAILED' && React.createElement(ExportResult, {
112
+ type: "error",
113
+ title: "Export failed",
114
+ subtitle: "Please try again",
115
+ leftSlotIcon: React.createElement(DangerTriangleIcon, {
116
+ size: "medium",
117
+ view: "filled"
118
+ }),
119
+ handleClose: hide
120
+ }));
121
+ };
@@ -0,0 +1,5 @@
1
+ export declare const useExportVisibility: (key: string) => {
2
+ isHidden: boolean;
3
+ hide: () => void;
4
+ show: () => void;
5
+ };
@@ -0,0 +1,17 @@
1
+ import { useCallback, useState } from 'react';
2
+ export const useExportVisibility = key => {
3
+ const [isHidden, setIsHidden] = useState(() => Boolean(+(localStorage.getItem(key) ?? 0)));
4
+ const hide = useCallback(() => {
5
+ localStorage.setItem(key, '1');
6
+ setIsHidden(true);
7
+ }, [key]);
8
+ const show = useCallback(() => {
9
+ localStorage.setItem(key, '0');
10
+ setIsHidden(false);
11
+ }, [key]);
12
+ return {
13
+ isHidden,
14
+ hide,
15
+ show
16
+ };
17
+ };
@@ -0,0 +1,2 @@
1
+ export { ExportCsvBanner } from './ExportCsvBanner';
2
+ export type { ExportTask } from './ExportCsvBanner';
@@ -0,0 +1 @@
1
+ export { ExportCsvBanner } from './ExportCsvBanner';
@@ -0,0 +1,2 @@
1
+ export * from './ExportCsvBanner';
2
+ export * from './useExportService';
@@ -0,0 +1,2 @@
1
+ export * from './ExportCsvBanner';
2
+ export * from './useExportService';
@@ -0,0 +1,2 @@
1
+ export declare const MAX_RETRIES = 180;
2
+ export declare const API_CHECK_INTERVAL = 1000;
@@ -0,0 +1,2 @@
1
+ export const MAX_RETRIES = 180;
2
+ export const API_CHECK_INTERVAL = 1000;
@@ -0,0 +1 @@
1
+ export * from './useExportService';
@@ -0,0 +1 @@
1
+ export * from './useExportService';
@@ -0,0 +1,12 @@
1
+ import type { StatusRequest, StatusResponse, ResultRequest, ResultResponse, ExportRequest, GetLastTasksRequest, TaskInfo, ResultResponse_result } from '@pushwoosh/rpc-v2-http-api-data/pushwoosh_export_messages_v2';
2
+ export declare const useExportService: () => {
3
+ getLastTasks: (params: GetLastTasksRequest) => Promise<TaskInfo[]>;
4
+ startExport: (params: ExportRequest) => Promise<number>;
5
+ getStatus: (params: StatusRequest) => Promise<StatusResponse>;
6
+ getResult: (params: ResultRequest) => Promise<ResultResponse>;
7
+ clearExport: () => void;
8
+ error: string;
9
+ progress: number;
10
+ isTaskInProgress: boolean;
11
+ taskResult: ResultResponse_result | undefined;
12
+ };
@@ -0,0 +1,119 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { API_CHECK_INTERVAL, MAX_RETRIES } from './constants';
3
+ import { useSPAContext } from '../../context';
4
+ export const useExportService = () => {
5
+ const [error, setError] = useState('');
6
+ const [progress, setProgress] = useState(0);
7
+ const [isTaskInProgress, setIsTaskInProgress] = useState(false);
8
+ const [taskResult, setTaskResult] = useState();
9
+ const timeoutStatusRef = useRef(null);
10
+ const retriesRef = useRef(0);
11
+ const {
12
+ rpcGateway
13
+ } = useSPAContext();
14
+ const clearExport = useCallback(() => {
15
+ setError('');
16
+ setIsTaskInProgress(false);
17
+ setTaskResult(undefined);
18
+ setProgress(0);
19
+ }, []);
20
+ const clearStatusTimeout = useCallback(() => {
21
+ if (timeoutStatusRef.current) {
22
+ clearTimeout(timeoutStatusRef.current);
23
+ timeoutStatusRef.current = null;
24
+ }
25
+ }, []);
26
+ const startExport = useCallback(async params => {
27
+ try {
28
+ clearExport();
29
+ setIsTaskInProgress(true);
30
+ const {
31
+ uid
32
+ } = await rpcGateway.exportStatistics.Export(params);
33
+ return uid;
34
+ } catch (err) {
35
+ setError(err === null || err === void 0 ? void 0 : err.message);
36
+ setIsTaskInProgress(false);
37
+ return 0;
38
+ }
39
+ }, [clearExport, rpcGateway.exportStatistics]);
40
+ const getResult = useCallback(async params => {
41
+ try {
42
+ const result = await rpcGateway.exportStatistics.Result(params);
43
+ setTaskResult(result.result);
44
+ return result;
45
+ } catch (err) {
46
+ setError(err === null || err === void 0 ? void 0 : err.message);
47
+ return err;
48
+ } finally {
49
+ setIsTaskInProgress(false);
50
+ }
51
+ }, [rpcGateway]);
52
+ const getStatus = useCallback(async params => {
53
+ try {
54
+ const result = await rpcGateway.exportStatistics.Status(params);
55
+ switch (result.status) {
56
+ case 'STATUS_PENDING':
57
+ if (result.progress > progress) {
58
+ setProgress(Math.round(result.progress));
59
+ }
60
+ clearStatusTimeout();
61
+ if (retriesRef.current < MAX_RETRIES) {
62
+ retriesRef.current += 1;
63
+ timeoutStatusRef.current = setTimeout(() => {
64
+ getStatus(params);
65
+ clearStatusTimeout();
66
+ }, API_CHECK_INTERVAL);
67
+ } else {
68
+ setError('Max retries reached. Please try again later.');
69
+ setIsTaskInProgress(false);
70
+ }
71
+ break;
72
+ case 'STATUS_SUCCESS':
73
+ getResult(params);
74
+ retriesRef.current = 0;
75
+ setIsTaskInProgress(false);
76
+ break;
77
+ case 'STATUS_FAILED':
78
+ setError('Error. File has not been generated. Please contact with our support team');
79
+ setIsTaskInProgress(false);
80
+ retriesRef.current = 0;
81
+ throw new Error('Export failed');
82
+ default:
83
+ break;
84
+ }
85
+ return result;
86
+ } catch (err) {
87
+ setError('Export failed. File not found');
88
+ setIsTaskInProgress(false);
89
+ retriesRef.current = 0;
90
+ return err;
91
+ }
92
+ }, [clearStatusTimeout, getResult, progress, rpcGateway]);
93
+ const getLastTasks = useCallback(async params => {
94
+ try {
95
+ const {
96
+ tasks
97
+ } = await rpcGateway.exportStatistics.GetLastTasks(params);
98
+ return tasks;
99
+ } catch (err) {
100
+ setError(err === null || err === void 0 ? void 0 : err.message);
101
+ return err;
102
+ }
103
+ }, [rpcGateway]);
104
+ useEffect(() => () => {
105
+ clearStatusTimeout();
106
+ setIsTaskInProgress(false);
107
+ }, [clearStatusTimeout]);
108
+ return {
109
+ getLastTasks,
110
+ startExport,
111
+ getStatus,
112
+ getResult,
113
+ clearExport,
114
+ error,
115
+ progress,
116
+ isTaskInProgress,
117
+ taskResult
118
+ };
119
+ };
package/index.d.ts CHANGED
@@ -5,3 +5,4 @@ export * from './PlatformsConfigurationDrawer';
5
5
  export * from './LanguagesSelector';
6
6
  export * from './RichMessageEditorSmart';
7
7
  export * from './CampaignsConfigurationDrawer';
8
+ export * from './ExportCSV';
package/index.js CHANGED
@@ -4,4 +4,5 @@ export * from './DynamicContentPickerForm';
4
4
  export * from './PlatformsConfigurationDrawer';
5
5
  export * from './LanguagesSelector';
6
6
  export * from './RichMessageEditorSmart';
7
- export * from './CampaignsConfigurationDrawer';
7
+ export * from './CampaignsConfigurationDrawer';
8
+ export * from './ExportCSV';
package/package.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "dependencies": {
19
19
  "@emoji-mart/react": "^1.1.1",
20
20
  "@floating-ui/react-dom": "^2.1.2",
21
- "@pushwoosh/dumb-components": "^1.0.74",
21
+ "@pushwoosh/dumb-components": "^1.1.2",
22
22
  "@pushwoosh/kit-constants": "^1.6.9",
23
23
  "@pushwoosh/kit-helpers": "^4.8.1",
24
24
  "@pushwoosh/kit-icons": "^2.1.2",
@@ -50,5 +50,5 @@
50
50
  "engines": {
51
51
  "node": ">= 18"
52
52
  },
53
- "version": "1.0.23"
53
+ "version": "1.0.25"
54
54
  }