@icvdeveloper/common-module 1.4.13 → 2.0.0
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/CHANGELOG.md +4 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +10 -0
- package/dist/runtime/@types/components.d.ts +22 -0
- package/dist/runtime/@types/configVariables.d.ts +6 -0
- package/dist/runtime/analytics.d.ts +1 -1
- package/dist/runtime/assets/scss/index.css +0 -705
- package/dist/runtime/assets/svg/icon-minus.svg +6 -0
- package/dist/runtime/assets/svg/icon-video.svg +6 -0
- package/dist/runtime/components/affiliates/AffiliateModal.vue +66 -0
- package/dist/runtime/components/affiliates/AffiliatePage.vue +337 -132
- package/dist/runtime/components/agenda/AgendaTabbed.vue +43 -34
- package/dist/runtime/components/agenda/components/Calendar.vue +8 -3
- package/dist/runtime/components/agenda/components/Favorite.vue +44 -0
- package/dist/runtime/components/agenda/components/PlayIcon.vue +1 -1
- package/dist/runtime/components/agenda/components/PresentationLink.vue +26 -15
- package/dist/runtime/components/chat/ChatConversationList.vue +108 -0
- package/dist/runtime/components/chat/ChatCreateConversation.vue +205 -0
- package/dist/runtime/components/chat/ChatCreateGroupConversation.vue +159 -0
- package/dist/runtime/components/chat/ChatHeader.vue +98 -0
- package/dist/runtime/components/chat/ChatMessage.vue +40 -0
- package/dist/runtime/components/chat/ChatShowConversation.vue +77 -0
- package/dist/runtime/components/chat/ChatWidget.vue +65 -0
- package/dist/runtime/components/chat/ChatWindow.vue +211 -0
- package/dist/runtime/components/chat/ChatWindow.vue.d.ts +6 -0
- package/dist/runtime/components/chat/MessageInput.vue +30 -0
- package/dist/runtime/components/chat/SearchInput.vue +32 -0
- package/dist/runtime/components/core/Accordion.vue +1 -1
- package/dist/runtime/components/core/AttendeeList.vue +25 -16
- package/dist/runtime/components/core/CountdownTimer.vue +1 -1
- package/dist/runtime/components/core/Modal.vue +21 -13
- package/dist/runtime/components/core/ModalButton.vue +43 -0
- package/dist/runtime/components/core/Navbar.vue +3 -3
- package/dist/runtime/components/core/Navigation.vue +293 -0
- package/dist/runtime/components/core/SvgIcon.vue +31 -1
- package/dist/runtime/components/core/VButton.vue +41 -0
- package/dist/runtime/components/core/ZoomModal.vue +1 -1
- package/dist/runtime/components/events/ListEvents.vue +3 -4
- package/dist/runtime/components/forms/CheckboxGroup.vue +46 -0
- package/dist/runtime/components/forms/ErrorField.vue +11 -2
- package/dist/runtime/components/forms/RadioGroup.vue +50 -0
- package/dist/runtime/components/forms/SelectDropDown.vue +47 -0
- package/dist/runtime/components/forms/SupportForm.vue +6 -6
- package/dist/runtime/components/layouts/Accordion.vue +2 -2
- package/dist/runtime/components/media/ArchivePlayerAndContentContainer.vue +20 -4
- package/dist/runtime/components/media/ArchiveVideoPlayer.vue +14 -6
- package/dist/runtime/components/media/WebcastVideoPlayer.vue +1 -1
- package/dist/runtime/components/media/components/ArchiveMediaContainer.vue +8 -8
- package/dist/runtime/components/media/components/CeCreditNotification.vue +2 -2
- package/dist/runtime/components/media/components/ContentArea.vue +51 -14
- package/dist/runtime/components/media/components/ContentTabs.vue +2 -2
- package/dist/runtime/components/media/components/DocumentsPanel.vue +2 -2
- package/dist/runtime/components/media/components/MediaContainer.vue +3 -7
- package/dist/runtime/components/media/components/PresentersPanel.vue +69 -50
- package/dist/runtime/components/media/components/SessionReporting.vue +5 -4
- package/dist/runtime/components/media/components/SponsorsPanel.vue +3 -3
- package/dist/runtime/components/presenters/PresenterListing.vue +30 -20
- package/dist/runtime/components/presenters/PresenterModal.vue +26 -21
- package/dist/runtime/components/presenters/Presenters.vue +139 -0
- package/dist/runtime/components/profile/Profile.vue +10 -6
- package/dist/runtime/components/profile/components/Sidebar.vue +1 -1
- package/dist/runtime/components/profile/components/SidebarNavItem.vue +1 -1
- package/dist/runtime/components/profile/tabs/Favorites.vue +5 -4
- package/dist/runtime/components/profile/tabs/GeneralInformation.vue +26 -16
- package/dist/runtime/components/registration/AlreadyRegisteredModal.vue +99 -0
- package/dist/runtime/components/registration/PaymentForm.vue +136 -0
- package/dist/runtime/components/registration/RegistrationForm.vue +417 -0
- package/dist/runtime/components/registration/RegistrationGroupSelect.vue +142 -0
- package/dist/runtime/components/registration/StripePaymentForm.vue +141 -0
- package/dist/runtime/composables/useAgenda.d.ts +12 -0
- package/dist/runtime/composables/useAgenda.mjs +101 -10
- package/dist/runtime/composables/useAuth.mjs +1 -1
- package/dist/runtime/composables/useConferenceHelpers.d.ts +5 -1
- package/dist/runtime/composables/useConferenceHelpers.mjs +15 -1
- package/dist/runtime/composables/useEventHooks.d.ts +26 -0
- package/dist/runtime/composables/useEventHooks.mjs +21 -0
- package/dist/runtime/composables/useEvents.d.ts +17 -1
- package/dist/runtime/composables/useEvents.mjs +29 -1
- package/dist/runtime/composables/useLogin.mjs +7 -3
- package/dist/runtime/composables/usePresentation.mjs +1 -1
- package/dist/runtime/composables/usePusher.d.ts +4 -0
- package/dist/runtime/composables/usePusher.mjs +38 -26
- package/dist/runtime/composables/useStream.mjs +7 -1
- package/dist/runtime/enums/general.d.ts +4 -1
- package/dist/runtime/enums/general.mjs +4 -1
- package/dist/runtime/models/authUser.d.ts +1 -0
- package/dist/runtime/models/conference.d.ts +14 -0
- package/dist/runtime/models/conversation.d.ts +2 -4
- package/dist/runtime/models/globalConfig.d.ts +6 -2
- package/dist/runtime/models/group.d.ts +32 -2
- package/dist/runtime/models/icons.d.ts +7 -0
- package/dist/runtime/models/templateConfig.d.ts +6 -0
- package/dist/runtime/models/user.d.ts +1 -0
- package/dist/runtime/models/virtualPagesConfig.d.ts +335 -0
- package/dist/runtime/models/virtualPagesConfig.mjs +0 -0
- package/dist/runtime/plugin.mjs +11 -1
- package/dist/runtime/store/affiliates.d.ts +3 -0
- package/dist/runtime/store/affiliates.mjs +38 -0
- package/dist/runtime/store/auth.mjs +6 -0
- package/dist/runtime/store/conferences.d.ts +3 -1
- package/dist/runtime/store/conferences.mjs +7 -2
- package/dist/runtime/store/conversations.d.ts +4040 -10
- package/dist/runtime/store/conversations.mjs +255 -22
- package/dist/runtime/store/modalPlayerConfig.d.ts +498 -0
- package/dist/runtime/store/modalPlayerConfig.mjs +58 -0
- package/dist/runtime/store/templateConfigs.d.ts +3 -2
- package/dist/runtime/store/templateConfigs.mjs +2 -1
- package/package.json +5 -2
- package/dist/runtime/components/media/components/PresentersPanel.vue.d.ts +0 -32
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { inject, onMounted, onBeforeUnmount, ref, toRefs, watch } from 'vue';
|
|
3
|
+
import { storeToRefs } from 'pinia';
|
|
4
|
+
import { debounce, find, remove } from 'lodash-es';
|
|
5
|
+
import { VueEternalLoading, LoadAction } from "@ts-pro/vue-eternal-loading";
|
|
6
|
+
import { useConversationStore } from '#imports';
|
|
7
|
+
import { chatSearchEventHook } from '../../composables/useEventHooks';
|
|
8
|
+
import type { UsersResult } from '../../store/conversations';
|
|
9
|
+
import type { User } from '../../models/user';
|
|
10
|
+
|
|
11
|
+
const conversationStore = useConversationStore();
|
|
12
|
+
|
|
13
|
+
const { user, users, isInitial } = storeToRefs(conversationStore);
|
|
14
|
+
|
|
15
|
+
const { getName, createConversation } = conversationStore;
|
|
16
|
+
|
|
17
|
+
// data
|
|
18
|
+
const selectedUsers = ref<User[]>([] as User[]);
|
|
19
|
+
const filteredUsers = ref<UsersResult>({} as UsersResult);
|
|
20
|
+
|
|
21
|
+
// emits
|
|
22
|
+
const emit = defineEmits<{
|
|
23
|
+
(event: 'onCreate', value: User[]): void;
|
|
24
|
+
}>();
|
|
25
|
+
|
|
26
|
+
// injected load function
|
|
27
|
+
// (see Vue Eternal Loading docs for reference: https://ts-pro.github.io/vue-eternal-loading/guide/simple-usage.html)
|
|
28
|
+
const load = inject('attendeeListLoad', (loaded: LoadAction) => { console.log('no scroll'); loaded(0); })
|
|
29
|
+
|
|
30
|
+
// methods
|
|
31
|
+
const toggle = (user: User) => {
|
|
32
|
+
console.log('selected: ', user.name);
|
|
33
|
+
if (exists(user) == undefined) {
|
|
34
|
+
console.log('user not already selected');
|
|
35
|
+
selectedUsers.value?.push(user);
|
|
36
|
+
} else {
|
|
37
|
+
console.log('user already selected, removing');
|
|
38
|
+
const array = selectedUsers.value as User[];
|
|
39
|
+
|
|
40
|
+
remove(array, (element) => {
|
|
41
|
+
return element.id === user.id;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
selectedUsers.value = [...array];
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const exists = (user: User): User | undefined => {
|
|
49
|
+
return find(selectedUsers.value, {'id': user.id});
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const onSearchChange = debounce((value: string) => {
|
|
53
|
+
console.log('debounced');
|
|
54
|
+
chatSearchEventHook.trigger({value: value, iterate: true});
|
|
55
|
+
}, 500);
|
|
56
|
+
|
|
57
|
+
const clear = (): void => {
|
|
58
|
+
console.log('clear');
|
|
59
|
+
chatSearchEventHook.trigger({value: undefined, iterate: true});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
watch(users.value, (_users, _newUsers) => {
|
|
63
|
+
filteredUsers.value = _newUsers;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// lifecycle hooks
|
|
67
|
+
onMounted(() => {
|
|
68
|
+
filteredUsers.value = users.value;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
onBeforeUnmount(() => {
|
|
72
|
+
clear();
|
|
73
|
+
});
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<div class="flex h-full justify-between flex-col overflow-y-hidden">
|
|
78
|
+
<CommonSearchInput
|
|
79
|
+
@on-change="onSearchChange"
|
|
80
|
+
@clear="clear"
|
|
81
|
+
/>
|
|
82
|
+
<div class="overflow-y-auto h-full bg-gray-300">
|
|
83
|
+
<!-- Selected Users -->
|
|
84
|
+
<div class="z-50 sticky flex pin-t border-b-4 border-blue bg-gray-300 overflow-x-auto">
|
|
85
|
+
<div
|
|
86
|
+
v-if="selectedUsers?.length"
|
|
87
|
+
class="flex flex-row"
|
|
88
|
+
>
|
|
89
|
+
<div
|
|
90
|
+
v-for="currentUser in selectedUsers"
|
|
91
|
+
:key="currentUser.id"
|
|
92
|
+
class="py-1"
|
|
93
|
+
>
|
|
94
|
+
<div
|
|
95
|
+
v-if="currentUser.id !== user.data.id"
|
|
96
|
+
class="selected-user-item"
|
|
97
|
+
@click="toggle(currentUser)"
|
|
98
|
+
>
|
|
99
|
+
<CommonSvgIcon icon="person" />
|
|
100
|
+
<div class="text-sm py-2">
|
|
101
|
+
<p class="pt-2 text-black leading-none">
|
|
102
|
+
{{ getName(currentUser) }}
|
|
103
|
+
</p>
|
|
104
|
+
</div>
|
|
105
|
+
<CommonSvgIcon icon="close" />
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div
|
|
111
|
+
v-else
|
|
112
|
+
class="flex py-4 w-full"
|
|
113
|
+
>
|
|
114
|
+
<p class="text-center mb-0 text-green-500 w-full">
|
|
115
|
+
Select one or more users to chat with,
|
|
116
|
+
<br>
|
|
117
|
+
then click Start Chat
|
|
118
|
+
</p>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<!-- All Users -->
|
|
123
|
+
<div
|
|
124
|
+
v-for="currentUser in filteredUsers?.data"
|
|
125
|
+
:key="currentUser.id"
|
|
126
|
+
>
|
|
127
|
+
<div
|
|
128
|
+
v-if="currentUser.id !== user.data.id && !exists(currentUser)"
|
|
129
|
+
class="user-item"
|
|
130
|
+
@click="toggle(currentUser)"
|
|
131
|
+
>
|
|
132
|
+
<CommonSvgIcon
|
|
133
|
+
v-if="currentUser.online"
|
|
134
|
+
icon="online"
|
|
135
|
+
/>
|
|
136
|
+
<CommonSvgIcon
|
|
137
|
+
v-if="!currentUser.online"
|
|
138
|
+
icon="offline"
|
|
139
|
+
/>
|
|
140
|
+
<CommonSvgIcon
|
|
141
|
+
icon="person"
|
|
142
|
+
/>
|
|
143
|
+
<div class="text-sm py-4">
|
|
144
|
+
<p class="pt-2 text-black leading-none">
|
|
145
|
+
{{ getName(currentUser) }}
|
|
146
|
+
</p>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
<VueEternalLoading
|
|
151
|
+
v-model:is-initial="isInitial"
|
|
152
|
+
:load="load"
|
|
153
|
+
>
|
|
154
|
+
<template #no-more>
|
|
155
|
+
|
|
156
|
+
</template>
|
|
157
|
+
</VueEternalLoading>
|
|
158
|
+
</div>
|
|
159
|
+
<button
|
|
160
|
+
v-if="selectedUsers?.length !== 0"
|
|
161
|
+
class="create-conversation-button bg-blue-500 border-0 hover:bg-blue-700 text-white font-bold py-3 px-4 focus:outline-none cursor-pointer"
|
|
162
|
+
type="button"
|
|
163
|
+
@click="createConversation(selectedUsers as User[])"
|
|
164
|
+
>
|
|
165
|
+
Start Chat
|
|
166
|
+
</button>
|
|
167
|
+
</div>
|
|
168
|
+
</template>
|
|
169
|
+
|
|
170
|
+
<style scoped>
|
|
171
|
+
.disabled {
|
|
172
|
+
opacity: 50%;
|
|
173
|
+
cursor: not-allowed;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.disabled:hover {
|
|
177
|
+
background-color: #3490dc !important;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.create-conversation-button {
|
|
181
|
+
border-bottom-left-radius: 9px;
|
|
182
|
+
border-bottom-right-radius: 9px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.user-item {
|
|
186
|
+
@apply cursor-pointer flex items-center px-4 bg-gray-300;
|
|
187
|
+
border-bottom: 1px solid #dae1e7;
|
|
188
|
+
}
|
|
189
|
+
.user-item:hover {
|
|
190
|
+
background-color: #f9fafb;
|
|
191
|
+
}
|
|
192
|
+
.user-item:active {
|
|
193
|
+
background-color: #bbc8d3;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.selected-user-item {
|
|
197
|
+
@apply cursor-pointer flex items-center px-4 border-r-2 border-gray-400;
|
|
198
|
+
}
|
|
199
|
+
.selected-user-item:hover {
|
|
200
|
+
background-color: #f9fafb;
|
|
201
|
+
}
|
|
202
|
+
.selected-user-item:active {
|
|
203
|
+
background-color: #bbc8d3;
|
|
204
|
+
}
|
|
205
|
+
</style>
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { inject, onMounted, onBeforeUnmount, ref, toRefs, watch } from 'vue';
|
|
3
|
+
import { storeToRefs } from 'pinia';
|
|
4
|
+
import { debounce, find, remove } from 'lodash-es';
|
|
5
|
+
import { VueEternalLoading, LoadAction } from "@ts-pro/vue-eternal-loading";
|
|
6
|
+
import { useConversationStore } from '#imports';
|
|
7
|
+
import { chatSearchEventHook } from '../../composables/useEventHooks';
|
|
8
|
+
import type { User } from '../../models/user';
|
|
9
|
+
|
|
10
|
+
// data
|
|
11
|
+
const selectedUsers = ref<User[]>();
|
|
12
|
+
const filteredUsers = ref<User[]>();
|
|
13
|
+
|
|
14
|
+
const conversationStore = useConversationStore();
|
|
15
|
+
|
|
16
|
+
const { user, users, isInitial } = storeToRefs(conversationStore);
|
|
17
|
+
|
|
18
|
+
// emits
|
|
19
|
+
const emit = defineEmits<{
|
|
20
|
+
(event: 'onCreate', value: User[]): void;
|
|
21
|
+
}>();
|
|
22
|
+
|
|
23
|
+
// injected load function
|
|
24
|
+
// (see Vue Eternal Loading docs for reference: https://ts-pro.github.io/vue-eternal-loading/guide/simple-usage.html)
|
|
25
|
+
const load = inject('attendeeListLoad', (loaded: LoadAction) => { console.log('no scroll'); loaded(0); })
|
|
26
|
+
|
|
27
|
+
const { getName } = conversationStore;
|
|
28
|
+
|
|
29
|
+
// methods
|
|
30
|
+
const toggle = (user: User) => {
|
|
31
|
+
if (exists(user) == undefined) {
|
|
32
|
+
selectedUsers.value?.push(user);
|
|
33
|
+
} else {
|
|
34
|
+
const array = selectedUsers.value as User[];
|
|
35
|
+
|
|
36
|
+
remove(array, (element) => {
|
|
37
|
+
return element.id === user.id;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
selectedUsers.value = [...array];
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const exists = (user: User): User | undefined => {
|
|
45
|
+
return find(selectedUsers.value, {'id': user.id});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const onSearchChange = debounce((value: string) => {
|
|
49
|
+
chatSearchEventHook.trigger({value: value, iterate: true});
|
|
50
|
+
}, 500);
|
|
51
|
+
|
|
52
|
+
const clear = (): void => {
|
|
53
|
+
chatSearchEventHook.trigger({value: undefined, iterate: true});
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
watch(users.value, (_users, _newUsers) => {
|
|
57
|
+
filteredUsers.value = _newUsers.data;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// lifecycle hooks
|
|
61
|
+
onMounted(() => {
|
|
62
|
+
filteredUsers.value = users.value.data;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
onBeforeUnmount(() => {
|
|
66
|
+
clear();
|
|
67
|
+
});
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<div class="flex h-full justify-between flex-col overflow-y-hidden">
|
|
72
|
+
<CommonSearchInput
|
|
73
|
+
@on-change="onSearchChange"
|
|
74
|
+
/>
|
|
75
|
+
<div class="overflow-y-auto h-full bg-grey-lighter">
|
|
76
|
+
<!-- Selected Users -->
|
|
77
|
+
<div
|
|
78
|
+
v-if="selectedUsers?.length"
|
|
79
|
+
class="z-50 sticky pin-t border-b-4 border-blue bg-grey-lighter"
|
|
80
|
+
>
|
|
81
|
+
<div
|
|
82
|
+
v-for="currentUser in selectedUsers"
|
|
83
|
+
:key="currentUser.id"
|
|
84
|
+
>
|
|
85
|
+
<div
|
|
86
|
+
v-if="currentUser.id !== user.id"
|
|
87
|
+
class="cursor-pointer flex items-center px-4"
|
|
88
|
+
style="border-bottom: 1px solid #dae1e7"
|
|
89
|
+
@click="toggle(currentUser)"
|
|
90
|
+
>
|
|
91
|
+
<CommonSvgIcon icon="check" />
|
|
92
|
+
<CommonSvgIcon icon="person" />
|
|
93
|
+
<div class="text-sm py-2">
|
|
94
|
+
<p class="pt-2 text-black leading-none">
|
|
95
|
+
{{ getName(currentUser) }}
|
|
96
|
+
</p>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<!-- All Users -->
|
|
103
|
+
<div
|
|
104
|
+
v-for="currentUser in filteredUsers"
|
|
105
|
+
:key="currentUser.id"
|
|
106
|
+
>
|
|
107
|
+
<div
|
|
108
|
+
v-if="currentUser.id !== user.id"
|
|
109
|
+
:class="{selected: exists(currentUser), 'bg-grey-lighter': !exists(currentUser) }"
|
|
110
|
+
class="cursor-pointer flex items-center px-4"
|
|
111
|
+
style="border-bottom: 1px solid #dae1e7"
|
|
112
|
+
@click="toggle(currentUser)"
|
|
113
|
+
>
|
|
114
|
+
<CommonSvgIcon
|
|
115
|
+
v-if="currentUser.online"
|
|
116
|
+
icon="online"
|
|
117
|
+
/>
|
|
118
|
+
<CommonSvgIcon
|
|
119
|
+
v-else
|
|
120
|
+
icon="online"
|
|
121
|
+
/>
|
|
122
|
+
<CommonSvgIcon
|
|
123
|
+
icon="person"
|
|
124
|
+
/>
|
|
125
|
+
<div class="text-sm py-4">
|
|
126
|
+
<p class="pt-2 text-black leading-none">
|
|
127
|
+
{{ getName(currentUser) }}
|
|
128
|
+
</p>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
<VueEternalLoading
|
|
133
|
+
v-model:is-initial="isInitial"
|
|
134
|
+
:load="load"
|
|
135
|
+
>
|
|
136
|
+
<template #no-more>
|
|
137
|
+
|
|
138
|
+
</template>
|
|
139
|
+
</VueEternalLoading>
|
|
140
|
+
</div>
|
|
141
|
+
<button
|
|
142
|
+
class="create-conversation-button bg-blue border-0 hover:bg-blue-dark text-white font-bold py-3 px-4 focus:outline-none cursor-pointer"
|
|
143
|
+
type="button"
|
|
144
|
+
@click="emit('onCreate', selectedUsers as User[])"
|
|
145
|
+
>
|
|
146
|
+
Create Conversation
|
|
147
|
+
</button>
|
|
148
|
+
</div>
|
|
149
|
+
</template>
|
|
150
|
+
|
|
151
|
+
<style scoped>
|
|
152
|
+
.selected {
|
|
153
|
+
background-color: #b8c2cc;
|
|
154
|
+
}
|
|
155
|
+
.create-conversation-button {
|
|
156
|
+
border-bottom-left-radius: 9px;
|
|
157
|
+
border-bottom-right-radius: 9px;
|
|
158
|
+
}
|
|
159
|
+
</style>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { useConversationStore } from '#imports';
|
|
3
|
+
|
|
4
|
+
import { MenuOptions } from './ChatWindow.vue';
|
|
5
|
+
|
|
6
|
+
const { toggleChat } = useConversationStore();
|
|
7
|
+
|
|
8
|
+
const emit = defineEmits<{
|
|
9
|
+
(event: 'itemSelected', value: MenuOptions): void;
|
|
10
|
+
}>();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<div class="header bg-blue-500">
|
|
15
|
+
<div class="flex flex-row text-center text-white w-full">
|
|
16
|
+
<div
|
|
17
|
+
class="flex-1 grow flex items-center h-full header-button"
|
|
18
|
+
@click="emit('itemSelected', MenuOptions.LIST)"
|
|
19
|
+
>
|
|
20
|
+
<p class="flex-1 py-0 px-2 m-0">
|
|
21
|
+
All Chats
|
|
22
|
+
</p>
|
|
23
|
+
</div>
|
|
24
|
+
<div
|
|
25
|
+
class="flex-1 flex items-center h-full header-button"
|
|
26
|
+
@click="emit('itemSelected', MenuOptions.CREATE)"
|
|
27
|
+
>
|
|
28
|
+
<p class="flex-1 py-0 px-2 m-0">
|
|
29
|
+
New Chat
|
|
30
|
+
</p>
|
|
31
|
+
</div>
|
|
32
|
+
<div
|
|
33
|
+
class="flex-shrink flex items-center h-full header-button"
|
|
34
|
+
@click="toggleChat"
|
|
35
|
+
>
|
|
36
|
+
<CommonSvgIcon
|
|
37
|
+
class="flex-1 flex items-center justify-center"
|
|
38
|
+
fill-color="white"
|
|
39
|
+
icon="close"
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<style scoped>
|
|
47
|
+
.header {
|
|
48
|
+
border-top-left-radius: 9px;
|
|
49
|
+
border-top-right-radius: 9px;
|
|
50
|
+
padding: 0.25rem;
|
|
51
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
|
|
52
|
+
position: relative;
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
display: flex;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.header-title {
|
|
58
|
+
align-self: center;
|
|
59
|
+
padding: 10px;
|
|
60
|
+
flex: 1;
|
|
61
|
+
user-select: none;
|
|
62
|
+
font-size: 16px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.header-button {
|
|
66
|
+
align-self: center;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
border-radius: 5px;
|
|
69
|
+
padding: 0.5rem;
|
|
70
|
+
}
|
|
71
|
+
.header-button:hover {
|
|
72
|
+
@apply shadow;
|
|
73
|
+
}
|
|
74
|
+
.header-button:hover:active {
|
|
75
|
+
@apply shadow-inner;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.icon-button {
|
|
79
|
+
width: 40px;
|
|
80
|
+
height: 40px;
|
|
81
|
+
padding: 13px;
|
|
82
|
+
margin-left: auto;
|
|
83
|
+
margin-right: 10px;
|
|
84
|
+
box-sizing: border-box;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.header-button img, .header-button svg {
|
|
88
|
+
width: 100%;
|
|
89
|
+
height: 100%;
|
|
90
|
+
box-sizing: border-box;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@media (max-width: 450px) {
|
|
94
|
+
.header {
|
|
95
|
+
border-radius: 0px;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
</style>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { toRefs } from 'vue';
|
|
3
|
+
type Props = {
|
|
4
|
+
from: string;
|
|
5
|
+
time: string;
|
|
6
|
+
text: string;
|
|
7
|
+
inbound: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const props = defineProps<Props>();
|
|
11
|
+
|
|
12
|
+
const { from, time, text, inbound } = toRefs(props);
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div class="clearfix">
|
|
17
|
+
<div
|
|
18
|
+
class="w-3/4 mx-4"
|
|
19
|
+
:class="{ 'float-right': !inbound }"
|
|
20
|
+
>
|
|
21
|
+
<div class="flex items-start items-center mb-4 text-sm">
|
|
22
|
+
<CommonSvgIcon icon="person" />
|
|
23
|
+
<div class="flex-1 overflow-hidden">
|
|
24
|
+
<p class="text-gray-500 text-xs mt-0 pt-1">
|
|
25
|
+
{{ from }}
|
|
26
|
+
</p>
|
|
27
|
+
<p
|
|
28
|
+
class="rounded border-2 border-gray-100 leading-normal m-0 p-2"
|
|
29
|
+
:class="{'bg-blue-500 text-white' : !inbound, 'bg-gray-100 text-black' : inbound}"
|
|
30
|
+
>
|
|
31
|
+
{{ text }}
|
|
32
|
+
</p>
|
|
33
|
+
<p class="text-gray-500 text-xs mt-0 pt-1">
|
|
34
|
+
{{ time }}
|
|
35
|
+
</p>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { toRefs } from 'vue';
|
|
3
|
+
import { storeToRefs } from 'pinia';
|
|
4
|
+
import { useConversationStore } from '#imports';
|
|
5
|
+
import MessageInput from './MessageInput.vue';
|
|
6
|
+
import { sendMessageEventHook } from '../../composables/useEventHooks';
|
|
7
|
+
import type { User } from '../../models/user';
|
|
8
|
+
import type { Conversation, Message } from '../../models/conversation';
|
|
9
|
+
|
|
10
|
+
const conversationStore = useConversationStore();
|
|
11
|
+
|
|
12
|
+
const { selectedConversation, user } = storeToRefs(conversationStore);
|
|
13
|
+
|
|
14
|
+
const { getName } = conversationStore;
|
|
15
|
+
|
|
16
|
+
// methods
|
|
17
|
+
const isInbound = (userArg: User): boolean => {
|
|
18
|
+
return userArg.id !== user.value.data.id;
|
|
19
|
+
};
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div class="flex justify-between flex-col h-full overflow-y-hidden">
|
|
24
|
+
<div class="overflow-y-auto">
|
|
25
|
+
<div class="z-50 sticky flex pin-t border-b-4 border-blue-500 bg-gray-300 overflow-x-auto">
|
|
26
|
+
<div class="flex flex-row">
|
|
27
|
+
<div
|
|
28
|
+
v-for="currentUser in selectedConversation?.users"
|
|
29
|
+
:key="currentUser.id"
|
|
30
|
+
class="py-1"
|
|
31
|
+
>
|
|
32
|
+
<div
|
|
33
|
+
v-if="currentUser.id !== user.id"
|
|
34
|
+
class="flex items-center px-4 border-r-2 border-gray-400"
|
|
35
|
+
>
|
|
36
|
+
<CommonSvgIcon icon="person" />
|
|
37
|
+
<div class="text-sm py-2">
|
|
38
|
+
<p class="pt-2 text-black leading-none">
|
|
39
|
+
{{ getName(currentUser) }}
|
|
40
|
+
</p>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div
|
|
46
|
+
v-if="Object.keys(selectedConversation as Conversation[]).length > 0 && selectedConversation?.user?.id !== user.id"
|
|
47
|
+
class="py-1"
|
|
48
|
+
>
|
|
49
|
+
<div
|
|
50
|
+
class="flex items-center px-4 border-r-2 border-gray-400"
|
|
51
|
+
>
|
|
52
|
+
<CommonSvgIcon icon="person" />
|
|
53
|
+
<div class="text-sm py-2">
|
|
54
|
+
<p class="pt-2 text-black leading-none">
|
|
55
|
+
{{ getName(selectedConversation?.user as User) }}
|
|
56
|
+
</p>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div>
|
|
64
|
+
<CommonChatMessage
|
|
65
|
+
v-for="message in selectedConversation?.messages"
|
|
66
|
+
:key="message.id"
|
|
67
|
+
:from="message?.user?.name"
|
|
68
|
+
:text="message.message"
|
|
69
|
+
:time="message.created_at"
|
|
70
|
+
:inbound="isInbound(message?.user as User)"
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<MessageInput @send-message="(message: string) => {console.log('message event: ', message); sendMessageEventHook.trigger(message)}" />
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { toRefs } from 'vue';
|
|
3
|
+
import { toggleChatWindowEventHook } from '../../composables/useEventHooks';
|
|
4
|
+
import ChatWindow from './ChatWindow.vue';
|
|
5
|
+
import SvgIcon from '../core/SvgIcon.vue';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
hasNotifications: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const props = defineProps<Props>();
|
|
12
|
+
|
|
13
|
+
const { hasNotifications } = toRefs(props);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<div>
|
|
18
|
+
<div
|
|
19
|
+
class="launcher"
|
|
20
|
+
@click="toggleChatWindowEventHook.trigger()"
|
|
21
|
+
>
|
|
22
|
+
<SvgIcon icon="chat" />
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div
|
|
26
|
+
v-if="hasNotifications"
|
|
27
|
+
class="bell"
|
|
28
|
+
>
|
|
29
|
+
<SvgIcon icon="bell" />
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<ChatWindow
|
|
33
|
+
@close="toggleChatWindowEventHook.trigger()"
|
|
34
|
+
/>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<style scoped>
|
|
39
|
+
.launcher {
|
|
40
|
+
z-index: 9999;
|
|
41
|
+
width: 60px;
|
|
42
|
+
height: 60px;
|
|
43
|
+
background-position: center;
|
|
44
|
+
background-repeat: no-repeat;
|
|
45
|
+
position: fixed;
|
|
46
|
+
right: 75px;
|
|
47
|
+
bottom: 25px;
|
|
48
|
+
border-radius: 50%;
|
|
49
|
+
box-shadow: none;
|
|
50
|
+
transition: box-shadow 0.2s ease-in-out;
|
|
51
|
+
cursor: pointer;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.bell {
|
|
55
|
+
z-index: 9999;
|
|
56
|
+
position: fixed;
|
|
57
|
+
bottom: 60px;
|
|
58
|
+
right: 15px;
|
|
59
|
+
padding: 2px 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.bell svg {
|
|
63
|
+
height: 90px;
|
|
64
|
+
}
|
|
65
|
+
</style>
|