@nyaruka/temba-components 0.26.8 → 0.26.11

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/demo/index.html +9 -1
  3. package/dist/{d08b61e5.js → fc8a85d9.js} +498 -46
  4. package/dist/index.js +498 -46
  5. package/dist/static/icons/symbol-defs.svg +48 -5
  6. package/dist/static/img/schemes/email.svg +1 -0
  7. package/dist/static/img/schemes/facebook.svg +1 -0
  8. package/dist/static/img/schemes/instagram.svg +1 -0
  9. package/dist/static/img/schemes/line.svg +1 -0
  10. package/dist/static/img/schemes/messenger.svg +1 -0
  11. package/dist/static/img/schemes/tel.svg +34 -0
  12. package/dist/static/img/schemes/telegram.svg +1 -0
  13. package/dist/static/img/schemes/twitter.svg +1 -0
  14. package/dist/static/img/schemes/viber.svg +1 -0
  15. package/dist/static/img/schemes/vk.svg +1 -0
  16. package/dist/static/img/schemes/whatsapp.svg +1 -0
  17. package/dist/sw.js +1 -1
  18. package/dist/sw.js.map +1 -1
  19. package/dist/templates/components-body.html +1 -1
  20. package/dist/templates/components-head.html +1 -1
  21. package/out-tsc/src/RapidElement.js.map +1 -1
  22. package/out-tsc/src/RefreshElement.js +28 -0
  23. package/out-tsc/src/RefreshElement.js.map +1 -0
  24. package/out-tsc/src/button/Button.js +4 -0
  25. package/out-tsc/src/button/Button.js.map +1 -1
  26. package/out-tsc/src/contacts/ContactBadges.js +97 -0
  27. package/out-tsc/src/contacts/ContactBadges.js.map +1 -0
  28. package/out-tsc/src/contacts/ContactChat.js +5 -13
  29. package/out-tsc/src/contacts/ContactChat.js.map +1 -1
  30. package/out-tsc/src/contacts/ContactFieldEditor.js +211 -0
  31. package/out-tsc/src/contacts/ContactFieldEditor.js.map +1 -0
  32. package/out-tsc/src/contacts/ContactFields.js +163 -0
  33. package/out-tsc/src/contacts/ContactFields.js.map +1 -0
  34. package/out-tsc/src/contacts/ContactGroups.js +39 -0
  35. package/out-tsc/src/contacts/ContactGroups.js.map +1 -0
  36. package/out-tsc/src/contacts/ContactName.js +40 -0
  37. package/out-tsc/src/contacts/ContactName.js.map +1 -0
  38. package/out-tsc/src/contacts/ContactStoreElement.js +44 -0
  39. package/out-tsc/src/contacts/ContactStoreElement.js.map +1 -0
  40. package/out-tsc/src/contacts/ContactUrn.js +38 -0
  41. package/out-tsc/src/contacts/ContactUrn.js.map +1 -0
  42. package/out-tsc/src/contacts/events.js +42 -4
  43. package/out-tsc/src/contacts/events.js.map +1 -1
  44. package/out-tsc/src/interfaces.js +1 -0
  45. package/out-tsc/src/interfaces.js.map +1 -1
  46. package/out-tsc/src/label/Label.js +57 -12
  47. package/out-tsc/src/label/Label.js.map +1 -1
  48. package/out-tsc/src/list/TembaMenu.js +8 -6
  49. package/out-tsc/src/list/TembaMenu.js.map +1 -1
  50. package/out-tsc/src/select/Select.js +4 -4
  51. package/out-tsc/src/select/Select.js.map +1 -1
  52. package/out-tsc/src/store/Store.js +113 -3
  53. package/out-tsc/src/store/Store.js.map +1 -1
  54. package/out-tsc/src/store/StoreElement.js +55 -0
  55. package/out-tsc/src/store/StoreElement.js.map +1 -0
  56. package/out-tsc/src/tabpane/Tab.js +14 -1
  57. package/out-tsc/src/tabpane/Tab.js.map +1 -1
  58. package/out-tsc/src/tabpane/TabPane.js +35 -0
  59. package/out-tsc/src/tabpane/TabPane.js.map +1 -1
  60. package/out-tsc/src/textinput/TextInput.js +37 -19
  61. package/out-tsc/src/textinput/TextInput.js.map +1 -1
  62. package/out-tsc/src/vectoricon/VectorIcon.js +28 -15
  63. package/out-tsc/src/vectoricon/VectorIcon.js.map +1 -1
  64. package/out-tsc/temba-modules.js +12 -0
  65. package/out-tsc/temba-modules.js.map +1 -1
  66. package/package.json +3 -3
  67. package/rollup.config.js +1 -0
  68. package/src/RapidElement.ts +0 -1
  69. package/src/RefreshElement.ts +33 -0
  70. package/src/button/Button.ts +4 -0
  71. package/src/contacts/ContactBadges.ts +104 -0
  72. package/src/contacts/ContactChat.ts +7 -16
  73. package/src/contacts/ContactFieldEditor.ts +215 -0
  74. package/src/contacts/ContactFields.ts +178 -0
  75. package/src/contacts/ContactGroups.ts +41 -0
  76. package/src/contacts/ContactName.ts +37 -0
  77. package/src/contacts/ContactStoreElement.ts +51 -0
  78. package/src/contacts/ContactUrn.ts +38 -0
  79. package/src/contacts/events.ts +41 -4
  80. package/src/interfaces.ts +5 -1
  81. package/src/label/Label.ts +55 -7
  82. package/src/list/TembaMenu.ts +7 -5
  83. package/src/select/Select.ts +4 -4
  84. package/src/store/Store.ts +147 -3
  85. package/src/store/StoreElement.ts +71 -0
  86. package/src/tabpane/Tab.ts +14 -1
  87. package/src/tabpane/TabPane.ts +36 -0
  88. package/src/textinput/TextInput.ts +50 -29
  89. package/src/vectoricon/VectorIcon.ts +33 -15
  90. package/static/css/temba-components.css +3 -0
  91. package/static/icons/Read Me.txt +1 -1
  92. package/static/icons/SVG/bookmark-filled.svg +5 -0
  93. package/static/icons/SVG/bookmark.svg +1 -1
  94. package/static/icons/SVG/calendar1.svg +5 -0
  95. package/static/icons/SVG/corner-down-left.svg +5 -0
  96. package/static/icons/SVG/external-link1.svg +5 -0
  97. package/static/icons/SVG/globe.svg +5 -0
  98. package/static/icons/SVG/language.svg +5 -0
  99. package/static/icons/SVG/more-horizontal.svg +5 -0
  100. package/static/icons/SVG/refresh-cw.svg +5 -0
  101. package/static/icons/SVG/search.svg +5 -0
  102. package/static/icons/demo-external-svg.html +235 -162
  103. package/static/icons/demo-files/demo.css +6 -3
  104. package/static/icons/demo.html +283 -167
  105. package/static/icons/selection.json +569 -339
  106. package/static/icons/style.css +4 -0
  107. package/static/icons/symbol-defs.svg +48 -5
  108. package/static/img/schemes/email.svg +1 -0
  109. package/static/img/schemes/facebook.svg +1 -0
  110. package/static/img/schemes/instagram.svg +1 -0
  111. package/static/img/schemes/line.svg +1 -0
  112. package/static/img/schemes/messenger.svg +1 -0
  113. package/static/img/schemes/tel.svg +34 -0
  114. package/static/img/schemes/telegram.svg +1 -0
  115. package/static/img/schemes/twitter.svg +1 -0
  116. package/static/img/schemes/viber.svg +1 -0
  117. package/static/img/schemes/vk.svg +1 -0
  118. package/static/img/schemes/whatsapp.svg +1 -0
  119. package/temba-modules.ts +13 -0
