@webitel/ui-chats 26.8.3 → 26.8.4
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/package.json +9 -2
- package/src/locale/en/en.ts +3 -0
- package/src/locale/es/es.ts +3 -0
- package/src/locale/kz/kz.ts +3 -0
- package/src/locale/pl/pl.ts +3 -0
- package/src/locale/ro/ro.ts +3 -0
- package/src/locale/ru/ru.ts +3 -0
- package/src/locale/uk/uk.ts +3 -0
- package/src/locale/uz/uz.ts +3 -0
- package/src/locale/vi/vi.ts +3 -0
- package/src/shared/composables/__tests__/useChatScroll.spec.ts +164 -0
- package/src/shared/composables/__tests__/useObserveHeightUntilStable.spec.ts +48 -0
- package/src/{ui/messaging → shared}/composables/useChatScroll.ts +37 -9
- package/src/{ui/messaging → shared}/composables/useObserveHeightUntilStable.ts +2 -0
- package/src/ui/index.ts +2 -2
- package/src/ui/messaging/components/the-messages-container.vue +2 -2
- package/src/v2/index.ts +4 -0
- package/src/v2/locale/en.ts +29 -0
- package/src/v2/locale/es.ts +28 -0
- package/src/v2/locale/kz.ts +28 -0
- package/src/v2/locale/pl.ts +28 -0
- package/src/v2/locale/ro.ts +28 -0
- package/src/v2/locale/ru.ts +27 -0
- package/src/v2/locale/uk.ts +27 -0
- package/src/v2/locale/useChatsV2I18n.ts +14 -0
- package/src/v2/locale/uz.ts +28 -0
- package/src/v2/locale/vi.ts +28 -0
- package/src/v2/scripts/__tests__/attachments.spec.ts +168 -0
- package/src/v2/scripts/__tests__/fixtures.ts +56 -0
- package/src/v2/scripts/__tests__/formatDate.spec.ts +96 -0
- package/src/v2/scripts/__tests__/getMessageStatus.spec.ts +214 -0
- package/src/v2/scripts/__tests__/isContactCentreSide.spec.ts +21 -0
- package/src/v2/scripts/__tests__/resolveSystemNotice.spec.ts +157 -0
- package/src/v2/scripts/__tests__/toHistoryItems.spec.ts +100 -0
- package/src/v2/scripts/attachments.ts +144 -0
- package/src/v2/scripts/formatDate.ts +74 -0
- package/src/v2/scripts/getMessageStatus.ts +58 -0
- package/src/v2/scripts/isContactCentreSide.ts +14 -0
- package/src/v2/scripts/resolveSystemNotice.ts +119 -0
- package/src/v2/scripts/toHistoryItems.ts +63 -0
- package/src/v2/scripts/toTimestamp.ts +21 -0
- package/src/v2/types/index.ts +74 -0
- package/src/v2/ui/__tests__/mountWithChats.ts +38 -0
- package/src/v2/ui/chat-composer/__tests__/chat-composer.spec.ts +221 -0
- package/src/v2/ui/chat-composer/chat-composer.vue +212 -0
- package/src/v2/ui/chat-history/__tests__/chat-history.spec.ts +235 -0
- package/src/v2/ui/chat-history/chat-history.vue +262 -0
- package/src/v2/ui/chat-history/components/chat-date-divider.vue +36 -0
- package/src/v2/ui/chat-history/components/chat-message.vue +148 -0
- package/src/v2/ui/chat-history/components/chat-system-notice.vue +100 -0
- package/src/v2/ui/chat-history/components/message-attachments.vue +162 -0
- package/src/v2/ui/chat-history/components/message-status.vue +31 -0
- package/src/v2/ui/chat-history/components/message-text.vue +37 -0
- package/src/v2/ui/chat-history/components/scroll-to-bottom-btn.vue +55 -0
- package/src/v2/ui/chat-history/gallery.ts +8 -0
- package/src/v2/ui/chat-thread/__tests__/chat-thread.spec.ts +122 -0
- package/src/v2/ui/chat-thread/chat-thread.vue +111 -0
- package/types/.tsbuildinfo +1 -1
- package/types/locale/en/en.d.ts +25 -0
- package/types/locale/es/es.d.ts +25 -0
- package/types/locale/index.d.ts +225 -0
- package/types/locale/kz/kz.d.ts +25 -0
- package/types/locale/pl/pl.d.ts +25 -0
- package/types/locale/ro/ro.d.ts +25 -0
- package/types/locale/ru/ru.d.ts +25 -0
- package/types/locale/uk/uk.d.ts +25 -0
- package/types/locale/uz/uz.d.ts +25 -0
- package/types/locale/vi/vi.d.ts +25 -0
- package/types/{ui/messaging → shared}/composables/useChatScroll.d.ts +14 -4
- package/types/ui/index.d.ts +2 -2
- package/types/v2/index.d.ts +4 -0
- package/types/v2/locale/en.d.ts +27 -0
- package/types/v2/locale/es.d.ts +26 -0
- package/types/v2/locale/kz.d.ts +26 -0
- package/types/v2/locale/pl.d.ts +26 -0
- package/types/v2/locale/ro.d.ts +26 -0
- package/types/v2/locale/ru.d.ts +26 -0
- package/types/v2/locale/uk.d.ts +26 -0
- package/types/v2/locale/useChatsV2I18n.d.ts +5 -0
- package/types/v2/locale/uz.d.ts +26 -0
- package/types/v2/locale/vi.d.ts +26 -0
- package/types/v2/scripts/__tests__/fixtures.d.ts +7 -0
- package/types/v2/scripts/attachments.d.ts +30 -0
- package/types/v2/scripts/formatDate.d.ts +17 -0
- package/types/v2/scripts/getMessageStatus.d.ts +8 -0
- package/types/v2/scripts/isContactCentreSide.d.ts +8 -0
- package/types/v2/scripts/resolveSystemNotice.d.ts +23 -0
- package/types/v2/scripts/toHistoryItems.d.ts +19 -0
- package/types/v2/scripts/toTimestamp.d.ts +7 -0
- package/types/v2/types/index.d.ts +54 -0
- package/types/v2/ui/__tests__/mountWithChats.d.ts +8 -0
- package/types/v2/ui/chat-composer/chat-composer.vue.d.ts +31 -0
- package/types/v2/ui/chat-history/chat-history.vue.d.ts +11 -0
- package/types/v2/ui/chat-history/components/chat-date-divider.vue.d.ts +6 -0
- package/types/v2/ui/chat-history/components/chat-message.vue.d.ts +10 -0
- package/types/v2/ui/chat-history/components/chat-system-notice.vue.d.ts +9 -0
- package/types/v2/ui/chat-history/components/message-attachments.vue.d.ts +7 -0
- package/types/v2/ui/chat-history/components/message-status.vue.d.ts +7 -0
- package/types/v2/ui/chat-history/components/message-text.vue.d.ts +6 -0
- package/types/v2/ui/chat-history/components/scroll-to-bottom-btn.vue.d.ts +12 -0
- package/types/v2/ui/chat-history/gallery.d.ts +6 -0
- package/types/v2/ui/chat-thread/chat-thread.vue.d.ts +26 -0
- /package/src/{ui/messaging → shared}/composables/useScrollToBottomBtn.ts +0 -0
- /package/types/{ui/messaging → shared}/composables/useObserveHeightUntilStable.d.ts +0 -0
- /package/types/{ui/messaging → shared}/composables/useScrollToBottomBtn.d.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webitel/ui-chats",
|
|
3
|
-
"version": "26.8.
|
|
3
|
+
"version": "26.8.4",
|
|
4
4
|
"description": "Reusable Webitel Frontend Code for Chats UI",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
"../../",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"typecheck": "vue-tsc --noEmit -p ./tsconfig.typecheck.json",
|
|
14
14
|
"lint:fix": "npx biome check --write ./src",
|
|
15
15
|
"biome:ci:gh": "biome ci ./src --reporter=github",
|
|
16
|
-
"test:unit": "
|
|
16
|
+
"test:unit": "vitest run --root ../.. packages/ui-chats/src",
|
|
17
17
|
"lint": "biome ci ./src",
|
|
18
18
|
"test": "npm run test:unit",
|
|
19
19
|
"ci:check": "npm run biome:ci:gh && npm run test:unit",
|
|
@@ -21,7 +21,10 @@
|
|
|
21
21
|
"utils:publish": "npm publish --access public"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"@vueuse/core": "^14.0.0",
|
|
24
25
|
"autolinker": "^4.1.5",
|
|
26
|
+
"date-fns": "^4.1.0",
|
|
27
|
+
"date-fns-tz": "^3.2.0",
|
|
25
28
|
"insert-text-at-cursor": "^0.3.0"
|
|
26
29
|
},
|
|
27
30
|
"devDependencies": {
|
|
@@ -75,6 +78,10 @@
|
|
|
75
78
|
"./adapters": {
|
|
76
79
|
"types": "./types/adapters/index.d.ts",
|
|
77
80
|
"import": "./src/adapters/index.ts"
|
|
81
|
+
},
|
|
82
|
+
"./v2": {
|
|
83
|
+
"types": "./types/v2/index.d.ts",
|
|
84
|
+
"import": "./src/v2/index.ts"
|
|
78
85
|
}
|
|
79
86
|
},
|
|
80
87
|
"author": "webitel",
|
package/src/locale/en/en.ts
CHANGED
package/src/locale/es/es.ts
CHANGED
package/src/locale/kz/kz.ts
CHANGED
package/src/locale/pl/pl.ts
CHANGED
package/src/locale/ro/ro.ts
CHANGED
package/src/locale/ru/ru.ts
CHANGED
package/src/locale/uk/uk.ts
CHANGED
package/src/locale/uz/uz.ts
CHANGED
package/src/locale/vi/vi.ts
CHANGED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { computed, defineComponent, h, nextTick, ref } from 'vue';
|
|
4
|
+
|
|
5
|
+
import { useChatScroll } from '../useChatScroll';
|
|
6
|
+
|
|
7
|
+
const Host = defineComponent({
|
|
8
|
+
props: {
|
|
9
|
+
items: {
|
|
10
|
+
type: Array,
|
|
11
|
+
required: true,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
setup(props) {
|
|
15
|
+
const container = ref<HTMLElement | null>(null);
|
|
16
|
+
const content = ref<HTMLElement | null>(null);
|
|
17
|
+
const api = useChatScroll<{
|
|
18
|
+
mine: boolean;
|
|
19
|
+
}>({
|
|
20
|
+
chatContainer: container,
|
|
21
|
+
chatContent: content,
|
|
22
|
+
messages: computed(
|
|
23
|
+
() =>
|
|
24
|
+
props.items as {
|
|
25
|
+
mine: boolean;
|
|
26
|
+
}[],
|
|
27
|
+
),
|
|
28
|
+
isSelf: (item) => item.mine,
|
|
29
|
+
itemClass: 'row',
|
|
30
|
+
chatId: computed(() => 'c1'),
|
|
31
|
+
isChatClosed: computed(() => false),
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
container,
|
|
35
|
+
content,
|
|
36
|
+
api,
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
render() {
|
|
40
|
+
return h(
|
|
41
|
+
'div',
|
|
42
|
+
{
|
|
43
|
+
ref: 'container',
|
|
44
|
+
},
|
|
45
|
+
[
|
|
46
|
+
h('div', {
|
|
47
|
+
ref: 'content',
|
|
48
|
+
}),
|
|
49
|
+
],
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('useChatScroll (shared)', () => {
|
|
55
|
+
it('mounts with a custom isSelf / itemClass and exposes its API', () => {
|
|
56
|
+
const wrapper = mount(Host, {
|
|
57
|
+
props: {
|
|
58
|
+
items: [
|
|
59
|
+
{
|
|
60
|
+
mine: false,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const { api } = wrapper.vm as unknown as {
|
|
66
|
+
api: ReturnType<typeof useChatScroll>;
|
|
67
|
+
};
|
|
68
|
+
expect(api.newUnseenMessagesCount.value).toBe(0);
|
|
69
|
+
expect(typeof api.scrollToBottom).toBe('function');
|
|
70
|
+
wrapper.unmount();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('still accepts v1 items without isSelf', () => {
|
|
74
|
+
const V1Host = defineComponent({
|
|
75
|
+
setup() {
|
|
76
|
+
const container = ref<HTMLElement | null>(null);
|
|
77
|
+
useChatScroll({
|
|
78
|
+
chatContainer: container,
|
|
79
|
+
chatContent: ref(null),
|
|
80
|
+
messages: computed(() => [
|
|
81
|
+
{
|
|
82
|
+
member: {
|
|
83
|
+
self: true,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
]),
|
|
87
|
+
chatId: computed(() => 'c1'),
|
|
88
|
+
isChatClosed: computed(() => false),
|
|
89
|
+
});
|
|
90
|
+
return () =>
|
|
91
|
+
h('div', {
|
|
92
|
+
ref: container,
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
expect(() => mount(V1Host).unmount()).not.toThrow();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('useChatScroll — thread switch during a pending load', () => {
|
|
101
|
+
it('does not restore the old thread’s scroll anchor into the new thread', async () => {
|
|
102
|
+
const chatId = ref('a');
|
|
103
|
+
const isLoading = ref(false);
|
|
104
|
+
const container = ref<HTMLElement | null>(null);
|
|
105
|
+
const Host = defineComponent({
|
|
106
|
+
setup() {
|
|
107
|
+
const api = useChatScroll({
|
|
108
|
+
chatContainer: container,
|
|
109
|
+
chatContent: ref(null),
|
|
110
|
+
messages: computed(() => []),
|
|
111
|
+
chatId: computed(() => chatId.value),
|
|
112
|
+
isChatClosed: computed(() => false),
|
|
113
|
+
isLoading,
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
api,
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
render() {
|
|
120
|
+
return h(
|
|
121
|
+
'div',
|
|
122
|
+
{
|
|
123
|
+
ref: (el) => {
|
|
124
|
+
container.value = el as HTMLElement;
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
[
|
|
128
|
+
h('div', {
|
|
129
|
+
class: 'chat-message',
|
|
130
|
+
}),
|
|
131
|
+
],
|
|
132
|
+
);
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
const wrapper = mount(Host);
|
|
136
|
+
await nextTick();
|
|
137
|
+
const scrollTo = vi.fn();
|
|
138
|
+
(container.value as HTMLElement).scrollTo = scrollTo;
|
|
139
|
+
const { api } = wrapper.vm as unknown as {
|
|
140
|
+
api: ReturnType<typeof useChatScroll>;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
api.loadNextMessages(true, () => {
|
|
144
|
+
isLoading.value = true;
|
|
145
|
+
});
|
|
146
|
+
await nextTick();
|
|
147
|
+
chatId.value = 'b';
|
|
148
|
+
await nextTick();
|
|
149
|
+
await nextTick();
|
|
150
|
+
scrollTo.mockClear();
|
|
151
|
+
|
|
152
|
+
isLoading.value = false;
|
|
153
|
+
await nextTick();
|
|
154
|
+
await nextTick();
|
|
155
|
+
|
|
156
|
+
// 'auto' is the prepend restore; scrollToBottom uses 'instant'
|
|
157
|
+
expect(scrollTo).not.toHaveBeenCalledWith(
|
|
158
|
+
expect.objectContaining({
|
|
159
|
+
behavior: 'auto',
|
|
160
|
+
}),
|
|
161
|
+
);
|
|
162
|
+
wrapper.unmount();
|
|
163
|
+
});
|
|
164
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { defineComponent, h, ref } from 'vue';
|
|
4
|
+
|
|
5
|
+
import { useObserveHeightUntilStable } from '../useObserveHeightUntilStable';
|
|
6
|
+
|
|
7
|
+
const observers: Array<{
|
|
8
|
+
disconnect: ReturnType<typeof vi.fn>;
|
|
9
|
+
}> = [];
|
|
10
|
+
|
|
11
|
+
class TrackedResizeObserver {
|
|
12
|
+
disconnect = vi.fn();
|
|
13
|
+
observe = vi.fn();
|
|
14
|
+
unobserve = vi.fn();
|
|
15
|
+
constructor() {
|
|
16
|
+
observers.push(this);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('useObserveHeightUntilStable', () => {
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
observers.length = 0;
|
|
23
|
+
vi.unstubAllGlobals();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// a second start (thread switch) must not leave the first observer scrolling forever
|
|
27
|
+
it('stops the previous observer when started again', () => {
|
|
28
|
+
vi.stubGlobal('ResizeObserver', TrackedResizeObserver);
|
|
29
|
+
const target = ref<HTMLElement | null>(document.createElement('div'));
|
|
30
|
+
const Host = defineComponent({
|
|
31
|
+
setup() {
|
|
32
|
+
return useObserveHeightUntilStable(target, () => {}, 2000);
|
|
33
|
+
},
|
|
34
|
+
render: () => h('div'),
|
|
35
|
+
});
|
|
36
|
+
const wrapper = mount(Host);
|
|
37
|
+
const api = wrapper.vm as unknown as {
|
|
38
|
+
startObserve: () => void;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
api.startObserve();
|
|
42
|
+
api.startObserve();
|
|
43
|
+
|
|
44
|
+
expect(observers).toHaveLength(2);
|
|
45
|
+
expect(observers[0].disconnect).toHaveBeenCalled();
|
|
46
|
+
wrapper.unmount();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -9,14 +9,23 @@ import {
|
|
|
9
9
|
watch,
|
|
10
10
|
} from 'vue';
|
|
11
11
|
|
|
12
|
-
import type { ChatMessageType } from '../types/ChatMessage.types';
|
|
13
|
-
|
|
14
12
|
import { useScrollToBottomBtn } from './useScrollToBottomBtn';
|
|
15
13
|
|
|
16
|
-
export interface UseChatScrollOptions {
|
|
14
|
+
export interface UseChatScrollOptions<TItem = unknown> {
|
|
17
15
|
chatContainer: Ref<HTMLElement | null>;
|
|
18
16
|
chatContent: Ref<HTMLElement | null>;
|
|
19
|
-
messages: Ref<
|
|
17
|
+
messages: Ref<readonly TItem[]> | ComputedRef<readonly TItem[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Whether a history item was sent by the viewer. The viewer's own new
|
|
20
|
+
* message always scrolls the history to the bottom.
|
|
21
|
+
* Defaults to v1's `item.member.self`.
|
|
22
|
+
*/
|
|
23
|
+
isSelf?: (item: TItem) => boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Class carried by every history row. The topmost row anchors the scroll
|
|
26
|
+
* position while older items are prepended.
|
|
27
|
+
*/
|
|
28
|
+
itemClass?: string;
|
|
20
29
|
chatId: ComputedRef<string>;
|
|
21
30
|
isChatClosed: ComputedRef<boolean>;
|
|
22
31
|
isLoading?: Ref<boolean> | ComputedRef<boolean>;
|
|
@@ -31,10 +40,23 @@ export interface UseChatScrollOptions {
|
|
|
31
40
|
onSeen?: () => void;
|
|
32
41
|
}
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
const isSelfByMember = (item: unknown): boolean =>
|
|
44
|
+
!!(
|
|
45
|
+
item as
|
|
46
|
+
| {
|
|
47
|
+
member?: {
|
|
48
|
+
self?: boolean;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
| undefined
|
|
52
|
+
)?.member?.self;
|
|
53
|
+
|
|
54
|
+
export const useChatScroll = <TItem = unknown>({
|
|
35
55
|
chatContainer,
|
|
36
56
|
chatContent,
|
|
37
57
|
messages,
|
|
58
|
+
isSelf = isSelfByMember,
|
|
59
|
+
itemClass = 'chat-message',
|
|
38
60
|
chatId,
|
|
39
61
|
isChatClosed,
|
|
40
62
|
isLoading,
|
|
@@ -42,7 +64,7 @@ export const useChatScroll = ({
|
|
|
42
64
|
options.scrollToBottom();
|
|
43
65
|
},
|
|
44
66
|
onSeen,
|
|
45
|
-
}: UseChatScrollOptions) => {
|
|
67
|
+
}: UseChatScrollOptions<TItem>) => {
|
|
46
68
|
const { arrivedState } = useScroll(chatContainer);
|
|
47
69
|
|
|
48
70
|
const {
|
|
@@ -70,8 +92,10 @@ export const useChatScroll = ({
|
|
|
70
92
|
|
|
71
93
|
const newUnseenMessagesCount = ref(0);
|
|
72
94
|
|
|
73
|
-
const
|
|
74
|
-
|
|
95
|
+
const isLastMessageMy = computed(() => {
|
|
96
|
+
const lastMessage = messages.value?.at(-1);
|
|
97
|
+
return lastMessage !== undefined && isSelf(lastMessage);
|
|
98
|
+
});
|
|
75
99
|
|
|
76
100
|
const isViewingBottom = (el: HTMLElement) =>
|
|
77
101
|
el.clientHeight > 0 &&
|
|
@@ -112,7 +136,7 @@ export const useChatScroll = ({
|
|
|
112
136
|
if (!chatContainer.value?.children) return;
|
|
113
137
|
lastVisibleMessageEl =
|
|
114
138
|
(chatContainer.value?.getElementsByClassName(
|
|
115
|
-
|
|
139
|
+
itemClass,
|
|
116
140
|
)[0] as HTMLElement) ?? null;
|
|
117
141
|
};
|
|
118
142
|
|
|
@@ -198,6 +222,10 @@ export const useChatScroll = ({
|
|
|
198
222
|
|
|
199
223
|
const resetScrollState = () => {
|
|
200
224
|
stopStickToBottomObserving();
|
|
225
|
+
// a page still loading for the previous chat must not restore its
|
|
226
|
+
// anchor into this one
|
|
227
|
+
isLoadingNextMessages = false;
|
|
228
|
+
lastVisibleMessageEl = null;
|
|
201
229
|
prevScrollHeight = 0;
|
|
202
230
|
newUnseenMessagesCount.value = 0;
|
|
203
231
|
resetScrollToBottomBtn();
|
|
@@ -39,6 +39,8 @@ export const useObserveHeightUntilStable = (
|
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
const startObserve = () => {
|
|
42
|
+
// a restart (e.g. switching chats) must not leave the previous observer running
|
|
43
|
+
stopObserve();
|
|
42
44
|
if (!target.value) return;
|
|
43
45
|
|
|
44
46
|
observer = new ResizeObserver(() => {
|
package/src/ui/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
export { useChatScroll } from '../shared/composables/useChatScroll';
|
|
2
|
+
export { useObserveHeightUntilStable } from '../shared/composables/useObserveHeightUntilStable';
|
|
1
3
|
export { ChatAction } from './chat-footer/modules/user-input/enums/ChatAction.enum';
|
|
2
|
-
export { useChatScroll } from './messaging/composables/useChatScroll';
|
|
3
|
-
export { useObserveHeightUntilStable } from './messaging/composables/useObserveHeightUntilStable';
|
|
4
4
|
export { useChatMessageFile } from './messaging/modules/message/composables/useChatMessageFile';
|
|
5
5
|
export { MessageAction } from './messaging/modules/message/enums/MessageAction.enum';
|
|
6
6
|
export type {
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
import { WebitelContactsContact } from '@webitel/api-services/gen/models';
|
|
53
53
|
import type { Emitter } from 'mitt';
|
|
54
54
|
import { computed, inject, useTemplateRef } from 'vue';
|
|
55
|
+
import { useChatScroll } from '../../../shared/composables/useChatScroll';
|
|
56
|
+
import { useObserveHeightUntilStable } from '../../../shared/composables/useObserveHeightUntilStable';
|
|
55
57
|
import { ChatAction } from '../../chat-footer/modules/user-input/enums/ChatAction.enum';
|
|
56
58
|
import type { UiChatsEmitterEvents } from '../../utils/emitter';
|
|
57
|
-
import { useChatScroll } from '../composables/useChatScroll';
|
|
58
|
-
import { useObserveHeightUntilStable } from '../composables/useObserveHeightUntilStable';
|
|
59
59
|
import ChatMessage from '../modules/message/components/chat-message.vue';
|
|
60
60
|
import { useChatMessages } from '../modules/message/composables/useChatMessage';
|
|
61
61
|
import { MessageAction } from '../modules/message/enums/MessageAction.enum';
|
package/src/v2/index.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const en = {
|
|
2
|
+
composer: {
|
|
3
|
+
placeholder: 'Write a message...',
|
|
4
|
+
attach: 'Attach files',
|
|
5
|
+
emoji: 'Emoji',
|
|
6
|
+
send: 'Send',
|
|
7
|
+
},
|
|
8
|
+
history: {
|
|
9
|
+
today: 'Today',
|
|
10
|
+
waitingForOperator: 'Waiting for operator to accept…',
|
|
11
|
+
deletedMessage: 'Message deleted',
|
|
12
|
+
unsupportedMessage: 'Unsupported message',
|
|
13
|
+
download: 'Download',
|
|
14
|
+
},
|
|
15
|
+
systemNotice: {
|
|
16
|
+
started: 'Chat started by {actor}',
|
|
17
|
+
joined: '{actor} joined the chat',
|
|
18
|
+
accepted: '{actor} accepted the chat',
|
|
19
|
+
transferred: '{actor} transferred the chat',
|
|
20
|
+
left: '{actor} left the chat',
|
|
21
|
+
ended: 'Chat ended by {actor}',
|
|
22
|
+
unknown: 'System event',
|
|
23
|
+
system: 'system',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type ChatsV2Locale = typeof en;
|
|
28
|
+
|
|
29
|
+
export default en;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// DRAFT: needs native-speaker review (WS-50)
|
|
2
|
+
import type { ChatsV2Locale } from './en';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
composer: {
|
|
6
|
+
placeholder: 'Escribe un mensaje...',
|
|
7
|
+
attach: 'Adjuntar archivos',
|
|
8
|
+
emoji: 'Emoji',
|
|
9
|
+
send: 'Enviar',
|
|
10
|
+
},
|
|
11
|
+
history: {
|
|
12
|
+
today: 'Hoy',
|
|
13
|
+
waitingForOperator: 'Esperando a que el operador acepte…',
|
|
14
|
+
deletedMessage: 'Mensaje eliminado',
|
|
15
|
+
unsupportedMessage: 'Tipo de mensaje no compatible',
|
|
16
|
+
download: 'Descargar',
|
|
17
|
+
},
|
|
18
|
+
systemNotice: {
|
|
19
|
+
started: 'Chat iniciado por {actor}',
|
|
20
|
+
joined: '{actor} se unió al chat',
|
|
21
|
+
accepted: '{actor} aceptó el chat',
|
|
22
|
+
transferred: '{actor} transfirió el chat',
|
|
23
|
+
left: '{actor} salió del chat',
|
|
24
|
+
ended: 'Chat finalizado por {actor}',
|
|
25
|
+
unknown: 'Evento del sistema',
|
|
26
|
+
system: 'el sistema',
|
|
27
|
+
},
|
|
28
|
+
} satisfies ChatsV2Locale;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// DRAFT: needs native-speaker review (WS-50)
|
|
2
|
+
import type { ChatsV2Locale } from './en';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
composer: {
|
|
6
|
+
placeholder: 'Хабарлама жазыңыз...',
|
|
7
|
+
attach: 'Файлдарды тіркеу',
|
|
8
|
+
emoji: 'Эмодзи',
|
|
9
|
+
send: 'Жіберу',
|
|
10
|
+
},
|
|
11
|
+
history: {
|
|
12
|
+
today: 'Бүгін',
|
|
13
|
+
waitingForOperator: 'Оператордың қабылдауы күтілуде…',
|
|
14
|
+
deletedMessage: 'Хабарлама жойылды',
|
|
15
|
+
unsupportedMessage: 'Қолдау көрсетілмейтін хабарлама түрі',
|
|
16
|
+
download: 'Жүктеп алу',
|
|
17
|
+
},
|
|
18
|
+
systemNotice: {
|
|
19
|
+
started: 'Чат басталды: {actor}',
|
|
20
|
+
joined: 'Чатқа жаңа қатысушы: {actor}',
|
|
21
|
+
accepted: 'Чат қабылданды: {actor}',
|
|
22
|
+
transferred: 'Чат ауыстырылды: {actor}',
|
|
23
|
+
left: 'Қатысушы чаттан шықты: {actor}',
|
|
24
|
+
ended: 'Чат аяқталды: {actor}',
|
|
25
|
+
unknown: 'Жүйелік оқиға',
|
|
26
|
+
system: 'жүйе',
|
|
27
|
+
},
|
|
28
|
+
} satisfies ChatsV2Locale;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// DRAFT: needs native-speaker review (WS-50)
|
|
2
|
+
import type { ChatsV2Locale } from './en';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
composer: {
|
|
6
|
+
placeholder: 'Napisz wiadomość...',
|
|
7
|
+
attach: 'Załącz pliki',
|
|
8
|
+
emoji: 'Emoji',
|
|
9
|
+
send: 'Wyślij',
|
|
10
|
+
},
|
|
11
|
+
history: {
|
|
12
|
+
today: 'Dzisiaj',
|
|
13
|
+
waitingForOperator: 'Oczekiwanie na przyjęcie przez operatora…',
|
|
14
|
+
deletedMessage: 'Wiadomość usunięta',
|
|
15
|
+
unsupportedMessage: 'Nieobsługiwany typ wiadomości',
|
|
16
|
+
download: 'Pobierz',
|
|
17
|
+
},
|
|
18
|
+
systemNotice: {
|
|
19
|
+
started: 'Czat rozpoczęty: {actor}',
|
|
20
|
+
joined: 'Nowy uczestnik czatu: {actor}',
|
|
21
|
+
accepted: 'Czat przyjęty: {actor}',
|
|
22
|
+
transferred: 'Czat przekazany: {actor}',
|
|
23
|
+
left: 'Uczestnik opuścił czat: {actor}',
|
|
24
|
+
ended: 'Czat zakończony: {actor}',
|
|
25
|
+
unknown: 'Zdarzenie systemowe',
|
|
26
|
+
system: 'system',
|
|
27
|
+
},
|
|
28
|
+
} satisfies ChatsV2Locale;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// DRAFT: needs native-speaker review (WS-50)
|
|
2
|
+
import type { ChatsV2Locale } from './en';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
composer: {
|
|
6
|
+
placeholder: 'Scrie un mesaj...',
|
|
7
|
+
attach: 'Atașează fișiere',
|
|
8
|
+
emoji: 'Emoji',
|
|
9
|
+
send: 'Trimite',
|
|
10
|
+
},
|
|
11
|
+
history: {
|
|
12
|
+
today: 'Astăzi',
|
|
13
|
+
waitingForOperator: 'Se așteaptă acceptarea de către operator…',
|
|
14
|
+
deletedMessage: 'Mesaj șters',
|
|
15
|
+
unsupportedMessage: 'Tip de mesaj neacceptat',
|
|
16
|
+
download: 'Descarcă',
|
|
17
|
+
},
|
|
18
|
+
systemNotice: {
|
|
19
|
+
started: 'Chat început de {actor}',
|
|
20
|
+
joined: '{actor} s-a alăturat chatului',
|
|
21
|
+
accepted: '{actor} a acceptat chatul',
|
|
22
|
+
transferred: '{actor} a transferat chatul',
|
|
23
|
+
left: '{actor} a părăsit chatul',
|
|
24
|
+
ended: 'Chat încheiat de {actor}',
|
|
25
|
+
unknown: 'Eveniment de sistem',
|
|
26
|
+
system: 'sistem',
|
|
27
|
+
},
|
|
28
|
+
} satisfies ChatsV2Locale;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ChatsV2Locale } from './en';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
composer: {
|
|
5
|
+
placeholder: 'Напишите сообщение...',
|
|
6
|
+
attach: 'Прикрепить файлы',
|
|
7
|
+
emoji: 'Эмодзи',
|
|
8
|
+
send: 'Отправить',
|
|
9
|
+
},
|
|
10
|
+
history: {
|
|
11
|
+
today: 'Сегодня',
|
|
12
|
+
waitingForOperator: 'Ожидание, пока оператор примет чат…',
|
|
13
|
+
deletedMessage: 'Сообщение удалено',
|
|
14
|
+
unsupportedMessage: 'Неподдерживаемый тип сообщения',
|
|
15
|
+
download: 'Скачать',
|
|
16
|
+
},
|
|
17
|
+
systemNotice: {
|
|
18
|
+
started: 'Чат начат: {actor}',
|
|
19
|
+
joined: 'Новый участник чата: {actor}',
|
|
20
|
+
accepted: 'Чат принят: {actor}',
|
|
21
|
+
transferred: 'Чат переведён: {actor}',
|
|
22
|
+
left: 'Участник вышел из чата: {actor}',
|
|
23
|
+
ended: 'Чат завершён: {actor}',
|
|
24
|
+
unknown: 'Системное событие',
|
|
25
|
+
system: 'система',
|
|
26
|
+
},
|
|
27
|
+
} satisfies ChatsV2Locale;
|