@nyaruka/temba-components 0.90.0 → 0.91.2
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/.github/workflows/build.yml +4 -4
- package/.github/workflows/publish.yml +1 -1
- package/CHANGELOG.md +17 -0
- package/dist/temba-components.js +11 -6
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/templates/TemplateEditor.js +22 -15
- package/out-tsc/src/templates/TemplateEditor.js.map +1 -1
- package/package.json +1 -1
- package/src/templates/TemplateEditor.ts +24 -16
|
@@ -85,6 +85,10 @@ export class TemplateEditor extends FormElement {
|
|
|
85
85
|
align-items: center;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
.button .content {
|
|
89
|
+
margin-bottom: 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
88
92
|
.button .display {
|
|
89
93
|
margin-right: 0.5em;
|
|
90
94
|
background: #f9f9f9;
|
|
@@ -108,6 +112,7 @@ export class TemplateEditor extends FormElement {
|
|
|
108
112
|
max-height: 50vh;
|
|
109
113
|
overflow-y: auto;
|
|
110
114
|
overflow-x: hidden;
|
|
115
|
+
padding-bottom: 0;
|
|
111
116
|
}
|
|
112
117
|
`;
|
|
113
118
|
}
|
|
@@ -184,7 +189,10 @@ export class TemplateEditor extends FormElement {
|
|
|
184
189
|
// create a regex match based on the variable names
|
|
185
190
|
const variableRegex = new RegExp(`{{(${Object.keys(component.variables || []).join('|')})}}`, 'g');
|
|
186
191
|
let variables = null;
|
|
187
|
-
|
|
192
|
+
let parts = [];
|
|
193
|
+
if (component.content && component.content.trim().length > 0) {
|
|
194
|
+
parts = ((_a = component.content) === null || _a === void 0 ? void 0 : _a.split(variableRegex)) || [];
|
|
195
|
+
}
|
|
188
196
|
if (parts.length > 0) {
|
|
189
197
|
variables = parts.map((part, index) => {
|
|
190
198
|
if (index % 2 === 0) {
|
|
@@ -205,16 +213,15 @@ export class TemplateEditor extends FormElement {
|
|
|
205
213
|
});
|
|
206
214
|
}
|
|
207
215
|
else {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const index = Object.values(component.variables)[0];
|
|
216
|
+
variables = Object.values(component.variables).map((variableIndex) => {
|
|
217
|
+
const variableSpec = this.translation.variables[variableIndex];
|
|
218
|
+
if (variableSpec.type === 'image' ||
|
|
219
|
+
variableSpec.type === 'document' ||
|
|
220
|
+
variableSpec.type === 'audio' ||
|
|
221
|
+
variableSpec.type === 'video') {
|
|
215
222
|
let attachments = [];
|
|
216
|
-
if (this.variables[
|
|
217
|
-
const parts = this.variables[
|
|
223
|
+
if (this.variables[variableIndex]) {
|
|
224
|
+
const parts = this.variables[variableIndex].split(':');
|
|
218
225
|
attachments = [{ url: parts[1], content_type: parts[0] }];
|
|
219
226
|
}
|
|
220
227
|
return html `<div
|
|
@@ -228,18 +235,18 @@ export class TemplateEditor extends FormElement {
|
|
|
228
235
|
"
|
|
229
236
|
>
|
|
230
237
|
<temba-media-picker
|
|
231
|
-
accept="${
|
|
238
|
+
accept="${variableSpec.type === 'document'
|
|
232
239
|
? 'application/pdf'
|
|
233
|
-
:
|
|
240
|
+
: variableSpec.type + '/*'}"
|
|
234
241
|
max="1"
|
|
235
|
-
index=${
|
|
236
|
-
icon="attachment_${
|
|
242
|
+
index=${variableIndex}
|
|
243
|
+
icon="attachment_${variableSpec.type}"
|
|
237
244
|
attachments=${JSON.stringify(attachments)}
|
|
238
245
|
@change=${this.handleAttachmentsChanged.bind(this)}
|
|
239
246
|
></temba-media-picker>
|
|
240
247
|
<div>
|
|
241
248
|
${attachments.length == 0
|
|
242
|
-
? html `Attach ${
|
|
249
|
+
? html `Attach ${variableSpec.type} to continue`
|
|
243
250
|
: ''}
|
|
244
251
|
</div>
|
|
245
252
|
</div>`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateEditor.js","sourceRoot":"","sources":["../../../src/templates/TemplateEditor.ts"],"names":[],"mappings":"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","sourcesContent":["import { property } from 'lit/decorators.js';\nimport { FormElement } from '../FormElement';\nimport { TemplateResult, html, css, PropertyValueMap, LitElement } from 'lit';\nimport { CustomEventType } from '../interfaces';\nimport { MediaPicker } from '../mediapicker/MediaPicker';\n\ninterface Component {\n name: string;\n type: string;\n content: string;\n variables: { [key: string]: number };\n params: [{ type: string }];\n}\n\ninterface Translation {\n locale: string;\n status: string;\n channel: { uuid: string; name: string };\n components: Component[];\n variables: { type: string }[];\n}\n\ninterface Template {\n created_on: string;\n modified_on: string;\n name: string;\n translations: Translation[];\n uuid: string;\n}\n\nexport class TemplateEditor extends FormElement {\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true\n };\n\n static get styles() {\n return css`\n .component {\n background: #fff;\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature);\n padding: 1em;\n margin-top: 1em;\n }\n\n .content {\n margin-bottom: 1em;\n }\n\n .picker {\n margin-bottom: 0.5em;\n display: block;\n }\n .param {\n display: flex;\n margin-bottom: 0.5em;\n align-items: center;\n }\n label {\n margin-right: 0.5em;\n }\n\n .content span {\n margin-right: 0.25em;\n }\n\n .error-message {\n padding-left: 0.5em;\n }\n\n .variable {\n display: inline-block;\n margin: 0.25em 0em;\n margin-right: 0.25em;\n }\n\n .button-wrapper {\n background: #f9f9f9;\n border-radius: var(--curvature);\n padding: 0.5em;\n display: flex;\n flex-direction: column;\n }\n\n .button-header {\n font-weight: normal;\n margin-left: 0.25em;\n margin-bottom: -0.5em;\n font-size: 0.9em;\n color: #777;\n }\n\n .buttons {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n }\n\n .button {\n background: #fff;\n padding: 0.3em 1em;\n border: 1px solid #e6e6e6;\n border-radius: var(--curvature);\n min-height: 23px;\n display: flex;\n flex-direction: row;\n align-items: center;\n margin-right: 0.5em;\n margin-top: 0.5em;\n align-items: center;\n }\n\n .button .display {\n margin-right: 0.5em;\n background: #f9f9f9;\n padding: 0.25em 1em;\n border-radius: var(--curvature);\n }\n\n temba-textinput,\n temba-completion {\n --temba-textinput-padding: 5px 5px;\n --temba-textinput-font-size: 0.9em;\n line-height: initial;\n }\n\n .template {\n background: #fff;\n border-radius: var(--curvature);\n border: 1px solid var(--color-widget-border);\n padding: 1em;\n line-height: 2.2em;\n max-height: 50vh;\n overflow-y: auto;\n overflow-x: hidden;\n }\n `;\n }\n\n @property({ type: String })\n url: string;\n\n // initial template uuid\n @property({ type: String })\n template: string;\n\n @property({ type: Object })\n selectedTemplate: Template;\n\n @property({ type: String })\n lang = 'eng-US';\n\n @property({ type: Array })\n variables: string[];\n\n @property({ type: Object, attribute: false })\n translation: Translation;\n\n @property({ type: Boolean })\n translating: boolean;\n\n public firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changes);\n }\n\n public updated(changedProperties: Map<string, any>): void {\n super.updated(changedProperties);\n }\n\n private handleTemplateChanged(event: CustomEvent) {\n const prev = this.selectedTemplate;\n this.selectedTemplate = (event.target as any).values[0] as Template;\n const [lang, loc] = this.lang.split('-');\n if (this.selectedTemplate) {\n this.selectedTemplate.translations.forEach((translation) => {\n if (\n translation.locale === this.lang ||\n (!loc && translation.locale.split('-')[0] === lang)\n ) {\n this.translation = translation;\n // initialize our variables array\n const newVariables = new Array(\n (translation.variables || []).length\n ).fill('');\n\n if (!prev) {\n // copy our previous variables into newVariables\n if (this.variables) {\n this.variables.forEach((variable, index) => {\n newVariables[index] = variable;\n });\n }\n }\n this.variables = newVariables;\n }\n });\n } else {\n this.translation = null;\n }\n\n this.fireCustomEvent(CustomEventType.ContextChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n variables: this.variables\n });\n }\n\n private handleAttachmentsChanged(event: CustomEvent) {\n const media = event.target as MediaPicker;\n const index = parseInt(media.getAttribute('index'));\n\n if (media.attachments.length === 0) {\n this.variables[index] = '';\n } else {\n const attachment = media.attachments[0];\n if (attachment.url && attachment.content_type) {\n this.variables[index] = `${attachment.content_type}:${attachment.url}`;\n } else {\n this.variables[index] = ``;\n }\n }\n this.fireContentChange();\n }\n\n private handleVariableChanged(event: CustomEvent) {\n const target = event.target as HTMLInputElement;\n const variableIndex = parseInt(target.getAttribute('index'));\n this.variables[variableIndex] = target.value;\n this.fireContentChange();\n }\n\n private fireContentChange() {\n this.fireCustomEvent(CustomEventType.ContentChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n variables: this.variables\n });\n }\n\n private renderVariables(component: Component) {\n // create a regex match based on the variable names\n const variableRegex = new RegExp(\n `{{(${Object.keys(component.variables || []).join('|')})}}`,\n 'g'\n );\n\n let variables = null;\n const parts = component.content?.split(variableRegex) || [];\n if (parts.length > 0) {\n variables = parts.map((part, index) => {\n if (index % 2 === 0) {\n return html`<span class=\"text\">${part}</span>`;\n }\n const variableIndex = component.variables[part];\n return html`<temba-completion\n class=\"variable\"\n type=\"text\"\n value=${variableIndex < this.variables.length\n ? this.variables[variableIndex]\n : null}\n @keyup=${this.handleVariableChanged}\n name=\"${component.name}\"\n index=\"${variableIndex}\"\n placeholder=\"{{${part}}}\"\n ></temba-completion>`;\n });\n } else {\n // no content, let's do params intead\n variables = component.params.map((param) => {\n if (\n param.type === 'image' ||\n param.type === 'document' ||\n param.type === 'audio' ||\n param.type === 'video'\n ) {\n const index = Object.values(component.variables)[0];\n let attachments = [];\n if (this.variables[index]) {\n const parts = this.variables[index].split(':');\n attachments = [{ url: parts[1], content_type: parts[0] }];\n }\n\n return html`<div\n style=\"\n display: flex; \n align-items: center; \n border-radius: var(--curvature);\n ${attachments.length === 0\n ? `background-color:rgba(255,0,0,.07);`\n : ``}\n \"\n >\n <temba-media-picker\n accept=\"${param.type === 'document'\n ? 'application/pdf'\n : param.type + '/*'}\"\n max=\"1\"\n index=${index}\n icon=\"attachment_${param.type}\"\n attachments=${JSON.stringify(attachments)}\n @change=${this.handleAttachmentsChanged.bind(this)}\n ></temba-media-picker>\n <div>\n ${attachments.length == 0\n ? html`Attach ${param.type} to continue`\n : ''}\n </div>\n </div>`;\n }\n });\n }\n\n return html`<div class=\"content\">${variables}</div> `;\n }\n\n public renderComponents(components: Component[]): TemplateResult {\n const nonButtons = components\n .filter((comp) => !comp.type.startsWith('button/'))\n .map(\n (component) =>\n html`<div class=\"${component['name']}\">\n ${this.renderVariables(component)}\n </div>`\n );\n const buttonComponents = components.filter((comp) =>\n comp.type.startsWith('button/')\n );\n const buttons =\n buttonComponents.length > 0 ? this.renderButtons(buttonComponents) : null;\n return html`<div class=\"main\">${nonButtons}</div>\n <div class=\"buttons\">\n ${buttons}\n <div></div>\n </div>`;\n }\n\n public renderButtons(components): TemplateResult {\n const buttons = components.map((component) => {\n if (component.display) {\n return html`\n <div class=\"button\">\n <div class=\"display\">${component.display}</div>\n ${this.renderVariables(component)}\n </div>\n `;\n } else {\n return html`\n <div class=\"button\">${this.renderVariables(component)}</div>\n `;\n }\n });\n return html`<div class=\"button-wrapper\">\n <div class=\"button-header\">Template Buttons</div>\n <div class=\"buttons\">${buttons}</div>\n </div>`;\n }\n\n public render(): TemplateResult {\n let content = null;\n if (this.translation) {\n content = this.renderComponents(this.translation.components);\n } else {\n content = html`<div class=\"error-message\">\n No approved translation was found for current language.\n </div>`;\n }\n\n return html`\n <div>\n <temba-select\n searchable\n ?clearable=${!this.translating}\n ?disabled=${this.translating}\n valuekey=\"uuid\"\n class=\"picker\"\n value=\"${this.template}\"\n endpoint=\"${this.url}?comps_as_list=true\"\n shouldExclude=${(template) => template.status !== 'approved'}\n placeholder=\"Select a template\"\n @temba-content-changed=${this.swallowEvent}\n @change=${this.handleTemplateChanged}\n >\n </temba-select>\n\n ${this.template ? html` <div class=\"template\">${content}</div>` : null}\n </div>\n `;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"TemplateEditor.js","sourceRoot":"","sources":["../../../src/templates/TemplateEditor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAkB,IAAI,EAAE,GAAG,EAAoB,UAAU,EAAE,MAAM,KAAK,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA0BhD,MAAM,OAAO,cAAe,SAAQ,WAAW;IAA/C;;QA8HE,SAAI,GAAG,QAAQ,CAAC;IAoPlB,CAAC;IA5WC,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyGT,CAAC;IACJ,CAAC;IAwBM,YAAY,CACjB,OAA0D;QAE1D,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAEM,OAAO,CAAC,iBAAmC;QAChD,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACnC,CAAC;IAEO,qBAAqB,CAAC,KAAkB;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACnC,IAAI,CAAC,gBAAgB,GAAI,KAAK,CAAC,MAAc,CAAC,MAAM,CAAC,CAAC,CAAa,CAAC;QACpE,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;gBACzD,IACE,WAAW,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI;oBAChC,CAAC,CAAC,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,EACnD,CAAC;oBACD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;oBAC/B,iCAAiC;oBACjC,MAAM,YAAY,GAAG,IAAI,KAAK,CAC5B,CAAC,WAAW,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CACrC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBAEX,IAAI,CAAC,IAAI,EAAE,CAAC;wBACV,gDAAgD;wBAChD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;4BACnB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;gCACzC,YAAY,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;4BACjC,CAAC,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBACD,IAAI,CAAC,SAAS,GAAG,YAAY,CAAC;gBAChC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAC1B,CAAC;QAED,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,cAAc,EAAE;YACnD,QAAQ,EAAE,IAAI,CAAC,gBAAgB;YAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC,CAAC;IACL,CAAC;IAEO,wBAAwB,CAAC,KAAkB;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAqB,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QAEpD,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YACxC,IAAI,UAAU,CAAC,GAAG,IAAI,UAAU,CAAC,YAAY,EAAE,CAAC;gBAC9C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,UAAU,CAAC,YAAY,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;YACzE,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAEO,qBAAqB,CAAC,KAAkB;QAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,MAA0B,CAAC;QAChD,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC;QAC7C,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAEO,iBAAiB;QACvB,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,cAAc,EAAE;YACnD,QAAQ,EAAE,IAAI,CAAC,gBAAgB;YAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC,CAAC;IACL,CAAC;IAEO,eAAe,CAAC,SAAoB;;QAC1C,mDAAmD;QACnD,MAAM,aAAa,GAAG,IAAI,MAAM,CAC9B,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAC3D,GAAG,CACJ,CAAC;QAEF,IAAI,SAAS,GAAG,IAAI,CAAC;QAErB,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,IAAI,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7D,KAAK,GAAG,CAAA,MAAA,SAAS,CAAC,OAAO,0CAAE,KAAK,CAAC,aAAa,CAAC,KAAI,EAAE,CAAC;QACxD,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBACpC,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBACpB,OAAO,IAAI,CAAA,sBAAsB,IAAI,SAAS,CAAC;gBACjD,CAAC;gBACD,MAAM,aAAa,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBAChD,OAAO,IAAI,CAAA;;;kBAGD,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM;oBAC3C,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;oBAC/B,CAAC,CAAC,IAAI;mBACC,IAAI,CAAC,qBAAqB;kBAC3B,SAAS,CAAC,IAAI;mBACb,aAAa;2BACL,IAAI;6BACF,CAAC;YACxB,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,EAAE;gBACnE,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;gBAC/D,IACE,YAAY,CAAC,IAAI,KAAK,OAAO;oBAC7B,YAAY,CAAC,IAAI,KAAK,UAAU;oBAChC,YAAY,CAAC,IAAI,KAAK,OAAO;oBAC7B,YAAY,CAAC,IAAI,KAAK,OAAO,EAC7B,CAAC;oBACD,IAAI,WAAW,GAAG,EAAE,CAAC;oBACrB,IAAI,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC;wBAClC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;wBACvD,WAAW,GAAG,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC5D,CAAC;oBAED,OAAO,IAAI,CAAA;;;;;gBAKL,WAAW,CAAC,MAAM,KAAK,CAAC;wBAC1B,CAAC,CAAC,qCAAqC;wBACvC,CAAC,CAAC,EAAE;;;;wBAIM,YAAY,CAAC,IAAI,KAAK,UAAU;wBACxC,CAAC,CAAC,iBAAiB;wBACnB,CAAC,CAAC,YAAY,CAAC,IAAI,GAAG,IAAI;;sBAEpB,aAAa;iCACF,YAAY,CAAC,IAAI;4BACtB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;wBAC/B,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC;;;gBAGhD,WAAW,CAAC,MAAM,IAAI,CAAC;wBACvB,CAAC,CAAC,IAAI,CAAA,UAAU,YAAY,CAAC,IAAI,cAAc;wBAC/C,CAAC,CAAC,EAAE;;iBAEH,CAAC;gBACV,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAA,wBAAwB,SAAS,SAAS,CAAC;IACxD,CAAC;IAEM,gBAAgB,CAAC,UAAuB;QAC7C,MAAM,UAAU,GAAG,UAAU;aAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;aAClD,GAAG,CACF,CAAC,SAAS,EAAE,EAAE,CACZ,IAAI,CAAA,eAAe,SAAS,CAAC,MAAM,CAAC;cAChC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC;iBAC5B,CACV,CAAC;QACJ,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAClD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAChC,CAAC;QACF,MAAM,OAAO,GACX,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5E,OAAO,IAAI,CAAA,qBAAqB,UAAU;;UAEpC,OAAO;;aAEJ,CAAC;IACZ,CAAC;IAEM,aAAa,CAAC,UAAU;QAC7B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE;YAC3C,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAA;;mCAEgB,SAAS,CAAC,OAAO;cACtC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC;;SAEpC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,IAAI,CAAA;gCACa,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC;SACtD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAA;;6BAEc,OAAO;WACzB,CAAC;IACV,CAAC;IAEM,MAAM;QACX,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,IAAI,CAAA;;aAEP,CAAC;QACV,CAAC;QAED,OAAO,IAAI,CAAA;;;;uBAIQ,CAAC,IAAI,CAAC,WAAW;sBAClB,IAAI,CAAC,WAAW;;;mBAGnB,IAAI,CAAC,QAAQ;sBACV,IAAI,CAAC,GAAG;0BACJ,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,KAAK,UAAU;;mCAEnC,IAAI,CAAC,YAAY;oBAChC,IAAI,CAAC,qBAAqB;;;;UAIpC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAA,0BAA0B,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI;;KAEzE,CAAC;IACJ,CAAC;;AAhXM,gCAAiB,GAAG;IACzB,GAAG,UAAU,CAAC,iBAAiB;IAC/B,cAAc,EAAE,IAAI;CACrB,AAHuB,CAGtB;AAgHF;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2CACf;AAIZ;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDACV;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDACA;AAG3B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CACX;AAGhB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;iDACN;AAGpB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;mDACpB;AAGzB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;mDACP","sourcesContent":["import { property } from 'lit/decorators.js';\nimport { FormElement } from '../FormElement';\nimport { TemplateResult, html, css, PropertyValueMap, LitElement } from 'lit';\nimport { CustomEventType } from '../interfaces';\nimport { MediaPicker } from '../mediapicker/MediaPicker';\n\ninterface Component {\n name: string;\n type: string;\n content: string;\n variables: { [key: string]: number };\n}\n\ninterface Translation {\n locale: string;\n status: string;\n channel: { uuid: string; name: string };\n components: Component[];\n variables: { type: string }[];\n}\n\ninterface Template {\n created_on: string;\n modified_on: string;\n name: string;\n translations: Translation[];\n uuid: string;\n}\n\nexport class TemplateEditor extends FormElement {\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true\n };\n\n static get styles() {\n return css`\n .component {\n background: #fff;\n border: 1px solid var(--color-widget-border);\n border-radius: var(--curvature);\n padding: 1em;\n margin-top: 1em;\n }\n\n .content {\n margin-bottom: 1em;\n }\n\n .picker {\n margin-bottom: 0.5em;\n display: block;\n }\n .param {\n display: flex;\n margin-bottom: 0.5em;\n align-items: center;\n }\n label {\n margin-right: 0.5em;\n }\n\n .content span {\n margin-right: 0.25em;\n }\n\n .error-message {\n padding-left: 0.5em;\n }\n\n .variable {\n display: inline-block;\n margin: 0.25em 0em;\n margin-right: 0.25em;\n }\n\n .button-wrapper {\n background: #f9f9f9;\n border-radius: var(--curvature);\n padding: 0.5em;\n display: flex;\n flex-direction: column;\n }\n\n .button-header {\n font-weight: normal;\n margin-left: 0.25em;\n margin-bottom: -0.5em;\n font-size: 0.9em;\n color: #777;\n }\n\n .buttons {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n }\n\n .button {\n background: #fff;\n padding: 0.3em 1em;\n border: 1px solid #e6e6e6;\n border-radius: var(--curvature);\n min-height: 23px;\n display: flex;\n flex-direction: row;\n align-items: center;\n margin-right: 0.5em;\n margin-top: 0.5em;\n align-items: center;\n }\n\n .button .content {\n margin-bottom: 0;\n }\n\n .button .display {\n margin-right: 0.5em;\n background: #f9f9f9;\n padding: 0.25em 1em;\n border-radius: var(--curvature);\n }\n\n temba-textinput,\n temba-completion {\n --temba-textinput-padding: 5px 5px;\n --temba-textinput-font-size: 0.9em;\n line-height: initial;\n }\n\n .template {\n background: #fff;\n border-radius: var(--curvature);\n border: 1px solid var(--color-widget-border);\n padding: 1em;\n line-height: 2.2em;\n max-height: 50vh;\n overflow-y: auto;\n overflow-x: hidden;\n padding-bottom: 0;\n }\n `;\n }\n\n @property({ type: String })\n url: string;\n\n // initial template uuid\n @property({ type: String })\n template: string;\n\n @property({ type: Object })\n selectedTemplate: Template;\n\n @property({ type: String })\n lang = 'eng-US';\n\n @property({ type: Array })\n variables: string[];\n\n @property({ type: Object, attribute: false })\n translation: Translation;\n\n @property({ type: Boolean })\n translating: boolean;\n\n public firstUpdated(\n changes: PropertyValueMap<any> | Map<PropertyKey, unknown>\n ): void {\n super.firstUpdated(changes);\n }\n\n public updated(changedProperties: Map<string, any>): void {\n super.updated(changedProperties);\n }\n\n private handleTemplateChanged(event: CustomEvent) {\n const prev = this.selectedTemplate;\n this.selectedTemplate = (event.target as any).values[0] as Template;\n const [lang, loc] = this.lang.split('-');\n if (this.selectedTemplate) {\n this.selectedTemplate.translations.forEach((translation) => {\n if (\n translation.locale === this.lang ||\n (!loc && translation.locale.split('-')[0] === lang)\n ) {\n this.translation = translation;\n // initialize our variables array\n const newVariables = new Array(\n (translation.variables || []).length\n ).fill('');\n\n if (!prev) {\n // copy our previous variables into newVariables\n if (this.variables) {\n this.variables.forEach((variable, index) => {\n newVariables[index] = variable;\n });\n }\n }\n this.variables = newVariables;\n }\n });\n } else {\n this.translation = null;\n }\n\n this.fireCustomEvent(CustomEventType.ContextChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n variables: this.variables\n });\n }\n\n private handleAttachmentsChanged(event: CustomEvent) {\n const media = event.target as MediaPicker;\n const index = parseInt(media.getAttribute('index'));\n\n if (media.attachments.length === 0) {\n this.variables[index] = '';\n } else {\n const attachment = media.attachments[0];\n if (attachment.url && attachment.content_type) {\n this.variables[index] = `${attachment.content_type}:${attachment.url}`;\n } else {\n this.variables[index] = ``;\n }\n }\n this.fireContentChange();\n }\n\n private handleVariableChanged(event: CustomEvent) {\n const target = event.target as HTMLInputElement;\n const variableIndex = parseInt(target.getAttribute('index'));\n this.variables[variableIndex] = target.value;\n this.fireContentChange();\n }\n\n private fireContentChange() {\n this.fireCustomEvent(CustomEventType.ContentChanged, {\n template: this.selectedTemplate,\n translation: this.translation,\n variables: this.variables\n });\n }\n\n private renderVariables(component: Component) {\n // create a regex match based on the variable names\n const variableRegex = new RegExp(\n `{{(${Object.keys(component.variables || []).join('|')})}}`,\n 'g'\n );\n\n let variables = null;\n\n let parts = [];\n if (component.content && component.content.trim().length > 0) {\n parts = component.content?.split(variableRegex) || [];\n }\n\n if (parts.length > 0) {\n variables = parts.map((part, index) => {\n if (index % 2 === 0) {\n return html`<span class=\"text\">${part}</span>`;\n }\n const variableIndex = component.variables[part];\n return html`<temba-completion\n class=\"variable\"\n type=\"text\"\n value=${variableIndex < this.variables.length\n ? this.variables[variableIndex]\n : null}\n @keyup=${this.handleVariableChanged}\n name=\"${component.name}\"\n index=\"${variableIndex}\"\n placeholder=\"{{${part}}}\"\n ></temba-completion>`;\n });\n } else {\n variables = Object.values(component.variables).map((variableIndex) => {\n const variableSpec = this.translation.variables[variableIndex];\n if (\n variableSpec.type === 'image' ||\n variableSpec.type === 'document' ||\n variableSpec.type === 'audio' ||\n variableSpec.type === 'video'\n ) {\n let attachments = [];\n if (this.variables[variableIndex]) {\n const parts = this.variables[variableIndex].split(':');\n attachments = [{ url: parts[1], content_type: parts[0] }];\n }\n\n return html`<div\n style=\"\n display: flex; \n align-items: center; \n border-radius: var(--curvature);\n ${attachments.length === 0\n ? `background-color:rgba(255,0,0,.07);`\n : ``}\n \"\n >\n <temba-media-picker\n accept=\"${variableSpec.type === 'document'\n ? 'application/pdf'\n : variableSpec.type + '/*'}\"\n max=\"1\"\n index=${variableIndex}\n icon=\"attachment_${variableSpec.type}\"\n attachments=${JSON.stringify(attachments)}\n @change=${this.handleAttachmentsChanged.bind(this)}\n ></temba-media-picker>\n <div>\n ${attachments.length == 0\n ? html`Attach ${variableSpec.type} to continue`\n : ''}\n </div>\n </div>`;\n }\n });\n }\n\n return html`<div class=\"content\">${variables}</div> `;\n }\n\n public renderComponents(components: Component[]): TemplateResult {\n const nonButtons = components\n .filter((comp) => !comp.type.startsWith('button/'))\n .map(\n (component) =>\n html`<div class=\"${component['name']}\">\n ${this.renderVariables(component)}\n </div>`\n );\n const buttonComponents = components.filter((comp) =>\n comp.type.startsWith('button/')\n );\n const buttons =\n buttonComponents.length > 0 ? this.renderButtons(buttonComponents) : null;\n return html`<div class=\"main\">${nonButtons}</div>\n <div class=\"buttons\">\n ${buttons}\n <div></div>\n </div>`;\n }\n\n public renderButtons(components): TemplateResult {\n const buttons = components.map((component) => {\n if (component.display) {\n return html`\n <div class=\"button\">\n <div class=\"display\">${component.display}</div>\n ${this.renderVariables(component)}\n </div>\n `;\n } else {\n return html`\n <div class=\"button\">${this.renderVariables(component)}</div>\n `;\n }\n });\n return html`<div class=\"button-wrapper\">\n <div class=\"button-header\">Template Buttons</div>\n <div class=\"buttons\">${buttons}</div>\n </div>`;\n }\n\n public render(): TemplateResult {\n let content = null;\n if (this.translation) {\n content = this.renderComponents(this.translation.components);\n } else {\n content = html`<div class=\"error-message\">\n No approved translation was found for current language.\n </div>`;\n }\n\n return html`\n <div>\n <temba-select\n searchable\n ?clearable=${!this.translating}\n ?disabled=${this.translating}\n valuekey=\"uuid\"\n class=\"picker\"\n value=\"${this.template}\"\n endpoint=\"${this.url}?comps_as_list=true\"\n shouldExclude=${(template) => template.status !== 'approved'}\n placeholder=\"Select a template\"\n @temba-content-changed=${this.swallowEvent}\n @change=${this.handleTemplateChanged}\n >\n </temba-select>\n\n ${this.template ? html` <div class=\"template\">${content}</div>` : null}\n </div>\n `;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -9,7 +9,6 @@ interface Component {
|
|
|
9
9
|
type: string;
|
|
10
10
|
content: string;
|
|
11
11
|
variables: { [key: string]: number };
|
|
12
|
-
params: [{ type: string }];
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
interface Translation {
|
|
@@ -111,6 +110,10 @@ export class TemplateEditor extends FormElement {
|
|
|
111
110
|
align-items: center;
|
|
112
111
|
}
|
|
113
112
|
|
|
113
|
+
.button .content {
|
|
114
|
+
margin-bottom: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
114
117
|
.button .display {
|
|
115
118
|
margin-right: 0.5em;
|
|
116
119
|
background: #f9f9f9;
|
|
@@ -134,6 +137,7 @@ export class TemplateEditor extends FormElement {
|
|
|
134
137
|
max-height: 50vh;
|
|
135
138
|
overflow-y: auto;
|
|
136
139
|
overflow-x: hidden;
|
|
140
|
+
padding-bottom: 0;
|
|
137
141
|
}
|
|
138
142
|
`;
|
|
139
143
|
}
|
|
@@ -248,7 +252,12 @@ export class TemplateEditor extends FormElement {
|
|
|
248
252
|
);
|
|
249
253
|
|
|
250
254
|
let variables = null;
|
|
251
|
-
|
|
255
|
+
|
|
256
|
+
let parts = [];
|
|
257
|
+
if (component.content && component.content.trim().length > 0) {
|
|
258
|
+
parts = component.content?.split(variableRegex) || [];
|
|
259
|
+
}
|
|
260
|
+
|
|
252
261
|
if (parts.length > 0) {
|
|
253
262
|
variables = parts.map((part, index) => {
|
|
254
263
|
if (index % 2 === 0) {
|
|
@@ -268,18 +277,17 @@ export class TemplateEditor extends FormElement {
|
|
|
268
277
|
></temba-completion>`;
|
|
269
278
|
});
|
|
270
279
|
} else {
|
|
271
|
-
|
|
272
|
-
|
|
280
|
+
variables = Object.values(component.variables).map((variableIndex) => {
|
|
281
|
+
const variableSpec = this.translation.variables[variableIndex];
|
|
273
282
|
if (
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
283
|
+
variableSpec.type === 'image' ||
|
|
284
|
+
variableSpec.type === 'document' ||
|
|
285
|
+
variableSpec.type === 'audio' ||
|
|
286
|
+
variableSpec.type === 'video'
|
|
278
287
|
) {
|
|
279
|
-
const index = Object.values(component.variables)[0];
|
|
280
288
|
let attachments = [];
|
|
281
|
-
if (this.variables[
|
|
282
|
-
const parts = this.variables[
|
|
289
|
+
if (this.variables[variableIndex]) {
|
|
290
|
+
const parts = this.variables[variableIndex].split(':');
|
|
283
291
|
attachments = [{ url: parts[1], content_type: parts[0] }];
|
|
284
292
|
}
|
|
285
293
|
|
|
@@ -294,18 +302,18 @@ export class TemplateEditor extends FormElement {
|
|
|
294
302
|
"
|
|
295
303
|
>
|
|
296
304
|
<temba-media-picker
|
|
297
|
-
accept="${
|
|
305
|
+
accept="${variableSpec.type === 'document'
|
|
298
306
|
? 'application/pdf'
|
|
299
|
-
:
|
|
307
|
+
: variableSpec.type + '/*'}"
|
|
300
308
|
max="1"
|
|
301
|
-
index=${
|
|
302
|
-
icon="attachment_${
|
|
309
|
+
index=${variableIndex}
|
|
310
|
+
icon="attachment_${variableSpec.type}"
|
|
303
311
|
attachments=${JSON.stringify(attachments)}
|
|
304
312
|
@change=${this.handleAttachmentsChanged.bind(this)}
|
|
305
313
|
></temba-media-picker>
|
|
306
314
|
<div>
|
|
307
315
|
${attachments.length == 0
|
|
308
|
-
? html`Attach ${
|
|
316
|
+
? html`Attach ${variableSpec.type} to continue`
|
|
309
317
|
: ''}
|
|
310
318
|
</div>
|
|
311
319
|
</div>`;
|