@antelopejs/dms-marketing 0.4.0 → 0.5.0
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/dist/hooks/index.js +1 -5
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/pages/funnels/page.js +5 -5
- package/dist/pages/funnels/page.js.map +1 -1
- package/dist/routes/public-endpoints.d.ts +2 -0
- package/dist/routes/public-endpoints.js +14 -0
- package/dist/routes/public-endpoints.js.map +1 -0
- package/frontend-vue/app/components/Context.vue +37 -61
- package/frontend-vue/app/components/FunnelBuilder.vue +22 -19
- package/frontend-vue/app/components/FunnelReport.vue +1 -1
- package/frontend-vue/app/components/FunnelTemplates.vue +16 -27
- package/frontend-vue/app/components/InstallGuide.vue +40 -57
- package/frontend-vue/app/components/PagePreview.vue +60 -76
- package/frontend-vue/app/components/PagesExplorer.vue +86 -80
- package/frontend-vue/app/components/WebsitesGrid.vue +32 -23
- package/frontend-vue/app/composables/useMarketingApi.ts +7 -120
- package/frontend-vue/app/composables/useMarketingContext.ts +1 -10
- package/frontend-vue/app/composables/useMarketingNow.ts +29 -0
- package/frontend-vue/app/composables/useMarketingReads.ts +314 -0
- package/frontend-vue/app/utils/format.ts +37 -1
- package/frontend-vue/package.json +1 -2
- package/frontend-vue/pnpm-lock.yaml +51 -19
- package/frontend-vue/tests/format.test.ts +21 -0
- package/frontend-vue/tests/marketing-reads.test.ts +252 -0
- package/frontend-vue/tests/registration.test.ts +0 -4
- package/frontend-vue/vitest.config.ts +3 -1
- package/package.json +3 -3
package/dist/hooks/index.js
CHANGED
|
@@ -31,10 +31,7 @@ async function exportTenantMarketingData(tenantId) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
function registerMarketingHookListeners() {
|
|
34
|
-
(0, hooks_1.RegisterHook)(hooks_1.Hook.TENANT_DELETED,
|
|
35
|
-
await purgeTenantMarketingData(tenantId);
|
|
36
|
-
return undefined;
|
|
37
|
-
});
|
|
34
|
+
(0, hooks_1.RegisterHook)(hooks_1.Hook.TENANT_DELETED, purgeTenantMarketingData);
|
|
38
35
|
(0, hooks_1.RegisterHook)(hooks_1.Hook.TENANT_DATA_EXPORT, exportTenantMarketingData);
|
|
39
36
|
(0, hooks_1.RegisterHook)(hooks_1.Hook.USER_DELETED, forgetUserPreferences);
|
|
40
37
|
}
|
|
@@ -42,6 +39,5 @@ async function forgetUserPreferences(payload) {
|
|
|
42
39
|
for (const tenantId of payload.tenantIds) {
|
|
43
40
|
await (0, interface_database_decorators_1.GetModel)(db_1.MarketingPreferencesModel, tenantId).forget(payload.userId);
|
|
44
41
|
}
|
|
45
|
-
return undefined;
|
|
46
42
|
}
|
|
47
43
|
//# sourceMappingURL=index.js.map
|
package/dist/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":";;AA4DA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":";;AA4DA,wEAIC;AAhED,6FAAqE;AAKrE,2DAAqE;AACrE,6BAQc;AACd,iDAAwD;AAQxD,MAAM,aAAa,GAAkD;IACnE,yBAAoB;IACpB,2BAAsB;IACtB,uBAAkB;IAClB,2BAAsB;IACtB,iBAAY;IACZ,8BAAyB;CAC1B,CAAC;AAEF,KAAK,UAAU,wBAAwB,CAAC,QAAgB;IACtD,KAAK,MAAM,UAAU,IAAI,aAAa,EAAE,CAAC;QACvC,MAAM,IAAA,wCAAQ,EAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC;IAC5D,CAAC;IAGD,MAAM,IAAA,wCAAQ,EAAC,kBAAa,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED,KAAK,UAAU,yBAAyB,CACtC,QAAgB;IAEhB,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACxD,IAAA,wCAAQ,EAAC,kBAAa,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC;QAC7C,IAAA,wCAAQ,EAAC,iBAAY,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE;QACzC,IAAA,wCAAQ,EAAC,2BAAsB,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE;KACpD,CAAC,CAAC;IACH,OAAO;QACL,QAAQ,EAAE,+BAAmB;QAC7B,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE;KACxC,CAAC;AACJ,CAAC;AAOD,SAAgB,8BAA8B;IAC5C,IAAA,oBAAY,EAAC,YAAI,CAAC,cAAc,EAAE,wBAAwB,CAAC,CAAC;IAC5D,IAAA,oBAAY,EAAC,YAAI,CAAC,kBAAkB,EAAE,yBAAyB,CAAC,CAAC;IACjE,IAAA,oBAAY,EAAC,YAAI,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAC;AACzD,CAAC;AAGD,KAAK,UAAU,qBAAqB,CAClC,OAA+B;IAE/B,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACzC,MAAM,IAAA,wCAAQ,EAAC,8BAAyB,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,7 @@ const page_1 = require("@antelopejs/interface-dms/page");
|
|
|
52
52
|
const node_cron_1 = __importDefault(require("node-cron"));
|
|
53
53
|
const config_1 = require("./config");
|
|
54
54
|
const hooks_2 = require("./hooks");
|
|
55
|
+
const public_endpoints_1 = require("./routes/public-endpoints");
|
|
55
56
|
const services_1 = require("./services");
|
|
56
57
|
const constants_1 = require("./types/constants");
|
|
57
58
|
const HOURLY_CRON = "0 * * * *";
|
|
@@ -69,6 +70,7 @@ async function construct(config) {
|
|
|
69
70
|
sourcePath: node_path_1.default.join(__dirname, "../frontend-vue"),
|
|
70
71
|
renderer: { name: "vue", version: "3" },
|
|
71
72
|
priority: 0,
|
|
73
|
+
publicEndpoints: public_endpoints_1.TRACKER_PUBLIC_ENDPOINTS,
|
|
72
74
|
});
|
|
73
75
|
}
|
|
74
76
|
async function onDatabaseInitialized() {
|
|
@@ -83,7 +85,6 @@ async function onDatabaseInitialized() {
|
|
|
83
85
|
.then(() => (0, services_1.pruneAllTenants)(logPruneError))
|
|
84
86
|
.catch(logPruneError);
|
|
85
87
|
});
|
|
86
|
-
return undefined;
|
|
87
88
|
}
|
|
88
89
|
function logPruneError(err) {
|
|
89
90
|
logging_1.Logging.Error("[dms-marketing] retention prune failed:", err);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,8BAsBC;AAiCD,0BAAkC;AAElC,oBAWC;AAlGD,6BAA8C;AAC9C,sBAAoB;AACpB,oBAAkB;AAClB,mBAAiB;AAEjB,0DAA6B;AAC7B,+DAAgE;AAChE,gEAA6D;AAC7D,6FAAqE;AACrE,2DAAqE;AACrE,yDAAmE;AACnE,0DAAqD;AACrD,qCAA8D;AAC9D,mCAAyD;AACzD,gEAAqE;AACrE,yCAKoB;AACpB,iDAAwE;AAExE,MAAM,WAAW,GAAG,WAAW,CAAC;AAEhC,MAAM,kBAAkB,GAAG,EAAE,GAAG,yBAAa,CAAC;AAE9C,IAAI,SAAS,GAAyB,IAAI,CAAC;AAC3C,IAAI,cAAc,GAA0B,IAAI,CAAC;AAE1C,KAAK,UAAU,SAAS,CAC7B,MAAoC;IAEpC,IAAA,kBAAS,EAAC,MAAM,CAAC,CAAC;IAClB,MAAM,IAAA,4BAAiB,GAAE,CAAC;IAC1B,IAAA,sCAA8B,GAAE,CAAC;IACjC,IAAA,oBAAY,EAAC,YAAI,CAAC,oBAAoB,EAAE,qBAAqB,CAAC,CAAC;IAI/D,IAAA,mCAAkB,EAChB,wDAAa,qCAAqC,GAAC,EACnD,wDAAa,iCAAiC,GAAC,CAChD,CAAC;IAEF,MAAM,IAAA,wBAAiB,EAAC;QACtB,IAAI,EAAE,gCAAoB;QAC1B,UAAU,EAAE,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC;QACnD,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE;QACvC,QAAQ,EAAE,CAAC;QACX,eAAe,EAAE,2CAAwB;KAC1C,CAAC,CAAC;AACL,CAAC;AAQD,KAAK,UAAU,qBAAqB;IAClC,MAAM,QAAQ,GAAG,IAAA,wCAAQ,EAAC,2BAAsB,CAAC,CAAC;IAClD,MAAM,IAAA,uBAAY,EAAC,QAAQ,CAAC,CAAC;IAI7B,cAAc,KAAK,WAAW,CAAC,GAAG,EAAE;QAClC,KAAK,IAAA,yBAAc,EAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACtD,CAAC,EAAE,kBAAkB,CAAC,CAAC;IACvB,cAAc,CAAC,KAAK,EAAE,CAAC;IACvB,SAAS,KAAK,mBAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QAC5C,KAAK,IAAA,yBAAc,EAAC,QAAQ,CAAC;aAC1B,IAAI,CAAC,GAAG,EAAE,CAAC,IAAA,0BAAe,EAAC,aAAa,CAAC,CAAC;aAC1C,KAAK,CAAC,aAAa,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,aAAa,CAAC,GAAY;IACjC,iBAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,cAAc,CAAC,GAAY;IAClC,iBAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;AAChE,CAAC;AAED,SAAgB,OAAO,KAAU,CAAC;AAElC,SAAgB,IAAI;IAClB,IAAI,cAAc,EAAE,CAAC;QACnB,aAAa,CAAC,cAAc,CAAC,CAAC;QAC9B,cAAc,GAAG,IAAI,CAAC;IACxB,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QAGd,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;QACtB,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -130,7 +130,7 @@ const funnelsTable = table_view_1.TableView.fromSource({
|
|
|
130
130
|
icon: "i-ph-arrow-right",
|
|
131
131
|
target: {
|
|
132
132
|
type: "page",
|
|
133
|
-
url: `${constants_1.MARKETING_MODULE_PATH}/funnel?id={_id}&${blocks_1.CONTEXT_QUERY}`,
|
|
133
|
+
url: `${constants_1.MARKETING_MODULE_PATH}/funnel?id={{row._id}}&${blocks_1.CONTEXT_QUERY}`,
|
|
134
134
|
},
|
|
135
135
|
isDefault: true,
|
|
136
136
|
},
|
|
@@ -139,7 +139,7 @@ const funnelsTable = table_view_1.TableView.fromSource({
|
|
|
139
139
|
icon: "i-ph-pencil-simple",
|
|
140
140
|
target: {
|
|
141
141
|
type: "page",
|
|
142
|
-
url: `${BUILDER_URL}?id={_id}&${blocks_1.CONTEXT_QUERY}`,
|
|
142
|
+
url: `${BUILDER_URL}?id={{row._id}}&${blocks_1.CONTEXT_QUERY}`,
|
|
143
143
|
},
|
|
144
144
|
},
|
|
145
145
|
{
|
|
@@ -147,7 +147,7 @@ const funnelsTable = table_view_1.TableView.fromSource({
|
|
|
147
147
|
icon: "i-ph-copy",
|
|
148
148
|
target: {
|
|
149
149
|
type: "page",
|
|
150
|
-
url: `${BUILDER_URL}?copy={_id}&${blocks_1.CONTEXT_QUERY}`,
|
|
150
|
+
url: `${BUILDER_URL}?copy={{row._id}}&${blocks_1.CONTEXT_QUERY}`,
|
|
151
151
|
},
|
|
152
152
|
},
|
|
153
153
|
{
|
|
@@ -157,10 +157,10 @@ const funnelsTable = table_view_1.TableView.fromSource({
|
|
|
157
157
|
target: {
|
|
158
158
|
type: "api",
|
|
159
159
|
method: "DELETE",
|
|
160
|
-
url: `${FUNNELS_TABLE_API}/delete?id={_id}`,
|
|
160
|
+
url: `${FUNNELS_TABLE_API}/delete?id={{row._id}}`,
|
|
161
161
|
successMessage: "$page.marketing.funnel.delete.done",
|
|
162
162
|
},
|
|
163
|
-
confirm: { from: `${FUNNELS_API}/{id}/delete-confirmation` },
|
|
163
|
+
confirm: { from: `${FUNNELS_API}/{{row.id}}/delete-confirmation` },
|
|
164
164
|
},
|
|
165
165
|
],
|
|
166
166
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/pages/funnels/page.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/pages/funnels/page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TRACKER_PUBLIC_ENDPOINTS = void 0;
|
|
4
|
+
const constants_1 = require("@/types/constants");
|
|
5
|
+
const SCRIPT_METHODS = ["GET", "HEAD"];
|
|
6
|
+
const BEACON_METHODS = ["POST"];
|
|
7
|
+
exports.TRACKER_PUBLIC_ENDPOINTS = [
|
|
8
|
+
{ path: `${constants_1.API_BASE_PATH}/tracker.js`, methods: SCRIPT_METHODS },
|
|
9
|
+
{ path: `${constants_1.API_BASE_PATH}/experiments.js`, methods: SCRIPT_METHODS },
|
|
10
|
+
{ path: `${constants_1.API_BASE_PATH}/snapshot.js`, methods: SCRIPT_METHODS },
|
|
11
|
+
{ path: `${constants_1.API_BASE_PATH}/collect`, methods: BEACON_METHODS },
|
|
12
|
+
{ path: `${constants_1.API_BASE_PATH}/snapshot`, methods: BEACON_METHODS },
|
|
13
|
+
];
|
|
14
|
+
//# sourceMappingURL=public-endpoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-endpoints.js","sourceRoot":"","sources":["../../src/routes/public-endpoints.ts"],"names":[],"mappings":";;;AACA,iDAAkD;AAElD,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AACvC,MAAM,cAAc,GAAG,CAAC,MAAM,CAAC,CAAC;AAQnB,QAAA,wBAAwB,GAA6B;IAChE,EAAE,IAAI,EAAE,GAAG,yBAAa,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE;IAChE,EAAE,IAAI,EAAE,GAAG,yBAAa,iBAAiB,EAAE,OAAO,EAAE,cAAc,EAAE;IACpE,EAAE,IAAI,EAAE,GAAG,yBAAa,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE;IACjE,EAAE,IAAI,EAAE,GAAG,yBAAa,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE;IAC7D,EAAE,IAAI,EAAE,GAAG,yBAAa,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE;CAC/D,CAAC"}
|
|
@@ -4,11 +4,12 @@ import { useDmsRoute, useDmsRouter, useI18n } from '#dms/frontend-module'
|
|
|
4
4
|
import {
|
|
5
5
|
MARKETING_CONTEXT_KEY,
|
|
6
6
|
type ContextWebsite,
|
|
7
|
-
type MarketingContextPayload,
|
|
8
7
|
} from '../composables/useMarketingContext'
|
|
9
8
|
import { useMarketingApi } from '../composables/useMarketingApi'
|
|
9
|
+
import { useMarketingContextRead } from '../composables/useMarketingReads'
|
|
10
|
+
import { useMarketingNow } from '../composables/useMarketingNow'
|
|
10
11
|
import { installLink } from '../composables/useMarketingRoutes'
|
|
11
|
-
import { formatRelativeTime, initials } from '../utils/format'
|
|
12
|
+
import { formatRelativeTime, initials, utcDayStart } from '../utils/format'
|
|
12
13
|
import { MAX_PERIOD_DAYS, MS_PER_DAY, PERIOD_SCOPE } from '../constants'
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -30,7 +31,9 @@ import { MAX_PERIOD_DAYS, MS_PER_DAY, PERIOD_SCOPE } from '../constants'
|
|
|
30
31
|
* Its children render once the URL names one of the tenant's websites; with
|
|
31
32
|
* no website at all the first-run hero takes their place, and with
|
|
32
33
|
* `waitingGuide` a website still waiting for its first event shows the way
|
|
33
|
-
* to its install guide instead.
|
|
34
|
+
* to its install guide instead. A server render reads the context first: a
|
|
35
|
+
* URL naming no website (or one the tenant does not have) is redirected to
|
|
36
|
+
* the one saved, and the page renders on it.
|
|
34
37
|
*/
|
|
35
38
|
const props = withDefaults(
|
|
36
39
|
defineProps<{
|
|
@@ -88,11 +91,22 @@ const comparisonLabels = computed(() =>
|
|
|
88
91
|
),
|
|
89
92
|
)
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
+
// The minute's activity of every website: read on the bar's own clock.
|
|
95
|
+
const contextRead = useMarketingContextRead({
|
|
96
|
+
refreshInterval: LIVE_REFRESH_MS,
|
|
97
|
+
})
|
|
98
|
+
const context = contextRead.data
|
|
99
|
+
/**
|
|
100
|
+
* The context could not be read, and none is shown: a failed re-read (the
|
|
101
|
+
* minute's activity, a retry) keeps the bar as it is.
|
|
102
|
+
*/
|
|
103
|
+
const failed = computed(
|
|
104
|
+
() =>
|
|
105
|
+
!!contextRead.error.value &&
|
|
106
|
+
contextRead.status.value !== 'pending' &&
|
|
107
|
+
!context.value,
|
|
108
|
+
)
|
|
94
109
|
const switching = ref(false)
|
|
95
|
-
const refreshToken = ref(0)
|
|
96
110
|
|
|
97
111
|
const websites = computed(() => context.value?.websites ?? [])
|
|
98
112
|
/** The URL's website, while it is one of the tenant's. */
|
|
@@ -109,26 +123,8 @@ const selected = computed<ContextWebsite | null>(
|
|
|
109
123
|
() => websites.value.find((site) => site.id === selectedId.value) ?? null,
|
|
110
124
|
)
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
failed.value = false
|
|
115
|
-
try {
|
|
116
|
-
context.value = await api.getContext()
|
|
117
|
-
} catch {
|
|
118
|
-
failed.value = true
|
|
119
|
-
} finally {
|
|
120
|
-
loading.value = false
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** The websites' last events again, quietly: a failure keeps the bar as is. */
|
|
125
|
-
async function refreshActivity(): Promise<void> {
|
|
126
|
-
try {
|
|
127
|
-
context.value = await api.getContext()
|
|
128
|
-
} catch {
|
|
129
|
-
// The next refresh tries again.
|
|
130
|
-
}
|
|
131
|
-
}
|
|
126
|
+
/** The websites and their last events again; a failure keeps the bar as is. */
|
|
127
|
+
const reload = (): Promise<void> => contextRead.refresh()
|
|
132
128
|
|
|
133
129
|
async function select(id: string): Promise<void> {
|
|
134
130
|
if (id === selectedId.value) {
|
|
@@ -153,8 +149,10 @@ async function select(id: string): Promise<void> {
|
|
|
153
149
|
}
|
|
154
150
|
|
|
155
151
|
// The URL names no website, or one the tenant does not have: fill in the
|
|
156
|
-
// saved one, without a history entry
|
|
157
|
-
// rewriting the URL for its own state
|
|
152
|
+
// saved one, without a history entry (a server render redirects to it).
|
|
153
|
+
// Watched with the query too, so a block rewriting the URL for its own state
|
|
154
|
+
// (the heatmap path) keeps it. Set up once the context is read.
|
|
155
|
+
await contextRead
|
|
158
156
|
watch(
|
|
159
157
|
[selectedId, () => route.query],
|
|
160
158
|
([id]) => {
|
|
@@ -165,8 +163,6 @@ watch(
|
|
|
165
163
|
{ immediate: true },
|
|
166
164
|
)
|
|
167
165
|
|
|
168
|
-
watch(refreshToken, () => refreshPageBlocks())
|
|
169
|
-
|
|
170
166
|
// --- Period --------------------------------------------------------------------
|
|
171
167
|
|
|
172
168
|
const period = usePeriodScope(props.periodScope)
|
|
@@ -190,52 +186,40 @@ const cutHint = computed(() => {
|
|
|
190
186
|
provide(MARKETING_CONTEXT_KEY, {
|
|
191
187
|
websites,
|
|
192
188
|
selected,
|
|
193
|
-
refreshToken,
|
|
194
189
|
select,
|
|
195
190
|
reload,
|
|
196
191
|
})
|
|
197
192
|
|
|
198
|
-
onMounted(reload)
|
|
199
|
-
|
|
200
193
|
// --- Clock -------------------------------------------------------------------
|
|
201
194
|
// A period reaching today follows the clock: its blocks read again every
|
|
202
195
|
// minute, through the page's live gate. The selector itself moves a day
|
|
203
196
|
// preset on at midnight.
|
|
204
197
|
|
|
205
|
-
const now =
|
|
198
|
+
const now = useMarketingNow(CLOCK_TICK_MS)
|
|
206
199
|
|
|
207
200
|
/** The period covers the present: its counts are still moving. */
|
|
208
201
|
const reachesToday = computed(
|
|
209
202
|
() => !!range.value && range.value.to.getTime() >= now.value,
|
|
210
203
|
)
|
|
211
204
|
|
|
212
|
-
/** Refresh: every block reads again. */
|
|
205
|
+
/** Refresh: every block reads again, and the bar. */
|
|
213
206
|
function refresh(): void {
|
|
214
|
-
|
|
215
|
-
void
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function tick(): void {
|
|
219
|
-
now.value = Date.now()
|
|
207
|
+
refreshPageBlocks()
|
|
208
|
+
void reload()
|
|
220
209
|
}
|
|
221
210
|
|
|
211
|
+
/** A period reaching today: its blocks read again, through the live gate. */
|
|
222
212
|
function liveRefresh(): void {
|
|
223
213
|
if (reachesToday.value && linkedId.value) {
|
|
224
214
|
refreshLivePageBlocks()
|
|
225
215
|
}
|
|
226
|
-
void refreshActivity()
|
|
227
216
|
}
|
|
228
217
|
|
|
229
|
-
let clock: ReturnType<typeof setInterval> | null = null
|
|
230
218
|
let live: ReturnType<typeof setInterval> | null = null
|
|
231
219
|
onMounted(() => {
|
|
232
|
-
clock = setInterval(tick, CLOCK_TICK_MS)
|
|
233
220
|
live = setInterval(liveRefresh, LIVE_REFRESH_MS)
|
|
234
221
|
})
|
|
235
222
|
onBeforeUnmount(() => {
|
|
236
|
-
if (clock) {
|
|
237
|
-
clearInterval(clock)
|
|
238
|
-
}
|
|
239
223
|
if (live) {
|
|
240
224
|
clearInterval(live)
|
|
241
225
|
}
|
|
@@ -298,18 +282,10 @@ const websiteItems = computed(() => [
|
|
|
298
282
|
* UTC's, the bar says when their days really start.
|
|
299
283
|
*/
|
|
300
284
|
const utcHint = computed(() => {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
const utcMidnight = new Date(
|
|
306
|
-
Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()),
|
|
307
|
-
)
|
|
308
|
-
const time = new Intl.DateTimeFormat(locale.value, {
|
|
309
|
-
hour: '2-digit',
|
|
310
|
-
minute: '2-digit',
|
|
311
|
-
}).format(utcMidnight)
|
|
312
|
-
return t('page.marketing.context.utc_days', { time })
|
|
285
|
+
// The reader's zone: the browser's, which a server render reads from its
|
|
286
|
+
// cookie.
|
|
287
|
+
const time = utcDayStart(now.value, locale.value, readerTimeZone())
|
|
288
|
+
return time ? t('page.marketing.context.utc_days', { time }) : ''
|
|
313
289
|
})
|
|
314
290
|
</script>
|
|
315
291
|
|
|
@@ -320,7 +296,7 @@ const utcHint = computed(() => {
|
|
|
320
296
|
role="toolbar"
|
|
321
297
|
:aria-label="t('page.marketing.context.label')"
|
|
322
298
|
>
|
|
323
|
-
<USkeleton v-if="
|
|
299
|
+
<USkeleton v-if="!context && !failed" class="h-7 w-72" />
|
|
324
300
|
<template v-else-if="selected">
|
|
325
301
|
<UDropdownMenu :items="websiteItems" :content="{ align: 'start' }">
|
|
326
302
|
<UButton
|
|
@@ -11,6 +11,11 @@ import {
|
|
|
11
11
|
type MarketingFunnelStep,
|
|
12
12
|
type MarketingFunnelSuggestions,
|
|
13
13
|
} from '../composables/useMarketingApi'
|
|
14
|
+
import {
|
|
15
|
+
useContextOnDemand,
|
|
16
|
+
useFunnelRead,
|
|
17
|
+
useFunnelSuggestions,
|
|
18
|
+
} from '../composables/useMarketingReads'
|
|
14
19
|
import type { ContextWebsite } from '../composables/useMarketingContext'
|
|
15
20
|
import {
|
|
16
21
|
funnelBuilderLink,
|
|
@@ -199,9 +204,13 @@ function clearVariationError(): void {
|
|
|
199
204
|
|
|
200
205
|
// --- Loading -------------------------------------------------------------------
|
|
201
206
|
|
|
207
|
+
// The definition edited, or the one a Duplicate copies.
|
|
208
|
+
const readDefinition = useFunnelRead(funnelId || sourceId)
|
|
209
|
+
const readContext = useContextOnDemand()
|
|
210
|
+
|
|
202
211
|
/** A stored definition as the form holds it. */
|
|
203
|
-
async function fetchDefinition(
|
|
204
|
-
const row = await
|
|
212
|
+
async function fetchDefinition() {
|
|
213
|
+
const row = await readDefinition()
|
|
205
214
|
const experiment = parseExperimentValue(row.experiment)
|
|
206
215
|
const draft: FunnelDraftValues = {
|
|
207
216
|
name: row.name,
|
|
@@ -230,7 +239,7 @@ function objectiveOf(draft: FunnelDraftValues): string {
|
|
|
230
239
|
}
|
|
231
240
|
|
|
232
241
|
async function loadExisting(): Promise<void> {
|
|
233
|
-
const { draft, experiment } = await fetchDefinition(
|
|
242
|
+
const { draft, experiment } = await fetchDefinition()
|
|
234
243
|
applyValues(draft)
|
|
235
244
|
original.value = experiment
|
|
236
245
|
savedObjective.value = objectiveOf(draft)
|
|
@@ -242,7 +251,7 @@ const copied = ref<FunnelDraftValues | null>(null)
|
|
|
242
251
|
/** Duplicate: the copy is a new draft, unsaved until the user saves it — its
|
|
243
252
|
* experiment key must change, keys being unique per site. */
|
|
244
253
|
async function loadCopy(): Promise<void> {
|
|
245
|
-
const { draft } = await fetchDefinition(
|
|
254
|
+
const { draft } = await fetchDefinition()
|
|
246
255
|
applyValues({
|
|
247
256
|
...draft,
|
|
248
257
|
name: t('page.marketing.builder.copy_name', { name: draft.name }).slice(
|
|
@@ -260,7 +269,7 @@ async function loadCopy(): Promise<void> {
|
|
|
260
269
|
const websites = ref<ContextWebsite[]>([])
|
|
261
270
|
|
|
262
271
|
async function loadWebsites(): Promise<void> {
|
|
263
|
-
const payload = await
|
|
272
|
+
const payload = await readContext()
|
|
264
273
|
websites.value = payload.websites
|
|
265
274
|
const linked = queryParam('website')
|
|
266
275
|
websiteId.value ||=
|
|
@@ -301,21 +310,15 @@ onMounted(load)
|
|
|
301
310
|
|
|
302
311
|
// --- Suggestions and preview -------------------------------------------------
|
|
303
312
|
|
|
304
|
-
const
|
|
313
|
+
const NO_SUGGESTIONS: MarketingFunnelSuggestions = { pages: [], events: [] }
|
|
305
314
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
suggestions.value = { pages: [], events: [] }
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
// Fires once the site is known (the context, or the funnel being edited).
|
|
318
|
-
watch(websiteId, () => void loadSuggestions())
|
|
315
|
+
// Read once the site is known (the context, or the funnel being edited).
|
|
316
|
+
const suggestionsRead = useFunnelSuggestions(websiteId)
|
|
317
|
+
const suggestions = computed(() =>
|
|
318
|
+
suggestionsRead.error.value
|
|
319
|
+
? NO_SUGGESTIONS
|
|
320
|
+
: (suggestionsRead.data.value ?? NO_SUGGESTIONS),
|
|
321
|
+
)
|
|
319
322
|
|
|
320
323
|
const focusedStep = ref<number | null>(null)
|
|
321
324
|
/** The step whose list Escape closed, until it is typed in again. */
|
|
@@ -323,7 +323,7 @@ async function resume(): Promise<void> {
|
|
|
323
323
|
|
|
324
324
|
/** Worded by the server, as the funnels table's own Delete. */
|
|
325
325
|
const DELETE_CONFIRMATION_URL =
|
|
326
|
-
'/api/marketing/funnels/{id}/delete-confirmation'
|
|
326
|
+
'/api/marketing/funnels/{{row.id}}/delete-confirmation'
|
|
327
327
|
|
|
328
328
|
async function remove(): Promise<void> {
|
|
329
329
|
const shown = funnel.value
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed
|
|
2
|
+
import { computed } from 'vue'
|
|
3
3
|
import { useDmsRouter, useI18n } from '#dms/frontend-module'
|
|
4
4
|
import { useMarketingContext } from '../composables/useMarketingContext'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
type MarketingFunnelStep,
|
|
8
|
-
type MarketingFunnelTemplate,
|
|
9
|
-
} from '../composables/useMarketingApi'
|
|
5
|
+
import type { MarketingFunnelStep } from '../composables/useMarketingApi'
|
|
6
|
+
import { useFunnelTemplates } from '../composables/useMarketingReads'
|
|
10
7
|
import {
|
|
11
8
|
funnelBuilderLink,
|
|
12
9
|
installLink,
|
|
@@ -31,31 +28,23 @@ void props
|
|
|
31
28
|
const { t, locale } = useI18n()
|
|
32
29
|
const inContext = useContextLink()
|
|
33
30
|
const router = useDmsRouter()
|
|
34
|
-
const api = useMarketingApi()
|
|
35
31
|
const context = useMarketingContext()
|
|
36
32
|
const period = usePeriodScope(PERIOD_SCOPE)
|
|
37
33
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
[
|
|
42
|
-
() => context.selected.value?.id,
|
|
43
|
-
() => period.value?.range?.from.getTime(),
|
|
44
|
-
() => period.value?.range?.to.getTime(),
|
|
45
|
-
],
|
|
46
|
-
async ([website]) => {
|
|
47
|
-
if (!website) {
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
templates.value = null
|
|
51
|
-
try {
|
|
52
|
-
templates.value = await api.getFunnelTemplates(website, period.value)
|
|
53
|
-
} catch {
|
|
54
|
-
templates.value = []
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
{ immediate: true },
|
|
34
|
+
const templatesRead = useFunnelTemplates(
|
|
35
|
+
() => context.selected.value?.id,
|
|
36
|
+
period,
|
|
58
37
|
)
|
|
38
|
+
/**
|
|
39
|
+
* The site's templates; `null` while they load (the previous site's or
|
|
40
|
+
* period's included), none once the read failed.
|
|
41
|
+
*/
|
|
42
|
+
const templates = computed(() => {
|
|
43
|
+
if (templatesRead.error.value && templatesRead.status.value !== 'pending') {
|
|
44
|
+
return []
|
|
45
|
+
}
|
|
46
|
+
return templatesRead.placeholder.value ? null : templatesRead.data.value
|
|
47
|
+
})
|
|
59
48
|
|
|
60
49
|
/** The site has sent nothing yet: templates cannot come before the tracker. */
|
|
61
50
|
const waiting = computed(() => context.selected.value?.state === 'waiting')
|