contactstudiocstools 1.0.224
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/README.md +94 -0
- package/dist/module.cjs +5 -0
- package/dist/module.d.ts +7 -0
- package/dist/module.json +5 -0
- package/dist/module.mjs +72 -0
- package/dist/runtime/components/Atom.Alert.vue +46 -0
- package/dist/runtime/components/Atom.Auth.vue +37 -0
- package/dist/runtime/components/Atom.BannerChatEmpty.vue +18 -0
- package/dist/runtime/components/Atom.BannerPage404.vue +28 -0
- package/dist/runtime/components/Atom.BannerPageUnauthorized.vue +18 -0
- package/dist/runtime/components/Atom.Breadcrumb.vue +26 -0
- package/dist/runtime/components/Atom.ChatContact.vue +136 -0
- package/dist/runtime/components/Atom.ChatContactSchedule.vue +87 -0
- package/dist/runtime/components/Atom.ChatMessageFooter.vue +25 -0
- package/dist/runtime/components/Atom.DarkMode.vue +67 -0
- package/dist/runtime/components/Atom.DraggableWindow.vue +102 -0
- package/dist/runtime/components/Atom.Dropdown.vue +9 -0
- package/dist/runtime/components/Atom.DropdownSearchable.vue +25 -0
- package/dist/runtime/components/Atom.Fetch.vue +46 -0
- package/dist/runtime/components/Atom.Field.vue +43 -0
- package/dist/runtime/components/Atom.FieldDate.vue +19 -0
- package/dist/runtime/components/Atom.FieldNumber.vue +19 -0
- package/dist/runtime/components/Atom.FieldPhone.vue +92 -0
- package/dist/runtime/components/Atom.FieldSelect.vue +28 -0
- package/dist/runtime/components/Atom.FieldSelectMultiple.vue +49 -0
- package/dist/runtime/components/Atom.FieldText.vue +19 -0
- package/dist/runtime/components/Atom.FieldTextarea.vue +41 -0
- package/dist/runtime/components/Atom.Loading.vue +80 -0
- package/dist/runtime/components/Atom.Notification.vue +48 -0
- package/dist/runtime/components/Atom.Ringtone.vue +23 -0
- package/dist/runtime/components/Atom.SelectTreeField.vue +49 -0
- package/dist/runtime/components/Atom.Snapshot.vue +33 -0
- package/dist/runtime/components/Atom.Tabs.vue +60 -0
- package/dist/runtime/components/Molecule.ChatMessageFile.vue +102 -0
- package/dist/runtime/components/Molecule.ChatMessageOption.vue +85 -0
- package/dist/runtime/components/Molecule.ChatMessageText.vue +36 -0
- package/dist/runtime/components/Molecule.ClientHistory.vue +62 -0
- package/dist/runtime/components/Molecule.DropdownDDI.vue +333 -0
- package/dist/runtime/components/Molecule.FieldGroup.vue +73 -0
- package/dist/runtime/components/Molecule.FieldSelectMultiple.vue +19 -0
- package/dist/runtime/components/Molecule.File.vue +84 -0
- package/dist/runtime/components/Molecule.SelectTreeSearchable.vue +126 -0
- package/dist/runtime/components/Molecule.Status.vue +154 -0
- package/dist/runtime/components/Molecule.TimeDaily.vue +9 -0
- package/dist/runtime/components/Organism.Attachments.vue +139 -0
- package/dist/runtime/components/Organism.ChatMessages.vue +31 -0
- package/dist/runtime/components/Organism.ChatRoom.vue +342 -0
- package/dist/runtime/components/Organism.ChatSchedule.vue +110 -0
- package/dist/runtime/components/Organism.ClientHistoryTable.vue +85 -0
- package/dist/runtime/components/Organism.ClientHistoryTimeline.vue +77 -0
- package/dist/runtime/components/Organism.FAQ.vue +88 -0
- package/dist/runtime/components/Organism.Form.vue +67 -0
- package/dist/runtime/components/Organism.FormMailing.vue +112 -0
- package/dist/runtime/components/Organism.HeaderMain.vue +79 -0
- package/dist/runtime/components/Organism.Manifestation.vue +146 -0
- package/dist/runtime/components/Organism.Nav.vue +27 -0
- package/dist/runtime/components/Organism.NavMain.vue +187 -0
- package/dist/runtime/components/Organism.PageContainer.vue +22 -0
- package/dist/runtime/components/Organism.Schedule.vue +170 -0
- package/dist/runtime/components/Organism.Tabulation.vue +237 -0
- package/dist/runtime/components/types/dto.d.ts +16 -0
- package/dist/runtime/components/types/dto.mjs +236 -0
- package/dist/runtime/components/types/helpers.d.ts +39 -0
- package/dist/runtime/components/types/helpers.mjs +295 -0
- package/dist/runtime/components/types/index.d.ts +4 -0
- package/dist/runtime/components/types/index.mjs +4 -0
- package/dist/runtime/components/types/types.d.ts +198 -0
- package/dist/runtime/components/types/types.mjs +35 -0
- package/dist/runtime/index.css +1 -0
- package/dist/runtime/plugins/clickOutside.d.ts +2 -0
- package/dist/runtime/plugins/clickOutside.mjs +16 -0
- package/dist/runtime/plugins/emitter.d.ts +2 -0
- package/dist/runtime/plugins/emitter.mjs +17 -0
- package/dist/runtime/public/192x192.png +0 -0
- package/dist/runtime/public/404.svg +1 -0
- package/dist/runtime/public/512x512.png +0 -0
- package/dist/runtime/public/chat.svg +138 -0
- package/dist/runtime/public/chatbg.png +0 -0
- package/dist/runtime/public/dev-sw.d.ts +0 -0
- package/dist/runtime/public/dev-sw.mjs +0 -0
- package/dist/runtime/public/empty.svg +1 -0
- package/dist/runtime/public/loading.svg +1 -0
- package/dist/runtime/public/messages.svg +1 -0
- package/dist/runtime/public/privacy.svg +1 -0
- package/dist/runtime/public/ringtone.mp3 +0 -0
- package/dist/runtime/public/security.svg +188 -0
- package/dist/runtime/public/snapshot.d.ts +15 -0
- package/dist/runtime/public/snapshot.mjs +77 -0
- package/dist/runtime/public/unauthorized.svg +1 -0
- package/dist/types.d.ts +10 -0
- package/package.json +50 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<header class="w-full h-12 flex items-center justify-between px-3">
|
|
4
|
+
<slot />
|
|
5
|
+
</header>
|
|
6
|
+
|
|
7
|
+
<div class="divider" />
|
|
8
|
+
|
|
9
|
+
<div class="flex items-center text-xs opacity-75 py-2 px-4">
|
|
10
|
+
<span class="w-full">
|
|
11
|
+
{{ visibleSchedules ? "Convites Enviados" : "Conversas" }}
|
|
12
|
+
</span>
|
|
13
|
+
<span
|
|
14
|
+
v-if="!visibleSchedules"
|
|
15
|
+
class="text-primary flex items-center gap-2 cursor-pointer whitespace-nowrap"
|
|
16
|
+
@click="changeSchedule"
|
|
17
|
+
>
|
|
18
|
+
Convites Enviados
|
|
19
|
+
<i class="bi-chevron-right leading-3 " />
|
|
20
|
+
</span>
|
|
21
|
+
<span
|
|
22
|
+
v-if="visibleSchedules"
|
|
23
|
+
class="text-error flex items-center gap-2 cursor-pointer"
|
|
24
|
+
@click="changeSchedule"
|
|
25
|
+
>
|
|
26
|
+
<i class="bi-chevron-left leading-3" />
|
|
27
|
+
Voltar
|
|
28
|
+
</span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="divider" />
|
|
32
|
+
|
|
33
|
+
<article class="overflow-auto max-h-full scrollbar pb-24">
|
|
34
|
+
<!-- contacts -->
|
|
35
|
+
<div
|
|
36
|
+
v-for="(contact, i) in contacts"
|
|
37
|
+
v-show="!visibleSchedules"
|
|
38
|
+
:key="i"
|
|
39
|
+
>
|
|
40
|
+
<ul class="list">
|
|
41
|
+
<AtomChatContact
|
|
42
|
+
:timeout="timeout"
|
|
43
|
+
:contact="contact"
|
|
44
|
+
:class="getSelectedClass(contact)"
|
|
45
|
+
@click="select(contact)"
|
|
46
|
+
/>
|
|
47
|
+
</ul>
|
|
48
|
+
<div class="divider" />
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<!-- schedules -->
|
|
52
|
+
<div
|
|
53
|
+
v-for="(schedule, i) in schedules"
|
|
54
|
+
v-show="visibleSchedules"
|
|
55
|
+
:key="i"
|
|
56
|
+
>
|
|
57
|
+
<ul class="list my-2">
|
|
58
|
+
<AtomChatContactSchedule :schedule="schedule" />
|
|
59
|
+
</ul>
|
|
60
|
+
<div class="divider" />
|
|
61
|
+
</div>
|
|
62
|
+
</article>
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<script setup lang="ts">
|
|
67
|
+
import { ref, computed } from "vue";
|
|
68
|
+
import { IChatContact, IChatContacts, IPortfolioSchedules } from "./types";
|
|
69
|
+
|
|
70
|
+
// props
|
|
71
|
+
interface IProps {
|
|
72
|
+
contacts: IChatContacts;
|
|
73
|
+
schedules: IPortfolioSchedules;
|
|
74
|
+
selected?: IChatContact;
|
|
75
|
+
timeout: number;
|
|
76
|
+
}
|
|
77
|
+
const props = defineProps<IProps>();
|
|
78
|
+
|
|
79
|
+
// emits
|
|
80
|
+
interface IEmits {
|
|
81
|
+
(e: "select", contact: IChatContact): void;
|
|
82
|
+
(e: "schedule", schedule: boolean): void;
|
|
83
|
+
}
|
|
84
|
+
const emit = defineEmits<IEmits>();
|
|
85
|
+
|
|
86
|
+
// computed
|
|
87
|
+
const getSelectedClass = computed<Function>(() => (contact: IChatContact) => {
|
|
88
|
+
if (props.selected?.id === contact.id)
|
|
89
|
+
return "bg-slate-100 dark:bg-slate-800";
|
|
90
|
+
return "";
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// data
|
|
94
|
+
const visibleSchedules = ref<boolean>(false)
|
|
95
|
+
|
|
96
|
+
// methods
|
|
97
|
+
function select(contact: IChatContact): void {
|
|
98
|
+
emit("select", contact);
|
|
99
|
+
}
|
|
100
|
+
function changeSchedule(): void {
|
|
101
|
+
visibleSchedules.value = !visibleSchedules.value
|
|
102
|
+
emit("schedule", visibleSchedules.value);
|
|
103
|
+
}
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<style scoped>
|
|
107
|
+
.text-2xs {
|
|
108
|
+
font-size: 0.7rem;
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full h-full overflow-auto scrollbar">
|
|
3
|
+
<table class="table bordered text-xs">
|
|
4
|
+
<thead class="bg-slate-100 dark:bg-slate-800">
|
|
5
|
+
<th />
|
|
6
|
+
<th>Canal</th>
|
|
7
|
+
<th>Operador</th>
|
|
8
|
+
<th>Data</th>
|
|
9
|
+
<th>Tabulação</th>
|
|
10
|
+
<th>Observação</th>
|
|
11
|
+
<slot name="header" />
|
|
12
|
+
</thead>
|
|
13
|
+
<tbody>
|
|
14
|
+
<tr
|
|
15
|
+
v-for="(history, i) in histories"
|
|
16
|
+
:key="i"
|
|
17
|
+
>
|
|
18
|
+
<td>
|
|
19
|
+
<i
|
|
20
|
+
v-if="isDigital(history)"
|
|
21
|
+
class="bi bi-eye-fill text-slate-500 px-1 text-base leading-3 cursor-pointer"
|
|
22
|
+
@click="emit('extract', history)"
|
|
23
|
+
/>
|
|
24
|
+
</td>
|
|
25
|
+
<td>
|
|
26
|
+
<span
|
|
27
|
+
v-if="isDigital(history)"
|
|
28
|
+
class="badge badge-solid-primary"
|
|
29
|
+
>
|
|
30
|
+
<i class="bi-chat-square-dots-fill" />
|
|
31
|
+
<b class="ml-1">Digital</b>
|
|
32
|
+
</span>
|
|
33
|
+
<span
|
|
34
|
+
v-else
|
|
35
|
+
class="badge badge-solid-primary"
|
|
36
|
+
>
|
|
37
|
+
<i class="bi-telephone-fill" />
|
|
38
|
+
<b class="ml-1">Outro</b>
|
|
39
|
+
</span>
|
|
40
|
+
</td>
|
|
41
|
+
<td>{{ history.agent }}</td>
|
|
42
|
+
<td>{{ history.lastMovementDate?.toLocaleString() }}</td>
|
|
43
|
+
<td>{{ history.lastTabulation }}</td>
|
|
44
|
+
<td class="!whitespace-normal">
|
|
45
|
+
{{ history.observation ?? "" }}
|
|
46
|
+
</td>
|
|
47
|
+
<slot
|
|
48
|
+
name="body"
|
|
49
|
+
:item="history"
|
|
50
|
+
/>
|
|
51
|
+
</tr>
|
|
52
|
+
</tbody>
|
|
53
|
+
</table>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<script setup lang="ts">
|
|
58
|
+
import { computed } from "vue";
|
|
59
|
+
import { IClientHistories, IClientHistory } from "./types";
|
|
60
|
+
|
|
61
|
+
// props
|
|
62
|
+
interface IProps {
|
|
63
|
+
histories: IClientHistories;
|
|
64
|
+
}
|
|
65
|
+
defineProps<IProps>();
|
|
66
|
+
|
|
67
|
+
// computed
|
|
68
|
+
const isDigital = computed<any>(() => ({ primitive }: any) => {
|
|
69
|
+
return !!primitive.room_id && primitive.room_id !== ""
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// emits
|
|
73
|
+
interface IEmits {
|
|
74
|
+
(e: "extract", history: IClientHistory): void;
|
|
75
|
+
}
|
|
76
|
+
const emit = defineEmits<IEmits>();
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<style scoped>
|
|
80
|
+
.table th,
|
|
81
|
+
.table td {
|
|
82
|
+
padding: 3px 10px;
|
|
83
|
+
white-space: nowrap;
|
|
84
|
+
}
|
|
85
|
+
</style>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<figure class="timeline">
|
|
3
|
+
<figcaption
|
|
4
|
+
v-for="(history, i) in histories"
|
|
5
|
+
:key="i"
|
|
6
|
+
class="checkpoint checkpoint-solid-primary !pr-0"
|
|
7
|
+
:icon="isDigital(history) ? `` : ``"
|
|
8
|
+
>
|
|
9
|
+
<!-- header -->
|
|
10
|
+
<header class="flex items-center justify-between">
|
|
11
|
+
<span class="font-medium">
|
|
12
|
+
{{ history.agent }}
|
|
13
|
+
<i
|
|
14
|
+
v-if="isDigital(history)"
|
|
15
|
+
class="bi bi-eye-fill text-slate-500 px-1 text-base leading-3 cursor-pointer"
|
|
16
|
+
@click="emit('extract', history)"
|
|
17
|
+
/>
|
|
18
|
+
</span>
|
|
19
|
+
|
|
20
|
+
<span
|
|
21
|
+
v-if="history.lastTabulation"
|
|
22
|
+
class="badge badge-soft-secondary font-medium w-fit"
|
|
23
|
+
> {{ history.lastTabulation }}</span>
|
|
24
|
+
</header>
|
|
25
|
+
|
|
26
|
+
<!-- last date -->
|
|
27
|
+
<span
|
|
28
|
+
v-if="history.lastMovementDate"
|
|
29
|
+
class="text-xs opacity-50"
|
|
30
|
+
>
|
|
31
|
+
{{ history.lastMovementDate.toLocaleString() }}
|
|
32
|
+
</span>
|
|
33
|
+
|
|
34
|
+
<article
|
|
35
|
+
v-if="history.observation"
|
|
36
|
+
class="accordion accordion-bordered mt-2"
|
|
37
|
+
>
|
|
38
|
+
<details class="item">
|
|
39
|
+
<summary class="text-xs !py-2 !px-4">
|
|
40
|
+
Observação
|
|
41
|
+
</summary>
|
|
42
|
+
<article class="text-xs !py-2 !px-4">
|
|
43
|
+
{{ history.observation }}
|
|
44
|
+
</article>
|
|
45
|
+
</details>
|
|
46
|
+
</article>
|
|
47
|
+
<slot
|
|
48
|
+
name="body"
|
|
49
|
+
:item="history"
|
|
50
|
+
/>
|
|
51
|
+
</figcaption>
|
|
52
|
+
</figure>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script setup lang="ts">
|
|
56
|
+
import { computed } from "vue"
|
|
57
|
+
import { IClientHistories, IClientHistory } from "./types";
|
|
58
|
+
|
|
59
|
+
// props
|
|
60
|
+
interface IProps {
|
|
61
|
+
histories: IClientHistories;
|
|
62
|
+
}
|
|
63
|
+
defineProps<IProps>();
|
|
64
|
+
|
|
65
|
+
// computed
|
|
66
|
+
const isDigital = computed<any>(() => ({ primitive }: any) => {
|
|
67
|
+
return !!primitive.room_id && primitive.room_id !== ""
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// emits
|
|
71
|
+
interface IEmits {
|
|
72
|
+
(e: "extract", history: IClientHistory): void;
|
|
73
|
+
}
|
|
74
|
+
const emit = defineEmits<IEmits>();
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<style scoped></style>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<aside class="relative">
|
|
3
|
+
<!-- field -->
|
|
4
|
+
<label class="field-group sticky top-0 z-10 bg-white dark:bg-slate-900">
|
|
5
|
+
<input
|
|
6
|
+
v-model="search"
|
|
7
|
+
type="text"
|
|
8
|
+
placeholder="Pesquise"
|
|
9
|
+
class="input sidenav-item"
|
|
10
|
+
>
|
|
11
|
+
<i class="bi-search addon w-10" />
|
|
12
|
+
</label>
|
|
13
|
+
<!-- accordion -->
|
|
14
|
+
<div class="accordion markdown">
|
|
15
|
+
<details
|
|
16
|
+
v-for="({ answer, question, primitive }, i) in getDoubtsBySearch"
|
|
17
|
+
:key="i"
|
|
18
|
+
class="item"
|
|
19
|
+
>
|
|
20
|
+
<summary v-html="question" />
|
|
21
|
+
<article class="flex">
|
|
22
|
+
<div
|
|
23
|
+
class="flex-1"
|
|
24
|
+
v-html="answer"
|
|
25
|
+
/>
|
|
26
|
+
<button
|
|
27
|
+
class="btn btn-outline-secondary max-h-none ml-2"
|
|
28
|
+
@click="copy(primitive.answer)"
|
|
29
|
+
>
|
|
30
|
+
<i class="bi bi-clipboard" />
|
|
31
|
+
</button>
|
|
32
|
+
</article>
|
|
33
|
+
</details>
|
|
34
|
+
</div>
|
|
35
|
+
</aside>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup lang="ts">
|
|
39
|
+
import { marked } from "marked";
|
|
40
|
+
import { ref, onMounted, computed } from "vue";
|
|
41
|
+
import { IDoubts } from "./types";
|
|
42
|
+
import { useNuxtApp } from "#app";
|
|
43
|
+
|
|
44
|
+
// props
|
|
45
|
+
interface IProps {
|
|
46
|
+
doubts: IDoubts;
|
|
47
|
+
}
|
|
48
|
+
const props = defineProps<IProps>();
|
|
49
|
+
|
|
50
|
+
// computed
|
|
51
|
+
const getDoubtsBySearch = computed<IDoubts>(() => {
|
|
52
|
+
if (!search.value.trim()) return props.doubts;
|
|
53
|
+
|
|
54
|
+
return props.doubts.filter(({ question, answer }) => {
|
|
55
|
+
return (
|
|
56
|
+
question.match(new RegExp(search.value, "i")) ||
|
|
57
|
+
answer.match(new RegExp(search.value, "i"))
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// data
|
|
63
|
+
const { $emit } = useNuxtApp();
|
|
64
|
+
const search = ref<string>("");
|
|
65
|
+
|
|
66
|
+
// methods
|
|
67
|
+
function init(): void {
|
|
68
|
+
for (const doubt of props.doubts) {
|
|
69
|
+
const { question, answer } = doubt;
|
|
70
|
+
doubt.primitive = {
|
|
71
|
+
question,
|
|
72
|
+
answer,
|
|
73
|
+
};
|
|
74
|
+
doubt.question = marked(question);
|
|
75
|
+
doubt.answer = marked(answer);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function copy(answer: string): Promise<void> {
|
|
79
|
+
$emit("faq:copy", answer);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// mounted
|
|
83
|
+
onMounted(() => {
|
|
84
|
+
init();
|
|
85
|
+
});
|
|
86
|
+
</script>
|
|
87
|
+
|
|
88
|
+
<style></style>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<form
|
|
3
|
+
class="form"
|
|
4
|
+
@submit.prevent="submit"
|
|
5
|
+
>
|
|
6
|
+
<slot
|
|
7
|
+
:get-ref="getRef"
|
|
8
|
+
:models="models"
|
|
9
|
+
/>
|
|
10
|
+
</form>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { reactive } from "vue";
|
|
15
|
+
import { useNuxtApp } from "#app";
|
|
16
|
+
|
|
17
|
+
interface IProps {
|
|
18
|
+
submit: Function;
|
|
19
|
+
deny?: Function;
|
|
20
|
+
defaults?: { [name: string]: string };
|
|
21
|
+
}
|
|
22
|
+
const props = defineProps<IProps>();
|
|
23
|
+
|
|
24
|
+
// data
|
|
25
|
+
const { $emit } = useNuxtApp()
|
|
26
|
+
const models = reactive<any>({ ...props.defaults });
|
|
27
|
+
const fields = reactive<any[]>([]);
|
|
28
|
+
|
|
29
|
+
// methods
|
|
30
|
+
function getRef(ref: any): void {
|
|
31
|
+
fields.push(ref);
|
|
32
|
+
}
|
|
33
|
+
async function submit(): Promise<void> {
|
|
34
|
+
if (!validate()) {
|
|
35
|
+
await deny();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await props.submit(models);
|
|
40
|
+
}
|
|
41
|
+
function validate(): boolean {
|
|
42
|
+
let valid = true;
|
|
43
|
+
|
|
44
|
+
for (const field of fields) {
|
|
45
|
+
if (!field.validateAndSetState()) {
|
|
46
|
+
valid = false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return valid;
|
|
51
|
+
}
|
|
52
|
+
async function deny(): Promise<void> {
|
|
53
|
+
if (props.deny) await props.deny();
|
|
54
|
+
}
|
|
55
|
+
function append(values: any): void {
|
|
56
|
+
Object.assign(models, values);
|
|
57
|
+
$emit("form:append", models)
|
|
58
|
+
}
|
|
59
|
+
function reset(): void {
|
|
60
|
+
for (const field in models) delete models[field];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// expose
|
|
64
|
+
defineExpose({ submit, append, reset, validate });
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<style scoped></style>
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<OrganismForm
|
|
3
|
+
v-slot="{ models, getRef }"
|
|
4
|
+
ref="form"
|
|
5
|
+
:submit="submit"
|
|
6
|
+
:deny="deny"
|
|
7
|
+
:defaults="defaults"
|
|
8
|
+
class="form"
|
|
9
|
+
>
|
|
10
|
+
<div
|
|
11
|
+
v-for="(field, i) in mailing"
|
|
12
|
+
:key="i"
|
|
13
|
+
class="flex-auto"
|
|
14
|
+
:disabled="field.disabled"
|
|
15
|
+
>
|
|
16
|
+
<MoleculeFieldGroup
|
|
17
|
+
:ref="getRef"
|
|
18
|
+
:label="field.label"
|
|
19
|
+
:rules="[getRulesByField(models[field.name], field)]"
|
|
20
|
+
>
|
|
21
|
+
<!-- ddi -->
|
|
22
|
+
<!-- <MoleculeDropdownDDI
|
|
23
|
+
v-if="field.type === EFieldTypes.phone"
|
|
24
|
+
v-model="models[field.name + '_DDI']"
|
|
25
|
+
:phone="models[field.name]"
|
|
26
|
+
class="addon"
|
|
27
|
+
/> -->
|
|
28
|
+
|
|
29
|
+
<!-- field -->
|
|
30
|
+
<!-- :options="field.options"
|
|
31
|
+
:disabled="field.disabled"
|
|
32
|
+
:maxlength="field.maxlength" -->
|
|
33
|
+
<AtomField
|
|
34
|
+
v-model="models[field.name]"
|
|
35
|
+
:type="field.type"
|
|
36
|
+
:field="field"
|
|
37
|
+
@blur.capture="
|
|
38
|
+
persist(field.name, models[field.name]);
|
|
39
|
+
routine({ models, field });
|
|
40
|
+
"
|
|
41
|
+
/>
|
|
42
|
+
</MoleculeFieldGroup>
|
|
43
|
+
</div>
|
|
44
|
+
</OrganismForm>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<script setup lang="ts">
|
|
48
|
+
import { ref, computed } from "vue";
|
|
49
|
+
import { IMailing, IField, IRule, EFieldTypes } from "./types";
|
|
50
|
+
import OrganismForm from "./Organism.Form.vue";
|
|
51
|
+
|
|
52
|
+
interface IProps {
|
|
53
|
+
mailing: IMailing;
|
|
54
|
+
submit: Function;
|
|
55
|
+
deny?: Function;
|
|
56
|
+
persist?: Function;
|
|
57
|
+
routine?: Function;
|
|
58
|
+
|
|
59
|
+
defaults?: { [name: string]: string };
|
|
60
|
+
}
|
|
61
|
+
const props = defineProps<IProps>();
|
|
62
|
+
|
|
63
|
+
// computed
|
|
64
|
+
const getRulesByField = computed<Function>(
|
|
65
|
+
() =>
|
|
66
|
+
(value: string, { regex, required, messages, type }: IField): IRule => {
|
|
67
|
+
const isPhoneField = type === EFieldTypes.phone;
|
|
68
|
+
const isBrazilianPhone = /^\+55[0-9]/.test(value);
|
|
69
|
+
const errorMessage = messages?.error || "";
|
|
70
|
+
|
|
71
|
+
if (isPhoneField && isBrazilianPhone) {
|
|
72
|
+
regex = /^\+55[0-9]{10,11}$/;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return buildRule({ value, regex, required, errorMessage });
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// data
|
|
80
|
+
const form = ref<InstanceType<typeof OrganismForm> | null>(null);
|
|
81
|
+
|
|
82
|
+
// methods
|
|
83
|
+
function buildRule({ value, regex, required, errorMessage }: any): IRule {
|
|
84
|
+
return () => {
|
|
85
|
+
if (value) return regex.test(value) || errorMessage;
|
|
86
|
+
if (required) return "Campo obrigatório!";
|
|
87
|
+
|
|
88
|
+
return true;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function persist(label: string, value: any) {
|
|
93
|
+
if (!props.persist) return;
|
|
94
|
+
|
|
95
|
+
props.persist({ [label]: value });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function routine({ models, field }: any) {
|
|
99
|
+
if (!props.routine) return;
|
|
100
|
+
|
|
101
|
+
props.routine({ models, field });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// expose
|
|
105
|
+
defineExpose({ form });
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<style scoped>
|
|
109
|
+
.field-group {
|
|
110
|
+
position: relative;
|
|
111
|
+
}
|
|
112
|
+
</style>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<header
|
|
3
|
+
class="w-full h-16 fixed flex justify-between items-center text-white py-2 px-4 z-20 bg-slate-800"
|
|
4
|
+
>
|
|
5
|
+
<!-- info -->
|
|
6
|
+
<div class="flex items-center">
|
|
7
|
+
<!-- logo -->
|
|
8
|
+
<figure
|
|
9
|
+
class="h-full flex justify-center items-center border-r-2 mr-4 pr-3 border-slate-700"
|
|
10
|
+
>
|
|
11
|
+
<img
|
|
12
|
+
src="../public/192x192.png"
|
|
13
|
+
class="w-8 max-sm:hidden"
|
|
14
|
+
alt="ContactStudio Logo"
|
|
15
|
+
>
|
|
16
|
+
<i
|
|
17
|
+
v-if="navIsVisible"
|
|
18
|
+
class="bi-x-lg w-6 text-xl sm:hidden"
|
|
19
|
+
/>
|
|
20
|
+
<i
|
|
21
|
+
v-if="!navIsVisible"
|
|
22
|
+
id="navopen"
|
|
23
|
+
class="bi-text-left w-6 text-2xl sm:hidden"
|
|
24
|
+
@click="showNav"
|
|
25
|
+
/>
|
|
26
|
+
</figure>
|
|
27
|
+
|
|
28
|
+
<!-- user -->
|
|
29
|
+
<header>
|
|
30
|
+
<p
|
|
31
|
+
class="overflow-hidden text-ellipsis text-sm sm:max-w-[350px] max-w-[150px]"
|
|
32
|
+
v-text="user.nickname"
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
<p class="text-xs opacity-50">
|
|
36
|
+
{{ config.public.PROJECT }}
|
|
37
|
+
[{{ config.public.VERSION }}]
|
|
38
|
+
</p>
|
|
39
|
+
</header>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<!-- slots -->
|
|
43
|
+
<div class="flex">
|
|
44
|
+
<slot />
|
|
45
|
+
</div>
|
|
46
|
+
</header>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script setup lang="ts">
|
|
50
|
+
import { ref } from "vue";
|
|
51
|
+
import { IUser } from "./types";
|
|
52
|
+
import { useRuntimeConfig, useNuxtApp } from "#app";
|
|
53
|
+
|
|
54
|
+
// props
|
|
55
|
+
interface IProps {
|
|
56
|
+
user: IUser;
|
|
57
|
+
}
|
|
58
|
+
defineProps<IProps>();
|
|
59
|
+
|
|
60
|
+
// app
|
|
61
|
+
const { $emit, $listen } = useNuxtApp();
|
|
62
|
+
|
|
63
|
+
// data
|
|
64
|
+
const config = useRuntimeConfig();
|
|
65
|
+
const navIsVisible = ref<boolean>(false);
|
|
66
|
+
|
|
67
|
+
// methods
|
|
68
|
+
function showNav(): void {
|
|
69
|
+
navIsVisible.value = true;
|
|
70
|
+
$emit("nav:show");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// emits
|
|
74
|
+
$listen("nav:hide", () => {
|
|
75
|
+
navIsVisible.value = false;
|
|
76
|
+
});
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<style scoped></style>
|