Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: timeline[WTEL-3534] #65

Merged
merged 32 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7b43291
feature: timeline[WTEL-3534]
Lera24 Apr 17, 2024
523240b
refactor: timeline restructurization [WTEL-3534]
dlohvinov Apr 19, 2024
329b7d9
Merge pull request #66 from webitel/refactor/timeline-restructurization
dlohvinov Apr 19, 2024
627cc25
fix: refactor components[WTEL-4418]
Lera24 Apr 22, 2024
278f878
refactor: timeline store refactors [WTEL-4465]
dlohvinov Apr 22, 2024
c8dddce
fix: refactor day components, API and some styles[WTEL-4418]
Lera24 Apr 22, 2024
594c39e
refactor: timeline filters [WTEL-4465]
dlohvinov Apr 22, 2024
9f52564
Merge branch 'feature/timeline' of https://github.com/webitel/crm int…
dlohvinov Apr 22, 2024
68b3549
fix:errors in header and API[WTEL-4418]
Lera24 Apr 23, 2024
4d64937
fix: refactor timeline-row components[WTEL-4418]
Lera24 Apr 23, 2024
f66ac88
feat: chats api and store [WTEL-4465]
dlohvinov Apr 23, 2024
92dcc55
Merge branch 'feature/timeline' of https://github.com/webitel/crm int…
dlohvinov Apr 23, 2024
b271d2a
feat: timeline chats module, store and api, components scaffolding [W…
dlohvinov Apr 23, 2024
ee9010d
feat: enabled timeline filters [WTEL-4465]
dlohvinov Apr 24, 2024
66fa2f1
fix: style, classes and locale[WTEL-4418]
Lera24 Apr 24, 2024
1a36b05
fix:components layout and some computeds[WTEL-4418]
Lera24 Apr 24, 2024
e4ab2aa
fix: computed props in chat-task-time-row component[WTEL-4418]
Lera24 Apr 25, 2024
c4a755e
refactor: refactoring timelines in progress [WTEL-4465]
dlohvinov Apr 25, 2024
85c6b67
refactor: timeline chats reorganization [WTEL-4465]
dlohvinov Apr 25, 2024
031de5b
feat: TaskKind enum [WTEL-4465]
dlohvinov Apr 25, 2024
4bd8152
feat: timeline task kind + timeline task pins [WTEL-4465]
dlohvinov Apr 25, 2024
91529c1
feature: add transition and timeline-rounded-action component[WTEL-3534]
Lera24 Apr 25, 2024
4537336
fix: small refactor[WYEL-4428]
Lera24 Apr 26, 2024
3a19152
refactor: timeline call components [WTEL-4465]
dlohvinov Apr 26, 2024
06fbde2
feat: timeline call points in progress [WTEL-4465]
dlohvinov Apr 29, 2024
a10e9b0
feature: add eventBus[WTEL-4418]
Lera24 Apr 29, 2024
ceb5358
merge changes[WTE-4418]
Lera24 Apr 29, 2024
b4adbe6
fix: display initiator[WTEL-4418]
Lera24 Apr 29, 2024
1b496f8
refactor: timeline refactors [WTEL-4465]
dlohvinov Apr 29, 2024
a9d14d5
refactor: timeline chat points in progress [WTEL-4465]
dlohvinov Apr 30, 2024
b434611
refactor: timeline calls [WTEL-4465]
dlohvinov Apr 30, 2024
d83e217
feat: timeline chat points [WTEL-4465]
dlohvinov May 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,955 changes: 1,678 additions & 1,277 deletions package-lock.json

Large diffs are not rendered by default.

32 changes: 14 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,35 @@
"test:unit": "vitest",
"lint:fix": "eslint --fix --ext .js,.vue src"
},
"type": "module",
"dependencies": {
"@vue/compat": "^3.3.9",
"@vue/compat": "^3.4.25",
"@vuelidate/core": "^2.0.0",
"@vuelidate/validators": "^2.0.2",
"@webitel/ui-sdk": "^24.4.16",
"axios": "^1.6.5",
"core-js": "^3.8.3",
"@webitel/ui-sdk": "^24.4.28",
"axios": "^1.6.8",
"deep-equal": "^2.2.1",
"lodash": "^4.17.21",
"vue": "^3.3.9",
"vue-i18n": "^9.2.2",
"vue-router": "^4.0.3",
"vue": "^3.4.25",
"vue-i18n": "^9.13.1",
"vue-router": "^4.3.2",
"vuex": "^4.1.0",
"webitel-sdk": "^24.2.4"
"webitel-sdk": "^24.2.9"
},
"devDependencies": {
"@vitejs/plugin-vue": "5.0.3",
"@vitest/coverage-v8": "^1.1.3",
"@vue/test-utils": "^2.0.0-0",
"@vue/test-utils": "^2.4.5",
"deep-copy": "^1.4.2",
"eslint": "^8.56.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-vue": "^9.20.0",
"happy-dom": "^13.0.0",
"husky": "^8.0.3",
"sass": "^1.32.7",
"sass": "^1.75.0",
"tslib": "^2.6.2",
"vite": "^5.0.11",
"vite-plugin-node-polyfills": "^0.19.0",
"vite": "=5.1",
"vite-plugin-node-polyfills": "^0.21.0",
"vite-plugin-svg-sprite": "^0.5.1",
"vitest": "^1.1.3"
},
"overrides": {
"url": "^0.11.0",
"axios": "^1.6.5"
"vitest": "^1.5.2"
}
}
19 changes: 19 additions & 0 deletions src/app/locale/en/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,34 @@ import ChatGatewayProvider
from '@webitel/ui-sdk/src/enums/ChatGatewayProvider/ChatGatewayProvider.enum';
import AccessMode
from '../../../modules/contacts/modules/permissions/enums/AccessMode.enum';
import TimelineTaskStatusEnum
from '../../../modules/contacts/modules/timeline/enums/TimelineTaskStatus.enum.js';
import { WebitelContactsTimelineEventType } from 'webitel-sdk';

