@inspirer-dev/crm-dashboard 1.0.52 → 1.0.54
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 +20 -28
- 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--Qa1Bd7y.js → index--YXTcU9K.js} +5 -28
- package/dist/_chunks/{index-wE233MhG.js → index-BZKQTqh5.js} +26 -14
- package/dist/_chunks/{index-5WkcveGM.mjs → index-CLXsV-bm.mjs} +5 -28
- package/dist/_chunks/{index-DLPqbGjQ.mjs → index-DPVdz0kv.mjs} +26 -14
- package/dist/admin/index.js +2 -2
- package/dist/admin/index.mjs +2 -2
- package/dist/server/index.js +18 -44
- package/dist/server/index.mjs +18 -44
- package/package.json +1 -1
- package/server/src/controllers/controller.ts +5 -0
- package/server/src/controllers/index.ts +0 -2
- package/server/src/routes/index.ts +8 -0
- package/server/src/services/index.ts +0 -2
- package/server/src/controllers/proxy.ts +0 -22
- package/server/src/services/proxy.ts +0 -28
|
@@ -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,18 +53,16 @@ const StepFlowBuilderInner = forwardRef<HTMLDivElement, StepFlowBuilderProps>(
|
|
|
49
53
|
},
|
|
50
54
|
});
|
|
51
55
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
const responseData = response?.data as
|
|
57
|
+
| { data?: { entrySegment?: { id: number; name: string } } }
|
|
58
|
+
| undefined;
|
|
59
|
+
const campaignData = responseData?.data;
|
|
60
|
+
if (campaignData?.entrySegment?.id) {
|
|
56
61
|
const seg = {
|
|
57
|
-
id:
|
|
58
|
-
name:
|
|
62
|
+
id: campaignData.entrySegment.id,
|
|
63
|
+
name: campaignData.entrySegment.name || `Segment #${campaignData.entrySegment.id}`,
|
|
59
64
|
};
|
|
60
|
-
console.log('[StepFlowBuilder] Setting initialSegment:', seg);
|
|
61
65
|
setInitialSegment(seg);
|
|
62
|
-
} else {
|
|
63
|
-
console.log('[StepFlowBuilder] No entrySegment.id found in API response');
|
|
64
66
|
}
|
|
65
67
|
} catch (err) {
|
|
66
68
|
console.error('[StepFlowBuilder] Fetch error:', err);
|
|
@@ -76,51 +78,36 @@ const StepFlowBuilderInner = forwardRef<HTMLDivElement, StepFlowBuilderProps>(
|
|
|
76
78
|
const values = form?.values as Record<string, unknown> | undefined;
|
|
77
79
|
const entrySegmentValue = values?.entrySegment as ConnectDisconnect | SegmentItem | undefined;
|
|
78
80
|
|
|
79
|
-
console.log('[StepFlowBuilder] currentSegment memo - form.values.entrySegment:', entrySegmentValue);
|
|
80
|
-
console.log('[StepFlowBuilder] currentSegment memo - initialSegment:', initialSegment);
|
|
81
|
-
console.log('[StepFlowBuilder] currentSegment memo - typeof entrySegmentValue:', typeof entrySegmentValue);
|
|
82
|
-
if (entrySegmentValue) {
|
|
83
|
-
console.log('[StepFlowBuilder] currentSegment memo - entrySegmentValue keys:', Object.keys(entrySegmentValue));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
81
|
if (!entrySegmentValue) {
|
|
87
|
-
console.log('[StepFlowBuilder] currentSegment memo - no entrySegmentValue, returning initialSegment');
|
|
88
82
|
return initialSegment;
|
|
89
83
|
}
|
|
90
84
|
|
|
91
85
|
// Handle connect/disconnect structure (user changed the segment in UI)
|
|
92
86
|
if ('connect' in entrySegmentValue || 'disconnect' in entrySegmentValue) {
|
|
93
|
-
console.log('[StepFlowBuilder] currentSegment memo - detected connect/disconnect structure');
|
|
94
87
|
const { connect = [], disconnect = [] } = entrySegmentValue as ConnectDisconnect;
|
|
95
88
|
|
|
96
89
|
if (connect.length > 0) {
|
|
97
90
|
const seg = connect[0];
|
|
98
|
-
console.log('[StepFlowBuilder] currentSegment memo - returning from connect:', seg);
|
|
99
91
|
return { id: seg.id!, name: seg.name || `Segment #${seg.id}` };
|
|
100
92
|
}
|
|
101
93
|
|
|
102
94
|
if (disconnect.length > 0 && initialSegment) {
|
|
103
95
|
const disconnectedId = disconnect[0]?.id;
|
|
104
96
|
if (disconnectedId === initialSegment.id) {
|
|
105
|
-
console.log('[StepFlowBuilder] currentSegment memo - segment disconnected, returning null');
|
|
106
97
|
return null;
|
|
107
98
|
}
|
|
108
99
|
}
|
|
109
100
|
|
|
110
|
-
console.log('[StepFlowBuilder] currentSegment memo - connect/disconnect but falling back to initialSegment');
|
|
111
101
|
return initialSegment;
|
|
112
102
|
}
|
|
113
103
|
|
|
114
104
|
// Handle direct segment object (loaded from server)
|
|
115
105
|
const segmentObj = entrySegmentValue as SegmentItem;
|
|
116
|
-
console.log('[StepFlowBuilder] currentSegment memo - treating as direct segment object:', segmentObj);
|
|
117
106
|
if (segmentObj.id) {
|
|
118
107
|
const result = { id: segmentObj.id, name: segmentObj.name || `Segment #${segmentObj.id}` };
|
|
119
|
-
console.log('[StepFlowBuilder] currentSegment memo - returning direct segment:', result);
|
|
120
108
|
return result;
|
|
121
109
|
}
|
|
122
110
|
|
|
123
|
-
console.log('[StepFlowBuilder] currentSegment memo - no id in segmentObj, returning initialSegment');
|
|
124
111
|
return initialSegment;
|
|
125
112
|
}, [form?.values, initialSegment]);
|
|
126
113
|
|
|
@@ -132,7 +119,6 @@ const StepFlowBuilderInner = forwardRef<HTMLDivElement, StepFlowBuilderProps>(
|
|
|
132
119
|
triggerConfig: values.triggerConfig as CampaignContext['triggerConfig'],
|
|
133
120
|
entrySegment: currentSegment,
|
|
134
121
|
};
|
|
135
|
-
console.log('[StepFlowBuilder] campaignContext:', ctx);
|
|
136
122
|
return ctx;
|
|
137
123
|
}, [form?.values, currentSegment]);
|
|
138
124
|
|
|
@@ -203,12 +189,18 @@ const StepFlowBuilderInner = forwardRef<HTMLDivElement, StepFlowBuilderProps>(
|
|
|
203
189
|
<Field.Label>{displayLabel}</Field.Label>
|
|
204
190
|
{validation && !validation.isValid && (
|
|
205
191
|
<Badge backgroundColor="danger100" textColor="danger600">
|
|
206
|
-
{validation.errors.length}
|
|
192
|
+
{validation.errors.length}{' '}
|
|
193
|
+
{validation.errors.length === 1
|
|
194
|
+
? 'ошибка'
|
|
195
|
+
: validation.errors.length < 5
|
|
196
|
+
? 'ошибки'
|
|
197
|
+
: 'ошибок'}
|
|
207
198
|
</Badge>
|
|
208
199
|
)}
|
|
209
200
|
{validation && validation.isValid && validation.warnings.length > 0 && (
|
|
210
201
|
<Badge backgroundColor="warning100" textColor="warning600">
|
|
211
|
-
{validation.warnings.length}
|
|
202
|
+
{validation.warnings.length}{' '}
|
|
203
|
+
{validation.warnings.length === 1 ? 'предупр.' : 'предупр.'}
|
|
212
204
|
</Badge>
|
|
213
205
|
)}
|
|
214
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('/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",
|
|
@@ -3682,18 +3678,14 @@ const StepFlowBuilderInner = React.forwardRef(
|
|
|
3682
3678
|
"populate[entrySegment][fields][1]": "name"
|
|
3683
3679
|
}
|
|
3684
3680
|
});
|
|
3685
|
-
const
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
if (data?.entrySegment?.id) {
|
|
3681
|
+
const responseData = response?.data;
|
|
3682
|
+
const campaignData = responseData?.data;
|
|
3683
|
+
if (campaignData?.entrySegment?.id) {
|
|
3689
3684
|
const seg = {
|
|
3690
|
-
id:
|
|
3691
|
-
name:
|
|
3685
|
+
id: campaignData.entrySegment.id,
|
|
3686
|
+
name: campaignData.entrySegment.name || `Segment #${campaignData.entrySegment.id}`
|
|
3692
3687
|
};
|
|
3693
|
-
console.log("[StepFlowBuilder] Setting initialSegment:", seg);
|
|
3694
3688
|
setInitialSegment(seg);
|
|
3695
|
-
} else {
|
|
3696
|
-
console.log("[StepFlowBuilder] No entrySegment.id found in API response");
|
|
3697
3689
|
}
|
|
3698
3690
|
} catch (err) {
|
|
3699
3691
|
console.error("[StepFlowBuilder] Fetch error:", err);
|
|
@@ -3706,42 +3698,28 @@ const StepFlowBuilderInner = React.forwardRef(
|
|
|
3706
3698
|
const currentSegment = React.useMemo(() => {
|
|
3707
3699
|
const values = form?.values;
|
|
3708
3700
|
const entrySegmentValue = values?.entrySegment;
|
|
3709
|
-
console.log("[StepFlowBuilder] currentSegment memo - form.values.entrySegment:", entrySegmentValue);
|
|
3710
|
-
console.log("[StepFlowBuilder] currentSegment memo - initialSegment:", initialSegment);
|
|
3711
|
-
console.log("[StepFlowBuilder] currentSegment memo - typeof entrySegmentValue:", typeof entrySegmentValue);
|
|
3712
|
-
if (entrySegmentValue) {
|
|
3713
|
-
console.log("[StepFlowBuilder] currentSegment memo - entrySegmentValue keys:", Object.keys(entrySegmentValue));
|
|
3714
|
-
}
|
|
3715
3701
|
if (!entrySegmentValue) {
|
|
3716
|
-
console.log("[StepFlowBuilder] currentSegment memo - no entrySegmentValue, returning initialSegment");
|
|
3717
3702
|
return initialSegment;
|
|
3718
3703
|
}
|
|
3719
3704
|
if ("connect" in entrySegmentValue || "disconnect" in entrySegmentValue) {
|
|
3720
|
-
console.log("[StepFlowBuilder] currentSegment memo - detected connect/disconnect structure");
|
|
3721
3705
|
const { connect = [], disconnect = [] } = entrySegmentValue;
|
|
3722
3706
|
if (connect.length > 0) {
|
|
3723
3707
|
const seg = connect[0];
|
|
3724
|
-
console.log("[StepFlowBuilder] currentSegment memo - returning from connect:", seg);
|
|
3725
3708
|
return { id: seg.id, name: seg.name || `Segment #${seg.id}` };
|
|
3726
3709
|
}
|
|
3727
3710
|
if (disconnect.length > 0 && initialSegment) {
|
|
3728
3711
|
const disconnectedId = disconnect[0]?.id;
|
|
3729
3712
|
if (disconnectedId === initialSegment.id) {
|
|
3730
|
-
console.log("[StepFlowBuilder] currentSegment memo - segment disconnected, returning null");
|
|
3731
3713
|
return null;
|
|
3732
3714
|
}
|
|
3733
3715
|
}
|
|
3734
|
-
console.log("[StepFlowBuilder] currentSegment memo - connect/disconnect but falling back to initialSegment");
|
|
3735
3716
|
return initialSegment;
|
|
3736
3717
|
}
|
|
3737
3718
|
const segmentObj = entrySegmentValue;
|
|
3738
|
-
console.log("[StepFlowBuilder] currentSegment memo - treating as direct segment object:", segmentObj);
|
|
3739
3719
|
if (segmentObj.id) {
|
|
3740
3720
|
const result = { id: segmentObj.id, name: segmentObj.name || `Segment #${segmentObj.id}` };
|
|
3741
|
-
console.log("[StepFlowBuilder] currentSegment memo - returning direct segment:", result);
|
|
3742
3721
|
return result;
|
|
3743
3722
|
}
|
|
3744
|
-
console.log("[StepFlowBuilder] currentSegment memo - no id in segmentObj, returning initialSegment");
|
|
3745
3723
|
return initialSegment;
|
|
3746
3724
|
}, [form?.values, initialSegment]);
|
|
3747
3725
|
const campaignContext = React.useMemo(() => {
|
|
@@ -3751,7 +3729,6 @@ const StepFlowBuilderInner = React.forwardRef(
|
|
|
3751
3729
|
triggerConfig: values.triggerConfig,
|
|
3752
3730
|
entrySegment: currentSegment
|
|
3753
3731
|
};
|
|
3754
|
-
console.log("[StepFlowBuilder] campaignContext:", ctx);
|
|
3755
3732
|
return ctx;
|
|
3756
3733
|
}, [form?.values, currentSegment]);
|
|
3757
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("/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",
|
|
@@ -3677,18 +3673,14 @@ const StepFlowBuilderInner = forwardRef(
|
|
|
3677
3673
|
"populate[entrySegment][fields][1]": "name"
|
|
3678
3674
|
}
|
|
3679
3675
|
});
|
|
3680
|
-
const
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
if (data?.entrySegment?.id) {
|
|
3676
|
+
const responseData = response?.data;
|
|
3677
|
+
const campaignData = responseData?.data;
|
|
3678
|
+
if (campaignData?.entrySegment?.id) {
|
|
3684
3679
|
const seg = {
|
|
3685
|
-
id:
|
|
3686
|
-
name:
|
|
3680
|
+
id: campaignData.entrySegment.id,
|
|
3681
|
+
name: campaignData.entrySegment.name || `Segment #${campaignData.entrySegment.id}`
|
|
3687
3682
|
};
|
|
3688
|
-
console.log("[StepFlowBuilder] Setting initialSegment:", seg);
|
|
3689
3683
|
setInitialSegment(seg);
|
|
3690
|
-
} else {
|
|
3691
|
-
console.log("[StepFlowBuilder] No entrySegment.id found in API response");
|
|
3692
3684
|
}
|
|
3693
3685
|
} catch (err) {
|
|
3694
3686
|
console.error("[StepFlowBuilder] Fetch error:", err);
|
|
@@ -3701,42 +3693,28 @@ const StepFlowBuilderInner = forwardRef(
|
|
|
3701
3693
|
const currentSegment = useMemo(() => {
|
|
3702
3694
|
const values = form?.values;
|
|
3703
3695
|
const entrySegmentValue = values?.entrySegment;
|
|
3704
|
-
console.log("[StepFlowBuilder] currentSegment memo - form.values.entrySegment:", entrySegmentValue);
|
|
3705
|
-
console.log("[StepFlowBuilder] currentSegment memo - initialSegment:", initialSegment);
|
|
3706
|
-
console.log("[StepFlowBuilder] currentSegment memo - typeof entrySegmentValue:", typeof entrySegmentValue);
|
|
3707
|
-
if (entrySegmentValue) {
|
|
3708
|
-
console.log("[StepFlowBuilder] currentSegment memo - entrySegmentValue keys:", Object.keys(entrySegmentValue));
|
|
3709
|
-
}
|
|
3710
3696
|
if (!entrySegmentValue) {
|
|
3711
|
-
console.log("[StepFlowBuilder] currentSegment memo - no entrySegmentValue, returning initialSegment");
|
|
3712
3697
|
return initialSegment;
|
|
3713
3698
|
}
|
|
3714
3699
|
if ("connect" in entrySegmentValue || "disconnect" in entrySegmentValue) {
|
|
3715
|
-
console.log("[StepFlowBuilder] currentSegment memo - detected connect/disconnect structure");
|
|
3716
3700
|
const { connect = [], disconnect = [] } = entrySegmentValue;
|
|
3717
3701
|
if (connect.length > 0) {
|
|
3718
3702
|
const seg = connect[0];
|
|
3719
|
-
console.log("[StepFlowBuilder] currentSegment memo - returning from connect:", seg);
|
|
3720
3703
|
return { id: seg.id, name: seg.name || `Segment #${seg.id}` };
|
|
3721
3704
|
}
|
|
3722
3705
|
if (disconnect.length > 0 && initialSegment) {
|
|
3723
3706
|
const disconnectedId = disconnect[0]?.id;
|
|
3724
3707
|
if (disconnectedId === initialSegment.id) {
|
|
3725
|
-
console.log("[StepFlowBuilder] currentSegment memo - segment disconnected, returning null");
|
|
3726
3708
|
return null;
|
|
3727
3709
|
}
|
|
3728
3710
|
}
|
|
3729
|
-
console.log("[StepFlowBuilder] currentSegment memo - connect/disconnect but falling back to initialSegment");
|
|
3730
3711
|
return initialSegment;
|
|
3731
3712
|
}
|
|
3732
3713
|
const segmentObj = entrySegmentValue;
|
|
3733
|
-
console.log("[StepFlowBuilder] currentSegment memo - treating as direct segment object:", segmentObj);
|
|
3734
3714
|
if (segmentObj.id) {
|
|
3735
3715
|
const result = { id: segmentObj.id, name: segmentObj.name || `Segment #${segmentObj.id}` };
|
|
3736
|
-
console.log("[StepFlowBuilder] currentSegment memo - returning direct segment:", result);
|
|
3737
3716
|
return result;
|
|
3738
3717
|
}
|
|
3739
|
-
console.log("[StepFlowBuilder] currentSegment memo - no id in segmentObj, returning initialSegment");
|
|
3740
3718
|
return initialSegment;
|
|
3741
3719
|
}, [form?.values, initialSegment]);
|
|
3742
3720
|
const campaignContext = useMemo(() => {
|
|
@@ -3746,7 +3724,6 @@ const StepFlowBuilderInner = forwardRef(
|
|
|
3746
3724
|
triggerConfig: values.triggerConfig,
|
|
3747
3725
|
entrySegment: currentSegment
|
|
3748
3726
|
};
|
|
3749
|
-
console.log("[StepFlowBuilder] campaignContext:", ctx);
|
|
3750
3727
|
return ctx;
|
|
3751
3728
|
}, [form?.values, currentSegment]);
|
|
3752
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("/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-BZKQTqh5.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-DPVdz0kv.mjs"
|
|
152
152
|
);
|
|
153
153
|
return component;
|
|
154
154
|
},
|
package/dist/server/index.js
CHANGED
|
@@ -36,10 +36,14 @@ const config = {
|
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
const contentTypes = {};
|
|
39
|
-
const controller
|
|
39
|
+
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
|
},
|
|
@@ -47,21 +51,8 @@ const controller$1 = ({ strapi }) => ({
|
|
|
47
51
|
ctx.body = await strapi.plugin("crm-dashboard").service("service").getAntiSpamLogs(ctx.query);
|
|
48
52
|
}
|
|
49
53
|
});
|
|
50
|
-
const controller = ({ strapi }) => ({
|
|
51
|
-
async proxy(ctx) {
|
|
52
|
-
const { path } = ctx.params;
|
|
53
|
-
const method = ctx.method.toUpperCase();
|
|
54
|
-
const fullPath = path ? `/${path}` : "";
|
|
55
|
-
const result = await strapi.plugin("crm-dashboard").service("proxy").proxy(fullPath, method, ctx.query, ctx.request.body);
|
|
56
|
-
if (result?.error && result?.status) {
|
|
57
|
-
ctx.status = result.status;
|
|
58
|
-
}
|
|
59
|
-
ctx.body = result;
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
54
|
const controllers = {
|
|
63
|
-
controller
|
|
64
|
-
proxy: controller
|
|
55
|
+
controller
|
|
65
56
|
};
|
|
66
57
|
const routes = [
|
|
67
58
|
{
|
|
@@ -72,6 +63,14 @@ const routes = [
|
|
|
72
63
|
policies: []
|
|
73
64
|
}
|
|
74
65
|
},
|
|
66
|
+
{
|
|
67
|
+
method: "GET",
|
|
68
|
+
path: "/config",
|
|
69
|
+
handler: "controller.getConfig",
|
|
70
|
+
config: {
|
|
71
|
+
policies: []
|
|
72
|
+
}
|
|
73
|
+
},
|
|
75
74
|
{
|
|
76
75
|
method: "GET",
|
|
77
76
|
path: "/logs",
|
|
@@ -2462,11 +2461,11 @@ const {
|
|
|
2462
2461
|
getAdapter,
|
|
2463
2462
|
mergeConfig
|
|
2464
2463
|
} = axios;
|
|
2465
|
-
const API_URL
|
|
2464
|
+
const API_URL = process.env.API_URL || "http://localhost:3100";
|
|
2466
2465
|
const service = ({ strapi }) => ({
|
|
2467
2466
|
async getLogs(query) {
|
|
2468
2467
|
try {
|
|
2469
|
-
const { data } = await axios.get(`${API_URL
|
|
2468
|
+
const { data } = await axios.get(`${API_URL}/api/crm/logs`, { params: query });
|
|
2470
2469
|
return data;
|
|
2471
2470
|
} catch (err) {
|
|
2472
2471
|
strapi.log.error("Failed to fetch CRM logs from backend", err);
|
|
@@ -2475,7 +2474,7 @@ const service = ({ strapi }) => ({
|
|
|
2475
2474
|
},
|
|
2476
2475
|
async getAntiSpamLogs(query) {
|
|
2477
2476
|
try {
|
|
2478
|
-
const { data } = await axios.get(`${API_URL
|
|
2477
|
+
const { data } = await axios.get(`${API_URL}/api/crm/anti-spam-logs`, { params: query });
|
|
2479
2478
|
return data;
|
|
2480
2479
|
} catch (err) {
|
|
2481
2480
|
strapi.log.error("Failed to fetch Anti-spam logs from backend", err);
|
|
@@ -2483,33 +2482,8 @@ const service = ({ strapi }) => ({
|
|
|
2483
2482
|
}
|
|
2484
2483
|
}
|
|
2485
2484
|
});
|
|
2486
|
-
const API_URL = process.env.API_URL ?? "";
|
|
2487
|
-
const proxy = ({ strapi }) => ({
|
|
2488
|
-
async proxy(path, method, query, body) {
|
|
2489
|
-
try {
|
|
2490
|
-
const url = `${API_URL}/api/crm${path}`;
|
|
2491
|
-
const { data } = await axios({
|
|
2492
|
-
method,
|
|
2493
|
-
url,
|
|
2494
|
-
params: query,
|
|
2495
|
-
data: body,
|
|
2496
|
-
headers: body ? { "Content-Type": "application/json" } : void 0
|
|
2497
|
-
});
|
|
2498
|
-
return data;
|
|
2499
|
-
} catch (err) {
|
|
2500
|
-
strapi.log.error(`CRM proxy failed: ${method} /api/crm${path}`, err);
|
|
2501
|
-
const error = err;
|
|
2502
|
-
return {
|
|
2503
|
-
error: "CRM API request failed",
|
|
2504
|
-
status: error.response?.status,
|
|
2505
|
-
details: error.response?.data || error.message
|
|
2506
|
-
};
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
});
|
|
2510
2485
|
const services = {
|
|
2511
|
-
service
|
|
2512
|
-
proxy
|
|
2486
|
+
service
|
|
2513
2487
|
};
|
|
2514
2488
|
const index = {
|
|
2515
2489
|
register,
|
package/dist/server/index.mjs
CHANGED
|
@@ -35,10 +35,14 @@ const config = {
|
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
const contentTypes = {};
|
|
38
|
-
const controller
|
|
38
|
+
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
|
},
|
|
@@ -46,21 +50,8 @@ const controller$1 = ({ strapi }) => ({
|
|
|
46
50
|
ctx.body = await strapi.plugin("crm-dashboard").service("service").getAntiSpamLogs(ctx.query);
|
|
47
51
|
}
|
|
48
52
|
});
|
|
49
|
-
const controller = ({ strapi }) => ({
|
|
50
|
-
async proxy(ctx) {
|
|
51
|
-
const { path } = ctx.params;
|
|
52
|
-
const method = ctx.method.toUpperCase();
|
|
53
|
-
const fullPath = path ? `/${path}` : "";
|
|
54
|
-
const result = await strapi.plugin("crm-dashboard").service("proxy").proxy(fullPath, method, ctx.query, ctx.request.body);
|
|
55
|
-
if (result?.error && result?.status) {
|
|
56
|
-
ctx.status = result.status;
|
|
57
|
-
}
|
|
58
|
-
ctx.body = result;
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
53
|
const controllers = {
|
|
62
|
-
controller
|
|
63
|
-
proxy: controller
|
|
54
|
+
controller
|
|
64
55
|
};
|
|
65
56
|
const routes = [
|
|
66
57
|
{
|
|
@@ -71,6 +62,14 @@ const routes = [
|
|
|
71
62
|
policies: []
|
|
72
63
|
}
|
|
73
64
|
},
|
|
65
|
+
{
|
|
66
|
+
method: "GET",
|
|
67
|
+
path: "/config",
|
|
68
|
+
handler: "controller.getConfig",
|
|
69
|
+
config: {
|
|
70
|
+
policies: []
|
|
71
|
+
}
|
|
72
|
+
},
|
|
74
73
|
{
|
|
75
74
|
method: "GET",
|
|
76
75
|
path: "/logs",
|
|
@@ -2461,11 +2460,11 @@ const {
|
|
|
2461
2460
|
getAdapter,
|
|
2462
2461
|
mergeConfig
|
|
2463
2462
|
} = axios;
|
|
2464
|
-
const API_URL
|
|
2463
|
+
const API_URL = process.env.API_URL || "http://localhost:3100";
|
|
2465
2464
|
const service = ({ strapi }) => ({
|
|
2466
2465
|
async getLogs(query) {
|
|
2467
2466
|
try {
|
|
2468
|
-
const { data } = await axios.get(`${API_URL
|
|
2467
|
+
const { data } = await axios.get(`${API_URL}/api/crm/logs`, { params: query });
|
|
2469
2468
|
return data;
|
|
2470
2469
|
} catch (err) {
|
|
2471
2470
|
strapi.log.error("Failed to fetch CRM logs from backend", err);
|
|
@@ -2474,7 +2473,7 @@ const service = ({ strapi }) => ({
|
|
|
2474
2473
|
},
|
|
2475
2474
|
async getAntiSpamLogs(query) {
|
|
2476
2475
|
try {
|
|
2477
|
-
const { data } = await axios.get(`${API_URL
|
|
2476
|
+
const { data } = await axios.get(`${API_URL}/api/crm/anti-spam-logs`, { params: query });
|
|
2478
2477
|
return data;
|
|
2479
2478
|
} catch (err) {
|
|
2480
2479
|
strapi.log.error("Failed to fetch Anti-spam logs from backend", err);
|
|
@@ -2482,33 +2481,8 @@ const service = ({ strapi }) => ({
|
|
|
2482
2481
|
}
|
|
2483
2482
|
}
|
|
2484
2483
|
});
|
|
2485
|
-
const API_URL = process.env.API_URL ?? "";
|
|
2486
|
-
const proxy = ({ strapi }) => ({
|
|
2487
|
-
async proxy(path, method, query, body) {
|
|
2488
|
-
try {
|
|
2489
|
-
const url = `${API_URL}/api/crm${path}`;
|
|
2490
|
-
const { data } = await axios({
|
|
2491
|
-
method,
|
|
2492
|
-
url,
|
|
2493
|
-
params: query,
|
|
2494
|
-
data: body,
|
|
2495
|
-
headers: body ? { "Content-Type": "application/json" } : void 0
|
|
2496
|
-
});
|
|
2497
|
-
return data;
|
|
2498
|
-
} catch (err) {
|
|
2499
|
-
strapi.log.error(`CRM proxy failed: ${method} /api/crm${path}`, err);
|
|
2500
|
-
const error = err;
|
|
2501
|
-
return {
|
|
2502
|
-
error: "CRM API request failed",
|
|
2503
|
-
status: error.response?.status,
|
|
2504
|
-
details: error.response?.data || error.message
|
|
2505
|
-
};
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
});
|
|
2509
2484
|
const services = {
|
|
2510
|
-
service
|
|
2511
|
-
proxy
|
|
2485
|
+
service
|
|
2512
2486
|
};
|
|
2513
2487
|
const index = {
|
|
2514
2488
|
register,
|
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')
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { Core } from '@strapi/strapi';
|
|
2
|
-
|
|
3
|
-
const controller = ({ strapi }: { strapi: Core.Strapi }) => ({
|
|
4
|
-
async proxy(ctx: any) {
|
|
5
|
-
const { path } = ctx.params;
|
|
6
|
-
const method = ctx.method.toUpperCase();
|
|
7
|
-
const fullPath = path ? `/${path}` : '';
|
|
8
|
-
|
|
9
|
-
const result = await strapi
|
|
10
|
-
.plugin('crm-dashboard')
|
|
11
|
-
.service('proxy')
|
|
12
|
-
.proxy(fullPath, method, ctx.query, ctx.request.body);
|
|
13
|
-
|
|
14
|
-
if (result?.error && result?.status) {
|
|
15
|
-
ctx.status = result.status;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
ctx.body = result;
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
export default controller;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { Core } from '@strapi/strapi';
|
|
2
|
-
import axios, { Method } from 'axios';
|
|
3
|
-
|
|
4
|
-
const API_URL = process.env.API_URL ?? '';
|
|
5
|
-
|
|
6
|
-
export default ({ strapi }: { strapi: Core.Strapi }) => ({
|
|
7
|
-
async proxy(path: string, method: Method, query: Record<string, unknown>, body?: unknown) {
|
|
8
|
-
try {
|
|
9
|
-
const url = `${API_URL}/api/crm${path}`;
|
|
10
|
-
const { data } = await axios({
|
|
11
|
-
method,
|
|
12
|
-
url,
|
|
13
|
-
params: query,
|
|
14
|
-
data: body,
|
|
15
|
-
headers: body ? { 'Content-Type': 'application/json' } : undefined,
|
|
16
|
-
});
|
|
17
|
-
return data;
|
|
18
|
-
} catch (err) {
|
|
19
|
-
strapi.log.error(`CRM proxy failed: ${method} /api/crm${path}`, err);
|
|
20
|
-
const error = err as { response?: { status?: number; data?: unknown }; message?: string };
|
|
21
|
-
return {
|
|
22
|
-
error: 'CRM API request failed',
|
|
23
|
-
status: error.response?.status,
|
|
24
|
-
details: error.response?.data || error.message,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
});
|