@bagelink/vue 0.0.439 → 0.0.447
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AccordionItem.vue.d.ts.map +1 -1
- package/dist/components/DataPreview.vue.d.ts +6 -0
- package/dist/components/DataPreview.vue.d.ts.map +1 -1
- package/dist/components/Flag.vue.d.ts +16 -0
- package/dist/components/Flag.vue.d.ts.map +1 -0
- package/dist/components/Modal.vue.d.ts.map +1 -1
- package/dist/components/TableSchema.vue.d.ts +6 -5
- package/dist/components/TableSchema.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/FileUpload.vue.d.ts +166 -2
- package/dist/components/form/inputs/FileUpload.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TelInput.vue.d.ts +165 -0
- package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -0
- package/dist/components/form/inputs/TextInput.vue.d.ts +2 -5
- package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/index.d.ts +1 -0
- package/dist/components/form/inputs/index.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
- package/dist/index.cjs +6513 -1544
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +6513 -1544
- package/dist/style.css +1877 -93
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/dist/utils/allCountries.d.ts +11 -0
- package/dist/utils/allCountries.d.ts.map +1 -0
- package/package.json +3 -4
- package/src/components/AccordionItem.vue +8 -5
- package/src/components/DataPreview.vue +14 -4
- package/src/components/Flag.vue +1349 -0
- package/src/components/Modal.vue +26 -9
- package/src/components/ModalForm.vue +1 -1
- package/src/components/PageTitle.vue +8 -1
- package/src/components/TableSchema.vue +34 -2
- package/src/components/form/inputs/FileUpload.vue +74 -61
- package/src/components/form/inputs/SelectInput.vue +6 -0
- package/src/components/form/inputs/TelInput.vue +401 -0
- package/src/components/form/inputs/TextInput.vue +16 -53
- package/src/components/form/inputs/index.ts +1 -0
- package/src/components/index.ts +1 -0
- package/src/components/layout/Tabs.vue +1 -0
- package/src/index.ts +1 -0
- package/src/styles/appearance.css +610 -0
- package/src/styles/buttons.css +8 -0
- package/src/styles/layout.css +46 -1
- package/src/styles/mobilLayout.css +37 -0
- package/src/styles/modal.css +5 -2
- package/src/styles/text.css +39 -0
- package/src/utils/BagelFormUtils.ts +11 -1
- package/src/utils/allCountries.ts +337 -0
- package/src/components/whatsapp/form/MsgTemplate.vue +0 -224
- package/src/components/whatsapp/form/TextVariableExamples.vue +0 -79
- package/src/components/whatsapp/index.ts +0 -2
- package/src/components/whatsapp/interfaces.ts +0 -58
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="main-content">
|
|
3
|
-
<PageTitle>Whatsapp Template</PageTitle>
|
|
4
|
-
<div class="view-wrapper bgl_card thin">
|
|
5
|
-
<div class="whatsapp-wrap">
|
|
6
|
-
<div class="create-template-form">
|
|
7
|
-
<BagelForm :schema="whatsappTemplateSchema" v-model="localWhatsappData" @submit="upsertTemplate" />
|
|
8
|
-
</div>
|
|
9
|
-
<div class="whatsapp-preview" :class="{ whatsappHebrew: localWhatsappData?.language === 'he' }">
|
|
10
|
-
{{ previewLabel }}
|
|
11
|
-
<div class="whatsapp-msg">
|
|
12
|
-
<b>{{
|
|
13
|
-
localWhatsappData?.headerText?.replace(regex, replaceHeader)
|
|
14
|
-
}}</b>
|
|
15
|
-
<p class="whatsapp-body">
|
|
16
|
-
{{ localWhatsappData?.bodyText?.replace(regex, replaceBody) }}
|
|
17
|
-
</p>
|
|
18
|
-
<p class="whatsapp-footer">
|
|
19
|
-
{{ localWhatsappData?.footerText }}
|
|
20
|
-
</p>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<script setup lang="ts">
|
|
29
|
-
import { onMounted } from 'vue';
|
|
30
|
-
|
|
31
|
-
import type { RouteLocationNormalizedLoaded, Router } from 'vue-router';
|
|
32
|
-
import {
|
|
33
|
-
useBagel, PageTitle, BagelForm, BglFormSchemaT,
|
|
34
|
-
} from '@bagelink/vue';
|
|
35
|
-
import {
|
|
36
|
-
BodyComponent,
|
|
37
|
-
HeaderComponent,
|
|
38
|
-
LocalTemplateData,
|
|
39
|
-
ServerTemplateData,
|
|
40
|
-
FooterComponent,
|
|
41
|
-
} from '../interfaces';
|
|
42
|
-
|
|
43
|
-
const props = withDefaults(
|
|
44
|
-
defineProps<{
|
|
45
|
-
whatsappTemplateSchema: BglFormSchemaT<LocalTemplateData>;
|
|
46
|
-
router: Router;
|
|
47
|
-
route: RouteLocationNormalizedLoaded;
|
|
48
|
-
previewLabel?: string;
|
|
49
|
-
}>(),
|
|
50
|
-
{ previewLabel: 'Preview' },
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const bagel = useBagel();
|
|
54
|
-
|
|
55
|
-
const regex = /\{\{(\d+)}}/g;
|
|
56
|
-
let localWhatsappData = $ref<LocalTemplateData>();
|
|
57
|
-
|
|
58
|
-
const serverToLocal = (data: ServerTemplateData): LocalTemplateData => ({
|
|
59
|
-
id: data.id,
|
|
60
|
-
status: data.status,
|
|
61
|
-
name: data.name,
|
|
62
|
-
language: data.language,
|
|
63
|
-
headerText: data.components.find(
|
|
64
|
-
(c): c is HeaderComponent => c.type === 'HEADER',
|
|
65
|
-
)?.text,
|
|
66
|
-
bodyText: data.components.find((c): c is BodyComponent => c.type === 'BODY')
|
|
67
|
-
?.text,
|
|
68
|
-
bodyExamples: data.components.find(
|
|
69
|
-
(c): c is BodyComponent => c.type === 'BODY',
|
|
70
|
-
)?.example?.body_text[0],
|
|
71
|
-
footerText: data.components.find(
|
|
72
|
-
(c): c is FooterComponent => c.type === 'FOOTER',
|
|
73
|
-
)?.text,
|
|
74
|
-
category: data.category,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const localToServer = (data: LocalTemplateData) => {
|
|
78
|
-
const obj: any = {};
|
|
79
|
-
obj.language = data.language;
|
|
80
|
-
if (data.id) obj.id = data.id;
|
|
81
|
-
obj.name = data.name;
|
|
82
|
-
obj.components = [];
|
|
83
|
-
obj.category = data.category;
|
|
84
|
-
if (data.headerText) {
|
|
85
|
-
obj.components.push({
|
|
86
|
-
type: 'HEADER',
|
|
87
|
-
format: 'TEXT',
|
|
88
|
-
text: data.headerText,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
if (data.bodyText) {
|
|
92
|
-
const bodyComponent: BodyComponent = { type: 'BODY', text: data.bodyText };
|
|
93
|
-
if (data.bodyExamples) { bodyComponent.example = { body_text: [data.bodyExamples] }; }
|
|
94
|
-
obj.components.push(bodyComponent);
|
|
95
|
-
}
|
|
96
|
-
if (data.footerText) { obj.components.push({ type: 'FOOTER', text: data.footerText }); }
|
|
97
|
-
return obj;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const loadTemplateData = async () => {
|
|
101
|
-
const template_name = props.route.params.id;
|
|
102
|
-
if (template_name) {
|
|
103
|
-
const res = await bagel.get(
|
|
104
|
-
`communication/whatsapp/get_template_by_name/${template_name}`,
|
|
105
|
-
);
|
|
106
|
-
localWhatsappData = serverToLocal(res.data[0]);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const replaceHeader = (match: any) => {
|
|
111
|
-
const index = +match[2];
|
|
112
|
-
const example = localWhatsappData?.headerExamples?.[index - 1];
|
|
113
|
-
return example || match;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const replaceBody = (match: any) => {
|
|
117
|
-
const index = +match[2];
|
|
118
|
-
const example = localWhatsappData?.bodyExamples?.[index - 1];
|
|
119
|
-
return example || match;
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const upsertTemplate = async () => {
|
|
123
|
-
if (!localWhatsappData) return;
|
|
124
|
-
const payload = localToServer(localWhatsappData);
|
|
125
|
-
console.log(payload);
|
|
126
|
-
if (payload.id) {
|
|
127
|
-
await bagel.put(
|
|
128
|
-
`communication/whatsapp/update_template/${payload.id}`,
|
|
129
|
-
payload,
|
|
130
|
-
);
|
|
131
|
-
} else {
|
|
132
|
-
await bagel.post('communication/whatsapp/create_template', payload);
|
|
133
|
-
void props.router.push(`/whatsapp/template/${payload.name}`);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
onMounted(loadTemplateData);
|
|
138
|
-
</script>
|
|
139
|
-
|
|
140
|
-
<style scoped>
|
|
141
|
-
.btn-end {
|
|
142
|
-
text-align: end;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.whatsapp-preview {
|
|
146
|
-
direction: ltr;
|
|
147
|
-
width: 400px;
|
|
148
|
-
padding: 1rem;
|
|
149
|
-
height: auto;
|
|
150
|
-
margin-top: 1rem;
|
|
151
|
-
/* border-left: 1px solid var(--border-color); */
|
|
152
|
-
margin-left: 20px;
|
|
153
|
-
position: sticky;
|
|
154
|
-
top: 15px;
|
|
155
|
-
flex: 1 1 40%;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.whatsapp-wrap {
|
|
159
|
-
display: flex;
|
|
160
|
-
gap: 1rem;
|
|
161
|
-
max-width: 1200px;
|
|
162
|
-
overflow: auto;
|
|
163
|
-
height: 100%;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.create-template-form {
|
|
167
|
-
flex: 1 0 50%;
|
|
168
|
-
min-width: 300px;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.whatsapp-msg {
|
|
172
|
-
background: var(--whatsapp-green);
|
|
173
|
-
border-radius: 0.5rem;
|
|
174
|
-
border-start-start-radius: 0px;
|
|
175
|
-
padding: 10px;
|
|
176
|
-
line-height: 1.5;
|
|
177
|
-
margin-top: 1rem;
|
|
178
|
-
filter: drop-shadow(0 0px 2px var(--bgl-shadow));
|
|
179
|
-
position: relative;
|
|
180
|
-
min-height: 30px;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
.whatsapp-msg::after {
|
|
184
|
-
content: '';
|
|
185
|
-
inset-inline-start: -5px;
|
|
186
|
-
border-radius: 0.1rem;
|
|
187
|
-
transform: skew(45deg);
|
|
188
|
-
top: 0;
|
|
189
|
-
height: 8px;
|
|
190
|
-
width: 8px;
|
|
191
|
-
background: var(--whatsapp-green);
|
|
192
|
-
position: absolute;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.whatsapp-body {
|
|
196
|
-
margin: 2px 0;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
.whatsapp-footer {
|
|
200
|
-
margin: 0;
|
|
201
|
-
opacity: 0.6;
|
|
202
|
-
font-size: 0.8rem;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
.whatsappHebrew {
|
|
206
|
-
direction: rtl;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.whatsappHebrew .whatsapp-msg::after {
|
|
210
|
-
transform: skew(-45deg);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
@media screen and (max-width: 1200px) {
|
|
214
|
-
.whatsapp-preview {
|
|
215
|
-
width: 300px;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
@media screen and (max-width: 910px) {
|
|
220
|
-
.whatsapp-preview {
|
|
221
|
-
display: none;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
</style>
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div ref="exampleEl">
|
|
3
|
-
<TextInput
|
|
4
|
-
v-for="v in variables"
|
|
5
|
-
:key="v"
|
|
6
|
-
:placeholder="`Variable ${v}`"
|
|
7
|
-
:modelValue="val?.[v - 1]"
|
|
8
|
-
@update:modelValue="($event: string) => handleUpdate($event, v)"
|
|
9
|
-
/>
|
|
10
|
-
</div>
|
|
11
|
-
</template>
|
|
12
|
-
|
|
13
|
-
<script setup lang="ts">
|
|
14
|
-
import { onMounted, watch } from 'vue';
|
|
15
|
-
import { FormKitNode } from '@formkit/core';
|
|
16
|
-
import { TextInput } from '@bagelink/vue';
|
|
17
|
-
|
|
18
|
-
const props = defineProps({
|
|
19
|
-
context: Object,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const exampleEl = $ref<HTMLElement>();
|
|
23
|
-
let boundValue = $ref<any>();
|
|
24
|
-
let boundNode = $ref<FormKitNode>();
|
|
25
|
-
let val = $ref<any[]>([]);
|
|
26
|
-
|
|
27
|
-
const handleUpdate = (value: string, index: number) => {
|
|
28
|
-
if (!boundValue) return;
|
|
29
|
-
if (index > val?.length) val = [...val, ...Array(index - val.length).fill(''), value];
|
|
30
|
-
else val?.splice(index - 1, 1, value);
|
|
31
|
-
props.context?.node.input(val);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const extractVariables = (text: string): number[] => {
|
|
35
|
-
const matches = text?.match(/{{(\d+)}}/g) || [];
|
|
36
|
-
return matches.map((match: any) => +match.match(/\d+/)[0]);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const txtType = $computed(() => (props.context?.id === 'bodyExamples' ? 'bodyText' : 'headerText'));
|
|
40
|
-
|
|
41
|
-
const variables = $computed(() => {
|
|
42
|
-
let vars = extractVariables(boundValue);
|
|
43
|
-
if (txtType === 'headerText') vars.slice(0, 1);
|
|
44
|
-
const nonSequentialDigits = vars?.reduce((acc: number[], currDigit: number, i: number) => {
|
|
45
|
-
const prevDigit = i > 0 ? vars[i - 1] : 0;
|
|
46
|
-
if (currDigit - prevDigit !== 1) {
|
|
47
|
-
acc.push(currDigit);
|
|
48
|
-
}
|
|
49
|
-
return acc;
|
|
50
|
-
}, []);
|
|
51
|
-
|
|
52
|
-
if (nonSequentialDigits?.length) {
|
|
53
|
-
const regex = new RegExp(nonSequentialDigits.map((d: number) => `\\{\\{${d}\\}\\}`).join('|'), 'g');
|
|
54
|
-
const newVal = `${boundValue}`.replace(regex, '');
|
|
55
|
-
void boundNode?.input(newVal); // TODO: Nati - should be awaited?
|
|
56
|
-
vars = extractVariables(boundValue);
|
|
57
|
-
}
|
|
58
|
-
const parentEl = exampleEl?.closest('.formkit-outer');
|
|
59
|
-
if (!vars.length && parentEl) {
|
|
60
|
-
parentEl.classList.add('hide');
|
|
61
|
-
} else if (parentEl) {
|
|
62
|
-
parentEl.classList.remove('hide');
|
|
63
|
-
}
|
|
64
|
-
return vars;
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const setupListners = (node?: FormKitNode) => {
|
|
68
|
-
node?.on('input', (v: any) => {
|
|
69
|
-
boundValue = v.payload;
|
|
70
|
-
});
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
onMounted(() => {
|
|
74
|
-
boundNode = props.context?.node.parent.children.find((c: any) => c.name === txtType);
|
|
75
|
-
setupListners(boundNode);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
watch(() => props.context?.value, (v: any) => val = v, { immediate: true });
|
|
79
|
-
</script>
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
export interface HeaderComponent {
|
|
2
|
-
type: 'HEADER';
|
|
3
|
-
text: string;
|
|
4
|
-
example_header?: string[];
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
interface Example {
|
|
8
|
-
body_text: string[][];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface BodyComponent {
|
|
12
|
-
type: 'BODY';
|
|
13
|
-
text: string;
|
|
14
|
-
example?: Example
|
|
15
|
-
add_security_recommendation?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface FooterComponent {
|
|
19
|
-
type: 'FOOTER';
|
|
20
|
-
text: string;
|
|
21
|
-
code_expiration_minutes?: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface Button {
|
|
25
|
-
type: 'OTP' | 'CATALOG' | 'MPM' | 'QUICK_REPLY' | 'PHONE_NUMBER' | 'URL';
|
|
26
|
-
text: string;
|
|
27
|
-
// Additional properties specific to each button type
|
|
28
|
-
// Add them here based on the possible button types
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface ButtonsComponent {
|
|
32
|
-
type: 'BUTTONS';
|
|
33
|
-
buttons: Button[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export type Component = BodyComponent | FooterComponent | HeaderComponent | ButtonsComponent
|
|
37
|
-
|
|
38
|
-
export interface ServerTemplateData {
|
|
39
|
-
id: string;
|
|
40
|
-
name: string;
|
|
41
|
-
status: string;
|
|
42
|
-
language: string;
|
|
43
|
-
category: string;
|
|
44
|
-
components: readonly Component[];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface LocalTemplateData {
|
|
48
|
-
id: string;
|
|
49
|
-
name: string;
|
|
50
|
-
language: string;
|
|
51
|
-
status: string;
|
|
52
|
-
category: string;
|
|
53
|
-
headerText?: string;
|
|
54
|
-
headerExamples?: string[];
|
|
55
|
-
bodyText?: string;
|
|
56
|
-
bodyExamples?: string[];
|
|
57
|
-
footerText?: string;
|
|
58
|
-
}
|