@carlonicora/nextjs-jsonapi 5.2.0 → 5.4.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/{BlockNoteEditor-EGY4ZAAM.js → BlockNoteEditor-4YCAIEPT.js} +23 -22
- package/dist/BlockNoteEditor-4YCAIEPT.js.map +1 -0
- package/dist/{BlockNoteEditor-2QJVK2HH.mjs → BlockNoteEditor-YQL2SGFR.mjs} +8 -7
- package/dist/BlockNoteEditor-YQL2SGFR.mjs.map +1 -0
- package/dist/{BlockNoteViewer-6BQXJ4TB.mjs → BlockNoteViewer-AEJKJ27Q.mjs} +2 -2
- package/dist/{BlockNoteViewer-I2MMFH3S.js → BlockNoteViewer-YL3J7J2Y.js} +3 -3
- package/dist/{BlockNoteViewer-I2MMFH3S.js.map → BlockNoteViewer-YL3J7J2Y.js.map} +1 -1
- package/dist/BlogCategoryFields-DO48vOTE.d.mts +14 -0
- package/dist/BlogCategoryFields-DO48vOTE.d.ts +14 -0
- package/dist/BlogPostInterface-BB_4wcDR.d.mts +124 -0
- package/dist/BlogPostInterface-bWAT1rfR.d.ts +124 -0
- package/dist/billing/index.js +441 -441
- package/dist/billing/index.mjs +3 -3
- package/dist/blog-public.types-BbrzsC1c.d.mts +30 -0
- package/dist/blog-public.types-BbrzsC1c.d.ts +30 -0
- package/dist/{chunk-3VEQ5JZJ.js → chunk-3NLAXVIN.js} +860 -849
- package/dist/{chunk-3VEQ5JZJ.js.map → chunk-3NLAXVIN.js.map} +1 -1
- package/dist/{chunk-YMUPTXOT.mjs → chunk-3YW35YHQ.mjs} +1 -101
- package/dist/chunk-3YW35YHQ.mjs.map +1 -0
- package/dist/{chunk-EXICQC4A.js → chunk-5PPG6PL7.js} +3 -3
- package/dist/{chunk-EXICQC4A.js.map → chunk-5PPG6PL7.js.map} +1 -1
- package/dist/{chunk-NPKFMRH5.mjs → chunk-6DC2WVVB.mjs} +2 -2
- package/dist/{chunk-2Z3ZCYXX.mjs → chunk-EUKTBOI2.mjs} +19 -8
- package/dist/chunk-EUKTBOI2.mjs.map +1 -0
- package/dist/{chunk-THKYH65N.js → chunk-KSYQEKJX.js} +11 -111
- package/dist/chunk-KSYQEKJX.js.map +1 -0
- package/dist/{chunk-S5MQDWWC.js → chunk-NFBOSPNJ.js} +1451 -176
- package/dist/chunk-NFBOSPNJ.js.map +1 -0
- package/dist/{chunk-JEZQTZQ4.mjs → chunk-QMYQRPQC.mjs} +2 -2
- package/dist/{chunk-HNOWSFM5.mjs → chunk-WC63PJSC.mjs} +1278 -3
- package/dist/chunk-WC63PJSC.mjs.map +1 -0
- package/dist/chunk-XCHSX3VC.mjs +107 -0
- package/dist/chunk-XCHSX3VC.mjs.map +1 -0
- package/dist/{chunk-75MLT74B.js → chunk-YNCQSWQW.js} +8 -8
- package/dist/{chunk-75MLT74B.js.map → chunk-YNCQSWQW.js.map} +1 -1
- package/dist/chunk-YW4ZCEWB.js +107 -0
- package/dist/chunk-YW4ZCEWB.js.map +1 -0
- package/dist/client/index.d.mts +6 -39
- package/dist/client/index.d.ts +6 -39
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/components/index.d.mts +15 -4
- package/dist/components/index.d.ts +15 -4
- package/dist/components/index.js +4 -4
- package/dist/components/index.mjs +3 -3
- package/dist/contexts/index.js +4 -4
- package/dist/contexts/index.mjs +3 -3
- package/dist/core/index.d.mts +400 -3
- package/dist/core/index.d.ts +400 -3
- package/dist/core/index.js +64 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +63 -1
- package/dist/email-automation-enrollment.fields-BZvF14qx.d.mts +82 -0
- package/dist/email-automation-enrollment.fields-Cp3VMzFq.d.ts +82 -0
- package/dist/email-automations/index.css +30 -0
- package/dist/email-automations/index.css.map +1 -0
- package/dist/email-automations/index.d.mts +303 -0
- package/dist/email-automations/index.d.ts +303 -0
- package/dist/email-automations/index.js +1705 -0
- package/dist/email-automations/index.js.map +1 -0
- package/dist/email-automations/index.mjs +1705 -0
- package/dist/email-automations/index.mjs.map +1 -0
- package/dist/features/analytics/index.js +122 -122
- package/dist/features/analytics/index.mjs +4 -4
- package/dist/features/analytics/server.js +6 -5
- package/dist/features/analytics/server.js.map +1 -1
- package/dist/features/analytics/server.mjs +4 -3
- package/dist/features/analytics/server.mjs.map +1 -1
- package/dist/features/blog/index.css +30 -0
- package/dist/features/blog/index.css.map +1 -0
- package/dist/features/blog/index.d.mts +266 -0
- package/dist/features/blog/index.d.ts +266 -0
- package/dist/features/blog/index.js +1799 -0
- package/dist/features/blog/index.js.map +1 -0
- package/dist/features/blog/index.mjs +1799 -0
- package/dist/features/blog/index.mjs.map +1 -0
- package/dist/features/blog/server.d.mts +33 -0
- package/dist/features/blog/server.d.ts +33 -0
- package/dist/features/blog/server.js +139 -0
- package/dist/features/blog/server.js.map +1 -0
- package/dist/features/blog/server.mjs +139 -0
- package/dist/features/blog/server.mjs.map +1 -0
- package/dist/features/help/index.js +37 -37
- package/dist/features/help/index.mjs +3 -3
- package/dist/features/tokenusage/index.js +125 -125
- package/dist/features/tokenusage/index.mjs +4 -4
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +65 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -2
- package/dist/{s3.service-CY-jgOAM.d.ts → s3.service-Bz_K-tjz.d.ts} +11 -0
- package/dist/{s3.service-Sri0QP7Z.d.mts → s3.service-D5zNCEW3.d.mts} +11 -0
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +8 -6
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +12 -10
- package/dist/types-70acd-8C.d.mts +39 -0
- package/dist/types-l8SFleXi.d.ts +39 -0
- package/messages/en.json +210 -0
- package/messages/it.json +210 -0
- package/package.json +21 -1
- package/src/components/editors/BlockNoteEditor.tsx +13 -3
- package/src/components/forms/FormBlockNote.tsx +4 -0
- package/src/components/forms/FormFieldWrapper.tsx +1 -1
- package/src/components/forms/FormTextarea.tsx +2 -1
- package/src/components/navigations/ContentTitle.tsx +14 -3
- package/src/core/index.ts +12 -0
- package/src/core/registry/ModuleRegistry.ts +11 -0
- package/src/email-automations/index.ts +5 -0
- package/src/features/blog/BlogModules.ts +49 -0
- package/src/features/blog/components/admin/BlogAdminContainer.tsx +32 -0
- package/src/features/blog/components/admin/BlogCategoriesList.tsx +56 -0
- package/src/features/blog/components/admin/BlogCategoryEditor.tsx +230 -0
- package/src/features/blog/components/admin/BlogCoverImageField.tsx +123 -0
- package/src/features/blog/components/admin/BlogLayoutSetting.tsx +86 -0
- package/src/features/blog/components/admin/BlogPostComparison.tsx +54 -0
- package/src/features/blog/components/admin/BlogPostContainer.tsx +102 -0
- package/src/features/blog/components/admin/BlogPostDeleter.tsx +35 -0
- package/src/features/blog/components/admin/BlogPostEditor.tsx +207 -0
- package/src/features/blog/components/admin/BlogPostPublishButton.tsx +50 -0
- package/src/features/blog/components/admin/BlogPostTranslationEditor.tsx +110 -0
- package/src/features/blog/components/admin/BlogPostTranslationPanel.tsx +136 -0
- package/src/features/blog/components/admin/BlogPostsList.tsx +58 -0
- package/src/features/blog/components/admin/BlogTranslationStatus.tsx +104 -0
- package/src/features/blog/components/admin/__tests__/BlogPostTranslationPanel.spec.tsx +100 -0
- package/src/features/blog/components/admin/__tests__/BlogPostsList.spec.tsx +30 -0
- package/src/features/blog/components/admin/index.ts +14 -0
- package/src/features/blog/components/public/BlogCategoryChips.tsx +59 -0
- package/src/features/blog/components/public/BlogList.tsx +21 -0
- package/src/features/blog/components/public/BlogListColumn.tsx +53 -0
- package/src/features/blog/components/public/BlogListFeatured.tsx +57 -0
- package/src/features/blog/components/public/BlogListParts.tsx +74 -0
- package/src/features/blog/components/public/BlogListRail.tsx +62 -0
- package/src/features/blog/components/public/BlogPostCard.tsx +132 -0
- package/src/features/blog/components/public/BlogPostMeta.tsx +49 -0
- package/src/features/blog/components/public/BlogPostView.tsx +74 -0
- package/src/features/blog/components/public/BlogSearchBox.tsx +52 -0
- package/src/features/blog/components/public/__tests__/BlogList.spec.tsx +173 -0
- package/src/features/blog/components/public/__tests__/BlogPostView.spec.tsx +128 -0
- package/src/features/blog/components/public/blogPublicHelpers.ts +30 -0
- package/src/features/blog/components/public/index.ts +3 -0
- package/src/features/blog/contexts/BlogPostContext.tsx +66 -0
- package/src/features/blog/contexts/index.ts +1 -0
- package/src/features/blog/data/BlogCategory.ts +93 -0
- package/src/features/blog/data/BlogCategoryFields.ts +4 -0
- package/src/features/blog/data/BlogCategoryInterface.ts +24 -0
- package/src/features/blog/data/BlogCategoryService.ts +54 -0
- package/src/features/blog/data/BlogCategoryTranslation.ts +90 -0
- package/src/features/blog/data/BlogCategoryTranslationInterface.ts +22 -0
- package/src/features/blog/data/BlogCategoryTranslationService.ts +30 -0
- package/src/features/blog/data/BlogPost.spec.ts +123 -0
- package/src/features/blog/data/BlogPost.ts +159 -0
- package/src/features/blog/data/BlogPostFields.ts +7 -0
- package/src/features/blog/data/BlogPostInterface.ts +39 -0
- package/src/features/blog/data/BlogPostService.ts +82 -0
- package/src/features/blog/data/BlogPostTranslation.spec.ts +73 -0
- package/src/features/blog/data/BlogPostTranslation.ts +110 -0
- package/src/features/blog/data/BlogPostTranslationInterface.ts +27 -0
- package/src/features/blog/data/BlogPostTranslationService.ts +30 -0
- package/src/features/blog/data/BlogSettings.ts +37 -0
- package/src/features/blog/data/BlogSettingsInterface.ts +11 -0
- package/src/features/blog/data/BlogSettingsService.ts +24 -0
- package/src/features/blog/data/index.ts +17 -0
- package/src/features/blog/hooks/index.ts +3 -0
- package/src/features/blog/hooks/useBlogCategoryNames.ts +34 -0
- package/src/features/blog/hooks/useBlogCategoryTableStructure.tsx +84 -0
- package/src/features/blog/hooks/useBlogPostTableStructure.tsx +126 -0
- package/src/features/blog/index.ts +15 -0
- package/src/features/blog/server/fetchers.ts +120 -0
- package/src/features/blog/server/toPublic.spec.ts +91 -0
- package/src/features/blog/server/toPublic.ts +36 -0
- package/src/features/blog/server-entry.ts +17 -0
- package/src/features/blog/types/blog-public.types.ts +34 -0
- package/src/features/blog/types/blog.constants.ts +40 -0
- package/src/features/email-automation/EmailAutomationEnrollmentModule.ts +11 -0
- package/src/features/email-automation/EmailAutomationModule.ts +30 -0
- package/src/features/email-automation/EmailAutomationStepModule.ts +11 -0
- package/src/features/email-automation/EmailAutomationTriggerModule.ts +11 -0
- package/src/features/email-automation/components/__tests__/EmailAutomationEditor.spec.tsx +104 -0
- package/src/features/email-automation/components/canvas/EmailAutomationActiveSwitch.tsx +49 -0
- package/src/features/email-automation/components/canvas/EmailAutomationCanvas.tsx +474 -0
- package/src/features/email-automation/components/canvas/EmailAutomationCanvasInspector.tsx +89 -0
- package/src/features/email-automation/components/canvas/EmailAutomationCanvasTab.tsx +32 -0
- package/src/features/email-automation/components/canvas/__tests__/buildCanvasGraph.spec.ts +67 -0
- package/src/features/email-automation/components/canvas/buildCanvasGraph.ts +141 -0
- package/src/features/email-automation/components/canvas/edges/DelayEdge.tsx +68 -0
- package/src/features/email-automation/components/canvas/nodes/EmailStepNode.tsx +43 -0
- package/src/features/email-automation/components/canvas/nodes/TriggerNode.tsx +23 -0
- package/src/features/email-automation/components/canvas/shared/CanvasToolbar.tsx +53 -0
- package/src/features/email-automation/components/canvas/shared/EmptyCanvas.tsx +11 -0
- package/src/features/email-automation/components/canvas/shared/__tests__/autoLayout.spec.ts +42 -0
- package/src/features/email-automation/components/canvas/shared/__tests__/longPress.spec.ts +51 -0
- package/src/features/email-automation/components/canvas/shared/autoLayout.ts +55 -0
- package/src/features/email-automation/components/canvas/shared/index.ts +4 -0
- package/src/features/email-automation/components/canvas/shared/longPress.ts +57 -0
- package/src/features/email-automation/components/containers/EmailAutomationContainer.tsx +80 -0
- package/src/features/email-automation/components/containers/EmailAutomationsListContainer.tsx +27 -0
- package/src/features/email-automation/components/forms/EmailAutomationEditor.tsx +153 -0
- package/src/features/email-automation/components/forms/EmailStepEditor.tsx +151 -0
- package/src/features/email-automation/components/index.ts +15 -0
- package/src/features/email-automation/components/lists/EmailAutomationRecipientsList.tsx +90 -0
- package/src/features/email-automation/components/lists/EmailAutomationsList.tsx +76 -0
- package/src/features/email-automation/components/unsubscribe/EmailUnsubscribe.tsx +99 -0
- package/src/features/email-automation/components/unsubscribe/__tests__/EmailUnsubscribe.spec.tsx +55 -0
- package/src/features/email-automation/contexts/EmailAutomationContext.tsx +175 -0
- package/src/features/email-automation/data/EmailAutomation.ts +87 -0
- package/src/features/email-automation/data/EmailAutomationEnrollment.ts +105 -0
- package/src/features/email-automation/data/EmailAutomationEnrollmentInterface.ts +18 -0
- package/src/features/email-automation/data/EmailAutomationEnrollmentService.ts +31 -0
- package/src/features/email-automation/data/EmailAutomationInterface.ts +22 -0
- package/src/features/email-automation/data/EmailAutomationService.ts +106 -0
- package/src/features/email-automation/data/EmailAutomationStep.ts +104 -0
- package/src/features/email-automation/data/EmailAutomationStepInterface.ts +23 -0
- package/src/features/email-automation/data/EmailAutomationStepService.ts +80 -0
- package/src/features/email-automation/data/EmailAutomationTrigger.ts +28 -0
- package/src/features/email-automation/data/EmailAutomationTriggerInterface.ts +6 -0
- package/src/features/email-automation/data/__tests__/email-automation-models.spec.ts +103 -0
- package/src/features/email-automation/data/email-automation-enrollment.fields.ts +8 -0
- package/src/features/email-automation/data/email-automation.fields.ts +9 -0
- package/src/features/email-automation/data/index.ts +13 -0
- package/src/features/email-automation/hooks/index.ts +2 -0
- package/src/features/email-automation/hooks/useEmailAutomationEnrollmentTableStructure.tsx +126 -0
- package/src/features/email-automation/hooks/useEmailAutomationTableStructure.tsx +119 -0
- package/src/features/email-automation/index.ts +5 -0
- package/src/features/s3/data/s3.service.ts +17 -0
- package/dist/BlockNoteEditor-2QJVK2HH.mjs.map +0 -1
- package/dist/BlockNoteEditor-EGY4ZAAM.js.map +0 -1
- package/dist/chunk-2Z3ZCYXX.mjs.map +0 -1
- package/dist/chunk-HNOWSFM5.mjs.map +0 -1
- package/dist/chunk-S5MQDWWC.js.map +0 -1
- package/dist/chunk-THKYH65N.js.map +0 -1
- package/dist/chunk-YMUPTXOT.mjs.map +0 -1
- /package/dist/{BlockNoteViewer-6BQXJ4TB.mjs.map → BlockNoteViewer-AEJKJ27Q.mjs.map} +0 -0
- /package/dist/{chunk-NPKFMRH5.mjs.map → chunk-6DC2WVVB.mjs.map} +0 -0
- /package/dist/{chunk-JEZQTZQ4.mjs.map → chunk-QMYQRPQC.mjs.map} +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { AbstractService, EndpointCreator, HttpMethod, Modules, NextRef, PreviousRef } from "../../../core";
|
|
2
|
+
import { EmailAutomationEnrollmentInterface } from "./EmailAutomationEnrollmentInterface";
|
|
3
|
+
import { EmailAutomationInput, EmailAutomationInterface } from "./EmailAutomationInterface";
|
|
4
|
+
import { EmailAutomationTriggerInterface } from "./EmailAutomationTriggerInterface";
|
|
5
|
+
|
|
6
|
+
export class EmailAutomationService extends AbstractService {
|
|
7
|
+
static async findMany(params: { next?: NextRef; previous?: PreviousRef } = {}): Promise<EmailAutomationInterface[]> {
|
|
8
|
+
const endpoint = new EndpointCreator({ endpoint: Modules.EmailAutomation });
|
|
9
|
+
|
|
10
|
+
if (Modules.EmailAutomation.inclusions?.lists?.fields)
|
|
11
|
+
endpoint.limitToFields(Modules.EmailAutomation.inclusions.lists.fields);
|
|
12
|
+
if (Modules.EmailAutomation.inclusions?.lists?.types)
|
|
13
|
+
endpoint.limitToType(Modules.EmailAutomation.inclusions.lists.types);
|
|
14
|
+
|
|
15
|
+
return this.callApi<EmailAutomationInterface[]>({
|
|
16
|
+
type: Modules.EmailAutomation,
|
|
17
|
+
method: HttpMethod.GET,
|
|
18
|
+
endpoint: endpoint.generate(),
|
|
19
|
+
next: params.next,
|
|
20
|
+
previous: params.previous,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static async findOne(params: { id: string }): Promise<EmailAutomationInterface> {
|
|
25
|
+
return this.callApi<EmailAutomationInterface>({
|
|
26
|
+
type: Modules.EmailAutomation,
|
|
27
|
+
method: HttpMethod.GET,
|
|
28
|
+
endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation, id: params.id }).generate(),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static async create(params: EmailAutomationInput): Promise<EmailAutomationInterface> {
|
|
33
|
+
return this.callApi<EmailAutomationInterface>({
|
|
34
|
+
type: Modules.EmailAutomation,
|
|
35
|
+
method: HttpMethod.POST,
|
|
36
|
+
endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation }).generate(),
|
|
37
|
+
input: params,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static async update(params: EmailAutomationInput): Promise<EmailAutomationInterface> {
|
|
42
|
+
return this.callApi<EmailAutomationInterface>({
|
|
43
|
+
type: Modules.EmailAutomation,
|
|
44
|
+
method: HttpMethod.PATCH,
|
|
45
|
+
endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation, id: params.id }).generate(),
|
|
46
|
+
input: params,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static async delete(params: { id: string }): Promise<void> {
|
|
51
|
+
await this.callApi({
|
|
52
|
+
type: Modules.EmailAutomation,
|
|
53
|
+
method: HttpMethod.DELETE,
|
|
54
|
+
endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation, id: params.id }).generate(),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* GET email-automations/triggers: the triggers the app declared to the API.
|
|
60
|
+
*/
|
|
61
|
+
static async findTriggers(): Promise<EmailAutomationTriggerInterface[]> {
|
|
62
|
+
return this.callApi<EmailAutomationTriggerInterface[]>({
|
|
63
|
+
type: Modules.EmailAutomationTrigger,
|
|
64
|
+
method: HttpMethod.GET,
|
|
65
|
+
endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomation, id: "triggers" }).generate(),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* POST email-automations/:id/tidy: clears every manual step position. Replies 204.
|
|
71
|
+
*/
|
|
72
|
+
static async tidy(params: { id: string }): Promise<void> {
|
|
73
|
+
await this.callApi({
|
|
74
|
+
type: Modules.EmailAutomation,
|
|
75
|
+
method: HttpMethod.POST,
|
|
76
|
+
endpoint: new EndpointCreator({
|
|
77
|
+
endpoint: Modules.EmailAutomation,
|
|
78
|
+
id: params.id,
|
|
79
|
+
childEndpoint: "tidy",
|
|
80
|
+
}).generate(),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static async findEnrollments(params: {
|
|
85
|
+
automationId: string;
|
|
86
|
+
status?: string;
|
|
87
|
+
next?: NextRef;
|
|
88
|
+
previous?: PreviousRef;
|
|
89
|
+
}): Promise<EmailAutomationEnrollmentInterface[]> {
|
|
90
|
+
const endpoint = new EndpointCreator({
|
|
91
|
+
endpoint: Modules.EmailAutomation,
|
|
92
|
+
id: params.automationId,
|
|
93
|
+
childEndpoint: Modules.EmailAutomationEnrollment,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (params.status) endpoint.addAdditionalParam("status", params.status);
|
|
97
|
+
|
|
98
|
+
return this.callApi<EmailAutomationEnrollmentInterface[]>({
|
|
99
|
+
type: Modules.EmailAutomationEnrollment,
|
|
100
|
+
method: HttpMethod.GET,
|
|
101
|
+
endpoint: endpoint.generate(),
|
|
102
|
+
next: params.next,
|
|
103
|
+
previous: params.previous,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { AbstractApiData, JsonApiHydratedDataInterface, Modules } from "../../../core";
|
|
2
|
+
import { EmailAutomationInterface } from "./EmailAutomationInterface";
|
|
3
|
+
import { EmailAutomationStepInput, EmailAutomationStepInterface } from "./EmailAutomationStepInterface";
|
|
4
|
+
|
|
5
|
+
export class EmailAutomationStep extends AbstractApiData implements EmailAutomationStepInterface {
|
|
6
|
+
private _subject?: string;
|
|
7
|
+
private _body?: string;
|
|
8
|
+
private _delayHours?: number;
|
|
9
|
+
private _positionX?: number;
|
|
10
|
+
private _positionY?: number;
|
|
11
|
+
private _sentCount?: number;
|
|
12
|
+
private _automation?: EmailAutomationInterface;
|
|
13
|
+
private _next?: EmailAutomationStepInterface;
|
|
14
|
+
|
|
15
|
+
get subject(): string {
|
|
16
|
+
return this._subject ?? "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get body(): string {
|
|
20
|
+
return this._body ?? "";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get delayHours(): number {
|
|
24
|
+
return this._delayHours ?? 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get positionX(): number | undefined {
|
|
28
|
+
return this._positionX;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get positionY(): number | undefined {
|
|
32
|
+
return this._positionY;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get sentCount(): number {
|
|
36
|
+
return this._sentCount ?? 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get automation(): EmailAutomationInterface | undefined {
|
|
40
|
+
return this._automation;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get next(): EmailAutomationStepInterface | undefined {
|
|
44
|
+
return this._next;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
rehydrate(data: JsonApiHydratedDataInterface): this {
|
|
48
|
+
super.rehydrate(data);
|
|
49
|
+
|
|
50
|
+
this._subject = data.jsonApi.attributes.subject;
|
|
51
|
+
this._body = data.jsonApi.attributes.body;
|
|
52
|
+
this._delayHours = data.jsonApi.attributes.delayHours;
|
|
53
|
+
this._positionX = data.jsonApi.attributes.positionX ?? undefined;
|
|
54
|
+
this._positionY = data.jsonApi.attributes.positionY ?? undefined;
|
|
55
|
+
this._sentCount = data.jsonApi.attributes.sentCount;
|
|
56
|
+
|
|
57
|
+
this._automation = this._readIncluded(data, "automation", Modules.EmailAutomation) as EmailAutomationInterface;
|
|
58
|
+
this._next = this._readIncluded(data, "next", Modules.EmailAutomationStep) as EmailAutomationStepInterface;
|
|
59
|
+
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
createJsonApi(data: EmailAutomationStepInput) {
|
|
64
|
+
const response: any = {
|
|
65
|
+
data: {
|
|
66
|
+
type: Modules.EmailAutomationStep.name,
|
|
67
|
+
id: data.id,
|
|
68
|
+
attributes: {},
|
|
69
|
+
meta: {},
|
|
70
|
+
relationships: {},
|
|
71
|
+
},
|
|
72
|
+
included: [],
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if (data.subject !== undefined) response.data.attributes.subject = data.subject;
|
|
76
|
+
if (data.body !== undefined) response.data.attributes.body = data.body;
|
|
77
|
+
if (data.delayHours !== undefined) response.data.attributes.delayHours = data.delayHours;
|
|
78
|
+
if (data.positionX !== undefined) response.data.attributes.positionX = data.positionX;
|
|
79
|
+
if (data.positionY !== undefined) response.data.attributes.positionY = data.positionY;
|
|
80
|
+
|
|
81
|
+
if (data.automationId) {
|
|
82
|
+
response.data.relationships.automation = {
|
|
83
|
+
data: {
|
|
84
|
+
type: Modules.EmailAutomation.name,
|
|
85
|
+
id: data.automationId,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return response;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Body of POST email-automation-steps/:stepId/next: the step the chain continues to.
|
|
95
|
+
*/
|
|
96
|
+
createNextJsonApi(params: { nextStepId: string }) {
|
|
97
|
+
return {
|
|
98
|
+
data: {
|
|
99
|
+
type: Modules.EmailAutomationStep.name,
|
|
100
|
+
id: params.nextStepId,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ApiDataInterface } from "../../../core";
|
|
2
|
+
import { EmailAutomationInterface } from "./EmailAutomationInterface";
|
|
3
|
+
|
|
4
|
+
export type EmailAutomationStepInput = {
|
|
5
|
+
id: string;
|
|
6
|
+
automationId: string;
|
|
7
|
+
subject: string;
|
|
8
|
+
body: string;
|
|
9
|
+
delayHours?: number;
|
|
10
|
+
positionX?: number;
|
|
11
|
+
positionY?: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export interface EmailAutomationStepInterface extends ApiDataInterface {
|
|
15
|
+
get subject(): string;
|
|
16
|
+
get body(): string;
|
|
17
|
+
get delayHours(): number;
|
|
18
|
+
get positionX(): number | undefined;
|
|
19
|
+
get positionY(): number | undefined;
|
|
20
|
+
get sentCount(): number;
|
|
21
|
+
get automation(): EmailAutomationInterface | undefined;
|
|
22
|
+
get next(): EmailAutomationStepInterface | undefined;
|
|
23
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { AbstractService, EndpointCreator, HttpMethod, Modules } from "../../../core";
|
|
2
|
+
import { EmailAutomationStep } from "./EmailAutomationStep";
|
|
3
|
+
import { EmailAutomationStepInput, EmailAutomationStepInterface } from "./EmailAutomationStepInterface";
|
|
4
|
+
|
|
5
|
+
export class EmailAutomationStepService extends AbstractService {
|
|
6
|
+
static async findByAutomation(params: { automationId: string }): Promise<EmailAutomationStepInterface[]> {
|
|
7
|
+
const endpoint = new EndpointCreator({
|
|
8
|
+
endpoint: Modules.EmailAutomation,
|
|
9
|
+
id: params.automationId,
|
|
10
|
+
childEndpoint: Modules.EmailAutomationStep,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
endpoint.addAdditionalParam("fetchAll", "true");
|
|
14
|
+
|
|
15
|
+
return this.callApi<EmailAutomationStepInterface[]>({
|
|
16
|
+
type: Modules.EmailAutomationStep,
|
|
17
|
+
method: HttpMethod.GET,
|
|
18
|
+
endpoint: endpoint.generate(),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static async create(params: EmailAutomationStepInput): Promise<EmailAutomationStepInterface> {
|
|
23
|
+
return this.callApi<EmailAutomationStepInterface>({
|
|
24
|
+
type: Modules.EmailAutomationStep,
|
|
25
|
+
method: HttpMethod.POST,
|
|
26
|
+
endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomationStep }).generate(),
|
|
27
|
+
input: params,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static async update(params: EmailAutomationStepInput): Promise<EmailAutomationStepInterface> {
|
|
32
|
+
return this.callApi<EmailAutomationStepInterface>({
|
|
33
|
+
type: Modules.EmailAutomationStep,
|
|
34
|
+
method: HttpMethod.PATCH,
|
|
35
|
+
endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomationStep, id: params.id }).generate(),
|
|
36
|
+
input: params,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static async delete(params: { id: string }): Promise<void> {
|
|
41
|
+
await this.callApi({
|
|
42
|
+
type: Modules.EmailAutomationStep,
|
|
43
|
+
method: HttpMethod.DELETE,
|
|
44
|
+
endpoint: new EndpointCreator({ endpoint: Modules.EmailAutomationStep, id: params.id }).generate(),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* POST email-automation-steps/:stepId/next: continues the chain from stepId to nextStepId.
|
|
50
|
+
*/
|
|
51
|
+
static async setNext(params: { stepId: string; nextStepId: string }): Promise<EmailAutomationStepInterface> {
|
|
52
|
+
const step = new EmailAutomationStep();
|
|
53
|
+
return this.callApi<EmailAutomationStepInterface>({
|
|
54
|
+
type: Modules.EmailAutomationStep,
|
|
55
|
+
method: HttpMethod.POST,
|
|
56
|
+
endpoint: new EndpointCreator({
|
|
57
|
+
endpoint: Modules.EmailAutomationStep,
|
|
58
|
+
id: params.stepId,
|
|
59
|
+
childEndpoint: "next",
|
|
60
|
+
}).generate(),
|
|
61
|
+
input: step.createNextJsonApi({ nextStepId: params.nextStepId }),
|
|
62
|
+
overridesJsonApiCreation: true,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* DELETE email-automation-steps/:stepId/next: the step becomes the end of the chain.
|
|
68
|
+
*/
|
|
69
|
+
static async clearNext(params: { stepId: string }): Promise<void> {
|
|
70
|
+
await this.callApi({
|
|
71
|
+
type: Modules.EmailAutomationStep,
|
|
72
|
+
method: HttpMethod.DELETE,
|
|
73
|
+
endpoint: new EndpointCreator({
|
|
74
|
+
endpoint: Modules.EmailAutomationStep,
|
|
75
|
+
id: params.stepId,
|
|
76
|
+
childEndpoint: "next",
|
|
77
|
+
}).generate(),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AbstractApiData, JsonApiHydratedDataInterface } from "../../../core";
|
|
2
|
+
import { EmailAutomationTriggerInterface } from "./EmailAutomationTriggerInterface";
|
|
3
|
+
|
|
4
|
+
export class EmailAutomationTrigger extends AbstractApiData implements EmailAutomationTriggerInterface {
|
|
5
|
+
private _key?: string;
|
|
6
|
+
private _label?: string;
|
|
7
|
+
|
|
8
|
+
get key(): string {
|
|
9
|
+
return this._key ?? "";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get label(): string {
|
|
13
|
+
return this._label ?? "";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
rehydrate(data: JsonApiHydratedDataInterface): this {
|
|
17
|
+
super.rehydrate(data);
|
|
18
|
+
|
|
19
|
+
this._key = data.jsonApi.attributes.key;
|
|
20
|
+
this._label = data.jsonApi.attributes.label;
|
|
21
|
+
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
createJsonApi(_data?: any): any {
|
|
26
|
+
throw new Error("EmailAutomationTrigger is declared by the API and is read-only");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
2
|
+
import { ModuleRegistry } from "../../../../core/registry/ModuleRegistry";
|
|
3
|
+
import { ModuleFactory, ModuleWithPermissions } from "../../../../permissions/types";
|
|
4
|
+
import { EmailAutomationEnrollmentModule } from "../../EmailAutomationEnrollmentModule";
|
|
5
|
+
import { EmailAutomationModule } from "../../EmailAutomationModule";
|
|
6
|
+
import { EmailAutomationStepModule } from "../../EmailAutomationStepModule";
|
|
7
|
+
import { EmailAutomationTriggerModule } from "../../EmailAutomationTriggerModule";
|
|
8
|
+
import { EmailAutomation } from "../EmailAutomation";
|
|
9
|
+
import { EMAIL_AUTOMATION_UNSUBSCRIBE_TYPE, EmailAutomationEnrollment } from "../EmailAutomationEnrollment";
|
|
10
|
+
import { EmailAutomationStep } from "../EmailAutomationStep";
|
|
11
|
+
|
|
12
|
+
// createJsonApi reads Modules.X.name (resolved lazily via ModuleRegistry), so
|
|
13
|
+
// the modules must be registered before a model serialises — mirrors the
|
|
14
|
+
// tokenusage-admin-models.spec setup convention in this package.
|
|
15
|
+
const moduleFactory: ModuleFactory = (params) =>
|
|
16
|
+
({
|
|
17
|
+
pageUrl: params.pageUrl,
|
|
18
|
+
name: params.name,
|
|
19
|
+
model: params.model,
|
|
20
|
+
}) as ModuleWithPermissions;
|
|
21
|
+
|
|
22
|
+
beforeAll(() => {
|
|
23
|
+
ModuleRegistry.register("EmailAutomation", EmailAutomationModule(moduleFactory));
|
|
24
|
+
ModuleRegistry.register("EmailAutomationStep", EmailAutomationStepModule(moduleFactory));
|
|
25
|
+
ModuleRegistry.register("EmailAutomationEnrollment", EmailAutomationEnrollmentModule(moduleFactory));
|
|
26
|
+
ModuleRegistry.register("EmailAutomationTrigger", EmailAutomationTriggerModule(moduleFactory));
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const hydrate = (attributes: Record<string, unknown>) =>
|
|
30
|
+
({ jsonApi: { id: "x", type: "t", attributes }, included: [] }) as any;
|
|
31
|
+
|
|
32
|
+
describe("email automation models", () => {
|
|
33
|
+
it("parses the enrollment datetimes into Date, not the wire string", () => {
|
|
34
|
+
const m = new EmailAutomationEnrollment().rehydrate(
|
|
35
|
+
hydrate({
|
|
36
|
+
email: "ada@example.com",
|
|
37
|
+
status: "active",
|
|
38
|
+
enrolledAt: "2026-10-21T08:00:00.000Z",
|
|
39
|
+
nextSendAt: "2026-10-22T08:00:00.000Z",
|
|
40
|
+
attempts: 0,
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
expect(m.enrolledAt).toBeInstanceOf(Date);
|
|
44
|
+
expect(m.enrolledAt.toISOString()).toBe("2026-10-21T08:00:00.000Z");
|
|
45
|
+
expect(m.nextSendAt).toBeInstanceOf(Date);
|
|
46
|
+
expect(m.nextSendAt?.toISOString()).toBe("2026-10-22T08:00:00.000Z");
|
|
47
|
+
expect(m.finishedAt).toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("reads the enrollment computed fields from attributes", () => {
|
|
51
|
+
const m = new EmailAutomationEnrollment().rehydrate(
|
|
52
|
+
hydrate({
|
|
53
|
+
email: "ada@example.com",
|
|
54
|
+
status: "active",
|
|
55
|
+
enrolledAt: "2026-10-21T08:00:00.000Z",
|
|
56
|
+
currentStepSubject: "Welcome aboard",
|
|
57
|
+
sentCount: 2,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
expect(m.currentStepSubject).toBe("Welcome aboard");
|
|
61
|
+
expect(m.sentCount).toBe(2);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("omits undefined automation attributes and includes isActive when given", () => {
|
|
65
|
+
const body = new EmailAutomation().createJsonApi({ id: "a1", name: "Onboarding", isActive: true });
|
|
66
|
+
expect(body.data.type).toBe("email-automations");
|
|
67
|
+
expect(body.data.id).toBe("a1");
|
|
68
|
+
expect(body.data.attributes).toEqual({ name: "Onboarding", isActive: true });
|
|
69
|
+
expect("trigger" in body.data.attributes).toBe(false);
|
|
70
|
+
expect("exitTrigger" in body.data.attributes).toBe(false);
|
|
71
|
+
expect("replyTo" in body.data.attributes).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("includes isActive false when given", () => {
|
|
75
|
+
const body = new EmailAutomation().createJsonApi({ id: "a1", name: "Onboarding", isActive: false });
|
|
76
|
+
expect(body.data.attributes.isActive).toBe(false);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("writes the step's automation relationship", () => {
|
|
80
|
+
const body = new EmailAutomationStep().createJsonApi({
|
|
81
|
+
id: "s1",
|
|
82
|
+
automationId: "a1",
|
|
83
|
+
subject: "Hello",
|
|
84
|
+
body: "Hi {{name}}",
|
|
85
|
+
delayHours: 24,
|
|
86
|
+
});
|
|
87
|
+
expect(body.data.type).toBe("email-automation-steps");
|
|
88
|
+
expect(body.data.attributes).toEqual({ subject: "Hello", body: "Hi {{name}}", delayHours: 24 });
|
|
89
|
+
expect(body.data.relationships.automation).toEqual({ data: { type: "email-automations", id: "a1" } });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("builds the next-step body", () => {
|
|
93
|
+
expect(new EmailAutomationStep().createNextJsonApi({ nextStepId: "s2" })).toEqual({
|
|
94
|
+
data: { type: "email-automation-steps", id: "s2" },
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("builds the unsubscribe body", () => {
|
|
99
|
+
expect(new EmailAutomationEnrollment().createUnsubscribeJsonApi({ scope: "all" })).toEqual({
|
|
100
|
+
data: { type: EMAIL_AUTOMATION_UNSUBSCRIBE_TYPE, attributes: { scope: "all" } },
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./EmailAutomationInterface";
|
|
2
|
+
export * from "./EmailAutomation";
|
|
3
|
+
export * from "./EmailAutomationService";
|
|
4
|
+
export * from "./EmailAutomationStepInterface";
|
|
5
|
+
export * from "./EmailAutomationStep";
|
|
6
|
+
export * from "./EmailAutomationStepService";
|
|
7
|
+
export * from "./EmailAutomationEnrollmentInterface";
|
|
8
|
+
export * from "./EmailAutomationEnrollment";
|
|
9
|
+
export * from "./EmailAutomationEnrollmentService";
|
|
10
|
+
export * from "./EmailAutomationTriggerInterface";
|
|
11
|
+
export * from "./EmailAutomationTrigger";
|
|
12
|
+
export * from "./email-automation.fields";
|
|
13
|
+
export * from "./email-automation-enrollment.fields";
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ColumnDef } from "@tanstack/react-table";
|
|
4
|
+
import { useLocale, useTranslations } from "next-intl";
|
|
5
|
+
import { useMemo } from "react";
|
|
6
|
+
import { Badge } from "../../../shadcnui";
|
|
7
|
+
import { registerTableGenerator, TableContent, UseTableStructureHook } from "../../../hooks";
|
|
8
|
+
import { dateFormatLocale, formatDate } from "../../../utils/date-formatter";
|
|
9
|
+
import { EmailAutomationEnrollmentFields } from "../data/email-automation-enrollment.fields";
|
|
10
|
+
import { EmailAutomationEnrollmentInterface } from "../data/EmailAutomationEnrollmentInterface";
|
|
11
|
+
|
|
12
|
+
const STATUS_VARIANTS: Record<string, "softGreen" | "softBlue" | "softGray" | "softRed"> = {
|
|
13
|
+
active: "softGreen",
|
|
14
|
+
completed: "softBlue",
|
|
15
|
+
unsubscribed: "softGray",
|
|
16
|
+
exited: "softGray",
|
|
17
|
+
failed: "softRed",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const useEmailAutomationEnrollmentTableStructure: UseTableStructureHook<
|
|
21
|
+
EmailAutomationEnrollmentInterface,
|
|
22
|
+
EmailAutomationEnrollmentFields
|
|
23
|
+
> = (params) => {
|
|
24
|
+
const t = useTranslations();
|
|
25
|
+
const locale = dateFormatLocale(useLocale());
|
|
26
|
+
|
|
27
|
+
const tableData = useMemo(() => {
|
|
28
|
+
return params.data.map((enrollment: EmailAutomationEnrollmentInterface) => {
|
|
29
|
+
const entry: TableContent<EmailAutomationEnrollmentInterface> = { jsonApiData: enrollment };
|
|
30
|
+
params.fields.forEach((field) => {
|
|
31
|
+
entry[field] = (enrollment as any)[field as keyof EmailAutomationEnrollmentInterface];
|
|
32
|
+
});
|
|
33
|
+
return entry;
|
|
34
|
+
});
|
|
35
|
+
}, [params.data, params.fields]);
|
|
36
|
+
|
|
37
|
+
const empty = <span className="text-muted-foreground text-xs">—</span>;
|
|
38
|
+
|
|
39
|
+
const fieldColumnMap: Partial<Record<EmailAutomationEnrollmentFields, () => any>> = {
|
|
40
|
+
[EmailAutomationEnrollmentFields.email]: () => ({
|
|
41
|
+
id: "email",
|
|
42
|
+
accessorKey: "email",
|
|
43
|
+
header: t("emailAutomations.recipients.columns.email"),
|
|
44
|
+
cell: ({ row }: { row: TableContent<EmailAutomationEnrollmentInterface> }) => {
|
|
45
|
+
const enrollment: EmailAutomationEnrollmentInterface = row.original.jsonApiData;
|
|
46
|
+
return <span className="text-sm">{enrollment.email}</span>;
|
|
47
|
+
},
|
|
48
|
+
enableSorting: false,
|
|
49
|
+
enableHiding: false,
|
|
50
|
+
}),
|
|
51
|
+
[EmailAutomationEnrollmentFields.name]: () => ({
|
|
52
|
+
id: "name",
|
|
53
|
+
accessorKey: "name",
|
|
54
|
+
header: t("emailAutomations.recipients.columns.name"),
|
|
55
|
+
cell: ({ row }: { row: TableContent<EmailAutomationEnrollmentInterface> }) => {
|
|
56
|
+
const enrollment: EmailAutomationEnrollmentInterface = row.original.jsonApiData;
|
|
57
|
+
return enrollment.name ? <span className="text-sm">{enrollment.name}</span> : empty;
|
|
58
|
+
},
|
|
59
|
+
enableSorting: false,
|
|
60
|
+
enableHiding: false,
|
|
61
|
+
}),
|
|
62
|
+
[EmailAutomationEnrollmentFields.status]: () => ({
|
|
63
|
+
id: "status",
|
|
64
|
+
accessorKey: "status",
|
|
65
|
+
header: t("emailAutomations.recipients.columns.status"),
|
|
66
|
+
cell: ({ row }: { row: TableContent<EmailAutomationEnrollmentInterface> }) => {
|
|
67
|
+
const enrollment: EmailAutomationEnrollmentInterface = row.original.jsonApiData;
|
|
68
|
+
return (
|
|
69
|
+
<Badge
|
|
70
|
+
variant={STATUS_VARIANTS[enrollment.status] ?? "softGray"}
|
|
71
|
+
title={enrollment.status === "failed" ? enrollment.lastError : undefined}
|
|
72
|
+
>
|
|
73
|
+
{t(`emailAutomations.recipients.status.${enrollment.status}`)}
|
|
74
|
+
</Badge>
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
enableSorting: false,
|
|
78
|
+
enableHiding: false,
|
|
79
|
+
}),
|
|
80
|
+
[EmailAutomationEnrollmentFields.currentStep]: () => ({
|
|
81
|
+
id: "currentStep",
|
|
82
|
+
accessorKey: "currentStep",
|
|
83
|
+
header: t("emailAutomations.recipients.columns.currentStep"),
|
|
84
|
+
cell: ({ row }: { row: TableContent<EmailAutomationEnrollmentInterface> }) => {
|
|
85
|
+
const enrollment: EmailAutomationEnrollmentInterface = row.original.jsonApiData;
|
|
86
|
+
return enrollment.currentStepSubject ? <span className="text-sm">{enrollment.currentStepSubject}</span> : empty;
|
|
87
|
+
},
|
|
88
|
+
enableSorting: false,
|
|
89
|
+
enableHiding: false,
|
|
90
|
+
}),
|
|
91
|
+
[EmailAutomationEnrollmentFields.nextSendAt]: () => ({
|
|
92
|
+
id: "nextSendAt",
|
|
93
|
+
accessorKey: "nextSendAt",
|
|
94
|
+
header: t("emailAutomations.recipients.columns.nextSendAt"),
|
|
95
|
+
cell: ({ row }: { row: TableContent<EmailAutomationEnrollmentInterface> }) => {
|
|
96
|
+
const enrollment: EmailAutomationEnrollmentInterface = row.original.jsonApiData;
|
|
97
|
+
if (!enrollment.nextSendAt) return empty;
|
|
98
|
+
return <span className="text-xs tabular-nums">{formatDate(enrollment.nextSendAt, "dateTime", locale)}</span>;
|
|
99
|
+
},
|
|
100
|
+
enableSorting: false,
|
|
101
|
+
enableHiding: false,
|
|
102
|
+
}),
|
|
103
|
+
[EmailAutomationEnrollmentFields.sentCount]: () => ({
|
|
104
|
+
id: "sentCount",
|
|
105
|
+
accessorKey: "sentCount",
|
|
106
|
+
header: t("emailAutomations.recipients.columns.sentCount"),
|
|
107
|
+
cell: ({ row }: { row: TableContent<EmailAutomationEnrollmentInterface> }) => {
|
|
108
|
+
const enrollment: EmailAutomationEnrollmentInterface = row.original.jsonApiData;
|
|
109
|
+
// Typography role 15 (numeric): tabular-nums, end-aligned.
|
|
110
|
+
return <span className="block text-xs tabular-nums text-end">{enrollment.sentCount ?? 0}</span>;
|
|
111
|
+
},
|
|
112
|
+
enableSorting: false,
|
|
113
|
+
enableHiding: false,
|
|
114
|
+
}),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const columns = useMemo(() => {
|
|
118
|
+
return params.fields.map((field) => fieldColumnMap[field]?.()).filter((col) => col !== undefined) as ColumnDef<
|
|
119
|
+
TableContent<EmailAutomationEnrollmentInterface>
|
|
120
|
+
>[];
|
|
121
|
+
}, [params.fields, fieldColumnMap, t, locale]);
|
|
122
|
+
|
|
123
|
+
return useMemo(() => ({ data: tableData, columns: columns }), [tableData, columns]);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
registerTableGenerator("email-automation-enrollments", useEmailAutomationEnrollmentTableStructure);
|