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: add shift template page[WTEL-5079] #780

Merged
merged 4 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
621 changes: 610 additions & 11 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"@vuelidate/validators": "^2.0.4",
"@vueuse/core": "^11.0.3",
"@webitel/flow-ui-sdk": "^0.1.14",
"@webitel/ui-sdk": "^24.10.15",
"@webitel/ui-sdk": "^24.10.20",
"axios": "^1.7.7",
"clipboard-copy": "^4.0.1",
"cron-validator": "^1.3.1",
Expand All @@ -40,7 +40,7 @@
"vue-router": "^4.4.3",
"vue2-dropzone": "^3.6.0",
"vuex": "^4.1.0",
"webitel-sdk": "^24.8.1"
"webitel-sdk": "^24.8.3"
},
"devDependencies": {
"@biomejs/biome": "^1.8.3",
Expand Down
5 changes: 4 additions & 1 deletion src/app/locale/en/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ export default {
allowSupervisor: 'Supervisor can change this status',
allowAgent: 'Agent can change this status',
},
shiftTemplates: {
shiftTemplates: 'Shift template | Shift templates',
},
},
routing: {
routing: 'Routing',
Expand Down Expand Up @@ -535,7 +538,7 @@ export default {
},
chatGateways: {
templates: {
templates: 'Templates',
templates: 'Template | Templates',
title: "Workspace member's name",
close: 'Chat complete message',
join: 'Agent joining message',
Expand Down
3 changes: 3 additions & 0 deletions src/app/locale/ru/ru.js
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,9 @@ export default {
allowSupervisor: 'Супервизор может изменять этот статус',
allowAgent: 'Оператор может изменять этот статус',
},
shiftTemplates: {
shiftTemplates: 'Шаблон смен | Шаблоны смен',
},
},
routing: {
routing: 'Маршрутизация',
Expand Down
3 changes: 3 additions & 0 deletions src/app/locale/ua/ua.js
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,9 @@ export default {
allowSupervisor: 'Супервізор може змінювати статус',
allowAgent: 'Оператор може змінювати статус',
},
shiftTemplates: {
shiftTemplates: 'Шаблон змін | Шаблони змін',
},
},
routing: {
routing: 'Маршрутизація',
Expand Down
5 changes: 5 additions & 0 deletions src/app/router/_internals/NavigationPages.lookup.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ const nav = Object.freeze([
locale: `WebitelApplications.${WebitelApplications.ADMIN}.sections.${AdminSections.MEDIA}`,
route: 'media',
},
{
value: AdminSections.SHIFT_TEMPLATES,
locale: `WebitelApplications.${WebitelApplications.ADMIN}.sections.${AdminSections.SHIFT_TEMPLATES}`,
route: 'shift-templates',
},
],
},
{
Expand Down
1 change: 1 addition & 0 deletions src/app/router/_internals/RouteNames.enum.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default Object.freeze({
COMMUNICATIONS: 'communications',
PAUSE_CAUSE: 'agent-pause-cause',
MEDIA: 'media',
SHIFT_TEMPLATES: 'shift-templates',

// CONTACT-CENTER
AGENTS: 'agents',
Expand Down
3 changes: 3 additions & 0 deletions src/app/router/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import AgentSkillsRoutes from "../../modules/lookups/modules/agent-skills/router
import BucketsRoutes from "../../modules/lookups/modules/buckets/router/buckets.js";
import BlacklistsRoutes from "../../modules/lookups/modules/blacklists/router/blacklists.js";
import MediaRoutes from "../../modules/lookups/modules/media/router/media.js";
import ShiftTemplates
from '../../modules/lookups/modules/shift-templates/router/shift-templates.js';
import CalendarsRoutes from "../../modules/lookups/modules/calendars/router/calendars.js";
import CommunicationsRoutes from "../../modules/lookups/modules/communications/router/communications.js";
import RegionsRoutes from "../../modules/lookups/modules/regions/router/regions.js";
Expand Down Expand Up @@ -107,6 +109,7 @@ const router = createRouter({
...CommunicationsRoutes,
...RegionsRoutes,
...AgentPauseCauseRoutes,
...ShiftTemplates,
// ----------LOOKUPS END------------

// --------------CONTACT CENTER-------------
Expand Down
107 changes: 107 additions & 0 deletions src/modules/lookups/modules/shift-templates/api/shiftTemplates.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { getDefaultGetListResponse, getDefaultGetParams } from '@webitel/ui-sdk/src/api/defaults/index.js';
import applyTransform, {
camelToSnake,
merge,
notify,
sanitize,
snakeToCamel,
starToSearch,
} from '@webitel/ui-sdk/src/api/transformers/index.js';
import { ShiftTemplateServiceApiFactory } from 'webitel-sdk';

import instance from '../../../../../app/api/instance';
import configuration from '../../../../../app/api/openAPIConfig';

const shiftTemplateService = new ShiftTemplateServiceApiFactory(configuration, '', instance);

const getShiftTemplateList = async (params) => {
const { search: q, page, size, sort, fields } = applyTransform(params, [
merge(getDefaultGetParams()),
starToSearch(),
]);

try {
const response = await shiftTemplateService.searchShiftTemplate(q, page, size, sort, fields);
const { items, next } = applyTransform(response.data, [
snakeToCamel(),
merge(getDefaultGetListResponse()),
]);
return {
items,
next,
};
} catch (err) {
throw applyTransform(err, [notify]);
}
};

const itemResponseHandler = (item) => {
const copy = {
...item.item,
};

copy.times = copy.times.map((time) => ({
...time,
duration: time.end - time.start,
}), []);

return copy;
};

const getShiftTemplate = async ({ itemId: id }) => {

try {
const response = await shiftTemplateService.readShiftTemplate(id);
return applyTransform(response.data, [snakeToCamel(), itemResponseHandler]);
} catch (err) {
throw applyTransform(err, [notify]);
}
};

const fieldsToSend = ['name', 'description', 'times'];

const addShiftTemplate = async ({ itemInstance }) => {
const item = applyTransform(itemInstance, [sanitize(fieldsToSend), camelToSnake()]);
try {
const response = await shiftTemplateService.createShiftTemplate({ item: { ...item } });
return applyTransform(response.data, [snakeToCamel()]);
} catch (err) {
throw applyTransform(err, [notify]);
}
};

const updateShiftTemplate = async ({ itemInstance, itemId: id }) => {
const item = applyTransform(itemInstance, [sanitize(fieldsToSend), camelToSnake()]);
try {
const response = await shiftTemplateService.updateShiftTemplate(id, { item: { ...item }});
return applyTransform(response.data, [snakeToCamel()]);
} catch (err) {
throw applyTransform(err, [notify]);
}
};

const deleteShiftTemplate = async ({ id }) => {
try {
const response = await shiftTemplateService.deleteShiftTemplate(id);
return applyTransform(response.data, []);
} catch (err) {
throw applyTransform(err, [notify]);
}
};

const getShiftTemplatesLookup = (params) =>
getShiftTemplateList({
...params,
fields: params.fields || ['id', 'name'],
});

const ShiftTemplatesAPI = {
getList: getShiftTemplateList,
get: getShiftTemplate,
add: addShiftTemplate,
update: updateShiftTemplate,
delete: deleteShiftTemplate,
getLookup: getShiftTemplatesLookup,
}

export default ShiftTemplatesAPI;
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template>
<section>
<header class="content-header">
<h3 class="content-title">
{{ $t('objects.generalInfo') }}
</h3>
</header>
<div class="object-input-grid object-input-grid__1-col object-input-grid__w50">
<wt-input
:disabled="disableUserInput"
:label="$t('objects.name')"
:v="v.itemInstance.name"
:value="itemInstance.name"
required
@input="setItemProp({ prop: 'name', value: $event })"
/>
<wt-textarea
:disabled="disableUserInput"
:label="$t('objects.description')"
:value="itemInstance.description"
@input="setItemProp({ prop: 'description', value: $event })"
/>
</div>
</section>
</template>

<script>
import openedTabComponentMixin from '../../../../../app/mixins/objectPagesMixins/openedObjectTabMixin/openedTabComponentMixin';

export default {
name: 'OpenedShiftTemplateGeneral',
mixins: [openedTabComponentMixin],
};
</script>

<style scoped>

</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<template>
<section class="opened-calendar-work-week">
<header class="content-header">
<h3 class="content-title">
{{ $tc('objects.routing.chatGateways.templates.templates', 1) }}
</h3>

<div class="content-header__actions-wrap">
<wt-icon-btn
v-if="!disableUserInput"
class="icon-action"
icon="plus"
@click="addTemplate"
/>
</div>
</header>

<div class="table-wrapper">
<div class="table-wrapper__visible-scroll-wrapper">
<wt-table
:data="itemInstance.times"
:grid-actions="!disableUserInput"
:headers="headers"
:selectable="false"
>
<template #start="{ item, index }">
<wt-timepicker
:disabled="disableUserInput"
:value="minToSec(item.start)"
:v="v.itemInstance.times.$each.$response.$data[index].start"
format="hh:mm"
@input="setStartTime({ index, value: secToMin($event) })"
/>
</template>
<template #end="{ item, index }">
<wt-timepicker
:disabled="disableUserInput"
:value="minToSec(item.end)"
format="hh:mm"
:v="v.itemInstance.times.$each.$response.$data[index].end"
@input="setEndTime({ index, value: secToMin($event) })"
/>
</template>
<template #duration="{ item, index }">
<wt-timepicker
:value="minToSec(item.duration)"
format="hh:mm"
type="number"
@input="setDuration({ index, value: secToMin($event) })"
/>
</template>
<template #actions="{ item, index }">
<wt-icon-action
action="delete"
@click="deleteTemplate(index)"
/>
</template>
</wt-table>
</div>
</div>
</section>
</template>

<script>
import { mapActions, mapState } from 'vuex';
import openedTabComponentMixin from '../../../../../app/mixins/objectPagesMixins/openedObjectTabMixin/openedTabComponentMixin';

export default {
name: 'OpenedShiftTemplateTemplate',
mixins: [openedTabComponentMixin],
computed: {
headers() {
return [
{
value: 'start',
text: this.$t('objects.lookups.calendars.start'),
},
{
value: 'end',
text: this.$t('objects.lookups.calendars.end'),
},
{
value: 'duration',
text: this.$t('objects.ccenter.queues.logs.duration'),
},
];
},
},

methods: {
...mapActions('lookups/shiftTemplates', {
addTemplate: 'ADD_TEMPLATE',
setTemplate: 'SET_TEMPLATE',
deleteTemplate: 'DELETE_TEMPLATE',
Lera24 marked this conversation as resolved.
Show resolved Hide resolved
}),
minToSec(min) {
return min * 60;
},
secToMin(sec) {
return sec / 60;
},
setStartTime({ index, value }) {
this.setTemplate({ prop: 'start', index, value });
this.setTemplate({ prop: 'duration', index, value: this.itemInstance.times[index].end - this.itemInstance.times[index].start });
},
setEndTime({ index, value }) {
this.setTemplate({ prop: 'end', index, value });
this.setTemplate({ prop: 'duration', index, value: this.itemInstance.times[index].end - this.itemInstance.times[index].start });
},
setDuration({ index, value }) {
this.setTemplate({ prop: 'duration', index, value });
this.setTemplate({ prop: 'end', index, value: this.itemInstance.times[index].start + this.itemInstance.times[index].duration });
},
},
};
</script>

<style lang="scss" scoped>
.wt-timepicker :deep(.wt-label) {
display: none;
Lera24 marked this conversation as resolved.
Show resolved Hide resolved
}
</style>

Loading
Loading