@passly-nl/data 1.0.2 → 1.0.4

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@passly-nl/data",
3
3
  "description": "API implementation for Passly.",
4
- "version": "1.0.2",
4
+ "version": "1.0.4",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "funding": "https://github.com/sponsors/basmilius",
@@ -50,16 +50,16 @@
50
50
  "./*": "./*"
51
51
  },
52
52
  "dependencies": {
53
- "@basmilius/http-client": "^3.11.1",
54
- "@flux-ui/types": "^3.0.0-next.32",
53
+ "@basmilius/http-client": "^3.14.0",
54
+ "@flux-ui/types": "^3.0.0-next.35",
55
55
  "@fortawesome/fontawesome-common-types": "^7.2.0",
56
- "apexcharts": "^5.10.3",
56
+ "apexcharts": "^5.10.4",
57
57
  "luxon": "^3.7.2"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/luxon": "^3.7.1",
61
- "@typescript/native-preview": "^7.0.0-dev.20260309.1",
62
- "tsdown": "^0.21.1"
61
+ "@typescript/native-preview": "^7.0.0-dev.20260320.1",
62
+ "tsdown": "^0.21.4"
63
63
  },
64
64
  "overrides": {
65
65
  "@disabled-basmilius/http-client": "link:@basmilius/http-client",
@@ -0,0 +1,25 @@
1
+ import { adapter, ForeignData } from '@basmilius/http-client';
2
+ import { DateTimeAdapter } from '#data/adapter';
3
+ import { EmailTemplateDto, RenderedMailDto } from '#data/dto';
4
+
5
+ @adapter
6
+ export class EmailTemplateAdapter {
7
+ static parseEmailTemplate(data: ForeignData): EmailTemplateDto {
8
+ return new EmailTemplateDto(
9
+ data.id,
10
+ data.type,
11
+ data.language ?? null,
12
+ data.subject,
13
+ data.content,
14
+ DateTimeAdapter.parseDateTime(data.created_on),
15
+ DateTimeAdapter.parseDateTime(data.updated_on)
16
+ );
17
+ }
18
+
19
+ static parseRenderedMail(data: ForeignData): RenderedMailDto {
20
+ return new RenderedMailDto(
21
+ data.subject,
22
+ data.content
23
+ );
24
+ }
25
+ }
@@ -1,5 +1,6 @@
1
1
  export * from './AddressAdapter';
2
2
  export * from './AuthAdapter';
3
+ export * from './EmailTemplateAdapter';
3
4
  export * from './BuyerAdapter';
4
5
  export * from './CommonAdapter';
5
6
  export * from './DateTimeAdapter';
@@ -0,0 +1,80 @@
1
+ import { dto } from '@basmilius/http-client';
2
+ import type { DateTime } from 'luxon';
3
+ import type { EmailTemplateLanguage, EmailTemplateType } from '#data/types';
4
+
5
+ @dto
6
+ export class EmailTemplateDto {
7
+ get id(): string {
8
+ return this.#id;
9
+ }
10
+
11
+ set id(value: string) {
12
+ this.#id = value;
13
+ }
14
+
15
+ get type(): EmailTemplateType {
16
+ return this.#type;
17
+ }
18
+
19
+ set type(value: EmailTemplateType) {
20
+ this.#type = value;
21
+ }
22
+
23
+ get language(): EmailTemplateLanguage | null {
24
+ return this.#language;
25
+ }
26
+
27
+ set language(value: EmailTemplateLanguage | null) {
28
+ this.#language = value;
29
+ }
30
+
31
+ get subject(): string {
32
+ return this.#subject;
33
+ }
34
+
35
+ set subject(value: string) {
36
+ this.#subject = value;
37
+ }
38
+
39
+ get content(): string {
40
+ return this.#content;
41
+ }
42
+
43
+ set content(value: string) {
44
+ this.#content = value;
45
+ }
46
+
47
+ get createdOn(): DateTime {
48
+ return this.#createdOn;
49
+ }
50
+
51
+ set createdOn(value: DateTime) {
52
+ this.#createdOn = value;
53
+ }
54
+
55
+ get updatedOn(): DateTime {
56
+ return this.#updatedOn;
57
+ }
58
+
59
+ set updatedOn(value: DateTime) {
60
+ this.#updatedOn = value;
61
+ }
62
+
63
+ #id: string;
64
+ #type: EmailTemplateType;
65
+ #language: EmailTemplateLanguage | null;
66
+ #subject: string;
67
+ #content: string;
68
+ #createdOn: DateTime;
69
+ #updatedOn: DateTime;
70
+
71
+ constructor(id: string, type: EmailTemplateType, language: EmailTemplateLanguage | null, subject: string, content: string, createdOn: DateTime, updatedOn: DateTime) {
72
+ this.#id = id;
73
+ this.#type = type;
74
+ this.#language = language;
75
+ this.#subject = subject;
76
+ this.#content = content;
77
+ this.#createdOn = createdOn;
78
+ this.#updatedOn = updatedOn;
79
+ }
80
+ }
@@ -0,0 +1,28 @@
1
+ import { dto } from '@basmilius/http-client';
2
+
3
+ @dto
4
+ export class RenderedMailDto {
5
+ get subject(): string {
6
+ return this.#subject;
7
+ }
8
+
9
+ set subject(value: string) {
10
+ this.#subject = value;
11
+ }
12
+
13
+ get content(): string {
14
+ return this.#content;
15
+ }
16
+
17
+ set content(value: string) {
18
+ this.#content = value;
19
+ }
20
+
21
+ #subject: string;
22
+ #content: string;
23
+
24
+ constructor(subject: string, content: string) {
25
+ this.#subject = subject;
26
+ this.#content = content;
27
+ }
28
+ }
@@ -0,0 +1,2 @@
1
+ export * from './EmailTemplateDto';
2
+ export * from './RenderedMailDto';
package/src/dto/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './address';
2
2
  export * from './auth';
3
3
  export * from './common';
4
+ export * from './emailTemplate';
4
5
  export * from './event';
5
6
  export * from './fileSystem';
6
7
  export * from './finance';
@@ -0,0 +1,286 @@
1
+ import type { EmailTemplateEditorBlock, EmailTemplateEditorButtonBlock, EmailTemplateEditorCondition, EmailTemplateEditorContext, EmailTemplateEditorH1Block, EmailTemplateEditorHeaderBlock, EmailTemplateEditorIfBlock, EmailTemplateEditorParagraphBlock, EmailTemplateEditorVariable, EmailTemplateType } from '#data/types';
2
+
3
+ const SHARED_VARIABLES: EmailTemplateEditorVariable[] = [
4
+ {label: 'variable.merchantName', path: 'merchant.name'},
5
+ {label: 'variable.weekDay', path: 'weekDay'}
6
+ ];
7
+
8
+ const BUYER_VARIABLES: EmailTemplateEditorVariable[] = [
9
+ {label: 'variable.buyerFirstName', path: 'buyer.firstName'},
10
+ {label: 'variable.buyerLastName', path: 'buyer.lastName'},
11
+ {label: 'variable.buyerFullName', path: 'buyer.fullName'},
12
+ {label: 'variable.buyerInitials', path: 'buyer.initials'},
13
+ {label: 'variable.buyerEmail', path: 'buyer.email'},
14
+ {label: 'variable.buyerPhoneNumber', path: 'buyer.phoneNumber'},
15
+ {label: 'variable.buyerDateOfBirth', path: 'buyer.dateOfBirth'},
16
+ {label: 'variable.buyerGender', path: 'buyer.gender'},
17
+ {label: 'variable.buyerLanguage', path: 'buyer.language'},
18
+ {label: 'variable.buyerAddressStreet', path: 'buyer.address.street'},
19
+ {label: 'variable.buyerAddressNumber', path: 'buyer.address.number'},
20
+ {label: 'variable.buyerAddressPostalCode', path: 'buyer.address.postalCode'},
21
+ {label: 'variable.buyerAddressCity', path: 'buyer.address.city'},
22
+ {label: 'variable.buyerAddressCountry', path: 'buyer.address.country'}
23
+ ];
24
+
25
+ const EVENT_VARIABLES: EmailTemplateEditorVariable[] = [
26
+ {label: 'variable.eventName', path: 'event.name'},
27
+ {label: 'variable.eventStartDate', path: 'event.startDate'},
28
+ {label: 'variable.eventStartTime', path: 'event.startTime'}
29
+ ];
30
+
31
+ const ORDER_VARIABLES: EmailTemplateEditorVariable[] = [
32
+ {label: 'variable.orderCode', path: 'order.code'}
33
+ ];
34
+
35
+ const HEADER_CONDITION: EmailTemplateEditorCondition = {label: 'condition.eventHasHeaderImage', condition: 'event.headerFile'};
36
+
37
+ export const EMAIL_TEMPLATE_EDITOR_CONTEXTS: Record<EmailTemplateType, EmailTemplateEditorContext> = {
38
+ merchant_invite: {
39
+ variables: [
40
+ ...SHARED_VARIABLES,
41
+ {label: 'variable.userFirstName', path: 'user.firstName'},
42
+ {label: 'variable.userLastName', path: 'user.lastName'},
43
+ {label: 'variable.acceptUrl', path: 'acceptUrl'}
44
+ ],
45
+ conditions: []
46
+ },
47
+ order_canceled: {
48
+ variables: [...SHARED_VARIABLES, ...BUYER_VARIABLES, ...EVENT_VARIABLES, ...ORDER_VARIABLES],
49
+ conditions: [HEADER_CONDITION]
50
+ },
51
+ order_confirmation: {
52
+ variables: [...SHARED_VARIABLES, ...BUYER_VARIABLES, ...EVENT_VARIABLES, ...ORDER_VARIABLES],
53
+ conditions: [
54
+ {label: 'condition.hasNormalTicketsOnly', condition: 'hasNormalTicketsOnly'},
55
+ {label: 'condition.hasPersonalizableTickets', condition: 'hasPersonalizableTickets'},
56
+ {label: 'condition.hasSealedTickets', condition: 'hasSealedTickets'},
57
+ HEADER_CONDITION
58
+ ]
59
+ },
60
+ order_expired: {
61
+ variables: [...SHARED_VARIABLES, ...BUYER_VARIABLES, ...EVENT_VARIABLES, ...ORDER_VARIABLES],
62
+ conditions: [HEADER_CONDITION]
63
+ },
64
+ order_failed: {
65
+ variables: [...SHARED_VARIABLES, ...BUYER_VARIABLES, ...EVENT_VARIABLES, ...ORDER_VARIABLES],
66
+ conditions: [HEADER_CONDITION]
67
+ },
68
+ personalization_invite: {
69
+ variables: [...SHARED_VARIABLES, ...BUYER_VARIABLES, ...EVENT_VARIABLES, {label: 'variable.personalizeUrl', path: 'personalizeUrl'}],
70
+ conditions: [HEADER_CONDITION]
71
+ },
72
+ personalization_request: {
73
+ variables: [...SHARED_VARIABLES, ...BUYER_VARIABLES, ...EVENT_VARIABLES, ...ORDER_VARIABLES, {label: 'variable.personalizeUrl', path: 'personalizeUrl'}],
74
+ conditions: [HEADER_CONDITION]
75
+ },
76
+ tickets: {
77
+ variables: [...SHARED_VARIABLES, ...BUYER_VARIABLES, ...EVENT_VARIABLES, ...ORDER_VARIABLES],
78
+ conditions: [HEADER_CONDITION]
79
+ }
80
+ };
81
+
82
+ interface ScanResult {
83
+ blocks: EmailTemplateEditorBlock[];
84
+ consumed: number;
85
+ }
86
+
87
+ /**
88
+ * Parses quoted or unquoted arguments from a Handlebars helper argument string.
89
+ * Returns an array of string values.
90
+ */
91
+ function parseArgs(args: string): string[] {
92
+ const result: string[] = [];
93
+ let remaining = args.trim();
94
+
95
+ while (remaining.length > 0) {
96
+ if (remaining[0] === '"') {
97
+ const end = remaining.indexOf('"', 1);
98
+ if (end === -1) break;
99
+ result.push(remaining.slice(1, end));
100
+ remaining = remaining.slice(end + 1).trim();
101
+ } else {
102
+ const spaceIdx = remaining.search(/\s/);
103
+ if (spaceIdx === -1) {
104
+ result.push(remaining);
105
+ break;
106
+ }
107
+ result.push(remaining.slice(0, spaceIdx));
108
+ remaining = remaining.slice(spaceIdx + 1).trim();
109
+ }
110
+ }
111
+
112
+ return result;
113
+ }
114
+
115
+ /**
116
+ * Builds a single EmailTemplateEditorBlock from a parsed Handlebars block.
117
+ */
118
+ function buildBlock(
119
+ type: string,
120
+ args: string,
121
+ children: EmailTemplateEditorBlock[],
122
+ rawContent: string
123
+ ): EmailTemplateEditorBlock | null {
124
+ const content = rawContent.trim().split('\n').map(line => line.replace(/^ {4}/, '')).join('\n');
125
+
126
+ switch (type) {
127
+ case 'h1':
128
+ return {type: 'h1', content} satisfies EmailTemplateEditorH1Block;
129
+
130
+ case 'paragraph':
131
+ return {type: 'paragraph', content} satisfies EmailTemplateEditorParagraphBlock;
132
+
133
+ case 'divider':
134
+ return {type: 'divider'};
135
+
136
+ case 'spacer':
137
+ return {type: 'spacer'};
138
+
139
+ case 'logo':
140
+ return {type: 'logo'};
141
+
142
+ case 'button': {
143
+ const [label = '', url = ''] = parseArgs(args);
144
+ return {type: 'button', label, url} satisfies EmailTemplateEditorButtonBlock;
145
+ }
146
+
147
+ case 'header': {
148
+ const [src = ''] = parseArgs(args);
149
+ return {type: 'header', src} satisfies EmailTemplateEditorHeaderBlock;
150
+ }
151
+
152
+ case 'if':
153
+ return {type: 'if', condition: args, children} satisfies EmailTemplateEditorIfBlock;
154
+
155
+ default:
156
+ return null;
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Recursively scans the template string starting from startPos, building blocks
162
+ * until a closing tag is found or the end of the string is reached.
163
+ */
164
+ function scan(template: string, startPos: number = 0): ScanResult {
165
+ const blocks: EmailTemplateEditorBlock[] = [];
166
+ let pos = startPos;
167
+
168
+ while (pos < template.length) {
169
+ const tokenStart = template.indexOf('{{', pos);
170
+ if (tokenStart === -1) break;
171
+
172
+ const ch = template[tokenStart + 2];
173
+
174
+ // Partial {{> ...}} — skip
175
+ if (ch === '>') {
176
+ const end = template.indexOf('}}', tokenStart);
177
+ if (end === -1) break;
178
+ pos = end + 2;
179
+ continue;
180
+ }
181
+
182
+ // Comment {{!-- ... --}} or {{! ...}} — skip
183
+ if (ch === '!') {
184
+ const end = template.indexOf('}}', tokenStart);
185
+ if (end === -1) break;
186
+ pos = end + 2;
187
+ continue;
188
+ }
189
+
190
+ // Closing tag {{/type}} — return to parent scanner
191
+ if (ch === '/') {
192
+ return {blocks, consumed: tokenStart};
193
+ }
194
+
195
+ // Opening block tag {{#type args}}
196
+ if (ch === '#') {
197
+ const closeTag = template.indexOf('}}', tokenStart);
198
+ if (closeTag === -1) break;
199
+
200
+ const tagContent = template.slice(tokenStart + 3, closeTag).trim();
201
+ const spaceIdx = tagContent.search(/\s/);
202
+ const type = spaceIdx === -1 ? tagContent : tagContent.slice(0, spaceIdx);
203
+ const args = spaceIdx === -1 ? '' : tagContent.slice(spaceIdx + 1).trim();
204
+
205
+ const innerStart = closeTag + 2;
206
+ const {blocks: children, consumed: innerEnd} = scan(template, innerStart);
207
+ const rawContent = template.slice(innerStart, innerEnd);
208
+
209
+ // Advance past the closing {{/type}} tag
210
+ const expectedClose = `{{/${type}}}`;
211
+ pos = innerEnd + expectedClose.length;
212
+
213
+ const block = buildBlock(type, args, children, rawContent);
214
+ if (block !== null) {
215
+ blocks.push(block);
216
+ }
217
+ continue;
218
+ }
219
+
220
+ // Variable or other expression — skip
221
+ const end = template.indexOf('}}', tokenStart);
222
+ if (end === -1) break;
223
+ pos = end + 2;
224
+ }
225
+
226
+ return {blocks, consumed: pos};
227
+ }
228
+
229
+ /**
230
+ * Serializes a single block back to its Handlebars string representation.
231
+ */
232
+ function serializeBlock(block: EmailTemplateEditorBlock): string {
233
+ switch (block.type) {
234
+ case 'h1': {
235
+ const indented = block.content.split('\n').map(line => ` ${line}`).join('\n');
236
+ return `{{#h1}}\n${indented}\n{{/h1}}`;
237
+ }
238
+
239
+ case 'paragraph': {
240
+ const indented = block.content.split('\n').map(line => ` ${line}`).join('\n');
241
+ return `{{#paragraph}}\n${indented}\n{{/paragraph}}`;
242
+ }
243
+
244
+ case 'divider':
245
+ return `{{#divider}}{{/divider}}`;
246
+
247
+ case 'spacer':
248
+ return `{{#spacer}}{{/spacer}}`;
249
+
250
+ case 'logo':
251
+ return `{{#logo}}{{/logo}}`;
252
+
253
+ case 'button':
254
+ return `{{#button "${block.label}" "${block.url}"}}{{/button}}`;
255
+
256
+ case 'header': {
257
+ const srcArg = block.src.includes('://') ? `"${block.src}"` : block.src;
258
+ return `{{#header ${srcArg}}}{{/header}}`;
259
+ }
260
+
261
+ case 'if': {
262
+ const indented = serializeBlocks(block.children)
263
+ .split('\n')
264
+ .map(line => ` ${line}`)
265
+ .join('\n');
266
+ return `{{#if ${block.condition}}}\n${indented}\n{{/if}}`;
267
+ }
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Parses a Handlebars template string into an array of editor blocks.
273
+ * Strips structure partials; only content blocks are returned.
274
+ */
275
+ export function parseEmailTemplate(template: string): EmailTemplateEditorBlock[] {
276
+ const {blocks} = scan(template);
277
+ return blocks;
278
+ }
279
+
280
+ /**
281
+ * Serializes an array of editor blocks back into a Handlebars content string.
282
+ * Does not include structure partials — those are added by the backend automatically.
283
+ */
284
+ export function serializeBlocks(blocks: EmailTemplateEditorBlock[]): string {
285
+ return blocks.map(serializeBlock).join('\n\n');
286
+ }
@@ -0,0 +1,43 @@
1
+ import { BaseResponse, BaseService } from '@basmilius/http-client';
2
+ import { CommonAdapter, EmailTemplateAdapter } from '#data/adapter';
3
+ import type { EmailTemplateDto, RenderedMailDto, StatusResponseDto } from '#data/dto';
4
+ import type { EmailTemplateLanguage } from '#data/types';
5
+
6
+ export class MerchantEmailTemplateService extends BaseService {
7
+ async getPreview(merchantId: string, emailTemplateId: string): Promise<BaseResponse<RenderedMailDto>> {
8
+ return await this
9
+ .request(`/merchants/${merchantId}/email-templates/${emailTemplateId}/preview`)
10
+ .method('get')
11
+ .bearerToken()
12
+ .runAdapter(EmailTemplateAdapter.parseRenderedMail);
13
+ }
14
+
15
+ async get(merchantId: string, emailTemplateId: string): Promise<BaseResponse<EmailTemplateDto>> {
16
+ return await this
17
+ .request(`/merchants/${merchantId}/email-templates/${emailTemplateId}`)
18
+ .method('get')
19
+ .bearerToken()
20
+ .runAdapter(EmailTemplateAdapter.parseEmailTemplate);
21
+ }
22
+
23
+ async patch(merchantId: string, emailTemplateId: string, subject: string, content: string, language: EmailTemplateLanguage | null = null): Promise<BaseResponse<EmailTemplateDto>> {
24
+ return await this
25
+ .request(`/merchants/${merchantId}/email-templates/${emailTemplateId}`)
26
+ .method('patch')
27
+ .bearerToken()
28
+ .body({
29
+ subject,
30
+ content,
31
+ language
32
+ })
33
+ .runAdapter(EmailTemplateAdapter.parseEmailTemplate);
34
+ }
35
+
36
+ async delete(merchantId: string, emailTemplateId: string): Promise<BaseResponse<StatusResponseDto>> {
37
+ return await this
38
+ .request(`/merchants/${merchantId}/email-templates/${emailTemplateId}`)
39
+ .method('delete')
40
+ .bearerToken()
41
+ .runAdapter(CommonAdapter.parseStatusResponse);
42
+ }
43
+ }
@@ -0,0 +1,31 @@
1
+ import { BaseResponse, BaseService, Paginated, QueryString } from '@basmilius/http-client';
2
+ import { EmailTemplateAdapter } from '#data/adapter';
3
+ import type { EmailTemplateDto } from '#data/dto';
4
+ import type { EmailTemplateLanguage, EmailTemplateType } from '#data/types';
5
+
6
+ export class MerchantEmailTemplatesService extends BaseService {
7
+ async get(merchantId: string, offset: number, limit: number): Promise<BaseResponse<Paginated<EmailTemplateDto>>> {
8
+ return await this
9
+ .request(`/merchants/${merchantId}/email-templates`)
10
+ .method('get')
11
+ .bearerToken()
12
+ .queryString(QueryString.builder()
13
+ .append('offset', offset)
14
+ .append('limit', limit))
15
+ .runPaginatedAdapter(EmailTemplateAdapter.parseEmailTemplate);
16
+ }
17
+
18
+ async post(merchantId: string, type: EmailTemplateType, subject: string, content: string, language: EmailTemplateLanguage | null = null): Promise<BaseResponse<EmailTemplateDto>> {
19
+ return await this
20
+ .request(`/merchants/${merchantId}/email-templates`)
21
+ .method('post')
22
+ .bearerToken()
23
+ .body({
24
+ type,
25
+ subject,
26
+ content,
27
+ language
28
+ })
29
+ .runAdapter(EmailTemplateAdapter.parseEmailTemplate);
30
+ }
31
+ }
@@ -0,0 +1,43 @@
1
+ import { BaseResponse, BaseService } from '@basmilius/http-client';
2
+ import { CommonAdapter, EmailTemplateAdapter } from '#data/adapter';
3
+ import type { EmailTemplateDto, RenderedMailDto, StatusResponseDto } from '#data/dto';
4
+ import type { EmailTemplateLanguage } from '#data/types';
5
+
6
+ export class MerchantEventEmailTemplateService extends BaseService {
7
+ async getPreview(merchantId: string, eventId: string, emailTemplateId: string): Promise<BaseResponse<RenderedMailDto>> {
8
+ return await this
9
+ .request(`/merchants/${merchantId}/events/${eventId}/email-templates/${emailTemplateId}/preview`)
10
+ .method('get')
11
+ .bearerToken()
12
+ .runAdapter(EmailTemplateAdapter.parseRenderedMail);
13
+ }
14
+
15
+ async get(merchantId: string, eventId: string, emailTemplateId: string): Promise<BaseResponse<EmailTemplateDto>> {
16
+ return await this
17
+ .request(`/merchants/${merchantId}/events/${eventId}/email-templates/${emailTemplateId}`)
18
+ .method('get')
19
+ .bearerToken()
20
+ .runAdapter(EmailTemplateAdapter.parseEmailTemplate);
21
+ }
22
+
23
+ async patch(merchantId: string, eventId: string, emailTemplateId: string, subject: string, content: string, language: EmailTemplateLanguage | null = null): Promise<BaseResponse<EmailTemplateDto>> {
24
+ return await this
25
+ .request(`/merchants/${merchantId}/events/${eventId}/email-templates/${emailTemplateId}`)
26
+ .method('patch')
27
+ .bearerToken()
28
+ .body({
29
+ subject,
30
+ content,
31
+ language
32
+ })
33
+ .runAdapter(EmailTemplateAdapter.parseEmailTemplate);
34
+ }
35
+
36
+ async delete(merchantId: string, eventId: string, emailTemplateId: string): Promise<BaseResponse<StatusResponseDto>> {
37
+ return await this
38
+ .request(`/merchants/${merchantId}/events/${eventId}/email-templates/${emailTemplateId}`)
39
+ .method('delete')
40
+ .bearerToken()
41
+ .runAdapter(CommonAdapter.parseStatusResponse);
42
+ }
43
+ }
@@ -0,0 +1,31 @@
1
+ import { BaseResponse, BaseService, Paginated, QueryString } from '@basmilius/http-client';
2
+ import { EmailTemplateAdapter } from '#data/adapter';
3
+ import type { EmailTemplateDto } from '#data/dto';
4
+ import type { EmailTemplateLanguage, EmailTemplateType } from '#data/types';
5
+
6
+ export class MerchantEventEmailTemplatesService extends BaseService {
7
+ async get(merchantId: string, eventId: string, offset: number, limit: number): Promise<BaseResponse<Paginated<EmailTemplateDto>>> {
8
+ return await this
9
+ .request(`/merchants/${merchantId}/events/${eventId}/email-templates`)
10
+ .method('get')
11
+ .bearerToken()
12
+ .queryString(QueryString.builder()
13
+ .append('offset', offset)
14
+ .append('limit', limit))
15
+ .runPaginatedAdapter(EmailTemplateAdapter.parseEmailTemplate);
16
+ }
17
+
18
+ async post(merchantId: string, eventId: string, type: EmailTemplateType, subject: string, content: string, language: EmailTemplateLanguage | null = null): Promise<BaseResponse<EmailTemplateDto>> {
19
+ return await this
20
+ .request(`/merchants/${merchantId}/events/${eventId}/email-templates`)
21
+ .method('post')
22
+ .bearerToken()
23
+ .body({
24
+ type,
25
+ subject,
26
+ content,
27
+ language
28
+ })
29
+ .runAdapter(EmailTemplateAdapter.parseEmailTemplate);
30
+ }
31
+ }
@@ -1,5 +1,4 @@
1
1
  import { BaseResponse, BaseService, QueryString } from '@basmilius/http-client';
2
- import type { DateTime } from 'luxon';
3
2
  import { ProductAdapter } from '#data/adapter';
4
3
  import type { ProductDto } from '#data/dto';
5
4
 
@@ -31,7 +31,7 @@ export class PublicShopService extends BaseService {
31
31
  number: addressNumber,
32
32
  postal_code: addressPostalCode,
33
33
  street: addressStreet
34
- }
34
+ };
35
35
  }
36
36
 
37
37
  return await this
@@ -20,6 +20,10 @@ export * from './MerchantEventShopsService';
20
20
  export * from './MerchantEventStockPoolsService';
21
21
  export * from './MerchantEventTicketTemplateService';
22
22
  export * from './MerchantEventTicketTemplatesService';
23
+ export * from './MerchantEmailTemplateService';
24
+ export * from './MerchantEmailTemplatesService';
25
+ export * from './MerchantEventEmailTemplateService';
26
+ export * from './MerchantEventEmailTemplatesService';
23
27
  export * from './MerchantEventsService';
24
28
  export * from './MerchantFinanceInvoiceService';
25
29
  export * from './MerchantFinanceInvoicesService';
@@ -42,4 +46,5 @@ export * from './PublicOrderService';
42
46
  export * from './PublicShopService';
43
47
  export * from './ReservationService';
44
48
  export * from './ServicesService';
49
+ export * from './EmailTemplateEditorService';
45
50
  export * from './UiSelectOptionsService';
@@ -0,0 +1,13 @@
1
+ export type EmailTemplateType =
2
+ | 'merchant_invite'
3
+ | 'order_canceled'
4
+ | 'order_confirmation'
5
+ | 'order_expired'
6
+ | 'order_failed'
7
+ | 'personalization_invite'
8
+ | 'personalization_request'
9
+ | 'tickets';
10
+
11
+ export type EmailTemplateLanguage =
12
+ | 'en'
13
+ | 'nl';