export default {
crm: 'CRM',
contacts: {
contact: 'Contact | Contacts',
manager: 'Owner | Owners',
destination: 'Destination',
collapseAll: 'Collapse all',
timeline: {
timeline: 'Timeline',
actions: {
openInHistory: 'Open in history',
playRecording: 'Play Recording',
transcription: 'Transcription',
},
status: {
[TimelineTaskStatusEnum.STARTED]: 'Started',
[TimelineTaskStatusEnum.MISSED]: 'Missed',
[TimelineTaskStatusEnum.TRANSFERRED]: 'Transferred',
[TimelineTaskStatusEnum.ENDED]: 'Ended',
},
eventType: {
[WebitelContactsTimelineEventType.Call]: 'Call | Calls',
[WebitelContactsTimelineEventType.Chat]: 'Chat | Chats',
},
},
communications: {
communications: 'Communication option | Communication options',
Expand Down
19 changes: 19 additions & 0 deletions src/app/locale/ru/ru.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import ChatGatewayProvider
from '@webitel/ui-sdk/src/enums/ChatGatewayProvider/ChatGatewayProvider.enum';
import { WebitelContactsTimelineEventType } from 'webitel-sdk';
import AccessMode
from '../../../modules/contacts/modules/permissions/enums/AccessMode.enum';
import TimelineTaskStatusEnum
from '../../../modules/contacts/modules/timeline/enums/TimelineTaskStatus.enum.js';

export default {
crm: 'CRM',
contacts: {
contact: 'Контакт | Контакты',
manager: 'Владелец | Владельцы',
destination: 'Назначение',
collapseAll: 'Свернуть все',
timeline: {
timeline: 'Хронология',
actions: {
openInHistory: 'Открыть в истории',
playRecording: 'Проиграть запись',
transcription: 'Транскрипция',
},
status: {
[TimelineTaskStatusEnum.STARTED]: 'Початок',
[TimelineTaskStatusEnum.MISSED]: 'Пропущений',
[TimelineTaskStatusEnum.TRANSFERRED]: 'Переведено',
[TimelineTaskStatusEnum.ENDED]: 'Кінець',
},
eventType: {
[WebitelContactsTimelineEventType.Call]: 'Звонок | Звонки',
[WebitelContactsTimelineEventType.Chat]: 'Чат | Чаты',
},
},
communications: {
communications: 'Средство связи | Средства связи',
Expand Down
19 changes: 19 additions & 0 deletions src/app/locale/ua/ua.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import ChatGatewayProvider
from '@webitel/ui-sdk/src/enums/ChatGatewayProvider/ChatGatewayProvider.enum';
import { WebitelContactsTimelineEventType } from 'webitel-sdk';
import AccessMode
from '../../../modules/contacts/modules/permissions/enums/AccessMode.enum';
import TimelineTaskStatusEnum
from '../../../modules/contacts/modules/timeline/enums/TimelineTaskStatus.enum.js';

export default {
crm: 'CRM',
contacts: {
contact: 'Контакт | Контакти',
manager: 'Власник | Власники',
destination: 'Призначення',
collapseAll: 'Згорнути все',
timeline: {
timeline: 'Хронологія',
actions: {
openInHistory: 'Відкрити в історії',
playRecording: 'Програти запис',
transcription: 'Транскрипція',
},
status: {
[TimelineTaskStatusEnum.STARTED]: 'Начало',
[TimelineTaskStatusEnum.MISSED]: 'Пропущен',
[TimelineTaskStatusEnum.TRANSFERRED]: 'Переведено',
[TimelineTaskStatusEnum.ENDED]: 'Конец',
},
eventType: {
[WebitelContactsTimelineEventType.Call]: 'Дзвінок | Дзвінки',
[WebitelContactsTimelineEventType.Chat]: 'Чат | Чати',
},
},
communications: {
communications: 'Засіб зв\'язку | Засоби зв\'язку',
Expand Down
8 changes: 7 additions & 1 deletion src/app/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import TheContacts from '../../modules/contacts/components/the-contacts.vue';
import OpenedContact
from '../../modules/contacts/components/opened-contact.vue';
import AccessDenied from '../components/utils/access-denied-component.vue';
import ContactTimeline from '../../modules/contacts/modules/timeline/components/the-timeline.vue';
import ContactCommunications
from '../../modules/contacts/components/opened-contact-communications.vue';
import ContactPermissions
Expand Down Expand Up @@ -53,8 +54,13 @@ const routes = [
name: `${CrmSections.CONTACTS}-edit`,
component: OpenedContact,
beforeEnter: checkRouteAccess,
redirect: { name: `${CrmSections.CONTACTS}-communications` },
redirect: { name: `${CrmSections.CONTACTS}-timeline` },
children: [
{
path: 'timeline',
name: `${CrmSections.CONTACTS}-timeline`,
component: ContactTimeline,
},
{
path: 'communications',
redirect: {
Expand Down
9 changes: 5 additions & 4 deletions src/modules/contacts/components/opened-contact-tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ const router = useRouter();
const route = useRoute();

const tabs = computed(() => [
// {
// text: t('contacts.timeline.timeline'),
// value: 'timeline',
// },
{
text: t('contacts.timeline.timeline'),
value: 'timeline',
pathName: `${CrmSections.CONTACTS}-timeline`,
},
{
text: t('contacts.communications.communications', 2),
value: 'communications',
Expand Down
74 changes: 45 additions & 29 deletions src/modules/contacts/components/opened-contact.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,41 @@
</wt-page-header>
</template>
<template #main>
<contact-popup
v-if="isContactPopup"
:id="id"
:namespace="baseNamespace"
@saved="loadItem"
@close="isContactPopup = false"
/>
<delete-confirmation-popup
v-show="isDeleteConfirmationPopup"
:delete-count="deleteCount"
:callback="deleteCallback"
@close="closeDelete"
/>
<div class="opened-contact-content">
<opened-contact-general
:common-name="itemInstance.name ? itemInstance.name.commonName : ''"
:timezones="itemInstance.timezones ? itemInstance.timezones : []"
:managers="itemInstance.managers ? itemInstance.managers : []"
:about="itemInstance.about"
:labels="itemInstance.labels ? itemInstance.labels : []"
@edit="isContactPopup = true"
@delete="askDeleteConfirmation({
<wt-loader v-if="isLoading "/>
<div
style="display: contents;"
v-else
>
<contact-popup
v-if="isContactPopup"
:id="id"
:namespace="baseNamespace"
@saved="loadItem"
@close="isContactPopup = false"
/>
<delete-confirmation-popup
v-show="isDeleteConfirmationPopup"
:delete-count="deleteCount"
:callback="deleteCallback"
@close="closeDelete"
/>
<div class="opened-contact-content">
<opened-contact-general
:common-name="itemInstance.name ? itemInstance.name.commonName : ''"
:timezones="itemInstance.timezones ? itemInstance.timezones : []"
:managers="itemInstance.managers ? itemInstance.managers : []"
:about="itemInstance.about"
:labels="itemInstance.labels ? itemInstance.labels : []"
@edit="isContactPopup = true"
@delete="askDeleteConfirmation({
deleted: [itemInstance],
callback: () => deleteContact(itemInstance),
})"
/>
<opened-contact-tabs
:namespace="namespace"
/>
/>
<opened-contact-tabs
:namespace="namespace"
/>
</div>
</div>
</template>
</wt-page-wrapper>
Expand Down Expand Up @@ -93,6 +99,8 @@ provide('access', computed(() => ({

const isContactPopup = ref(false);

const isLoading = ref(true);

const path = computed(() => {
const baseUrl = '/contacts';

Expand All @@ -107,9 +115,17 @@ const path = computed(() => {
});

async function initializeCard() {
const { id: itemId } = route.params;
await setId(itemId);
return loadItem();
try {
isLoading.value = true;

const { id: itemId } = route.params;
await setId(itemId);
await loadItem();
} finally {
setTimeout(() => {
isLoading.value = false;
}, 500);
}
}

function close() {
Expand Down
4 changes: 2 additions & 2 deletions src/modules/contacts/components/the-contacts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,11 @@ function edit({ id }) {

function communicationsLink({ id }) {
const routeName = CrmSections.CONTACTS;
return { name: `${routeName}-communications`, params: { id } };
return { name: `${routeName}-timeline`, params: { id } };
}

function saved(id) {
router.push(`/${CrmSections.CONTACTS}/${id}/communications`);
router.push(`/${CrmSections.CONTACTS}/${id}/timeline`);
}

function closeContactPopup() {
Expand Down
61 changes: 61 additions & 0 deletions src/modules/contacts/modules/timeline/api/TimelineAPI.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import applyTransform, {
merge, notify,
sanitize, snakeToCamel,
} from '@webitel/ui-sdk/src/api/transformers';
import deepCopy from 'deep-copy';
import { TimelineApiFactory, WebitelContactsTimelineEventType } from 'webitel-sdk';
import getDefaultGetListResponse
from '../../../../../app/api/defaults/getDefaultGetListResponse';
import configuration from '../../../../../app/api/openAPIConfig';
import instance from '../../../../../app/api/instance';

const timeline = new TimelineApiFactory(configuration, '', instance);

const listHandler = (items) => {
let copy = deepCopy(items);
if(copy.length) {
return copy.map(day => ({
...day,
items: day.items.map(item => ({
...item,
type: item.type || WebitelContactsTimelineEventType.Chat,
}))
}));
} return [];
}

const getList = async (params) => {
const fieldsToSend = ['parentId', 'dateFrom', 'dateTo', 'type'];
const {
parentId,
dateFrom,
dateTo,
type,
} = applyTransform(params, [
sanitize(fieldsToSend),
]);
try {
const response = await timeline.getTimeline(
parentId,
dateFrom,
dateTo,
type,
);
const { days, next } = applyTransform(response.data, [
snakeToCamel(),
merge(getDefaultGetListResponse()),
]);
return {
items: applyTransform(days, [
listHandler,
]),
next,
};
} catch (err) {
throw applyTransform(err, [
notify,
]);
}
};

export default { getList };
Loading
Loading