@inspirer-dev/crm-dashboard 1.0.53 → 1.0.55
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/admin/src/components/StepFlowBuilder/index.tsx +16 -25
- package/admin/src/components/StepFlowBuilder/panels/EntryConfig.tsx +2 -6
- package/admin/src/hooks/api/use-ab-tests.ts +1 -1
- package/admin/src/hooks/api/use-anti-spam-logs.ts +1 -1
- package/admin/src/hooks/api/use-campaign-mutations.ts +3 -3
- package/admin/src/hooks/api/use-campaigns.ts +3 -3
- package/admin/src/hooks/api/use-cohort-data.ts +1 -1
- package/admin/src/hooks/api/use-crm-logs.ts +1 -1
- package/admin/src/hooks/api/use-dashboard-stats.ts +1 -1
- package/admin/src/hooks/api/use-filter-options.ts +1 -1
- package/admin/src/hooks/api/use-realtime-stats.ts +1 -1
- package/admin/src/hooks/api/use-segment-stats.ts +1 -1
- package/admin/src/hooks/api/use-send-times.ts +1 -1
- package/admin/src/utils/getBackendUrl.ts +20 -6
- package/dist/_chunks/{index-C_zGO7mZ.js → index--YXTcU9K.js} +0 -24
- package/dist/_chunks/{index-wE233MhG.js → index-CCjUeHQa.js} +26 -14
- package/dist/_chunks/{index-6qhuoAbM.mjs → index-CLXsV-bm.mjs} +0 -24
- package/dist/_chunks/{index-DLPqbGjQ.mjs → index-bOPRBiEo.mjs} +26 -14
- package/dist/admin/index.js +2 -2
- package/dist/admin/index.mjs +2 -2
- package/dist/server/index.js +12 -0
- package/dist/server/index.mjs +12 -0
- package/package.json +1 -1
- package/server/src/controllers/controller.ts +5 -0
- package/server/src/routes/index.ts +8 -0
|
@@ -2,7 +2,11 @@ import React, { forwardRef, useCallback, useEffect, useMemo, useState, useRef }
|
|
|
2
2
|
import { ReactFlowProvider } from 'reactflow';
|
|
3
3
|
import 'reactflow/dist/style.css';
|
|
4
4
|
import { Box, Field, Flex, Typography, Badge } from '@strapi/design-system';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
useForm,
|
|
7
|
+
unstable_useContentManagerContext as useContentManagerContext,
|
|
8
|
+
useFetchClient,
|
|
9
|
+
} from '@strapi/strapi/admin';
|
|
6
10
|
|
|
7
11
|
import type { StepFlowBuilderProps, FlowStep, CampaignContext, EntrySegment } from './types';
|
|
8
12
|
import type { ValidationResult } from './validation';
|
|
@@ -49,19 +53,16 @@ const StepFlowBuilderInner = forwardRef<HTMLDivElement, StepFlowBuilderProps>(
|
|
|
49
53
|
},
|
|
50
54
|
});
|
|
51
55
|
|
|
52
|
-
const responseData = response?.data as
|
|
56
|
+
const responseData = response?.data as
|
|
57
|
+
| { data?: { entrySegment?: { id: number; name: string } } }
|
|
58
|
+
| undefined;
|
|
53
59
|
const campaignData = responseData?.data;
|
|
54
|
-
console.log('[StepFlowBuilder] Fetch response campaignData:', campaignData);
|
|
55
|
-
console.log('[StepFlowBuilder] entrySegment from API:', campaignData?.entrySegment);
|
|
56
60
|
if (campaignData?.entrySegment?.id) {
|
|
57
61
|
const seg = {
|
|
58
62
|
id: campaignData.entrySegment.id,
|
|
59
63
|
name: campaignData.entrySegment.name || `Segment #${campaignData.entrySegment.id}`,
|
|
60
64
|
};
|
|
61
|
-
console.log('[StepFlowBuilder] Setting initialSegment:', seg);
|
|
62
65
|
setInitialSegment(seg);
|
|
63
|
-
} else {
|
|
64
|
-
console.log('[StepFlowBuilder] No entrySegment.id found in API response');
|
|
65
66
|
}
|
|
66
67
|
} catch (err) {
|
|
67
68
|
console.error('[StepFlowBuilder] Fetch error:', err);
|
|
@@ -77,51 +78,36 @@ const StepFlowBuilderInner = forwardRef<HTMLDivElement, StepFlowBuilderProps>(
|
|
|
77
78
|
const values = form?.values as Record<string, unknown> | undefined;
|
|
78
79
|
const entrySegmentValue = values?.entrySegment as ConnectDisconnect | SegmentItem | undefined;
|
|
79
80
|
|
|
80
|
-
console.log('[StepFlowBuilder] currentSegment memo - form.values.entrySegment:', entrySegmentValue);
|
|
81
|
-
console.log('[StepFlowBuilder] currentSegment memo - initialSegment:', initialSegment);
|
|
82
|
-
console.log('[StepFlowBuilder] currentSegment memo - typeof entrySegmentValue:', typeof entrySegmentValue);
|
|
83
|
-
if (entrySegmentValue) {
|
|
84
|
-
console.log('[StepFlowBuilder] currentSegment memo - entrySegmentValue keys:', Object.keys(entrySegmentValue));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
81
|
if (!entrySegmentValue) {
|
|
88
|
-
console.log('[StepFlowBuilder] currentSegment memo - no entrySegmentValue, returning initialSegment');
|
|
89
82
|
return initialSegment;
|
|
90
83
|
}
|
|
91
84
|
|
|
92
85
|
// Handle connect/disconnect structure (user changed the segment in UI)
|
|
93
86
|
if ('connect' in entrySegmentValue || 'disconnect' in entrySegmentValue) {
|
|
94
|
-
console.log('[StepFlowBuilder] currentSegment memo - detected connect/disconnect structure');
|
|
95
87
|
const { connect = [], disconnect = [] } = entrySegmentValue as ConnectDisconnect;
|
|
96
88
|
|
|
97
89
|
if (connect.length > 0) {
|
|
98
90
|
const seg = connect[0];
|
|
99
|
-
console.log('[StepFlowBuilder] currentSegment memo - returning from connect:', seg);
|
|
100
91
|
return { id: seg.id!, name: seg.name || `Segment #${seg.id}` };
|
|
101
92
|
}
|
|
102
93
|
|
|
103
94
|
if (disconnect.length > 0 && initialSegment) {
|
|
104
95
|
const disconnectedId = disconnect[0]?.id;
|
|
105
96
|
if (disconnectedId === initialSegment.id) {
|
|
106
|
-
console.log('[StepFlowBuilder] currentSegment memo - segment disconnected, returning null');
|
|
107
97
|
return null;
|
|
108
98
|
}
|
|
109
99
|
}
|
|
110
100
|
|
|
111
|
-
console.log('[StepFlowBuilder] currentSegment memo - connect/disconnect but falling back to initialSegment');
|
|
112
101
|
return initialSegment;
|
|
113
102
|
}
|
|
114
103
|
|
|
115
104
|
// Handle direct segment object (loaded from server)
|
|
116
105
|
const segmentObj = entrySegmentValue as SegmentItem;
|
|
117
|
-
console.log('[StepFlowBuilder] currentSegment memo - treating as direct segment object:', segmentObj);
|
|
118
106
|
if (segmentObj.id) {
|
|
119
107
|
const result = { id: segmentObj.id, name: segmentObj.name || `Segment #${segmentObj.id}` };
|
|
120
|
-
console.log('[StepFlowBuilder] currentSegment memo - returning direct segment:', result);
|
|
121
108
|
return result;
|
|
122
109
|
}
|
|
123
110
|
|
|
124
|
-
console.log('[StepFlowBuilder] currentSegment memo - no id in segmentObj, returning initialSegment');
|
|
125
111
|
return initialSegment;
|
|
126
112
|
}, [form?.values, initialSegment]);
|
|
127
113
|
|
|
@@ -133,7 +119,6 @@ const StepFlowBuilderInner = forwardRef<HTMLDivElement, StepFlowBuilderProps>(
|
|
|
133
119
|
triggerConfig: values.triggerConfig as CampaignContext['triggerConfig'],
|
|
134
120
|
entrySegment: currentSegment,
|
|
135
121
|
};
|
|
136
|
-
console.log('[StepFlowBuilder] campaignContext:', ctx);
|
|
137
122
|
return ctx;
|
|
138
123
|
}, [form?.values, currentSegment]);
|
|
139
124
|
|
|
@@ -204,12 +189,18 @@ const StepFlowBuilderInner = forwardRef<HTMLDivElement, StepFlowBuilderProps>(
|
|
|
204
189
|
<Field.Label>{displayLabel}</Field.Label>
|
|
205
190
|
{validation && !validation.isValid && (
|
|
206
191
|
<Badge backgroundColor="danger100" textColor="danger600">
|
|
207
|
-
{validation.errors.length}
|
|
192
|
+
{validation.errors.length}{' '}
|
|
193
|
+
{validation.errors.length === 1
|
|
194
|
+
? 'ошибка'
|
|
195
|
+
: validation.errors.length < 5
|
|
196
|
+
? 'ошибки'
|
|
197
|
+
: 'ошибок'}
|
|
208
198
|
</Badge>
|
|
209
199
|
)}
|
|
210
200
|
{validation && validation.isValid && validation.warnings.length > 0 && (
|
|
211
201
|
<Badge backgroundColor="warning100" textColor="warning600">
|
|
212
|
-
{validation.warnings.length}
|
|
202
|
+
{validation.warnings.length}{' '}
|
|
203
|
+
{validation.warnings.length === 1 ? 'предупр.' : 'предупр.'}
|
|
213
204
|
</Badge>
|
|
214
205
|
)}
|
|
215
206
|
</Flex>
|
|
@@ -88,7 +88,6 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
88
88
|
entrySegment,
|
|
89
89
|
theme,
|
|
90
90
|
}) => {
|
|
91
|
-
console.log('[EntryConfig] Received entrySegment:', entrySegment);
|
|
92
91
|
const config = parseTriggerConfig(triggerConfig);
|
|
93
92
|
|
|
94
93
|
const renderTriggerInfo = () => {
|
|
@@ -235,11 +234,8 @@ const EntryConfigInner: React.FC<EntryConfigProps & { theme: FlowThemeColors }>
|
|
|
235
234
|
|
|
236
235
|
const renderSegmentInfo = () => {
|
|
237
236
|
const hasSegment = entrySegment && (entrySegment.id || entrySegment.name);
|
|
238
|
-
const segmentDisplayName =
|
|
239
|
-
|
|
240
|
-
console.log('[EntryConfig] renderSegmentInfo - entrySegment:', entrySegment);
|
|
241
|
-
console.log('[EntryConfig] renderSegmentInfo - hasSegment:', hasSegment);
|
|
242
|
-
console.log('[EntryConfig] renderSegmentInfo - segmentDisplayName:', segmentDisplayName);
|
|
237
|
+
const segmentDisplayName =
|
|
238
|
+
entrySegment?.name || (entrySegment?.id ? `Segment #${entrySegment.id}` : null);
|
|
243
239
|
|
|
244
240
|
if (!hasSegment || !segmentDisplayName) {
|
|
245
241
|
return (
|
|
@@ -16,7 +16,7 @@ const fetchABTestData = async (filters: StatsFilters): Promise<ABTestsResponse>
|
|
|
16
16
|
params.set('campaignIds', filters.campaigns.join(','));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const backendUrl = getBackendUrl();
|
|
19
|
+
const backendUrl = await getBackendUrl();
|
|
20
20
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/ab-tests?${params}`);
|
|
21
21
|
|
|
22
22
|
if (!res.ok) {
|
|
@@ -24,7 +24,7 @@ const fetchAntiSpamLogs = async (
|
|
|
24
24
|
if (filters.dateFrom) params.set('from', filters.dateFrom.toISOString());
|
|
25
25
|
if (filters.dateTo) params.set('to', filters.dateTo.toISOString());
|
|
26
26
|
|
|
27
|
-
const backendUrl = getBackendUrl();
|
|
27
|
+
const backendUrl = await getBackendUrl();
|
|
28
28
|
const res = await fetch(new URL(`/api/crm/anti-spam-logs?${params}`, backendUrl).toString());
|
|
29
29
|
|
|
30
30
|
if (!res.ok) {
|
|
@@ -7,7 +7,7 @@ type CreateCampaignInput = Omit<Campaign, 'id' | 'documentId'>;
|
|
|
7
7
|
type UpdateCampaignInput = Partial<Campaign> & { documentId: string };
|
|
8
8
|
|
|
9
9
|
const createCampaign = async (input: CreateCampaignInput): Promise<Campaign> => {
|
|
10
|
-
const backendUrl = getBackendUrl();
|
|
10
|
+
const backendUrl = await getBackendUrl();
|
|
11
11
|
const res = await fetch(new URL('/api/crm/campaigns', backendUrl).toString(), {
|
|
12
12
|
method: 'POST',
|
|
13
13
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -23,7 +23,7 @@ const createCampaign = async (input: CreateCampaignInput): Promise<Campaign> =>
|
|
|
23
23
|
|
|
24
24
|
const updateCampaign = async (input: UpdateCampaignInput): Promise<Campaign> => {
|
|
25
25
|
const { documentId, ...data } = input;
|
|
26
|
-
const backendUrl = getBackendUrl();
|
|
26
|
+
const backendUrl = await getBackendUrl();
|
|
27
27
|
const res = await fetch(new URL(`/api/crm/campaigns/${documentId}`, backendUrl).toString(), {
|
|
28
28
|
method: 'PUT',
|
|
29
29
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -38,7 +38,7 @@ const updateCampaign = async (input: UpdateCampaignInput): Promise<Campaign> =>
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
const deleteCampaign = async (documentId: string): Promise<void> => {
|
|
41
|
-
const backendUrl = getBackendUrl();
|
|
41
|
+
const backendUrl = await getBackendUrl();
|
|
42
42
|
const res = await fetch(new URL(`/api/crm/campaigns/${documentId}`, backendUrl).toString(), {
|
|
43
43
|
method: 'DELETE',
|
|
44
44
|
});
|
|
@@ -5,7 +5,7 @@ import type { Campaign } from './types';
|
|
|
5
5
|
import type { CrmSegment, CrmTemplate } from '../../types/crm';
|
|
6
6
|
|
|
7
7
|
const fetchCampaigns = async (): Promise<Campaign[]> => {
|
|
8
|
-
const backendUrl = getBackendUrl();
|
|
8
|
+
const backendUrl = await getBackendUrl();
|
|
9
9
|
const res = await fetch(new URL('/api/crm/campaigns', backendUrl).toString());
|
|
10
10
|
|
|
11
11
|
if (!res.ok) {
|
|
@@ -17,7 +17,7 @@ const fetchCampaigns = async (): Promise<Campaign[]> => {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const fetchSegments = async (): Promise<CrmSegment[]> => {
|
|
20
|
-
const backendUrl = getBackendUrl();
|
|
20
|
+
const backendUrl = await getBackendUrl();
|
|
21
21
|
const res = await fetch(new URL('/api/crm/segments', backendUrl).toString());
|
|
22
22
|
|
|
23
23
|
if (!res.ok) {
|
|
@@ -29,7 +29,7 @@ const fetchSegments = async (): Promise<CrmSegment[]> => {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
const fetchTemplates = async (): Promise<CrmTemplate[]> => {
|
|
32
|
-
const backendUrl = getBackendUrl();
|
|
32
|
+
const backendUrl = await getBackendUrl();
|
|
33
33
|
const res = await fetch(new URL('/api/crm/templates', backendUrl).toString());
|
|
34
34
|
|
|
35
35
|
if (!res.ok) {
|
|
@@ -20,7 +20,7 @@ const fetchCohortData = async (filters: CohortFilters): Promise<CohortData> => {
|
|
|
20
20
|
params.set('campaignIds', filters.campaigns.join(','));
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const backendUrl = getBackendUrl();
|
|
23
|
+
const backendUrl = await getBackendUrl();
|
|
24
24
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/cohorts?${params}`);
|
|
25
25
|
|
|
26
26
|
if (!res.ok) {
|
|
@@ -18,7 +18,7 @@ const fetchCrmLogs = async (filters: LogsFilters, page: number): Promise<CrmLogs
|
|
|
18
18
|
if (filters.sentFrom) params.set('sentFrom', filters.sentFrom.toISOString());
|
|
19
19
|
if (filters.sentTo) params.set('sentTo', filters.sentTo.toISOString());
|
|
20
20
|
|
|
21
|
-
const backendUrl = getBackendUrl();
|
|
21
|
+
const backendUrl = await getBackendUrl();
|
|
22
22
|
const res = await fetch(new URL(`/api/crm/logs?${params}`, backendUrl).toString());
|
|
23
23
|
|
|
24
24
|
if (!res.ok) {
|
|
@@ -13,7 +13,7 @@ const fetchDashboardStats = async (filters: StatsFilters): Promise<DashboardStat
|
|
|
13
13
|
if (filters.compareToPrevious) params.set('compareToPrevious', 'true');
|
|
14
14
|
if (filters.granularity) params.set('granularity', filters.granularity);
|
|
15
15
|
|
|
16
|
-
const backendUrl = getBackendUrl();
|
|
16
|
+
const backendUrl = await getBackendUrl();
|
|
17
17
|
const res = await fetch(new URL(`/api/crm/dashboard/stats?${params}`, backendUrl).toString());
|
|
18
18
|
|
|
19
19
|
if (!res.ok) {
|
|
@@ -4,7 +4,7 @@ import getBackendUrl from '../../utils/getBackendUrl';
|
|
|
4
4
|
import type { FilterOptions } from './types';
|
|
5
5
|
|
|
6
6
|
const fetchFilterOptions = async (): Promise<FilterOptions> => {
|
|
7
|
-
const backendUrl = getBackendUrl();
|
|
7
|
+
const backendUrl = await getBackendUrl();
|
|
8
8
|
const res = await fetch(new URL('/api/crm/filter-options', backendUrl).toString());
|
|
9
9
|
|
|
10
10
|
if (!res.ok) {
|
|
@@ -10,7 +10,7 @@ const fetchRealtimeStats = async (campaignIds?: string[]): Promise<RealtimeStats
|
|
|
10
10
|
params.set('campaignIds', campaignIds.join(','));
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
const backendUrl = getBackendUrl();
|
|
13
|
+
const backendUrl = await getBackendUrl();
|
|
14
14
|
const url = params.toString()
|
|
15
15
|
? `${backendUrl}/api/crm/dashboard/realtime?${params}`
|
|
16
16
|
: `${backendUrl}/api/crm/dashboard/realtime`;
|
|
@@ -12,7 +12,7 @@ const fetchSegmentStats = async (filters: StatsFilters): Promise<SegmentStats> =
|
|
|
12
12
|
params.set('campaignIds', filters.campaigns.join(','));
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const backendUrl = getBackendUrl();
|
|
15
|
+
const backendUrl = await getBackendUrl();
|
|
16
16
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/segments?${params}`);
|
|
17
17
|
|
|
18
18
|
if (!res.ok) {
|
|
@@ -12,7 +12,7 @@ const fetchSendTimeData = async (filters: StatsFilters): Promise<SendTimeData> =
|
|
|
12
12
|
params.set('campaignIds', filters.campaigns.join(','));
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const backendUrl = getBackendUrl();
|
|
15
|
+
const backendUrl = await getBackendUrl();
|
|
16
16
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/send-times?${params}`);
|
|
17
17
|
|
|
18
18
|
if (!res.ok) {
|
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
const raw = process.env.STRAPI_ADMIN_API_URL || 'http://localhost:3100';
|
|
1
|
+
let cachedUrl: string | undefined;
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const getBackendUrl = async (): Promise<string> => {
|
|
4
|
+
if (cachedUrl !== undefined) {
|
|
5
|
+
return cachedUrl;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
try {
|
|
9
|
+
const res = await fetch('/api/crm-dashboard/config');
|
|
10
|
+
if (res.ok) {
|
|
11
|
+
const data = await res.json();
|
|
12
|
+
cachedUrl = data.apiUrl || '';
|
|
13
|
+
}
|
|
14
|
+
} catch (e) {
|
|
15
|
+
console.error('[CRM]: Failed to fetch config', e);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (cachedUrl === undefined) {
|
|
19
|
+
cachedUrl = '';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return cachedUrl;
|
|
9
23
|
};
|
|
10
24
|
|
|
11
|
-
export default getBackendUrl;
|
|
25
|
+
export default getBackendUrl;
|
|
@@ -1926,7 +1926,6 @@ const EntryConfigInner = ({
|
|
|
1926
1926
|
entrySegment,
|
|
1927
1927
|
theme
|
|
1928
1928
|
}) => {
|
|
1929
|
-
console.log("[EntryConfig] Received entrySegment:", entrySegment);
|
|
1930
1929
|
const config = parseTriggerConfig(triggerConfig);
|
|
1931
1930
|
const renderTriggerInfo = () => {
|
|
1932
1931
|
if (!config) {
|
|
@@ -2058,9 +2057,6 @@ const EntryConfigInner = ({
|
|
|
2058
2057
|
const renderSegmentInfo = () => {
|
|
2059
2058
|
const hasSegment = entrySegment && (entrySegment.id || entrySegment.name);
|
|
2060
2059
|
const segmentDisplayName = entrySegment?.name || (entrySegment?.id ? `Segment #${entrySegment.id}` : null);
|
|
2061
|
-
console.log("[EntryConfig] renderSegmentInfo - entrySegment:", entrySegment);
|
|
2062
|
-
console.log("[EntryConfig] renderSegmentInfo - hasSegment:", hasSegment);
|
|
2063
|
-
console.log("[EntryConfig] renderSegmentInfo - segmentDisplayName:", segmentDisplayName);
|
|
2064
2060
|
if (!hasSegment || !segmentDisplayName) {
|
|
2065
2061
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2066
2062
|
"div",
|
|
@@ -3684,17 +3680,12 @@ const StepFlowBuilderInner = React.forwardRef(
|
|
|
3684
3680
|
});
|
|
3685
3681
|
const responseData = response?.data;
|
|
3686
3682
|
const campaignData = responseData?.data;
|
|
3687
|
-
console.log("[StepFlowBuilder] Fetch response campaignData:", campaignData);
|
|
3688
|
-
console.log("[StepFlowBuilder] entrySegment from API:", campaignData?.entrySegment);
|
|
3689
3683
|
if (campaignData?.entrySegment?.id) {
|
|
3690
3684
|
const seg = {
|
|
3691
3685
|
id: campaignData.entrySegment.id,
|
|
3692
3686
|
name: campaignData.entrySegment.name || `Segment #${campaignData.entrySegment.id}`
|
|
3693
3687
|
};
|
|
3694
|
-
console.log("[StepFlowBuilder] Setting initialSegment:", seg);
|
|
3695
3688
|
setInitialSegment(seg);
|
|
3696
|
-
} else {
|
|
3697
|
-
console.log("[StepFlowBuilder] No entrySegment.id found in API response");
|
|
3698
3689
|
}
|
|
3699
3690
|
} catch (err) {
|
|
3700
3691
|
console.error("[StepFlowBuilder] Fetch error:", err);
|
|
@@ -3707,42 +3698,28 @@ const StepFlowBuilderInner = React.forwardRef(
|
|
|
3707
3698
|
const currentSegment = React.useMemo(() => {
|
|
3708
3699
|
const values = form?.values;
|
|
3709
3700
|
const entrySegmentValue = values?.entrySegment;
|
|
3710
|
-
console.log("[StepFlowBuilder] currentSegment memo - form.values.entrySegment:", entrySegmentValue);
|
|
3711
|
-
console.log("[StepFlowBuilder] currentSegment memo - initialSegment:", initialSegment);
|
|
3712
|
-
console.log("[StepFlowBuilder] currentSegment memo - typeof entrySegmentValue:", typeof entrySegmentValue);
|
|
3713
|
-
if (entrySegmentValue) {
|
|
3714
|
-
console.log("[StepFlowBuilder] currentSegment memo - entrySegmentValue keys:", Object.keys(entrySegmentValue));
|
|
3715
|
-
}
|
|
3716
3701
|
if (!entrySegmentValue) {
|
|
3717
|
-
console.log("[StepFlowBuilder] currentSegment memo - no entrySegmentValue, returning initialSegment");
|
|
3718
3702
|
return initialSegment;
|
|
3719
3703
|
}
|
|
3720
3704
|
if ("connect" in entrySegmentValue || "disconnect" in entrySegmentValue) {
|
|
3721
|
-
console.log("[StepFlowBuilder] currentSegment memo - detected connect/disconnect structure");
|
|
3722
3705
|
const { connect = [], disconnect = [] } = entrySegmentValue;
|
|
3723
3706
|
if (connect.length > 0) {
|
|
3724
3707
|
const seg = connect[0];
|
|
3725
|
-
console.log("[StepFlowBuilder] currentSegment memo - returning from connect:", seg);
|
|
3726
3708
|
return { id: seg.id, name: seg.name || `Segment #${seg.id}` };
|
|
3727
3709
|
}
|
|
3728
3710
|
if (disconnect.length > 0 && initialSegment) {
|
|
3729
3711
|
const disconnectedId = disconnect[0]?.id;
|
|
3730
3712
|
if (disconnectedId === initialSegment.id) {
|
|
3731
|
-
console.log("[StepFlowBuilder] currentSegment memo - segment disconnected, returning null");
|
|
3732
3713
|
return null;
|
|
3733
3714
|
}
|
|
3734
3715
|
}
|
|
3735
|
-
console.log("[StepFlowBuilder] currentSegment memo - connect/disconnect but falling back to initialSegment");
|
|
3736
3716
|
return initialSegment;
|
|
3737
3717
|
}
|
|
3738
3718
|
const segmentObj = entrySegmentValue;
|
|
3739
|
-
console.log("[StepFlowBuilder] currentSegment memo - treating as direct segment object:", segmentObj);
|
|
3740
3719
|
if (segmentObj.id) {
|
|
3741
3720
|
const result = { id: segmentObj.id, name: segmentObj.name || `Segment #${segmentObj.id}` };
|
|
3742
|
-
console.log("[StepFlowBuilder] currentSegment memo - returning direct segment:", result);
|
|
3743
3721
|
return result;
|
|
3744
3722
|
}
|
|
3745
|
-
console.log("[StepFlowBuilder] currentSegment memo - no id in segmentObj, returning initialSegment");
|
|
3746
3723
|
return initialSegment;
|
|
3747
3724
|
}, [form?.values, initialSegment]);
|
|
3748
3725
|
const campaignContext = React.useMemo(() => {
|
|
@@ -3752,7 +3729,6 @@ const StepFlowBuilderInner = React.forwardRef(
|
|
|
3752
3729
|
triggerConfig: values.triggerConfig,
|
|
3753
3730
|
entrySegment: currentSegment
|
|
3754
3731
|
};
|
|
3755
|
-
console.log("[StepFlowBuilder] campaignContext:", ctx);
|
|
3756
3732
|
return ctx;
|
|
3757
3733
|
}, [form?.values, currentSegment]);
|
|
3758
3734
|
React.useEffect(() => {
|
|
@@ -41,15 +41,27 @@ const QueryProvider = ({ children }) => {
|
|
|
41
41
|
/* @__PURE__ */ jsxRuntime.jsx(reactQueryDevtools.ReactQueryDevtools, { initialIsOpen: false })
|
|
42
42
|
] });
|
|
43
43
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
return
|
|
44
|
+
let cachedUrl;
|
|
45
|
+
const getBackendUrl = async () => {
|
|
46
|
+
if (cachedUrl !== void 0) {
|
|
47
|
+
return cachedUrl;
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch("/api/crm-dashboard/config");
|
|
51
|
+
if (res.ok) {
|
|
52
|
+
const data = await res.json();
|
|
53
|
+
cachedUrl = data.apiUrl || "";
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
console.error("[CRM]: Failed to fetch config", e);
|
|
57
|
+
}
|
|
58
|
+
if (cachedUrl === void 0) {
|
|
59
|
+
cachedUrl = "";
|
|
60
|
+
}
|
|
61
|
+
return cachedUrl;
|
|
50
62
|
};
|
|
51
63
|
const fetchFilterOptions = async () => {
|
|
52
|
-
const backendUrl = getBackendUrl();
|
|
64
|
+
const backendUrl = await getBackendUrl();
|
|
53
65
|
const res = await fetch(new URL("/api/crm/filter-options", backendUrl).toString());
|
|
54
66
|
if (!res.ok) {
|
|
55
67
|
throw new Error("Failed to fetch filter options");
|
|
@@ -76,7 +88,7 @@ const fetchDashboardStats = async (filters) => {
|
|
|
76
88
|
if (filters.segments.length > 0) params.set("segmentIds", filters.segments.join(","));
|
|
77
89
|
if (filters.compareToPrevious) params.set("compareToPrevious", "true");
|
|
78
90
|
if (filters.granularity) params.set("granularity", filters.granularity);
|
|
79
|
-
const backendUrl = getBackendUrl();
|
|
91
|
+
const backendUrl = await getBackendUrl();
|
|
80
92
|
const res = await fetch(new URL(`/api/crm/dashboard/stats?${params}`, backendUrl).toString());
|
|
81
93
|
if (!res.ok) {
|
|
82
94
|
throw new Error("Failed to fetch dashboard stats");
|
|
@@ -103,7 +115,7 @@ const fetchCrmLogs = async (filters, page) => {
|
|
|
103
115
|
if (filters.scheduledTo) params.set("scheduledTo", filters.scheduledTo.toISOString());
|
|
104
116
|
if (filters.sentFrom) params.set("sentFrom", filters.sentFrom.toISOString());
|
|
105
117
|
if (filters.sentTo) params.set("sentTo", filters.sentTo.toISOString());
|
|
106
|
-
const backendUrl = getBackendUrl();
|
|
118
|
+
const backendUrl = await getBackendUrl();
|
|
107
119
|
const res = await fetch(new URL(`/api/crm/logs?${params}`, backendUrl).toString());
|
|
108
120
|
if (!res.ok) {
|
|
109
121
|
throw new Error("Failed to fetch CRM logs");
|
|
@@ -131,7 +143,7 @@ const fetchAntiSpamLogs = async (filters, page) => {
|
|
|
131
143
|
if (filters.campaigns.length > 0) params.set("campaignIds", filters.campaigns.join(","));
|
|
132
144
|
if (filters.dateFrom) params.set("from", filters.dateFrom.toISOString());
|
|
133
145
|
if (filters.dateTo) params.set("to", filters.dateTo.toISOString());
|
|
134
|
-
const backendUrl = getBackendUrl();
|
|
146
|
+
const backendUrl = await getBackendUrl();
|
|
135
147
|
const res = await fetch(new URL(`/api/crm/anti-spam-logs?${params}`, backendUrl).toString());
|
|
136
148
|
if (!res.ok) {
|
|
137
149
|
throw new Error("Failed to fetch anti-spam logs");
|
|
@@ -156,7 +168,7 @@ const fetchRealtimeStats = async (campaignIds) => {
|
|
|
156
168
|
if (campaignIds && campaignIds.length > 0) {
|
|
157
169
|
params.set("campaignIds", campaignIds.join(","));
|
|
158
170
|
}
|
|
159
|
-
const backendUrl = getBackendUrl();
|
|
171
|
+
const backendUrl = await getBackendUrl();
|
|
160
172
|
const url = params.toString() ? `${backendUrl}/api/crm/dashboard/realtime?${params}` : `${backendUrl}/api/crm/dashboard/realtime`;
|
|
161
173
|
const res = await fetch(url);
|
|
162
174
|
if (!res.ok) {
|
|
@@ -181,7 +193,7 @@ const fetchCohortData = async (filters) => {
|
|
|
181
193
|
if (filters.campaigns && filters.campaigns.length > 0) {
|
|
182
194
|
params.set("campaignIds", filters.campaigns.join(","));
|
|
183
195
|
}
|
|
184
|
-
const backendUrl = getBackendUrl();
|
|
196
|
+
const backendUrl = await getBackendUrl();
|
|
185
197
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/cohorts?${params}`);
|
|
186
198
|
if (!res.ok) {
|
|
187
199
|
throw new Error("Failed to fetch cohort data");
|
|
@@ -207,7 +219,7 @@ const fetchSegmentStats = async (filters) => {
|
|
|
207
219
|
if (filters.campaigns && filters.campaigns.length > 0) {
|
|
208
220
|
params.set("campaignIds", filters.campaigns.join(","));
|
|
209
221
|
}
|
|
210
|
-
const backendUrl = getBackendUrl();
|
|
222
|
+
const backendUrl = await getBackendUrl();
|
|
211
223
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/segments?${params}`);
|
|
212
224
|
if (!res.ok) {
|
|
213
225
|
throw new Error("Failed to fetch segment stats");
|
|
@@ -228,7 +240,7 @@ const fetchSendTimeData = async (filters) => {
|
|
|
228
240
|
if (filters.campaigns && filters.campaigns.length > 0) {
|
|
229
241
|
params.set("campaignIds", filters.campaigns.join(","));
|
|
230
242
|
}
|
|
231
|
-
const backendUrl = getBackendUrl();
|
|
243
|
+
const backendUrl = await getBackendUrl();
|
|
232
244
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/send-times?${params}`);
|
|
233
245
|
if (!res.ok) {
|
|
234
246
|
throw new Error("Failed to fetch send time data");
|
|
@@ -249,7 +261,7 @@ const fetchABTestData = async (filters) => {
|
|
|
249
261
|
if (filters.campaigns && filters.campaigns.length > 0) {
|
|
250
262
|
params.set("campaignIds", filters.campaigns.join(","));
|
|
251
263
|
}
|
|
252
|
-
const backendUrl = getBackendUrl();
|
|
264
|
+
const backendUrl = await getBackendUrl();
|
|
253
265
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/ab-tests?${params}`);
|
|
254
266
|
if (!res.ok) {
|
|
255
267
|
throw new Error("Failed to fetch A/B test data");
|
|
@@ -1921,7 +1921,6 @@ const EntryConfigInner = ({
|
|
|
1921
1921
|
entrySegment,
|
|
1922
1922
|
theme
|
|
1923
1923
|
}) => {
|
|
1924
|
-
console.log("[EntryConfig] Received entrySegment:", entrySegment);
|
|
1925
1924
|
const config = parseTriggerConfig(triggerConfig);
|
|
1926
1925
|
const renderTriggerInfo = () => {
|
|
1927
1926
|
if (!config) {
|
|
@@ -2053,9 +2052,6 @@ const EntryConfigInner = ({
|
|
|
2053
2052
|
const renderSegmentInfo = () => {
|
|
2054
2053
|
const hasSegment = entrySegment && (entrySegment.id || entrySegment.name);
|
|
2055
2054
|
const segmentDisplayName = entrySegment?.name || (entrySegment?.id ? `Segment #${entrySegment.id}` : null);
|
|
2056
|
-
console.log("[EntryConfig] renderSegmentInfo - entrySegment:", entrySegment);
|
|
2057
|
-
console.log("[EntryConfig] renderSegmentInfo - hasSegment:", hasSegment);
|
|
2058
|
-
console.log("[EntryConfig] renderSegmentInfo - segmentDisplayName:", segmentDisplayName);
|
|
2059
2055
|
if (!hasSegment || !segmentDisplayName) {
|
|
2060
2056
|
return /* @__PURE__ */ jsx(
|
|
2061
2057
|
"div",
|
|
@@ -3679,17 +3675,12 @@ const StepFlowBuilderInner = forwardRef(
|
|
|
3679
3675
|
});
|
|
3680
3676
|
const responseData = response?.data;
|
|
3681
3677
|
const campaignData = responseData?.data;
|
|
3682
|
-
console.log("[StepFlowBuilder] Fetch response campaignData:", campaignData);
|
|
3683
|
-
console.log("[StepFlowBuilder] entrySegment from API:", campaignData?.entrySegment);
|
|
3684
3678
|
if (campaignData?.entrySegment?.id) {
|
|
3685
3679
|
const seg = {
|
|
3686
3680
|
id: campaignData.entrySegment.id,
|
|
3687
3681
|
name: campaignData.entrySegment.name || `Segment #${campaignData.entrySegment.id}`
|
|
3688
3682
|
};
|
|
3689
|
-
console.log("[StepFlowBuilder] Setting initialSegment:", seg);
|
|
3690
3683
|
setInitialSegment(seg);
|
|
3691
|
-
} else {
|
|
3692
|
-
console.log("[StepFlowBuilder] No entrySegment.id found in API response");
|
|
3693
3684
|
}
|
|
3694
3685
|
} catch (err) {
|
|
3695
3686
|
console.error("[StepFlowBuilder] Fetch error:", err);
|
|
@@ -3702,42 +3693,28 @@ const StepFlowBuilderInner = forwardRef(
|
|
|
3702
3693
|
const currentSegment = useMemo(() => {
|
|
3703
3694
|
const values = form?.values;
|
|
3704
3695
|
const entrySegmentValue = values?.entrySegment;
|
|
3705
|
-
console.log("[StepFlowBuilder] currentSegment memo - form.values.entrySegment:", entrySegmentValue);
|
|
3706
|
-
console.log("[StepFlowBuilder] currentSegment memo - initialSegment:", initialSegment);
|
|
3707
|
-
console.log("[StepFlowBuilder] currentSegment memo - typeof entrySegmentValue:", typeof entrySegmentValue);
|
|
3708
|
-
if (entrySegmentValue) {
|
|
3709
|
-
console.log("[StepFlowBuilder] currentSegment memo - entrySegmentValue keys:", Object.keys(entrySegmentValue));
|
|
3710
|
-
}
|
|
3711
3696
|
if (!entrySegmentValue) {
|
|
3712
|
-
console.log("[StepFlowBuilder] currentSegment memo - no entrySegmentValue, returning initialSegment");
|
|
3713
3697
|
return initialSegment;
|
|
3714
3698
|
}
|
|
3715
3699
|
if ("connect" in entrySegmentValue || "disconnect" in entrySegmentValue) {
|
|
3716
|
-
console.log("[StepFlowBuilder] currentSegment memo - detected connect/disconnect structure");
|
|
3717
3700
|
const { connect = [], disconnect = [] } = entrySegmentValue;
|
|
3718
3701
|
if (connect.length > 0) {
|
|
3719
3702
|
const seg = connect[0];
|
|
3720
|
-
console.log("[StepFlowBuilder] currentSegment memo - returning from connect:", seg);
|
|
3721
3703
|
return { id: seg.id, name: seg.name || `Segment #${seg.id}` };
|
|
3722
3704
|
}
|
|
3723
3705
|
if (disconnect.length > 0 && initialSegment) {
|
|
3724
3706
|
const disconnectedId = disconnect[0]?.id;
|
|
3725
3707
|
if (disconnectedId === initialSegment.id) {
|
|
3726
|
-
console.log("[StepFlowBuilder] currentSegment memo - segment disconnected, returning null");
|
|
3727
3708
|
return null;
|
|
3728
3709
|
}
|
|
3729
3710
|
}
|
|
3730
|
-
console.log("[StepFlowBuilder] currentSegment memo - connect/disconnect but falling back to initialSegment");
|
|
3731
3711
|
return initialSegment;
|
|
3732
3712
|
}
|
|
3733
3713
|
const segmentObj = entrySegmentValue;
|
|
3734
|
-
console.log("[StepFlowBuilder] currentSegment memo - treating as direct segment object:", segmentObj);
|
|
3735
3714
|
if (segmentObj.id) {
|
|
3736
3715
|
const result = { id: segmentObj.id, name: segmentObj.name || `Segment #${segmentObj.id}` };
|
|
3737
|
-
console.log("[StepFlowBuilder] currentSegment memo - returning direct segment:", result);
|
|
3738
3716
|
return result;
|
|
3739
3717
|
}
|
|
3740
|
-
console.log("[StepFlowBuilder] currentSegment memo - no id in segmentObj, returning initialSegment");
|
|
3741
3718
|
return initialSegment;
|
|
3742
3719
|
}, [form?.values, initialSegment]);
|
|
3743
3720
|
const campaignContext = useMemo(() => {
|
|
@@ -3747,7 +3724,6 @@ const StepFlowBuilderInner = forwardRef(
|
|
|
3747
3724
|
triggerConfig: values.triggerConfig,
|
|
3748
3725
|
entrySegment: currentSegment
|
|
3749
3726
|
};
|
|
3750
|
-
console.log("[StepFlowBuilder] campaignContext:", ctx);
|
|
3751
3727
|
return ctx;
|
|
3752
3728
|
}, [form?.values, currentSegment]);
|
|
3753
3729
|
useEffect(() => {
|
|
@@ -37,15 +37,27 @@ const QueryProvider = ({ children }) => {
|
|
|
37
37
|
/* @__PURE__ */ jsx(ReactQueryDevtools, { initialIsOpen: false })
|
|
38
38
|
] });
|
|
39
39
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (
|
|
43
|
-
return
|
|
40
|
+
let cachedUrl;
|
|
41
|
+
const getBackendUrl = async () => {
|
|
42
|
+
if (cachedUrl !== void 0) {
|
|
43
|
+
return cachedUrl;
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
try {
|
|
46
|
+
const res = await fetch("/api/crm-dashboard/config");
|
|
47
|
+
if (res.ok) {
|
|
48
|
+
const data = await res.json();
|
|
49
|
+
cachedUrl = data.apiUrl || "";
|
|
50
|
+
}
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.error("[CRM]: Failed to fetch config", e);
|
|
53
|
+
}
|
|
54
|
+
if (cachedUrl === void 0) {
|
|
55
|
+
cachedUrl = "";
|
|
56
|
+
}
|
|
57
|
+
return cachedUrl;
|
|
46
58
|
};
|
|
47
59
|
const fetchFilterOptions = async () => {
|
|
48
|
-
const backendUrl = getBackendUrl();
|
|
60
|
+
const backendUrl = await getBackendUrl();
|
|
49
61
|
const res = await fetch(new URL("/api/crm/filter-options", backendUrl).toString());
|
|
50
62
|
if (!res.ok) {
|
|
51
63
|
throw new Error("Failed to fetch filter options");
|
|
@@ -72,7 +84,7 @@ const fetchDashboardStats = async (filters) => {
|
|
|
72
84
|
if (filters.segments.length > 0) params.set("segmentIds", filters.segments.join(","));
|
|
73
85
|
if (filters.compareToPrevious) params.set("compareToPrevious", "true");
|
|
74
86
|
if (filters.granularity) params.set("granularity", filters.granularity);
|
|
75
|
-
const backendUrl = getBackendUrl();
|
|
87
|
+
const backendUrl = await getBackendUrl();
|
|
76
88
|
const res = await fetch(new URL(`/api/crm/dashboard/stats?${params}`, backendUrl).toString());
|
|
77
89
|
if (!res.ok) {
|
|
78
90
|
throw new Error("Failed to fetch dashboard stats");
|
|
@@ -99,7 +111,7 @@ const fetchCrmLogs = async (filters, page) => {
|
|
|
99
111
|
if (filters.scheduledTo) params.set("scheduledTo", filters.scheduledTo.toISOString());
|
|
100
112
|
if (filters.sentFrom) params.set("sentFrom", filters.sentFrom.toISOString());
|
|
101
113
|
if (filters.sentTo) params.set("sentTo", filters.sentTo.toISOString());
|
|
102
|
-
const backendUrl = getBackendUrl();
|
|
114
|
+
const backendUrl = await getBackendUrl();
|
|
103
115
|
const res = await fetch(new URL(`/api/crm/logs?${params}`, backendUrl).toString());
|
|
104
116
|
if (!res.ok) {
|
|
105
117
|
throw new Error("Failed to fetch CRM logs");
|
|
@@ -127,7 +139,7 @@ const fetchAntiSpamLogs = async (filters, page) => {
|
|
|
127
139
|
if (filters.campaigns.length > 0) params.set("campaignIds", filters.campaigns.join(","));
|
|
128
140
|
if (filters.dateFrom) params.set("from", filters.dateFrom.toISOString());
|
|
129
141
|
if (filters.dateTo) params.set("to", filters.dateTo.toISOString());
|
|
130
|
-
const backendUrl = getBackendUrl();
|
|
142
|
+
const backendUrl = await getBackendUrl();
|
|
131
143
|
const res = await fetch(new URL(`/api/crm/anti-spam-logs?${params}`, backendUrl).toString());
|
|
132
144
|
if (!res.ok) {
|
|
133
145
|
throw new Error("Failed to fetch anti-spam logs");
|
|
@@ -152,7 +164,7 @@ const fetchRealtimeStats = async (campaignIds) => {
|
|
|
152
164
|
if (campaignIds && campaignIds.length > 0) {
|
|
153
165
|
params.set("campaignIds", campaignIds.join(","));
|
|
154
166
|
}
|
|
155
|
-
const backendUrl = getBackendUrl();
|
|
167
|
+
const backendUrl = await getBackendUrl();
|
|
156
168
|
const url = params.toString() ? `${backendUrl}/api/crm/dashboard/realtime?${params}` : `${backendUrl}/api/crm/dashboard/realtime`;
|
|
157
169
|
const res = await fetch(url);
|
|
158
170
|
if (!res.ok) {
|
|
@@ -177,7 +189,7 @@ const fetchCohortData = async (filters) => {
|
|
|
177
189
|
if (filters.campaigns && filters.campaigns.length > 0) {
|
|
178
190
|
params.set("campaignIds", filters.campaigns.join(","));
|
|
179
191
|
}
|
|
180
|
-
const backendUrl = getBackendUrl();
|
|
192
|
+
const backendUrl = await getBackendUrl();
|
|
181
193
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/cohorts?${params}`);
|
|
182
194
|
if (!res.ok) {
|
|
183
195
|
throw new Error("Failed to fetch cohort data");
|
|
@@ -203,7 +215,7 @@ const fetchSegmentStats = async (filters) => {
|
|
|
203
215
|
if (filters.campaigns && filters.campaigns.length > 0) {
|
|
204
216
|
params.set("campaignIds", filters.campaigns.join(","));
|
|
205
217
|
}
|
|
206
|
-
const backendUrl = getBackendUrl();
|
|
218
|
+
const backendUrl = await getBackendUrl();
|
|
207
219
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/segments?${params}`);
|
|
208
220
|
if (!res.ok) {
|
|
209
221
|
throw new Error("Failed to fetch segment stats");
|
|
@@ -224,7 +236,7 @@ const fetchSendTimeData = async (filters) => {
|
|
|
224
236
|
if (filters.campaigns && filters.campaigns.length > 0) {
|
|
225
237
|
params.set("campaignIds", filters.campaigns.join(","));
|
|
226
238
|
}
|
|
227
|
-
const backendUrl = getBackendUrl();
|
|
239
|
+
const backendUrl = await getBackendUrl();
|
|
228
240
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/send-times?${params}`);
|
|
229
241
|
if (!res.ok) {
|
|
230
242
|
throw new Error("Failed to fetch send time data");
|
|
@@ -245,7 +257,7 @@ const fetchABTestData = async (filters) => {
|
|
|
245
257
|
if (filters.campaigns && filters.campaigns.length > 0) {
|
|
246
258
|
params.set("campaignIds", filters.campaigns.join(","));
|
|
247
259
|
}
|
|
248
|
-
const backendUrl = getBackendUrl();
|
|
260
|
+
const backendUrl = await getBackendUrl();
|
|
249
261
|
const res = await fetch(`${backendUrl}/api/crm/dashboard/ab-tests?${params}`);
|
|
250
262
|
if (!res.ok) {
|
|
251
263
|
throw new Error("Failed to fetch A/B test data");
|
package/dist/admin/index.js
CHANGED
|
@@ -131,7 +131,7 @@ const index = {
|
|
|
131
131
|
components: {
|
|
132
132
|
Input: async () => Promise.resolve().then(() => require(
|
|
133
133
|
/* webpackChunkName: "crm-step-flow-builder" */
|
|
134
|
-
"../_chunks/index
|
|
134
|
+
"../_chunks/index--YXTcU9K.js"
|
|
135
135
|
))
|
|
136
136
|
},
|
|
137
137
|
options: {
|
|
@@ -149,7 +149,7 @@ const index = {
|
|
|
149
149
|
Component: async () => {
|
|
150
150
|
const component = await Promise.resolve().then(() => require(
|
|
151
151
|
/* webpackChunkName: "crm-dashboard-page" */
|
|
152
|
-
"../_chunks/index-
|
|
152
|
+
"../_chunks/index-CCjUeHQa.js"
|
|
153
153
|
));
|
|
154
154
|
return component;
|
|
155
155
|
},
|
package/dist/admin/index.mjs
CHANGED
|
@@ -130,7 +130,7 @@ const index = {
|
|
|
130
130
|
components: {
|
|
131
131
|
Input: async () => import(
|
|
132
132
|
/* webpackChunkName: "crm-step-flow-builder" */
|
|
133
|
-
"../_chunks/index-
|
|
133
|
+
"../_chunks/index-CLXsV-bm.mjs"
|
|
134
134
|
)
|
|
135
135
|
},
|
|
136
136
|
options: {
|
|
@@ -148,7 +148,7 @@ const index = {
|
|
|
148
148
|
Component: async () => {
|
|
149
149
|
const component = await import(
|
|
150
150
|
/* webpackChunkName: "crm-dashboard-page" */
|
|
151
|
-
"../_chunks/index-
|
|
151
|
+
"../_chunks/index-bOPRBiEo.mjs"
|
|
152
152
|
);
|
|
153
153
|
return component;
|
|
154
154
|
},
|
package/dist/server/index.js
CHANGED
|
@@ -40,6 +40,10 @@ const controller = ({ strapi }) => ({
|
|
|
40
40
|
async index(ctx) {
|
|
41
41
|
ctx.body = await strapi.plugin("crm-dashboard").service("service").getWelcomeMessage();
|
|
42
42
|
},
|
|
43
|
+
async getConfig(ctx) {
|
|
44
|
+
const apiUrl = strapi.config.get("server.apiUrl");
|
|
45
|
+
ctx.body = { apiUrl: apiUrl || "" };
|
|
46
|
+
},
|
|
43
47
|
async getLogs(ctx) {
|
|
44
48
|
ctx.body = await strapi.plugin("crm-dashboard").service("service").getLogs(ctx.query);
|
|
45
49
|
},
|
|
@@ -59,6 +63,14 @@ const routes = [
|
|
|
59
63
|
policies: []
|
|
60
64
|
}
|
|
61
65
|
},
|
|
66
|
+
{
|
|
67
|
+
method: "GET",
|
|
68
|
+
path: "/config",
|
|
69
|
+
handler: "controller.getConfig",
|
|
70
|
+
config: {
|
|
71
|
+
policies: []
|
|
72
|
+
}
|
|
73
|
+
},
|
|
62
74
|
{
|
|
63
75
|
method: "GET",
|
|
64
76
|
path: "/logs",
|
package/dist/server/index.mjs
CHANGED
|
@@ -39,6 +39,10 @@ const controller = ({ strapi }) => ({
|
|
|
39
39
|
async index(ctx) {
|
|
40
40
|
ctx.body = await strapi.plugin("crm-dashboard").service("service").getWelcomeMessage();
|
|
41
41
|
},
|
|
42
|
+
async getConfig(ctx) {
|
|
43
|
+
const apiUrl = strapi.config.get("server.apiUrl");
|
|
44
|
+
ctx.body = { apiUrl: apiUrl || "" };
|
|
45
|
+
},
|
|
42
46
|
async getLogs(ctx) {
|
|
43
47
|
ctx.body = await strapi.plugin("crm-dashboard").service("service").getLogs(ctx.query);
|
|
44
48
|
},
|
|
@@ -58,6 +62,14 @@ const routes = [
|
|
|
58
62
|
policies: []
|
|
59
63
|
}
|
|
60
64
|
},
|
|
65
|
+
{
|
|
66
|
+
method: "GET",
|
|
67
|
+
path: "/config",
|
|
68
|
+
handler: "controller.getConfig",
|
|
69
|
+
config: {
|
|
70
|
+
policies: []
|
|
71
|
+
}
|
|
72
|
+
},
|
|
61
73
|
{
|
|
62
74
|
method: "GET",
|
|
63
75
|
path: "/logs",
|
package/package.json
CHANGED
|
@@ -8,6 +8,11 @@ const controller = ({ strapi }: { strapi: Core.Strapi }) => ({
|
|
|
8
8
|
.getWelcomeMessage();
|
|
9
9
|
},
|
|
10
10
|
|
|
11
|
+
async getConfig(ctx: any) {
|
|
12
|
+
const apiUrl = strapi.config.get('server.apiUrl') as string;
|
|
13
|
+
ctx.body = { apiUrl: apiUrl || '' };
|
|
14
|
+
},
|
|
15
|
+
|
|
11
16
|
async getLogs(ctx: any) {
|
|
12
17
|
ctx.body = await strapi
|
|
13
18
|
.plugin('crm-dashboard')
|