@@ -0,0 +1,215 @@
1
+ import { css, html, TemplateResult } from 'lit';
2
+ import { property } from 'lit/decorators';
3
+ import { CustomEventType } from '../interfaces';
4
+ import { RapidElement } from '../RapidElement';
5
+ import { TextInput } from '../textinput/TextInput';
6
+
7
+ export class ContactFieldEditor extends RapidElement {
8
+ @property({ type: String })
9
+ key: string;
10
+
11
+ @property({ type: String })
12
+ value: string;
13
+
14
+ @property({ type: String })
15
+ name: string;
16
+
17
+ @property({ type: String })
18
+ type: string;
19
+
20
+ @property({ type: String })
21
+ icon = navigator.clipboard ? 'copy' : '';
22
+
23
+ @property({ type: String })
24
+ iconClass = '';
25
+
26
+ static get styles() {
27
+ return css`
28
+ .prefix {
29
+ background: rgba(0, 0, 0, 0.05);
30
+ border-top-left-radius: var(--curvature-widget);
31
+ border-bottom-left-radius: var(--curvature-widget);
32
+ color: #888;
33
+ cursor: pointer;
34
+ width: 200px;
35
+ white-space: nowrap;
36
+ overflow: hidden;
37
+ text-overflow: ellipsis;
38
+ display: flex;
39
+ padding: 0em 0.5em;
40
+ }
41
+
42
+ .wrapper {
43
+ margin-bottom: -1px;
44
+ }
45
+
46
+ .prefix .name {
47
+ padding: 0.5em 0em;
48
+ color: #888;
49
+ width: 200px;
50
+ white-space: nowrap;
51
+ overflow: hidden;
52
+ text-overflow: ellipsis;
53
+ }
54
+
55
+ .postfix {
56
+ display: flex;
57
+ align-items: stretch;
58
+ }
59
+
60
+ .popper {
61
+ padding: 0.5em 0.75em;
62
+ background: rgba(240, 240, 240, 1);
63
+ border-top-right-radius: var(--curvature-widget);
64
+ border-bottom-right-radius: var(--curvature-widget);
65
+ --icon-color: #888;
66
+ opacity: 0;
67
+ cursor: default;
68
+ transform: scale(0.5);
69
+ transition: all 300ms ease-in-out;
70
+ display: flex;
71
+ align-items: stretch;
72
+ z-index: 1000;
73
+ }
74
+
75
+ temba-icon[name='calendar'] {
76
+ --icon-color: rgba(0, 0, 0, 0.2);
77
+ }
78
+
79
+ temba-icon:hover {
80
+ --icon-color: rgba(0, 0, 0, 0.5);
81
+ }
82
+
83
+ temba-icon {
84
+ cursor: pointer;
85
+ --icon-color: rgba(0, 0, 0, 0.3);
86
+ }
87
+
88
+ temba-textinput:hover .popper {
89
+ opacity: 1;
90
+ transform: scale(1);
91
+ }
92
+
93
+ temba-textinput:focus .popper {
94
+ opacity: 1;
95
+ transform: scale(1);
96
+ }
97
+
98
+ .unset temba-textinput:focus .popper,
99
+ .unset temba-textinput:hover .popper {
100
+ opacity: 0;
101
+ }
102
+
103
+ .copy.clicked temba-icon {
104
+ transform: scale(1.2);
105
+ }
106
+
107
+ temba-icon {
108
+ transition: all 200ms ease-in-out;
109
+ }
110
+
111
+ temba-icon[name='search'] {
112
+ margin-right: 1em;
113
+ }
114
+ `;
115
+ }
116
+
117
+ connectedCallback(): void {
118
+ super.connectedCallback();
119
+ this.handleInput = this.handleInput.bind(this);
120
+ this.handleSubmit = this.handleSubmit.bind(this);
121
+ }
122
+
123
+ public handleIconClick(evt: MouseEvent) {
124
+ const ele = evt.target as HTMLDivElement;
125
+ const icon = ele.getAttribute('name');
126
+ const input = this.shadowRoot.querySelector('temba-textinput') as TextInput;
127
+
128
+ if (icon === 'copy') {
129
+ if (navigator.clipboard) {
130
+ this.iconClass = 'clicked';
131
+ navigator.clipboard.writeText(input.getDisplayValue()).then(() => {
132
+ window.setTimeout(() => {
133
+ this.iconClass = '';
134
+ }, 300);
135
+ });
136
+ }
137
+ }
138
+
139
+ if (icon === 'search') {
140
+ this.fireCustomEvent(CustomEventType.ButtonClicked, {
141
+ key: this.key,
142
+ value: this.value,
143
+ });
144
+ }
145
+
146
+ evt.preventDefault();
147
+ evt.stopPropagation();
148
+ }
149
+
150
+ public handleSubmit() {
151
+ const input = this.shadowRoot.querySelector('temba-textinput') as TextInput;
152
+ if (input.value !== this.value) {
153
+ this.value = input.value;
154
+ this.fireEvent('change');
155
+ }
156
+ this.icon = navigator.clipboard ? 'copy' : '';
157
+ }
158
+
159
+ public handleChange(evt: Event) {
160
+ evt.preventDefault();
161
+ evt.stopPropagation();
162
+ }
163
+
164
+ public handleInput(evt: KeyboardEvent) {
165
+ if (evt.key === 'Enter') {
166
+ const input = evt.currentTarget as TextInput;
167
+ input.blur();
168
+ }
169
+ }
170
+
171
+ public render(): TemplateResult {
172
+ return html`
173
+ <div class="wrapper ${this.value ? 'set' : 'unset'}">
174
+ <temba-textinput
175
+ value="${this.value ? this.value : ''}"
176
+ ?datetimepicker=${this.type === 'datetime'}
177
+ @blur=${this.handleSubmit}
178
+ @keydown=${this.handleInput}
179
+ @change=${this.handleChange}
180
+ >
181
+ <div class="prefix" slot="prefix">
182
+ <div class="name">${this.name}</div>
183
+ ${this.type === 'datetime'
184
+ ? html`<div style="position: relative; padding-top: .75em;">
185
+ <temba-icon name="calendar" animateclick="pulse" />
186
+ </div>`
187
+ : null}
188
+ </div>
189
+
190
+ <div class="postfix">
191
+ <div
192
+ class="popper ${this.iconClass}"
193
+ @click=${this.handleIconClick}
194
+ >
195
+ ${this.value
196
+ ? html`
197
+ <temba-icon
198
+ name="search"
199
+ animateclick="pulse"
200
+ ></temba-icon>
201
+ </div>
202
+ `
203
+ : null}
204
+ <temba-icon
205
+ name="${this.icon}"
206
+ animatechange="spin"
207
+ animateclick="pulse"
208
+ ></temba-icon>
209
+ </div>
210
+ </div>
211
+ </temba-textinput>
212
+ </div>
213
+ `;
214
+ }
215
+ }
@@ -0,0 +1,178 @@
1
+ import { css, html, PropertyValueMap, TemplateResult } from 'lit';
2
+ import { property } from 'lit/decorators';
3
+ import { postJSON } from '../utils';
4
+ import { ContactFieldEditor } from './ContactFieldEditor';
5
+ import { ContactStoreElement } from './ContactStoreElement';
6
+ import { Checkbox } from '../checkbox/Checkbox';
7
+
8
+ const MIN_FOR_FILTER = 10;
9
+
10
+ export class ContactFields extends ContactStoreElement {
11
+ static get styles() {
12
+ return css`
13
+ :host {
14
+ --curvature-widget: 0px;
15
+ border-radius: 6px;
16
+ }
17
+
18
+ .field {
19
+ display: flex;
20
+ margin: 0.3em 0.3em;
21
+ box-shadow: 0 0 0.2em rgba(0, 0, 0, 0.15);
22
+ border-radius: 0px;
23
+ align-items: center;
24
+ overflow: hidden;
25
+ }
26
+
27
+ .show-all .unset {
28
+ display: block;
29
+ }
30
+
31
+ .unset {
32
+ display: none;
33
+ }
34
+
35
+ .field:hover {
36
+ box-shadow: 1px 1px 6px 2px rgba(0, 0, 0, 0.05),
37
+ 0px 0px 0px 2px var(--color-link-primary);
38
+ cursor: pointer;
39
+ }
40
+
41
+ .label {
42
+ padding: 0.25em 1em;
43
+ border-top-left-radius: 0px;
44
+ border-bottom-left-radius: 0px;
45
+ color: #777;
46
+ font-size: 0.9em;
47
+ font-weight: 400;
48
+ box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.1) inset;
49
+ }
50
+
51
+ .value {
52
+ --icon-color: #ddd;
53
+ max-width: 150px;
54
+ white-space: nowrap;
55
+ overflow: hidden;
56
+ text-overflow: ellipsis;
57
+ padding: 0.25em 1em;
58
+ border-top-right-radius: 0px;
59
+ border-bottom-right-radius: 0px;
60
+ font-size: 0.9em;
61
+ }
62
+
63
+ temba-contact-field {
64
+ }
65
+
66
+ .footer {
67
+ margin-bottom: 0;
68
+ display: flex;
69
+ background: #fff;
70
+ align-items: center;
71
+ margin-top: 0.5em;
72
+ }
73
+ `;
74
+ }
75
+
76
+ @property({ type: Boolean })
77
+ pinned: boolean;
78
+
79
+ @property({ type: Boolean })
80
+ system: boolean;
81
+
82
+ @property({ type: Boolean })
83
+ dirty: boolean;
84
+
85
+ @property({ type: Boolean })
86
+ showAll: boolean;
87
+
88
+ connectedCallback(): void {
89
+ super.connectedCallback();
90
+ this.handleFieldChanged = this.handleFieldChanged.bind(this);
91
+ }
92
+
93
+ protected updated(
94
+ changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
95
+ ): void {
96
+ super.updated(changes);
97
+ if (changes.has('data')) {
98
+ if (Object.keys(this.data.fields).length <= MIN_FOR_FILTER) {
99
+ this.showAll = true;
100
+ }
101
+ }
102
+ }
103
+
104
+ public handleFieldChanged(evt: InputEvent) {
105
+ const field = evt.currentTarget as ContactFieldEditor;
106
+ this.data.fields[field.key] = field.value;
107
+ postJSON('/api/v2/contacts.json?uuid=' + this.data.uuid, {
108
+ fields: { [field.key]: field.value },
109
+ }).then(() => {
110
+ this.refresh();
111
+ });
112
+ }
113
+
114
+ public handleToggle(evt: Event) {
115
+ const checkbox = evt.currentTarget as Checkbox;
116
+ console.log(checkbox.checked);
117
+ this.showAll = checkbox.checked;
118
+ }
119
+
120
+ public render(): TemplateResult {
121
+ if (this.data) {
122
+ const fieldsToShow = Object.entries(this.data.fields)
123
+ .filter((entry: [string, string]) => {
124
+ return (
125
+ (this.pinned && this.store.getContactField(entry[0]).pinned) ||
126
+ (!this.pinned && !this.store.getContactField(entry[0]).pinned)
127
+ );
128
+ })
129
+ .sort((a: [string, string], b: [string, string]) => {
130
+ const [ak] = a;
131
+ const [bk] = b;
132
+ /* if (av && !bv) {
133
+ return -1;
134
+ }
135
+
136
+ if (bv && !av) {
137
+ return 1;
138
+ }*/
139
+
140
+ return ak.localeCompare(bk);
141
+ });
142
+
143
+ const fields = fieldsToShow.map((entry: [string, string]) => {
144
+ const [k, v] = entry;
145
+ const field = this.store.getContactField(k);
146
+ return html`<temba-contact-field
147
+ class=${v ? 'set' : 'unset'}
148
+ key=${field.key}
149
+ name=${field.label}
150
+ value=${v}
151
+ type=${field.value_type}
152
+ @change=${this.handleFieldChanged}
153
+ ></temba-contact-field>`;
154
+ });
155
+
156
+ return html`
157
+ <div class="${this.showAll || this.pinned ? 'show-all' : ''}">
158
+ ${fields}
159
+ </div>
160
+
161
+ ${!this.pinned && Object.keys(this.data.fields).length >= MIN_FOR_FILTER
162
+ ? html` <div class="footer">
163
+ <div style="flex-grow: 1"></div>
164
+ <div>
165
+ <temba-checkbox
166
+ ?checked=${this.showAll}
167
+ @change=${this.handleToggle}
168
+ label="Show All"
169
+ />
170
+ </div>
171
+ </div>`
172
+ : null}
173
+ `;
174
+ }
175
+
176
+ return null;
177
+ }
178
+ }
@@ -0,0 +1,41 @@
1
+ import { css, html, TemplateResult } from 'lit';
2
+ import { Group } from '../interfaces';
3
+ import { ContactStoreElement } from './ContactStoreElement';
4
+
5
+ export class ContactGroups extends ContactStoreElement {
6
+ static get styles() {
7
+ return css`
8
+ .groups {
9
+ display: flex;
10
+ flex-wrap: wrap;
11
+ }
12
+
13
+ temba-label {
14
+ margin: 0.3em;
15
+ }
16
+ `;
17
+ }
18
+
19
+ public render(): TemplateResult {
20
+ return html`${this.data
21
+ ? html`
22
+ <div class="groups">
23
+ ${this.data.groups.map((group: Group) => {
24
+ return html`
25
+ <temba-label
26
+ onclick="goto(event)"
27
+ href="/contact/filter/${group.uuid}/"
28
+ icon=${group.is_dynamic ? 'atom' : 'users'}
29
+ clickable
30
+ light
31
+ shadow
32
+ >
33
+ ${group.name}
34
+ </temba-label>
35
+ `;
36
+ })}
37
+ </div>
38
+ `
39
+ : null}`;
40
+ }
41
+ }
@@ -0,0 +1,37 @@
1
+ import { css, html, TemplateResult } from 'lit';
2
+ import { property } from 'lit/decorators';
3
+ import { ContactStoreElement } from './ContactStoreElement';
4
+
5
+ export class ContactName extends ContactStoreElement {
6
+ @property({ type: Number, attribute: 'icon-size' })
7
+ size = 20;
8
+
9
+ static get styles() {
10
+ return css`
11
+ :host {
12
+ display: flex;
13
+ }
14
+
15
+ temba-urn {
16
+ margin-right: 0.2em;
17
+ margin-top: 2px;
18
+ }
19
+ `;
20
+ }
21
+
22
+ public render(): TemplateResult {
23
+ if (this.data) {
24
+ const urn =
25
+ this.data.urns.length > 0
26
+ ? html`<temba-urn
27
+ size=${this.size}
28
+ urn="${this.data.urns[0]}"
29
+ ></temba-urn>`
30
+ : null;
31
+ return html`
32
+ ${urn}
33
+ <div class="name">${this.data.name}</div>
34
+ `;
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,51 @@
1
+ import { PropertyValueMap } from 'lit';
2
+ import { property } from 'lit/decorators';
3
+ import { Contact, Group } from '../interfaces';
4
+ import { StoreElement } from '../store/StoreElement';
5
+
6
+ export class ContactStoreElement extends StoreElement {
7
+ @property({ type: String })
8
+ contact: string;
9
+
10
+ @property({ type: Object, attribute: false })
11
+ data: Contact;
12
+
13
+ prepareData(data: any) {
14
+ if (data && data.length > 0) {
15
+ data = data[0];
16
+ data.groups.forEach((group: Group) => {
17
+ group.is_dynamic = this.store.isDynamicGroup(group.uuid);
18
+ });
19
+
20
+ data.groups.sort((a: Group, b: Group) => {
21
+ if (!a.is_dynamic || !b.is_dynamic) {
22
+ if (a.is_dynamic) {
23
+ return -1;
24
+ }
25
+
26
+ if (b.is_dynamic) {
27
+ return 1;
28
+ }
29
+ }
30
+
31
+ return a.name.localeCompare(b.name);
32
+ });
33
+
34
+ return data;
35
+ }
36
+ return null;
37
+ }
38
+
39
+ protected updated(
40
+ changes: PropertyValueMap<any> | Map<PropertyKey, unknown>
41
+ ): void {
42
+ super.updated(changes);
43
+ if (changes.has('contact')) {
44
+ if (this.contact) {
45
+ this.url = `/api/v2/contacts.json?uuid=${this.contact}`;
46
+ } else {
47
+ this.url = null;
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,38 @@
1
+ import { css, html, TemplateResult } from 'lit';
2
+ import { property } from 'lit/decorators';
3
+ import { RapidElement } from '../RapidElement';
4
+
5
+ export class ContactUrn extends RapidElement {
6
+ @property({ type: String })
7
+ urn: string;
8
+
9
+ @property({ type: Number })
10
+ size: number;
11
+
12
+ static get styles() {
13
+ return css`
14
+ .urn {
15
+ box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.04) inset;
16
+ padding: 3px;
17
+ border: 1px solid #ddd;
18
+ border-radius: 18rem;
19
+ background: #eee;
20
+ margin-right: 0.2em;
21
+ }
22
+ `;
23
+ }
24
+
25
+ public render(): TemplateResult {
26
+ const scheme = this.urn.split(':')[0];
27
+ return html`
28
+ <img
29
+ class="urn"
30
+ width="${this.size}em"
31
+ height="${this.size}em"
32
+ src="${this.prefix ||
33
+ (window as any).static_url ||
34
+ '/static/'}img/schemes/${scheme}.svg"
35
+ />
36
+ `;
37
+ }
38
+ }
@@ -436,6 +436,10 @@ export const getEventStyles = () => {
436
436
  .assigned .attn {
437
437
  color: #777;
438
438
  }
439
+
440
+ .attachments {
441
+ margin-top: 1em;
442
+ }
439
443
  `;
440
444
  };
441
445
 
@@ -674,12 +678,45 @@ export const renderAttachment = (attachment: string): TemplateResult => {
674
678
  inner = html`<div class="linked" onclick="goto(event)" href="${url}"><img src="${url}" style="width:100%;height:auto;display:block"></img></a>`;
675
679
  } else if (ext === 'pdf') {
676
680
  return html`<div
677
- style="width:100%;height:300px;border-radius:var(--curvature);box-shadow:0px 0px 10px -1px rgb(160 160 160);overflow:hidden"
678
- ><embed src="${url}#view=Fit" type="application/pdf" frameBorder="0" scrolling="auto" height="100%" width="100%"></embed></div>`;
681
+ style="width:100%;height:300px;border-radius:var(--curvature);box-shadow:0px 0px 12px 0px rgba(0,0,0,.1), 0px 0px 2px 0px rgba(0,0,0,.15);overflow:hidden"
682
+ ><embed src="${url}#view=Fit" type="application/pdf" frameBorder="0" scrolling="auto" height="100%" width="100%"></embed></div>`;
679
683
  } else if (mediaType === 'video') {
680
- return html`<video max-width="400px" height="auto" controls="controls">
684
+ return html`<video
685
+ style="border-radius:var(--curvature);box-shadow:0px 0px 12px 0px rgba(0,0,0,.1), 0px 0px 2px 0px rgba(0,0,0,.15);"
686
+ max-width="400px"
687
+ height="auto"
688
+ controls="controls"
689
+ >
681
690
  <source src="${url}" type="video/mp4" />
682
691
  </video> `;
692
+ } else if (mediaType === 'audio') {
693
+ return html`<audio
694
+ style="border-radius: 99px; box-shadow:0px 0px 12px 0px rgba(0,0,0,.1), 0px 0px 2px 0px rgba(0,0,0,.15);"
695
+ src="${url}"
696
+ type="${attType}"
697
+ controls
698
+ >
699
+ <a target="_" href="${url}">${url}</a>
700
+ </audio>`;
701
+ } else if (attType === 'geo') {
702
+ const [lat, long] = url.split(',');
703
+ const latFloat = parseFloat(lat);
704
+ const longFloat = parseFloat(long);
705
+ const geo = `${lat}000000%2C${long}000000`;
706
+
707
+ return html` <iframe
708
+ style="border-radius: var(--curvature);box-shadow:0px 0px 12px 0px rgba(0,0,0,.1), 0px 0px 2px 0px rgba(0,0,0,.15);"
709
+ width="300"
710
+ height="300"
711
+ frameborder="0"
712
+ scrolling="no"
713
+ marginheight="0"
714
+ marginwidth="0"
715
+ src="https://www.openstreetmap.org/export/embed.html?bbox=${longFloat -
716
+ 0.005}000000%2C${latFloat - 0.005}%2C${longFloat +
717
+ 0.005}000000%2C${latFloat +
718
+ 0.005}000000&amp;layer=mapnik&amp;marker=${geo}"
719
+ ></iframe>`;
683
720
  } else {
684
721
  return html`<div style="display:flex">
685
722
  <temba-icon name="download"></temba-icon>
@@ -688,7 +725,7 @@ export const renderAttachment = (attachment: string): TemplateResult => {
688
725
  }
689
726
 
690
727
  return html`<div
691
- style="width:100%;max-width:300px;border-radius:var(--curvature); box-shadow:0px 0px 10px -1px rgb(160 160 160);overflow:hidden"
728
+ style="width:100%;max-width:300px;border-radius:var(--curvature); box-shadow:0px 0px 6px 0px rgba(0,0,0,.15);overflow:hidden"
692
729
  >
693
730
  ${inner}
694
731
  </div>`;
package/src/interfaces.ts CHANGED
@@ -43,6 +43,7 @@ export interface ContactField {
43
43
  label: string;
44
44
  value_type: string;
45
45
  pinned: boolean;
46
+ priority: number;
46
47
  }
47
48
 
48
49
  export interface ContactGroup {
@@ -83,13 +84,15 @@ export interface Contact {
83
84
  stopped: boolean;
84
85
  blocked: boolean;
85
86
  urns: string[];
86
- lang: string;
87
+ language?: string;
87
88
  fields: { [key: string]: string };
88
89
  groups: Group[];
89
90
  modified_on: string;
90
91
  created_on: string;
91
92
  last_seen_on: string;
93
+ status: string;
92
94
 
95
+ flow?: ObjectReference;
93
96
  last_msg?: Msg;
94
97
  direction?: string;
95
98
  ticket: {
@@ -178,4 +181,5 @@ export enum CustomEventType {
178
181
  Submitted = 'temba-submitted',
179
182
  Redirected = 'temba-redirected',
180
183
  NoPath = 'temba-no-path',
184
+ StoreUpdated = 'temba-store-updated',
181
185
  }