@endora-commerce/mod-transactional-emails 0.100.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/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/admin/api/transactional-emails-client.d.ts +43 -0
- package/dist/admin/api/transactional-emails-client.d.ts.map +1 -0
- package/dist/admin/api/transactional-emails-client.js +47 -0
- package/dist/admin/api/transactional-emails-client.js.map +1 -0
- package/dist/admin/components/BrandingPanel.d.ts +10 -0
- package/dist/admin/components/BrandingPanel.d.ts.map +1 -0
- package/dist/admin/components/BrandingPanel.js +58 -0
- package/dist/admin/components/BrandingPanel.js.map +1 -0
- package/dist/admin/components/EmailEditorPane.d.ts +7 -0
- package/dist/admin/components/EmailEditorPane.d.ts.map +1 -0
- package/dist/admin/components/EmailEditorPane.js +48 -0
- package/dist/admin/components/EmailEditorPane.js.map +1 -0
- package/dist/admin/index.d.ts +46 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +92 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/EmailBlockEditorPage.d.ts +16 -0
- package/dist/admin/pages/EmailBlockEditorPage.d.ts.map +1 -0
- package/dist/admin/pages/EmailBlockEditorPage.js +19 -0
- package/dist/admin/pages/EmailBlockEditorPage.js.map +1 -0
- package/dist/admin/pages/EmailBlocksPage.d.ts +8 -0
- package/dist/admin/pages/EmailBlocksPage.d.ts.map +1 -0
- package/dist/admin/pages/EmailBlocksPage.js +55 -0
- package/dist/admin/pages/EmailBlocksPage.js.map +1 -0
- package/dist/admin/pages/EmailEditor.d.ts +8 -0
- package/dist/admin/pages/EmailEditor.d.ts.map +1 -0
- package/dist/admin/pages/EmailEditor.js +126 -0
- package/dist/admin/pages/EmailEditor.js.map +1 -0
- package/dist/admin/pages/EmailFragmentEditor.d.ts +9 -0
- package/dist/admin/pages/EmailFragmentEditor.d.ts.map +1 -0
- package/dist/admin/pages/EmailFragmentEditor.js +93 -0
- package/dist/admin/pages/EmailFragmentEditor.js.map +1 -0
- package/dist/admin/pages/EmailTemplateEditorPage.d.ts +12 -0
- package/dist/admin/pages/EmailTemplateEditorPage.d.ts.map +1 -0
- package/dist/admin/pages/EmailTemplateEditorPage.js +15 -0
- package/dist/admin/pages/EmailTemplateEditorPage.js.map +1 -0
- package/dist/admin/pages/EmailTemplatesPage.d.ts +8 -0
- package/dist/admin/pages/EmailTemplatesPage.d.ts.map +1 -0
- package/dist/admin/pages/EmailTemplatesPage.js +55 -0
- package/dist/admin/pages/EmailTemplatesPage.js.map +1 -0
- package/dist/admin/pages/EmailsList.d.ts +8 -0
- package/dist/admin/pages/EmailsList.d.ts.map +1 -0
- package/dist/admin/pages/EmailsList.js +85 -0
- package/dist/admin/pages/EmailsList.js.map +1 -0
- package/dist/backend/commands/email-activation.commands.d.ts +42 -0
- package/dist/backend/commands/email-activation.commands.d.ts.map +1 -0
- package/dist/backend/commands/email-activation.commands.js +51 -0
- package/dist/backend/commands/email-activation.commands.js.map +1 -0
- package/dist/backend/entities/email-block-sales-channel.entity.d.ts +11 -0
- package/dist/backend/entities/email-block-sales-channel.entity.d.ts.map +1 -0
- package/dist/backend/entities/email-block-sales-channel.entity.js +39 -0
- package/dist/backend/entities/email-block-sales-channel.entity.js.map +1 -0
- package/dist/backend/entities/email-block.entity.d.ts +24 -0
- package/dist/backend/entities/email-block.entity.d.ts.map +1 -0
- package/dist/backend/entities/email-block.entity.js +85 -0
- package/dist/backend/entities/email-block.entity.js.map +1 -0
- package/dist/backend/entities/email-template-sales-channel.entity.d.ts +10 -0
- package/dist/backend/entities/email-template-sales-channel.entity.d.ts.map +1 -0
- package/dist/backend/entities/email-template-sales-channel.entity.js +38 -0
- package/dist/backend/entities/email-template-sales-channel.entity.js.map +1 -0
- package/dist/backend/entities/email-template.entity.d.ts +19 -0
- package/dist/backend/entities/email-template.entity.d.ts.map +1 -0
- package/dist/backend/entities/email-template.entity.js +76 -0
- package/dist/backend/entities/email-template.entity.js.map +1 -0
- package/dist/backend/entities/transactional-email-content.entity.d.ts +25 -0
- package/dist/backend/entities/transactional-email-content.entity.d.ts.map +1 -0
- package/dist/backend/entities/transactional-email-content.entity.js +77 -0
- package/dist/backend/entities/transactional-email-content.entity.js.map +1 -0
- package/dist/backend/entities/transactional-email.entity.d.ts +32 -0
- package/dist/backend/entities/transactional-email.entity.d.ts.map +1 -0
- package/dist/backend/entities/transactional-email.entity.js +100 -0
- package/dist/backend/entities/transactional-email.entity.js.map +1 -0
- package/dist/backend/index.d.ts +105 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +126 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +49 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +54 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +23 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +133 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/services/branding.service.d.ts +63 -0
- package/dist/backend/services/branding.service.d.ts.map +1 -0
- package/dist/backend/services/branding.service.js +119 -0
- package/dist/backend/services/branding.service.js.map +1 -0
- package/dist/backend/services/content-resolver.d.ts +28 -0
- package/dist/backend/services/content-resolver.d.ts.map +1 -0
- package/dist/backend/services/content-resolver.js +64 -0
- package/dist/backend/services/content-resolver.js.map +1 -0
- package/dist/backend/services/email-block.service.d.ts +25 -0
- package/dist/backend/services/email-block.service.d.ts.map +1 -0
- package/dist/backend/services/email-block.service.js +162 -0
- package/dist/backend/services/email-block.service.js.map +1 -0
- package/dist/backend/services/email-builder-registry.d.ts +9 -0
- package/dist/backend/services/email-builder-registry.d.ts.map +1 -0
- package/dist/backend/services/email-builder-registry.js +14 -0
- package/dist/backend/services/email-builder-registry.js.map +1 -0
- package/dist/backend/services/email-defaults-registry.d.ts +63 -0
- package/dist/backend/services/email-defaults-registry.d.ts.map +1 -0
- package/dist/backend/services/email-defaults-registry.js +60 -0
- package/dist/backend/services/email-defaults-registry.js.map +1 -0
- package/dist/backend/services/email-template.service.d.ts +23 -0
- package/dist/backend/services/email-template.service.d.ts.map +1 -0
- package/dist/backend/services/email-template.service.js +155 -0
- package/dist/backend/services/email-template.service.js.map +1 -0
- package/dist/backend/services/embed-resolver.d.ts +21 -0
- package/dist/backend/services/embed-resolver.d.ts.map +1 -0
- package/dist/backend/services/embed-resolver.js +68 -0
- package/dist/backend/services/embed-resolver.js.map +1 -0
- package/dist/backend/services/manifest-reconciler.d.ts +28 -0
- package/dist/backend/services/manifest-reconciler.d.ts.map +1 -0
- package/dist/backend/services/manifest-reconciler.js +98 -0
- package/dist/backend/services/manifest-reconciler.js.map +1 -0
- package/dist/backend/services/template-email.d.ts +26 -0
- package/dist/backend/services/template-email.d.ts.map +1 -0
- package/dist/backend/services/template-email.js +69 -0
- package/dist/backend/services/template-email.js.map +1 -0
- package/dist/backend/services/transactional-email.service.d.ts +138 -0
- package/dist/backend/services/transactional-email.service.d.ts.map +1 -0
- package/dist/backend/services/transactional-email.service.js +410 -0
- package/dist/backend/services/transactional-email.service.js.map +1 -0
- package/dist/manifest.d.ts +195 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +367 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260629T113442_transactional_emails_init.d.ts +6 -0
- package/dist/migrations/20260629T113442_transactional_emails_init.d.ts.map +1 -0
- package/dist/migrations/20260629T113442_transactional_emails_init.js +133 -0
- package/dist/migrations/20260629T113442_transactional_emails_init.js.map +1 -0
- package/dist/migrations/20260801T111001_transactional_emails_email_defaults_reseed.d.ts +6 -0
- package/dist/migrations/20260801T111001_transactional_emails_email_defaults_reseed.d.ts.map +1 -0
- package/dist/migrations/20260801T111001_transactional_emails_email_defaults_reseed.js +49 -0
- package/dist/migrations/20260801T111001_transactional_emails_email_defaults_reseed.js.map +1 -0
- package/dist/migrations/20260903T101748_transactional_emails_namespace_block_names.d.ts +6 -0
- package/dist/migrations/20260903T101748_transactional_emails_namespace_block_names.d.ts.map +1 -0
- package/dist/migrations/20260903T101748_transactional_emails_namespace_block_names.js +60 -0
- package/dist/migrations/20260903T101748_transactional_emails_namespace_block_names.js.map +1 -0
- package/dist/migrations/index.d.ts +29 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +33 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/transactional-emails.md +176 -0
- package/i18n/en.json +92 -0
- package/i18n/pl.json +92 -0
- package/package.json +113 -0
- package/tailwind.css +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
|
|
2
|
+
|
|
3
|
+
# @endora-commerce/mod-transactional-emails
|
|
4
|
+
|
|
5
|
+
Admin-editable transactional email content and look (global + per sales channel), email-safe blocks/templates, variables, and preview.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
An **Endora Commerce module package**. Its module id is `transactional_emails` — the identity of record in the platform's registries, in its migrations and in its setting, permission and translation codes.
|
|
10
|
+
|
|
11
|
+
A module is not imported by application code. The platform discovers the extension packages an instance has installed, reads the manifest on the root subpath and composes the module from it, so installing this package and starting the instance is the whole integration.
|
|
12
|
+
|
|
13
|
+
## Entry points
|
|
14
|
+
|
|
15
|
+
| Import | Contents |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `@endora-commerce/mod-transactional-emails` | the module manifest — its id, version, dependencies, settings and activation |
|
|
18
|
+
| `@endora-commerce/mod-transactional-emails/admin` | the Admin UI contribution: the screens, navigation and palette actions it adds |
|
|
19
|
+
| `@endora-commerce/mod-transactional-emails/backend` | the composition root the platform calls, with the entities, services, routes and workers it registers |
|
|
20
|
+
| `@endora-commerce/mod-transactional-emails/migrations` | the module’s own schema migrations, in the order the platform runs them |
|
|
21
|
+
| `@endora-commerce/mod-transactional-emails/tailwind.css` | the Tailwind source declaration for the admin code above |
|
|
22
|
+
|
|
23
|
+
## Depends on
|
|
24
|
+
|
|
25
|
+
Everything below is a **peer** dependency, so the application resolves exactly one copy of each — two copies of a host or of React are a runtime failure rather than a type error. An entry marked *optional* is needed only by the layers that use it.
|
|
26
|
+
|
|
27
|
+
**Endora packages**
|
|
28
|
+
|
|
29
|
+
- `@endora-commerce/admin-kit` — *optional*
|
|
30
|
+
- `@endora-commerce/contracts`
|
|
31
|
+
- `@endora-commerce/email-components`
|
|
32
|
+
- `@endora-commerce/page-builder-admin` — *optional*
|
|
33
|
+
- `@endora-commerce/page-builder-core`
|
|
34
|
+
- `@endora-commerce/platform`
|
|
35
|
+
|
|
36
|
+
**Third-party**
|
|
37
|
+
|
|
38
|
+
- `@measured/puck` ^0 — *optional*
|
|
39
|
+
- `@mikro-orm/core` ^6
|
|
40
|
+
- `@mikro-orm/migrations` ^6
|
|
41
|
+
- `@mikro-orm/postgresql` ^6
|
|
42
|
+
- `fastify` ^5
|
|
43
|
+
- `lucide-react` ^1 — *optional*
|
|
44
|
+
- `react` ^19 — *optional*
|
|
45
|
+
- `react-router-dom` ^7 — *optional*
|
|
46
|
+
- `zod` ^4
|
|
47
|
+
|
|
48
|
+
## What the tarball carries
|
|
49
|
+
|
|
50
|
+
- `dist/` — the compiled JavaScript and its type declarations
|
|
51
|
+
- `i18n/` — the translation bundles this package ships (`en`, `pl`), loaded by the platform
|
|
52
|
+
- `docs/` — the package’s own pages in the Endora Commerce documentation site
|
|
53
|
+
- `tailwind.css` — the Tailwind source declaration
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm add @endora-commerce/mod-transactional-emails
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Licence
|
|
62
|
+
|
|
63
|
+
MIT — the text is in `LICENSE`, beside this file.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CreateEmailBlockRequest, CreateEmailTemplateRequest, EmailBlockDetail, EmailBlockSummary, EmailBranding, EmailPageBuilderDescriptor, EmailTemplateDetail, EmailTemplateSummary, PatchEmailBlockRequest, PatchEmailTemplateRequest, PreviewEmailResponse, PutEmailBlockContentRequest, PutEmailBrandingRequest, PutEmailContentRequest, ResolvedEmailContent, TransactionalEmailDetail, TransactionalEmailSummary } from '@endora-commerce/contracts';
|
|
2
|
+
/** Typed admin client for the transactional_emails module (feature 047). */
|
|
3
|
+
export declare const transactionalEmailsClient: {
|
|
4
|
+
pageBuilderConfig: () => Promise<EmailPageBuilderDescriptor>;
|
|
5
|
+
list: () => Promise<{
|
|
6
|
+
items: TransactionalEmailSummary[];
|
|
7
|
+
}>;
|
|
8
|
+
get: (code: string, salesChannelId: string | null, language?: string) => Promise<TransactionalEmailDetail>;
|
|
9
|
+
saveContent: (code: string, salesChannelId: string | null, language: string, body: PutEmailContentRequest) => Promise<ResolvedEmailContent>;
|
|
10
|
+
resetContent: (code: string, salesChannelId: string | null, language: string) => Promise<ResolvedEmailContent>;
|
|
11
|
+
/**
|
|
12
|
+
* Issue #89 — switch one email on or off. No optimistic update: the server's
|
|
13
|
+
* recomputed summary is what the list re-renders from, so a refusal or a
|
|
14
|
+
* protection the client did not know about cannot leave a stale toggle on
|
|
15
|
+
* screen.
|
|
16
|
+
*/
|
|
17
|
+
setActive: (code: string, active: boolean) => Promise<TransactionalEmailSummary>;
|
|
18
|
+
preview: (code: string, body: {
|
|
19
|
+
salesChannelId?: string;
|
|
20
|
+
language?: string;
|
|
21
|
+
draftSubject?: string;
|
|
22
|
+
draftContent?: unknown;
|
|
23
|
+
}) => Promise<PreviewEmailResponse>;
|
|
24
|
+
branding: (salesChannelId: string | null) => Promise<EmailBranding>;
|
|
25
|
+
putBranding: (salesChannelId: string | null, body: PutEmailBrandingRequest) => Promise<EmailBranding>;
|
|
26
|
+
listBlocks: (salesChannelId?: string) => Promise<{
|
|
27
|
+
items: EmailBlockSummary[];
|
|
28
|
+
}>;
|
|
29
|
+
getBlock: (id: string) => Promise<EmailBlockDetail>;
|
|
30
|
+
createBlock: (body: CreateEmailBlockRequest) => Promise<EmailBlockDetail>;
|
|
31
|
+
patchBlock: (id: string, body: PatchEmailBlockRequest) => Promise<EmailBlockDetail>;
|
|
32
|
+
putBlockContent: (id: string, language: string, body: PutEmailBlockContentRequest) => Promise<EmailBlockDetail>;
|
|
33
|
+
deleteBlock: (id: string) => Promise<void>;
|
|
34
|
+
listTemplates: (salesChannelId?: string) => Promise<{
|
|
35
|
+
items: EmailTemplateSummary[];
|
|
36
|
+
}>;
|
|
37
|
+
getTemplate: (id: string) => Promise<EmailTemplateDetail>;
|
|
38
|
+
createTemplate: (body: CreateEmailTemplateRequest) => Promise<EmailTemplateDetail>;
|
|
39
|
+
patchTemplate: (id: string, body: PatchEmailTemplateRequest) => Promise<EmailTemplateDetail>;
|
|
40
|
+
putTemplateContent: (id: string, language: string, body: PutEmailBlockContentRequest) => Promise<EmailTemplateDetail>;
|
|
41
|
+
deleteTemplate: (id: string) => Promise<void>;
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=transactional-emails-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transactional-emails-client.d.ts","sourceRoot":"","sources":["../../../src/admin/api/transactional-emails-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,uBAAuB,EACvB,0BAA0B,EAC1B,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,0BAA0B,EAC1B,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,EACpB,2BAA2B,EAC3B,uBAAuB,EACvB,sBAAsB,EACtB,oBAAoB,EAEpB,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,4BAA4B,CAAC;AAepC,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB;6BACb,OAAO,CAAC,0BAA0B,CAAC;gBAIhD,OAAO,CAAC;QAAE,KAAK,EAAE,yBAAyB,EAAE,CAAA;KAAE,CAAC;gBAG7C,MAAM,kBAAkB,MAAM,GAAG,IAAI,aAAa,MAAM,KAAG,OAAO,CAAC,wBAAwB,CAAC;wBAIhG,MAAM,kBACI,MAAM,GAAG,IAAI,YACnB,MAAM,QACV,sBAAsB,KAC3B,OAAO,CAAC,oBAAoB,CAAC;yBAQX,MAAM,kBAAkB,MAAM,GAAG,IAAI,YAAY,MAAM,KAAG,OAAO,CAAC,oBAAoB,CAAC;IAO5G;;;;;OAKG;sBACe,MAAM,UAAU,OAAO,KAAG,OAAO,CAAC,yBAAyB,CAAC;oBAStE,MAAM,QACN;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,KAClG,OAAO,CAAC,oBAAoB,CAAC;+BAIL,MAAM,GAAG,IAAI,KAAG,OAAO,CAAC,aAAa,CAAC;kCAEnC,MAAM,GAAG,IAAI,QAAQ,uBAAuB,KAAG,OAAO,CAAC,aAAa,CAAC;kCAIrE,MAAM,KAAG,OAAO,CAAC;QAAE,KAAK,EAAE,iBAAiB,EAAE,CAAA;KAAE,CAAC;mBAE/D,MAAM,KAAG,OAAO,CAAC,gBAAgB,CAAC;wBAE7B,uBAAuB,KAAG,OAAO,CAAC,gBAAgB,CAAC;qBAEtD,MAAM,QAAQ,sBAAsB,KAAG,OAAO,CAAC,gBAAgB,CAAC;0BAE3D,MAAM,YAAY,MAAM,QAAQ,2BAA2B,KAAG,OAAO,CAAC,gBAAgB,CAAC;sBAE3F,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;qCAIP,MAAM,KAAG,OAAO,CAAC;QAAE,KAAK,EAAE,oBAAoB,EAAE,CAAA;KAAE,CAAC;sBAElE,MAAM,KAAG,OAAO,CAAC,mBAAmB,CAAC;2BAEhC,0BAA0B,KAAG,OAAO,CAAC,mBAAmB,CAAC;wBAE5D,MAAM,QAAQ,yBAAyB,KAAG,OAAO,CAAC,mBAAmB,CAAC;6BAEjE,MAAM,YAAY,MAAM,QAAQ,2BAA2B,KAAG,OAAO,CAAC,mBAAmB,CAAC;yBAE9F,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;CAE5C,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { apiClient } from '@endora-commerce/admin-kit/lib';
|
|
2
|
+
const unwrap = (p) => p.then((r) => r.data);
|
|
3
|
+
const BASE = '/api/v1/admin/transactional-emails';
|
|
4
|
+
function scopeQs(salesChannelId, language) {
|
|
5
|
+
const params = new URLSearchParams();
|
|
6
|
+
if (salesChannelId)
|
|
7
|
+
params.set('salesChannelId', salesChannelId);
|
|
8
|
+
if (language)
|
|
9
|
+
params.set('language', language);
|
|
10
|
+
const s = params.toString();
|
|
11
|
+
return s ? `?${s}` : '';
|
|
12
|
+
}
|
|
13
|
+
/** Typed admin client for the transactional_emails module (feature 047). */
|
|
14
|
+
export const transactionalEmailsClient = {
|
|
15
|
+
pageBuilderConfig: () => unwrap(apiClient.get(`${BASE}/page-builder/config`)),
|
|
16
|
+
// Definitions
|
|
17
|
+
list: () => unwrap(apiClient.get(BASE)),
|
|
18
|
+
get: (code, salesChannelId, language) => unwrap(apiClient.get(`${BASE}/${encodeURIComponent(code)}${scopeQs(salesChannelId, language)}`)),
|
|
19
|
+
saveContent: (code, salesChannelId, language, body) => unwrap(apiClient.put(`${BASE}/${encodeURIComponent(code)}/content${scopeQs(salesChannelId, language)}`, body)),
|
|
20
|
+
resetContent: (code, salesChannelId, language) => unwrap(apiClient.delete(`${BASE}/${encodeURIComponent(code)}/content${scopeQs(salesChannelId, language)}`)),
|
|
21
|
+
/**
|
|
22
|
+
* Issue #89 — switch one email on or off. No optimistic update: the server's
|
|
23
|
+
* recomputed summary is what the list re-renders from, so a refusal or a
|
|
24
|
+
* protection the client did not know about cannot leave a stale toggle on
|
|
25
|
+
* screen.
|
|
26
|
+
*/
|
|
27
|
+
setActive: (code, active) => unwrap(apiClient.post(`${BASE}/${encodeURIComponent(code)}/activation`, { active })),
|
|
28
|
+
preview: (code, body) => unwrap(apiClient.post(`${BASE}/${encodeURIComponent(code)}/preview`, body)),
|
|
29
|
+
// Branding (read + write)
|
|
30
|
+
branding: (salesChannelId) => unwrap(apiClient.get(`${BASE}/branding${scopeQs(salesChannelId)}`)),
|
|
31
|
+
putBranding: (salesChannelId, body) => unwrap(apiClient.put(`${BASE}/branding${scopeQs(salesChannelId)}`, body)),
|
|
32
|
+
// Blocks
|
|
33
|
+
listBlocks: (salesChannelId) => unwrap(apiClient.get(`${BASE}/blocks${scopeQs(salesChannelId ?? null)}`)),
|
|
34
|
+
getBlock: (id) => unwrap(apiClient.get(`${BASE}/blocks/${encodeURIComponent(id)}`)),
|
|
35
|
+
createBlock: (body) => unwrap(apiClient.post(`${BASE}/blocks`, body)),
|
|
36
|
+
patchBlock: (id, body) => unwrap(apiClient.patch(`${BASE}/blocks/${encodeURIComponent(id)}`, body)),
|
|
37
|
+
putBlockContent: (id, language, body) => unwrap(apiClient.put(`${BASE}/blocks/${encodeURIComponent(id)}/content/${language}`, body)),
|
|
38
|
+
deleteBlock: (id) => apiClient.delete(`${BASE}/blocks/${encodeURIComponent(id)}`).then(() => undefined),
|
|
39
|
+
// Templates
|
|
40
|
+
listTemplates: (salesChannelId) => unwrap(apiClient.get(`${BASE}/templates${scopeQs(salesChannelId ?? null)}`)),
|
|
41
|
+
getTemplate: (id) => unwrap(apiClient.get(`${BASE}/templates/${encodeURIComponent(id)}`)),
|
|
42
|
+
createTemplate: (body) => unwrap(apiClient.post(`${BASE}/templates`, body)),
|
|
43
|
+
patchTemplate: (id, body) => unwrap(apiClient.patch(`${BASE}/templates/${encodeURIComponent(id)}`, body)),
|
|
44
|
+
putTemplateContent: (id, language, body) => unwrap(apiClient.put(`${BASE}/templates/${encodeURIComponent(id)}/content/${language}`, body)),
|
|
45
|
+
deleteTemplate: (id) => apiClient.delete(`${BASE}/templates/${encodeURIComponent(id)}`).then(() => undefined),
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=transactional-emails-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transactional-emails-client.js","sourceRoot":"","sources":["../../../src/admin/api/transactional-emails-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BrandingPanelProps {
|
|
2
|
+
/** null = global scope. */
|
|
3
|
+
salesChannelId: string | null;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Email branding editor (feature 047, US2). Logo (asset picker) + accent color,
|
|
7
|
+
* resolved and persisted per scope through the Settings-backed branding service.
|
|
8
|
+
*/
|
|
9
|
+
export declare function BrandingPanel({ salesChannelId }: BrandingPanelProps): React.ReactElement;
|
|
10
|
+
//# sourceMappingURL=BrandingPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandingPanel.d.ts","sourceRoot":"","sources":["../../../src/admin/components/BrandingPanel.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,kBAAkB;IACjC,2BAA2B;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,cAAc,EAAE,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CA6FxF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { AssetFieldPicker } from '@endora-commerce/admin-kit/components';
|
|
4
|
+
import { useAuth } from '@endora-commerce/admin-kit/lib';
|
|
5
|
+
import { Alert, AlertDescription, Button, Card, CardContent, CardHeader, CardTitle, ColorPicker, Label } from '@endora-commerce/admin-kit/ui';
|
|
6
|
+
import { toAbsoluteAssetUrl } from '@endora-commerce/admin-kit/lib';
|
|
7
|
+
import { transactionalEmailsClient } from '../api/transactional-emails-client.js';
|
|
8
|
+
/**
|
|
9
|
+
* Email branding editor (feature 047, US2). Logo (asset picker) + accent color,
|
|
10
|
+
* resolved and persisted per scope through the Settings-backed branding service.
|
|
11
|
+
*/
|
|
12
|
+
export function BrandingPanel({ salesChannelId }) {
|
|
13
|
+
const { hasPermission } = useAuth();
|
|
14
|
+
const canWrite = hasPermission('transactional_emails:write');
|
|
15
|
+
const [branding, setBranding] = useState(null);
|
|
16
|
+
const [logoAssetId, setLogoAssetId] = useState('');
|
|
17
|
+
const [accentColor, setAccentColor] = useState('');
|
|
18
|
+
const [error, setError] = useState(null);
|
|
19
|
+
const [notice, setNotice] = useState(null);
|
|
20
|
+
const [busy, setBusy] = useState(false);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
let live = true;
|
|
23
|
+
transactionalEmailsClient
|
|
24
|
+
.branding(salesChannelId)
|
|
25
|
+
.then((b) => {
|
|
26
|
+
if (!live)
|
|
27
|
+
return;
|
|
28
|
+
setBranding(b);
|
|
29
|
+
setLogoAssetId(b.logoAssetId);
|
|
30
|
+
setAccentColor(b.accentColor);
|
|
31
|
+
})
|
|
32
|
+
.catch((err) => {
|
|
33
|
+
if (live)
|
|
34
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
35
|
+
});
|
|
36
|
+
return () => {
|
|
37
|
+
live = false;
|
|
38
|
+
};
|
|
39
|
+
}, [salesChannelId]);
|
|
40
|
+
const save = async () => {
|
|
41
|
+
setBusy(true);
|
|
42
|
+
setError(null);
|
|
43
|
+
setNotice(null);
|
|
44
|
+
try {
|
|
45
|
+
const updated = await transactionalEmailsClient.putBranding(salesChannelId, { logoAssetId, accentColor });
|
|
46
|
+
setBranding(updated);
|
|
47
|
+
setNotice('Branding saved.');
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
setBusy(false);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs(CardTitle, { children: ["Branding ", salesChannelId ? '(channel)' : '(global)'] }) }), _jsxs(CardContent, { className: "space-y-4", children: [error ? (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { children: error }) })) : null, notice ? (_jsx(Alert, { children: _jsx(AlertDescription, { children: notice }) })) : null, _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: "te-logo", children: "Header logo" }), _jsx(AssetFieldPicker, { id: "te-logo", value: logoAssetId, onChange: setLogoAssetId, acceptMimePrefix: "image/", allowUpload: true, disabled: !canWrite, placeholder: "Select a logo from the Assets Library" }), branding?.logoUrl ? (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Resolved URL:", ' ', _jsx("span", { className: "font-mono", children: toAbsoluteAssetUrl(branding.logoUrl) })] })) : null] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Accent color" }), _jsx(ColorPicker, { value: accentColor, onChange: setAccentColor, label: "Accent color", customLabel: "Custom accent color", disabled: !canWrite })] }), _jsx(Button, { onClick: () => void save(), disabled: !canWrite || busy, children: "Save branding" })] })] }));
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=BrandingPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandingPanel.js","sourceRoot":"","sources":["../../../src/admin/components/BrandingPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type EmailEditorPaneProps } from '@endora-commerce/page-builder-admin/email';
|
|
2
|
+
/**
|
|
3
|
+
* Transactional-emails editor pane — loads TE blocks for embeds,
|
|
4
|
+
* then delegates to the shared EmailEditorPane.
|
|
5
|
+
*/
|
|
6
|
+
export declare function EmailEditorPane(props: Omit<EmailEditorPaneProps, 'blockOptions' | 'embeds' | 'embedTrees' | 'builderContext'>): React.ReactElement;
|
|
7
|
+
//# sourceMappingURL=EmailEditorPane.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailEditorPane.d.ts","sourceRoot":"","sources":["../../../src/admin/components/EmailEditorPane.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,2CAA2C,CAAC;AAOnD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,IAAI,CAAC,oBAAoB,EAAE,cAAc,GAAG,QAAQ,GAAG,YAAY,GAAG,gBAAgB,CAAC,GAC7F,KAAK,CAAC,YAAY,CA6CpB"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { EmailEditorPane as SharedEmailEditorPane, previewNode, } from '@endora-commerce/page-builder-admin/email';
|
|
4
|
+
import { transactionalEmailsClient } from '../api/transactional-emails-client.js';
|
|
5
|
+
function pickLanguageTree(content) {
|
|
6
|
+
return content['pl-PL'] ?? content['en-US'] ?? Object.values(content)[0] ?? null;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Transactional-emails editor pane — loads TE blocks for embeds,
|
|
10
|
+
* then delegates to the shared EmailEditorPane.
|
|
11
|
+
*/
|
|
12
|
+
export function EmailEditorPane(props) {
|
|
13
|
+
const [blockOptions, setBlockOptions] = useState([]);
|
|
14
|
+
const [embeds, setEmbeds] = useState({ blocks: {}, templates: {} });
|
|
15
|
+
const [embedTrees, setEmbedTrees] = useState({ blocks: {}, templates: {} });
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
let live = true;
|
|
18
|
+
void (async () => {
|
|
19
|
+
const blockRes = await transactionalEmailsClient.listBlocks().catch(() => ({ items: [] }));
|
|
20
|
+
if (!live)
|
|
21
|
+
return;
|
|
22
|
+
setBlockOptions(blockRes.items.map((b) => ({ label: `${b.name} (${b.code})`, value: b.code })));
|
|
23
|
+
const blockPreviews = {};
|
|
24
|
+
const blockTrees = {};
|
|
25
|
+
await Promise.all(blockRes.items.map(async (b) => {
|
|
26
|
+
try {
|
|
27
|
+
const detail = await transactionalEmailsClient.getBlock(b.id);
|
|
28
|
+
const tree = pickLanguageTree(detail.content);
|
|
29
|
+
if (tree)
|
|
30
|
+
blockTrees[b.code] = tree;
|
|
31
|
+
blockPreviews[b.code] = previewNode(detail.content);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
/* leave the code-only fallback */
|
|
35
|
+
}
|
|
36
|
+
}));
|
|
37
|
+
if (live) {
|
|
38
|
+
setEmbeds({ blocks: blockPreviews, templates: {} });
|
|
39
|
+
setEmbedTrees({ blocks: blockTrees, templates: {} });
|
|
40
|
+
}
|
|
41
|
+
})();
|
|
42
|
+
return () => {
|
|
43
|
+
live = false;
|
|
44
|
+
};
|
|
45
|
+
}, []);
|
|
46
|
+
return (_jsx(SharedEmailEditorPane, { ...props, builderContext: "email", blockOptions: blockOptions, embeds: embeds, embedTrees: embedTrees }));
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=EmailEditorPane.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailEditorPane.js","sourceRoot":"","sources":["../../../src/admin/components/EmailEditorPane.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAE5D,OAAO,EACL,eAAe,IAAI,qBAAqB,EACxC,WAAW,GAGZ,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAElF,SAAS,gBAAgB,CAAC,OAAqC;IAC7D,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACnF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,KAA8F;IAE9F,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAyB,EAAE,CAAC,CAAC;IAC7E,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAc,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAoB,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;IAE/F,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,GAAG,IAAI,CAAC;QAChB,KAAK,CAAC,KAAK,IAAmB,EAAE;YAC9B,MAAM,QAAQ,GAAG,MAAM,yBAAyB,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC3F,IAAI,CAAC,IAAI;gBAAE,OAAO;YAClB,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAEhG,MAAM,aAAa,GAA8B,EAAE,CAAC;YACpD,MAAM,UAAU,GAAiC,EAAE,CAAC;YACpD,MAAM,OAAO,CAAC,GAAG,CACf,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;gBAC7B,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC9D,MAAM,IAAI,GAAG,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;oBAC9C,IAAI,IAAI;wBAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;oBACpC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACtD,CAAC;gBAAC,MAAM,CAAC;oBACP,kCAAkC;gBACpC,CAAC;YACH,CAAC,CAAC,CACH,CAAC;YACF,IAAI,IAAI,EAAE,CAAC;gBACT,SAAS,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;gBACpD,aAAa,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;YACvD,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,GAAG,EAAE;YACV,IAAI,GAAG,KAAK,CAAC;QACf,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,KAAC,qBAAqB,OAChB,KAAK,EACT,cAAc,EAAC,OAAO,EACtB,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,GACtB,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `transactional_emails`' admin surface — six routes and three sidebar
|
|
3
|
+
* entries, declared by the module that owns them (feature 091, Phase 4, batch
|
|
4
|
+
* 11; `specs/091-module-owned-admin-surfaces/contracts/admin-contribution.md`).
|
|
5
|
+
*
|
|
6
|
+
* **Its drain is zero, re-derived on this branch before anything moved**, on
|
|
7
|
+
* the same evidence as its batch partner: no shard in
|
|
8
|
+
* `backend/scripts/ledgers/cross-module-imports/`, no key in
|
|
9
|
+
* `admin-surface.ts`, none in `foreign-module-ids.ts`. The reaches the plan
|
|
10
|
+
* recorded were into `admin/src/modules/_shared/email-builder/`, and P5b made
|
|
11
|
+
* them stop existing rather than repairing them — they are bare specifiers
|
|
12
|
+
* into `@endora-commerce/page-builder-admin/email` now.
|
|
13
|
+
*
|
|
14
|
+
* **`EmailEditorPane` here is this module's own and wraps the package's.** The
|
|
15
|
+
* one in `components/` loads this module's blocks so the builder can offer
|
|
16
|
+
* them as embeds, then delegates; the generic pane it delegates to is the
|
|
17
|
+
* package's. Two names, one of them a thin adapter holding the module
|
|
18
|
+
* knowledge the package must not have.
|
|
19
|
+
*
|
|
20
|
+
* **Two route files exist only to carry an argument.** `App.tsx` wrote
|
|
21
|
+
* `element={<EmailFragmentEditor kind="block" />}` and its template twin; a
|
|
22
|
+
* contribution declaration has nowhere to put a prop, so
|
|
23
|
+
* `EmailBlockEditorPage` and `EmailTemplateEditorPage` hold the two lines the
|
|
24
|
+
* host used to. That is batch 10's `CredentialsNewPage` decision arriving
|
|
25
|
+
* twice.
|
|
26
|
+
*
|
|
27
|
+
* **One palette action is declared here for the first time** —
|
|
28
|
+
* `open-email-blocks`, replacing the hand-written `PALETTE_ITEMS` row this
|
|
29
|
+
* batch deletes, with the same destination, code and keywords.
|
|
30
|
+
* `open-transactional-emails` and `open-email-templates` were already declared
|
|
31
|
+
* and are untouched.
|
|
32
|
+
*
|
|
33
|
+
* **`nonDeactivatable`, so the operator axis is the platform's** (`plan.md`
|
|
34
|
+
* Ruling 2). The manifest says why in its own words — this module is the
|
|
35
|
+
* platform's only acknowledgement path to a buyer, and the granularity a
|
|
36
|
+
* business wants is the individual e-mail, which `EmailsList` is the screen
|
|
37
|
+
* for. The permission axis is what this module still has and is what the
|
|
38
|
+
* off-state test drives; the missing axis is read off the manifest rather than
|
|
39
|
+
* skipped.
|
|
40
|
+
*
|
|
41
|
+
* **This entry exports data and nothing else** (R2); every component is a
|
|
42
|
+
* dynamic-import factory (R6).
|
|
43
|
+
*/
|
|
44
|
+
import type { AdminContributions } from '@endora-commerce/admin-kit/contributions';
|
|
45
|
+
export declare const contributions: AdminContributions;
|
|
46
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAoBnF,eAAO,MAAM,aAAa,EAAE,kBA2E3B,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** The module's landing route: the list of editable e-mails. */
|
|
2
|
+
const ROUTE_PATH = '/transactional-emails';
|
|
3
|
+
const BLOCKS_ROUTE = `${ROUTE_PATH}/blocks`;
|
|
4
|
+
const TEMPLATES_ROUTE = `${ROUTE_PATH}/templates`;
|
|
5
|
+
/**
|
|
6
|
+
* The one code every screen below needs to open.
|
|
7
|
+
*
|
|
8
|
+
* All eight `GET`s under `/api/v1/admin/transactional-emails` enforce it —
|
|
9
|
+
* the list, one e-mail, the blocks, the templates and the branding read — and
|
|
10
|
+
* every screen gates its own saves on `transactional_emails:write` through
|
|
11
|
+
* `useAuth().hasPermission`, which is the split the API already makes. It is
|
|
12
|
+
* the code the three hand-written sidebar rows carried and the code both
|
|
13
|
+
* declared palette actions carry.
|
|
14
|
+
*/
|
|
15
|
+
const READ_PERMISSION = 'transactional_emails:read';
|
|
16
|
+
export const contributions = {
|
|
17
|
+
routes: [
|
|
18
|
+
{
|
|
19
|
+
path: ROUTE_PATH,
|
|
20
|
+
component: () => import('./pages/EmailsList.js'),
|
|
21
|
+
requiredPermission: READ_PERMISSION,
|
|
22
|
+
index: true,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
path: BLOCKS_ROUTE,
|
|
26
|
+
component: () => import('./pages/EmailBlocksPage.js'),
|
|
27
|
+
requiredPermission: READ_PERMISSION,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
path: `${BLOCKS_ROUTE}/:id`,
|
|
31
|
+
component: () => import('./pages/EmailBlockEditorPage.js'),
|
|
32
|
+
requiredPermission: READ_PERMISSION,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
path: TEMPLATES_ROUTE,
|
|
36
|
+
component: () => import('./pages/EmailTemplatesPage.js'),
|
|
37
|
+
requiredPermission: READ_PERMISSION,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
path: `${TEMPLATES_ROUTE}/:id`,
|
|
41
|
+
component: () => import('./pages/EmailTemplateEditorPage.js'),
|
|
42
|
+
requiredPermission: READ_PERMISSION,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
// Declared last, and it is the one route here whose order used to be
|
|
46
|
+
// load-bearing: `/transactional-emails/:code` matches `/blocks` and
|
|
47
|
+
// `/templates` too. `<Routes>` ranks by specificity rather than by
|
|
48
|
+
// declaration order, so a static segment wins over a dynamic one — but
|
|
49
|
+
// the ordering is kept anyway, because a reader should not have to know
|
|
50
|
+
// that to see why the editor is safe here.
|
|
51
|
+
path: `${ROUTE_PATH}/:code`,
|
|
52
|
+
component: () => import('./pages/EmailEditor.js'),
|
|
53
|
+
requiredPermission: READ_PERMISSION,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
nav: [
|
|
57
|
+
{
|
|
58
|
+
to: ROUTE_PATH,
|
|
59
|
+
// Module-relative (R8), resolved in this module's own namespace out of
|
|
60
|
+
// `packages/modules/transactional_emails/i18n/`. It was
|
|
61
|
+
// `appShell.nav.transactionalEmails` in the shared `_i18n` bundle, one of
|
|
62
|
+
// the four shared files a module author had to edit.
|
|
63
|
+
labelKey: 'nav.transactionalEmails.label',
|
|
64
|
+
// The glyph `AppShell.tsx` rendered by hand for all three rows, and the
|
|
65
|
+
// one this module's `open-transactional-emails` action already names.
|
|
66
|
+
icon: 'Inbox',
|
|
67
|
+
section: 'messaging',
|
|
68
|
+
// The hand-written position times a hundred (batch four's convention).
|
|
69
|
+
// *Messaging* holds no host row once these three leave, so the weights
|
|
70
|
+
// are the whole order.
|
|
71
|
+
weight: 100,
|
|
72
|
+
requiredPermission: READ_PERMISSION,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
to: BLOCKS_ROUTE,
|
|
76
|
+
labelKey: 'nav.emailBlocks.label',
|
|
77
|
+
icon: 'Inbox',
|
|
78
|
+
section: 'messaging',
|
|
79
|
+
weight: 200,
|
|
80
|
+
requiredPermission: READ_PERMISSION,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
to: TEMPLATES_ROUTE,
|
|
84
|
+
labelKey: 'nav.emailTemplates.label',
|
|
85
|
+
icon: 'Inbox',
|
|
86
|
+
section: 'messaging',
|
|
87
|
+
weight: 300,
|
|
88
|
+
requiredPermission: READ_PERMISSION,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AA6CA,gEAAgE;AAChE,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAE3C,MAAM,YAAY,GAAG,GAAG,UAAU,SAAS,CAAC;AAC5C,MAAM,eAAe,GAAG,GAAG,UAAU,YAAY,CAAC;AAElD;;;;;;;;;GASG;AACH,MAAM,eAAe,GAAG,2BAA2B,CAAC;AAEpD,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,MAAM,EAAE;QACN;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,uBAAuB,CAAC;YAChD,kBAAkB,EAAE,eAAe;YACnC,KAAK,EAAE,IAAI;SACZ;QACD;YACE,IAAI,EAAE,YAAY;YAClB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,4BAA4B,CAAC;YACrD,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,IAAI,EAAE,GAAG,YAAY,MAAM;YAC3B,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iCAAiC,CAAC;YAC1D,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,IAAI,EAAE,eAAe;YACrB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,+BAA+B,CAAC;YACxD,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,IAAI,EAAE,GAAG,eAAe,MAAM;YAC9B,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,oCAAoC,CAAC;YAC7D,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,qEAAqE;YACrE,oEAAoE;YACpE,mEAAmE;YACnE,uEAAuE;YACvE,wEAAwE;YACxE,2CAA2C;YAC3C,IAAI,EAAE,GAAG,UAAU,QAAQ;YAC3B,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC;YACjD,kBAAkB,EAAE,eAAe;SACpC;KACF;IACD,GAAG,EAAE;QACH;YACE,EAAE,EAAE,UAAU;YACd,uEAAuE;YACvE,wDAAwD;YACxD,0EAA0E;YAC1E,qDAAqD;YACrD,QAAQ,EAAE,+BAA+B;YACzC,wEAAwE;YACxE,sEAAsE;YACtE,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,WAAW;YACpB,uEAAuE;YACvE,uEAAuE;YACvE,uBAAuB;YACvB,MAAM,EAAE,GAAG;YACX,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,EAAE,EAAE,YAAY;YAChB,QAAQ,EAAE,uBAAuB;YACjC,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,WAAW;YACpB,MAAM,EAAE,GAAG;YACX,kBAAkB,EAAE,eAAe;SACpC;QACD;YACE,EAAE,EAAE,eAAe;YACnB,QAAQ,EAAE,0BAA0B;YACpC,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,WAAW;YACpB,MAAM,EAAE,GAAG;YACX,kBAAkB,EAAE,eAAe;SACpC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* `/transactional-emails/blocks/:id` — the fragment editor, opened on a
|
|
4
|
+
* **block** (feature 047 US3; feature 091, Phase 4, batch 11).
|
|
5
|
+
*
|
|
6
|
+
* A file rather than a prop on the declaration, for `CredentialsNewPage`'s
|
|
7
|
+
* reason (batch 10): `AdminRouteDeclaration.component` is a factory returning a
|
|
8
|
+
* module and reads its `default`, so there is nowhere in the declaration to put
|
|
9
|
+
* an argument, and adding one would be a props channel the registry has to
|
|
10
|
+
* interpret for every module. `App.tsx` wrote
|
|
11
|
+
* `element={<EmailFragmentEditor kind="block" />}` here — the same two lines,
|
|
12
|
+
* with the host holding them.
|
|
13
|
+
*/
|
|
14
|
+
export declare function EmailBlockEditorPage(): ReactNode;
|
|
15
|
+
export default EmailBlockEditorPage;
|
|
16
|
+
//# sourceMappingURL=EmailBlockEditorPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailBlockEditorPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/EmailBlockEditorPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,IAAI,SAAS,CAEhD;AAED,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { EmailFragmentEditor } from './EmailFragmentEditor.js';
|
|
3
|
+
/**
|
|
4
|
+
* `/transactional-emails/blocks/:id` — the fragment editor, opened on a
|
|
5
|
+
* **block** (feature 047 US3; feature 091, Phase 4, batch 11).
|
|
6
|
+
*
|
|
7
|
+
* A file rather than a prop on the declaration, for `CredentialsNewPage`'s
|
|
8
|
+
* reason (batch 10): `AdminRouteDeclaration.component` is a factory returning a
|
|
9
|
+
* module and reads its `default`, so there is nowhere in the declaration to put
|
|
10
|
+
* an argument, and adding one would be a props channel the registry has to
|
|
11
|
+
* interpret for every module. `App.tsx` wrote
|
|
12
|
+
* `element={<EmailFragmentEditor kind="block" />}` here — the same two lines,
|
|
13
|
+
* with the host holding them.
|
|
14
|
+
*/
|
|
15
|
+
export function EmailBlockEditorPage() {
|
|
16
|
+
return _jsx(EmailFragmentEditor, { kind: "block" });
|
|
17
|
+
}
|
|
18
|
+
export default EmailBlockEditorPage;
|
|
19
|
+
//# sourceMappingURL=EmailBlockEditorPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailBlockEditorPage.js","sourceRoot":"","sources":["../../../src/admin/pages/EmailBlockEditorPage.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,KAAC,mBAAmB,IAAC,IAAI,EAAC,OAAO,GAAG,CAAC;AAC9C,CAAC;AAED,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function EmailBlocksPage(): React.ReactElement;
|
|
2
|
+
/**
|
|
3
|
+
* The registry loads a route component through a dynamic-import factory and
|
|
4
|
+
* reads its default export (feature 091, FR-013). The named export stays: it is
|
|
5
|
+
* the spelling this module's own code and its tests use.
|
|
6
|
+
*/
|
|
7
|
+
export default EmailBlocksPage;
|
|
8
|
+
//# sourceMappingURL=EmailBlocksPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailBlocksPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/EmailBlocksPage.tsx"],"names":[],"mappings":"AAOA,wBAAgB,eAAe,IAAI,KAAK,CAAC,YAAY,CAuGpD;AAED;;;;GAIG;AACH,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { Link } from 'react-router-dom';
|
|
4
|
+
import { useAuth } from '@endora-commerce/admin-kit/lib';
|
|
5
|
+
import { Alert, AlertDescription, Button, Card, CardContent, Input, PageHeader } from '@endora-commerce/admin-kit/ui';
|
|
6
|
+
import { transactionalEmailsClient } from '../api/transactional-emails-client.js';
|
|
7
|
+
export function EmailBlocksPage() {
|
|
8
|
+
const { hasPermission } = useAuth();
|
|
9
|
+
const canWrite = hasPermission('transactional_emails:write');
|
|
10
|
+
const [items, setItems] = useState([]);
|
|
11
|
+
const [error, setError] = useState(null);
|
|
12
|
+
const [code, setCode] = useState('');
|
|
13
|
+
const [name, setName] = useState('');
|
|
14
|
+
const reload = () => {
|
|
15
|
+
transactionalEmailsClient
|
|
16
|
+
.listBlocks()
|
|
17
|
+
.then((res) => setItems(res.items))
|
|
18
|
+
.catch((err) => setError(err instanceof Error ? err.message : String(err)));
|
|
19
|
+
};
|
|
20
|
+
useEffect(reload, []);
|
|
21
|
+
const create = async () => {
|
|
22
|
+
setError(null);
|
|
23
|
+
try {
|
|
24
|
+
await transactionalEmailsClient.createBlock({ code, name, languages: ['en-US', 'pl-PL'] });
|
|
25
|
+
setCode('');
|
|
26
|
+
setName('');
|
|
27
|
+
reload();
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const remove = async (id) => {
|
|
34
|
+
if (!window.confirm('Delete this block?'))
|
|
35
|
+
return;
|
|
36
|
+
try {
|
|
37
|
+
await transactionalEmailsClient.deleteBlock(id);
|
|
38
|
+
reload();
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
if (!hasPermission('transactional_emails:read')) {
|
|
45
|
+
return (_jsx(Alert, { children: _jsx(AlertDescription, { children: "You do not have permission to view email blocks." }) }));
|
|
46
|
+
}
|
|
47
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(PageHeader, { title: "Email Blocks", description: "Reusable email-safe blocks (e.g. header, footer)." }), error ? (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { children: error }) })) : null, canWrite ? (_jsx(Card, { children: _jsxs(CardContent, { className: "flex flex-wrap items-end gap-3 pt-6", children: [_jsx(Input, { placeholder: "code", value: code, onChange: (e) => setCode(e.target.value), className: "max-w-[200px]" }), _jsx(Input, { placeholder: "name", value: name, onChange: (e) => setName(e.target.value), className: "max-w-[240px]" }), _jsx(Button, { onClick: () => void create(), disabled: !code || !name, children: "Create block" })] }) })) : null, _jsx(Card, { children: _jsx(CardContent, { className: "p-0", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "border-b text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "p-3 font-medium", children: "Name" }), _jsx("th", { className: "p-3 font-medium", children: "Code" }), _jsx("th", { className: "p-3 font-medium", children: "Scope" }), _jsx("th", { className: "p-3 font-medium", children: "System" }), _jsx("th", { className: "p-3" })] }) }), _jsx("tbody", { children: items.map((b) => (_jsxs("tr", { className: "border-b last:border-0", children: [_jsx("td", { className: "p-3", children: _jsx(Link, { className: "font-medium text-primary hover:underline", to: `/transactional-emails/blocks/${b.id}`, children: b.name }) }), _jsx("td", { className: "p-3 font-mono text-xs", children: b.code }), _jsx("td", { className: "p-3", children: b.scope }), _jsx("td", { className: "p-3", children: b.isSystem ? 'Yes' : '—' }), _jsx("td", { className: "p-3 text-right", children: canWrite && !b.isSystem ? (_jsx(Button, { variant: "outline", size: "sm", onClick: () => void remove(b.id), children: "Delete" })) : null })] }, b.id))) })] }) }) })] }));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The registry loads a route component through a dynamic-import factory and
|
|
51
|
+
* reads its default export (feature 091, FR-013). The named export stays: it is
|
|
52
|
+
* the spelling this module's own code and its tests use.
|
|
53
|
+
*/
|
|
54
|
+
export default EmailBlocksPage;
|
|
55
|
+
//# sourceMappingURL=EmailBlocksPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmailBlocksPage.js","sourceRoot":"","sources":["../../../src/admin/pages/EmailBlocksPage.tsx"],"names":[],"mappings":"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"}
|