Merge branch 'main' of bitbucket.org:studiotem/jandl-taskmanager-app

This commit is contained in:
StudioTem committed 2023-01-24 17:38:32 +01:00
commit 33499107b7
47 files changed
+605 -1000

No files matched your search

+1 -1
View File
@@ -13,7 +13,6 @@
"@fullcalendar/core": "^6.0.2", "@fullcalendar/core": "^6.0.2",
"@fullcalendar/daygrid": "^6.0.2", "@fullcalendar/daygrid": "^6.0.2",
"@fullcalendar/vue3": "^6.0.2", "@fullcalendar/vue3": "^6.0.2",
"lodash-es": "^4.17.21",
"@ionic/vue": "^6.3.6", "@ionic/vue": "^6.3.6",
"@mdi/font": "5.9.55", "@mdi/font": "5.9.55",
"@vuelidate/core": "^2.0.0", "@vuelidate/core": "^2.0.0",
@@ -23,6 +22,7 @@
"axios-auth-refresh": "^3.3.4", "axios-auth-refresh": "^3.3.4",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"lodash-es": "^4.17.21",
"mitt": "^2.1.0", "mitt": "^2.1.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"node-polyfill-webpack-plugin": "^2.0.1", "node-polyfill-webpack-plugin": "^2.0.1",
@@ -3,10 +3,8 @@
"id": 1, "id": 1,
"name": "Master task 1", "name": "Master task 1",
"description": "Urna vitae, suscipit suspendisse lectus arcu, imperdiet. Vulputate sit nec ut et. Urna ut a ac amet, donec orci non. Posuere elit magna consequat volutpat bibendum. Accumsan gravida elit condimentum sed. Congue non, dictum nec accumsan egestas vel. Sed molestie pretium odio morbi. Amet nunc, diam ridiculus dis condimentum arcu. Rhoncus, elementum, quis aenean neque. Faucibus leo laoreet lobortis vitae elementum. Condimentum ornare iaculis in fames in ut sit enim.", "description": "Urna vitae, suscipit suspendisse lectus arcu, imperdiet. Vulputate sit nec ut et. Urna ut a ac amet, donec orci non. Posuere elit magna consequat volutpat bibendum. Accumsan gravida elit condimentum sed. Congue non, dictum nec accumsan egestas vel. Sed molestie pretium odio morbi. Amet nunc, diam ridiculus dis condimentum arcu. Rhoncus, elementum, quis aenean neque. Faucibus leo laoreet lobortis vitae elementum. Condimentum ornare iaculis in fames in ut sit enim.",
"duration": 5400000, "duration": 128,
"worked_time": 4400000, "worked_time": 133,
"remaining_time": 1200000,
"time_worked": 0,
"starts_at": "2022-05-10T00:00:00+00:00", "starts_at": "2022-05-10T00:00:00+00:00",
"deadline": "2022-11-10T00:00:00+00:00", "deadline": "2022-11-10T00:00:00+00:00",
"is_finished": false, "is_finished": false,
+9
View File
@@ -0,0 +1,9 @@
{
"Value is not a valid email address": "Value is not a valid email address",
"error": "chyba",
"Value is required": "Pole je povinné",
"This field should be at least 8 characters long": "Pole musí obsahovať aspoň 8 znakov",
"This field should be at least 6 characters long": "Pole musí obsahovať aspoň 6 znakov",
"This maximum length allowed is 6": "Pole musí obsahovať 6 znakov",
"The value must be equal to the other value": "Heslá sa nezhodujú"
}
+8 -7
View File
@@ -45,49 +45,50 @@ const routes: Array<RouteRecordRaw> = [
{ {
path: '/app/dashboard/tasks', path: '/app/dashboard/tasks',
name: 'Dashboard - Tasks', name: 'Dashboard - Tasks',
meta: { title: 'Úlohy' }, meta: { title: 'Tasks' },
component: () => import('@/plugins/tm@dashboard/tasks/tasks.vue') component: () => import('@/plugins/tm@dashboard/tasks/tasks.vue')
}, },
{ {
path: '/app/dashboard/teams', path: '/app/dashboard/teams',
name: 'Dashboard - Teams', name: 'Dashboard - Teams',
meta: { title: 'Tímové zobrazenie' }, meta: { title: 'Teams Overview' },
component: () => import('@/plugins/tm@dashboard/teams/teams.vue') component: () => import('@/plugins/tm@dashboard/teams/teams.vue')
}, },
{ {
path: '/app/dashboard/projects', path: '/app/dashboard/projects',
name: 'Dashboard - Projects', name: 'Dashboard - Projects',
meta: { title: 'Projektové zobrazenie' }, meta: { title: 'Projects overview' },
component: () => import('@/plugins/tm@dashboard/projects/projects.vue') component: () => import('@/plugins/tm@dashboard/projects/projects.vue')
}, },
{ {
path: '/app/overview/unscheduled', path: '/app/overview/unscheduled',
name: 'Overview - Unscheduled tasks', name: 'Overview - Unscheduled tasks',
meta: { title: 'Nenaplánované úlohy' }, meta: { title: 'Unscheduled tasks' },
component: () => import('@/plugins/tm@overview/tasks-unscheduled/tasks-unscheduled.vue') component: () => import('@/plugins/tm@overview/tasks-unscheduled/tasks-unscheduled.vue')
}, },
{ {
path: '/app/overview/ongoing', path: '/app/overview/ongoing',
name: 'Overview - Ongoing tasks', name: 'Overview - Ongoing tasks',
meta: { title: 'Prebiehajúce úlohy' }, meta: { title: 'Ongoing tasks' },
component: () => import('@/plugins/tm@overview/tasks-ongoing/tasks-ongoing.vue') component: () => import('@/plugins/tm@overview/tasks-ongoing/tasks-ongoing.vue')
}, },
{ {
path: '/app/overview/teams', path: '/app/overview/teams',
name: 'Overview - Teams', name: 'Overview - Teams',
meta: { title: 'Tímy' }, meta: { title: 'Teams' },
component: () => import('@/plugins/tm@overview/teams/teams.vue') component: () => import('@/plugins/tm@overview/teams/teams.vue')
}, },
{ {
path: '/app/dashboard/user', path: '/app/dashboard/user',
name: 'Dashboard - User', name: 'Dashboard - User',
meta: { title: 'Váš profil' }, meta: { title: 'Profile' },
component: () => import('@/plugins/tm@profile/profile/my-profile.vue') component: () => import('@/plugins/tm@profile/profile/my-profile.vue')
}, },
{ {
path: '/app/search', path: '/app/search',
name: 'Search', name: 'Search',
meta: { title: 'Search Results' },
component: () => import('@/plugins/lib@search/search/search.vue') component: () => import('@/plugins/lib@search/search/search.vue')
} }
] ]
@@ -7,7 +7,7 @@
<div class="d-flex justify-end align-center w-100 header-sm"> <div class="d-flex justify-end align-center w-100 header-sm">
<img class="search-icon" :src="require('@/plugins/app/_layout/app/_img/search-icon.svg')" alt="search-icon" /> <img class="search-icon" :src="require('@/plugins/app/_layout/app/_img/search-icon.svg')" alt="search-icon" />
<input class="search-input mx-2" v-model="search" type="text" placeholder="Vyhľadávanie" @click="$router.push({name: 'Search'})" @keyup="eventBus.emit('onSearch', search)" /> <input class="search-input mx-2" v-model="search" type="text" placeholder="Search" @click="$router.push({name: 'Search'})" @keyup="eventBus.emit('onSearch', search)" />
<v-menu> <v-menu>
<template v-slot:activator="{ props }"> <template v-slot:activator="{ props }">
@@ -85,7 +85,7 @@ export default {
methods: { methods: {
async logOut() { async logOut() {
try { try {
await this.$store.dispatch('wAuth/logout') await this.$store.dispatch('auth/logout')
this.$router.push('/') this.$router.push('/')
this.$toast.success('Boli ste odhlásený') this.$toast.success('Boli ste odhlásený')
} catch (error) { } catch (error) {
@@ -29,27 +29,27 @@ export default {
return { return {
unscheduledTasksLength: null, unscheduledTasksLength: null,
pages: [{ pages: [{
title: 'Úlohy', title: 'Tasks',
pageName: 'Dashboard - Tasks' pageName: 'Dashboard - Tasks'
}, },
{ {
title: 'Tímove zobrazenie', title: 'Teams overview',
pageName: 'Dashboard - Teams' pageName: 'Dashboard - Teams'
}, },
{ {
title: 'Projektové zobrazenie', title: 'Projects overview',
pageName: 'Dashboard - Projects' pageName: 'Dashboard - Projects'
}, },
{ {
title: 'Nenaplánované úlohy', title: 'Unscheduled tasks',
pageName: 'Overview - Unscheduled tasks' pageName: 'Overview - Unscheduled tasks'
}, },
{ {
title: 'Prebiehajúce úlohy', title: 'Ongoing tasks',
pageName: 'Overview - Ongoing tasks' pageName: 'Overview - Ongoing tasks'
}, },
{ {
title: 'Tímy', title: 'Teams',
pageName: 'Overview - Teams' pageName: 'Overview - Teams'
}] }]
} }
@@ -1,4 +0,0 @@
.cancel-btn {
border: thin solid rgba(var(--v-border-color), var(--v-border-opacity)) !important;
color: #7f39fb !important;
}/*# sourceMappingURL=z-cancel-btn.css.map */
@@ -1 +0,0 @@
{"version":3,"sources":["z-cancel-btn.sass","z-cancel-btn.css"],"names":[],"mappings":"AAAA;EACC,kFAAA;EACA,yBAAA;ACCD","file":"z-cancel-btn.css"}
@@ -1,5 +0,0 @@
.z-btn {
background: #7f39fb !important;
border-radius: 4px !important;
color: #fff !important;
}/*# sourceMappingURL=z-default-btn.css.map */
@@ -1 +0,0 @@
{"version":3,"sources":["z-default-btn.sass","z-default-btn.css"],"names":[],"mappings":"AAAA;EACC,8BAAA;EACA,6BAAA;EACA,sBAAA;ACCD","file":"z-default-btn.css"}
@@ -1,24 +0,0 @@
.dp__input {
height: 56px;
border: 1px solid #E5E5E5 !important;
}
.dp__range_end, .dp__range_start, .dp__active_date {
background: #7F39FB !important;
}
.dp__select {
color: #7F39FB !important;
}
.dp__today {
border: 1px solid #7F39FB !important;
}
.dp__range_between {
background: #F4E8FF !important;
}
.dp__action {
font-weight: 500 !important;
}/*# sourceMappingURL=date-picker.css.map */
@@ -1 +0,0 @@
{"version":3,"sources":["date-picker.sass","date-picker.css"],"names":[],"mappings":"AAAA;EACC,YAAA;EACA,oCAAA;ACCD;;ADCA;EACC,8BAAA;ACED;;ADAA;EACC,yBAAA;ACGD;;ADDA;EACC,oCAAA;ACID;;ADFA;EACC,8BAAA;ACKD;;ADHA;EACC,2BAAA;ACMD","file":"date-picker.css"}
-79
View File
@@ -1,79 +0,0 @@
.task-action .trash-icon {
padding: 10px;
background: rgba(0, 0, 0, 0.04);
margin-left: 12px;
border-radius: 50%;
cursor: pointer;
}
.task-action .pencil-icon {
padding: 10px;
background: rgba(0, 0, 0, 0.04);
border-radius: 50%;
cursor: pointer;
}
.status-badge {
background: #F2E7FE;
color: #7F39FB;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
.task-badge {
background: rgba(0, 0, 0, 0.04);
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
.description-detail {
background: rgba(0, 0, 0, 0.04);
color: rgba(0, 0, 0, 0.6);
height: -webkit-fit-content;
height: -moz-fit-content;
height: fit-content;
}
.employee-selected-avatar {
background: #6200EE;
color: #fff;
border-radius: 50%;
padding: 13px;
font-size: 11.5px;
height: 24px;
width: 24px;
}
th {
font-size: 16px !important;
}
.task-action {
width: 50%;
}
.v-card {
padding: 35px !important;
}
.cursor-pointer:hover {
cursor: pointer;
}
.hover-background:hover {
background-color: rgba(0, 0, 0, var(--v-hover-opacity));
}
.v-input__control {
border-radius: 4px;
}
.border-select .v-input__control {
border: 1px solid #E5E5E5 !important;
}
input[type=time]::-webkit-calendar-picker-indicator {
display: none;
border: 1px solid #E5E5E5 !important;
}/*# sourceMappingURL=global.css.map */
@@ -1 +0,0 @@
{"version":3,"sources":["global.sass","global.css"],"names":[],"mappings":"AACC;EACC,aAAA;EACA,+BAAA;EACA,iBAAA;EACA,kBAAA;EACA,eAAA;ACAF;ADCC;EACC,aAAA;EACA,+BAAA;EACA,kBAAA;EACA,eAAA;ACCF;;ADCA;EACC,mBAAA;EACA,cAAA;EACA,0BAAA;EAAA,uBAAA;EAAA,kBAAA;ACED;;ADAA;EACC,+BAAA;EACA,0BAAA;EAAA,uBAAA;EAAA,kBAAA;ACGD;;ADDA;EACC,+BAAA;EACA,yBAAA;EACA,2BAAA;EAAA,wBAAA;EAAA,mBAAA;ACID;;ADFA;EACC,mBAAA;EACA,WAAA;EACA,kBAAA;EACA,aAAA;EACA,iBAAA;EACA,YAAA;EACA,WAAA;ACKD;;ADHA;EACC,0BAAA;ACMD;;ADJA;EACC,UAAA;ACOD;;ADLA;EACC,wBAAA;ACQD;;ADNA;EACC,eAAA;ACSD;;ADPA;EACC,uDAAA;ACUD;;ADRA;EACC,kBAAA;ACWD;;ADTA;EACC,oCAAA;ACYD;;ADVA;EACC,aAAA;EACA,oCAAA;ACaD","file":"global.css"}
@@ -1,4 +0,0 @@
.v-dialog h1 {
font-size: 26px;
font-weight: 500;
}/*# sourceMappingURL=v-dialog.css.map */
@@ -1 +0,0 @@
{"version":3,"sources":["v-dialog.sass","v-dialog.css"],"names":[],"mappings":"AACC;EACC,eAAA;EACA,gBAAA;ACAF","file":"v-dialog.css"}
@@ -1,94 +0,0 @@
* {
margin: 0;
padding: 0;
}
html {
scroll-behavior: smooth;
}
#app {
overflow-x: hidden;
}
.w-app {
font: 15px "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: #fff !important;
color: #2c3e50;
margin-top: 8em;
padding-top: 12em;
}
.page-container {
width: 100%;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
a {
text-decoration: none;
color: #42b983;
}
a[name] {
position: relative;
top: -4em;
display: block;
}
.scrollable {
height: 250px;
overflow-y: scroll;
padding-right: 1.8em;
}
.footer {
font-size: 0.9em;
font-style: italic;
margin: 3em 0 3.5em;
}
.footer .w-icon {
font-size: 1.2em;
}
.footer .w-icon.heart {
transition: 1s ease-out;
cursor: pointer;
}
.footer .w-icon.heart:hover {
-webkit-animation: pulse 1.8s ease-out infinite;
animation: pulse 1.8s ease-out infinite;
}
@-webkit-keyframes pulse {
0%, 20%, 30%, 35%, 45%, 100% {
transform: scale(1);
}
25%, 40% {
transform: scale(1.3);
}
}
@keyframes pulse {
0%, 20%, 30%, 35%, 45%, 100% {
transform: scale(1);
}
25%, 40% {
transform: scale(1.3);
}
}
@media screen and (max-width: 1240px) {
:root {
--container-padding: 20px;
}
.page-container {
padding-left: var(--container-padding);
padding-right: var(--container-padding);
}
}
@media screen and (max-width: 524px) {
:root {
--container-padding: 12px;
}
}/*# sourceMappingURL=index.css.map */
@@ -1 +0,0 @@
{"version":3,"sources":["_base.scss","index.css","_variables.scss"],"names":[],"mappings":"AAGA;EAAG,SAAA;EAAU,UAAA;ACAb;;ADEA;EAAM,uBAAA;ACEN;;ADAA;EAAM,kBAAA;ACIN;;ADFA;EACE,iDAAA;EACA,mCAAA;EACA,kCAAA;EACA,iCAAA;EACA,cAAA;EACA,eAAA;EACA,iBAAA;ACKF;;ADFA;EACE,WAAA;EACA,iBEpBe;EFqBf,iBAAA;EACA,kBAAA;ACKF;;ADAA;EACE,qBAAA;EACA,cE9BQ;ADiCV;ADDE;EACE,kBAAA;EACA,SAAA;EACA,cAAA;ACGJ;;ADCA;EACE,aAAA;EACA,kBAAA;EACA,oBAAA;ACEF;;ADCA;EACE,gBAAA;EACA,kBAAA;EACA,mBAAA;ACEF;ADAE;EACE,gBAAA;ACEJ;ADAI;EAAS,uBAAA;EAAwB,eAAA;ACIrC;ADHI;EAAe,+CAAA;UAAA,uCAAA;ACMnB;;ADFA;EACE;IAA8B,mBAAA;ECM9B;EDLA;IAAU,qBAAA;ECQV;AACF;;ADXA;EACE;IAA8B,mBAAA;ECM9B;EDLA;IAAU,qBAAA;ECQV;AACF;ADJA;EACE;IAAO,yBAAA;ECOP;EDNA;IACE,sCAAA;IACA,uCAAA;ECQF;AACF;ADLA;EACE;IAAO,yBAAA;ECQP;AACF","file":"index.css"}
@@ -1,396 +0,0 @@
.vuecal {
height: 100%;
box-shadow: 0 0 0 1px inset rgba(0, 0, 0, 0.08);
}
.vuecal * {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.vuecal--has-touch *:not(.vuecal__event-title--edit) {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.vuecal .clickable {
cursor: pointer;
}
.vuecal--resizing-event, .vuecal--drag-creating-event {
cursor: ns-resize;
}
.vuecal--dragging-event {
cursor: move;
cursor: -webkit-grabbing;
cursor: grabbing;
}
.vuecal .dragging-helper {
position: absolute;
width: 60px;
height: 40px;
background: rgba(138, 190, 230, 0.8);
border: 1px solid #61a9e0;
z-index: 10;
}
.vuecal--xsmall {
font-size: 0.9em;
}
.vuecal__flex {
display: flex;
flex-direction: row;
}
.vuecal__flex[column] {
flex-direction: column;
flex: 1 1 auto;
}
.vuecal__flex[grow] {
flex: 1 1 auto;
width: 100%;
}
.vuecal__flex[wrap] {
flex-wrap: wrap;
}
.vuecal__split-days-headers.slide-fade--right-leave-active {
display: none;
}
.vuecal--week-numbers.vuecal--month-view .vuecal__split-days-headers {
margin-left: 3em;
}
.vuecal--day-view:not(.vuecal--overflow-x) .vuecal__split-days-headers {
margin-left: 3em;
height: 2.2em;
}
.vuecal--day-view.vuecal--twelve-hour:not(.vuecal--overflow-x) .vuecal__split-days-headers {
margin-left: 4em;
}
.vuecal__split-days-headers .day-split-header {
display: flex;
flex-grow: 1;
flex-basis: 0;
justify-content: center;
align-items: center;
height: 100%;
}
.vuecal__split-days-headers .vuecal--day-view.vuecal--overflow-x.vuecal--sticky-split-labels .day-split-header {
height: 1.5em;
}
.vuecal__body {
position: relative;
overflow: hidden;
}
.vuecal__all-day {
min-height: 1.7em;
margin-bottom: -1px;
flex-shrink: 0;
}
.vuecal__all-day-text {
width: 3em;
box-sizing: border-box;
color: #999;
padding-right: 2px;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: flex-end;
border-bottom: 1px solid #ddd;
-webkit-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
}
.vuecal__all-day-text span {
font-size: 0.85em;
text-align: right;
line-height: 1.1;
}
.vuecal--twelve-hour .vuecal__all-day > span {
width: 4em;
}
.vuecal__bg {
overflow: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
min-height: 60px;
position: relative;
width: 100%;
}
.vuecal--no-time .vuecal__bg {
display: flex;
flex: 1 1 auto;
overflow: auto;
}
.vuecal__week-numbers {
width: 3em;
flex-shrink: 0 !important;
}
.vuecal__week-numbers .vuecal__week-number-cell {
opacity: 0.4;
font-size: 0.9em;
align-items: center;
justify-items: center;
justify-content: center;
}
.vuecal__scrollbar-check {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: scroll;
visibility: hidden;
z-index: -1;
}
.vuecal__scrollbar-check div {
height: 120%;
}
.vuecal__time-column {
width: 3em;
height: 100%;
flex-shrink: 0;
}
.vuecal--twelve-hour .vuecal__time-column {
width: 4em;
font-size: 0.9em;
}
.vuecal--overflow-x.vuecal--week-view .vuecal__time-column {
margin-top: 4em;
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3);
}
.vuecal--overflow-x.vuecal--week-view.vuecal--sticky-split-labels .vuecal__time-column {
margin-top: 3.4em;
}
.vuecal--overflow-x.vuecal--day-view.vuecal--sticky-split-labels .vuecal__time-column {
margin-top: 1.5em;
}
.vuecal__time-column .vuecal__time-cell {
color: #999;
text-align: right;
padding-right: 2px;
font-size: 0.9em;
}
.vuecal__time-column .vuecal__time-cell-line:before {
content: "";
position: absolute;
left: 0;
right: 0;
border-top: 1px solid rgba(196, 196, 196, 0.3);
}
.vuecal__cells {
margin: 0 1px 1px 0;
}
.vuecal--overflow-x.vuecal--day-view .vuecal__cells {
margin: 0;
}
.vuecal--events-on-month-view.vuecal--short-events .vuecal__cells {
width: 99.9%;
}
.vuecal--overflow-x.vuecal--day-view .vuecal__cells, .vuecal--overflow-x.vuecal--week-view .vuecal__cells {
flex-wrap: nowrap;
overflow: auto;
}
.slide-fade--left-enter-active, .slide-fade--left-leave-active,
.slide-fade--right-enter-active, .slide-fade--right-leave-active {
transition: 0.25s ease-out;
}
.slide-fade--left-enter-from,
.slide-fade--right-leave-to {
transform: translateX(-15px);
opacity: 0;
}
.slide-fade--left-leave-to,
.slide-fade--right-enter-from {
transform: translateX(15px);
opacity: 0;
}
.slide-fade--left-leave-active,
.slide-fade--right-leave-active {
position: absolute !important;
height: 100%;
}
.vuecal__title-bar .slide-fade--left-leave-active,
.vuecal__title-bar .slide-fade--right-leave-active {
left: 0;
right: 0;
height: auto;
}
.vuecal__heading .slide-fade--left-leave-active,
.vuecal__heading .slide-fade--right-leave-active {
display: flex;
align-items: center;
}
.vuecal--green-theme .vuecal__menu, .vuecal--green-theme .vuecal__cell-events-count {
background-color: #42b983;
color: #fff;
}
.vuecal--green-theme .vuecal__title-bar {
background-color: #e4f5ef;
}
.vuecal--green-theme .vuecal__cell--today, .vuecal--green-theme .vuecal__cell--current {
background-color: rgba(240, 240, 255, 0.4);
}
.vuecal--green-theme:not(.vuecal--day-view) .vuecal__cell--selected {
background-color: rgba(235, 255, 245, 0.4);
}
.vuecal--green-theme .vuecal__cell--selected:before {
border-color: rgba(66, 185, 131, 0.5);
}
.vuecal--green-theme .vuecal__cell--highlighted:not(.vuecal__cell--has-splits),
.vuecal--green-theme .vuecal__cell-split--highlighted {
background-color: rgba(195, 255, 225, 0.5);
}
.vuecal--green-theme .vuecal__arrow--highlighted,
.vuecal--green-theme .vuecal__today-btn--highlighted,
.vuecal--green-theme .vuecal__view-btn--highlighted {
background-color: rgba(136, 236, 191, 0.25);
}
.vuecal--blue-theme .vuecal__menu, .vuecal--blue-theme .vuecal__cell-events-count {
background-color: rgba(66, 163, 185, 0.8);
color: #fff;
}
.vuecal--blue-theme .vuecal__title-bar {
background-color: rgba(0, 165, 188, 0.3);
}
.vuecal--blue-theme .vuecal__cell--today, .vuecal--blue-theme .vuecal__cell--current {
background-color: rgba(240, 240, 255, 0.4);
}
.vuecal--blue-theme:not(.vuecal--day-view) .vuecal__cell--selected {
background-color: rgba(235, 253, 255, 0.4);
}
.vuecal--blue-theme .vuecal__cell--selected:before {
border-color: rgba(115, 191, 204, 0.5);
}
.vuecal--blue-theme .vuecal__cell--highlighted:not(.vuecal__cell--has-splits),
.vuecal--blue-theme .vuecal__cell-split--highlighted {
background-color: rgba(0, 165, 188, 0.06);
}
.vuecal--blue-theme .vuecal__arrow--highlighted,
.vuecal--blue-theme .vuecal__today-btn--highlighted,
.vuecal--blue-theme .vuecal__view-btn--highlighted {
background-color: rgba(66, 163, 185, 0.2);
}
.vuecal--rounded-theme .vuecal__weekdays-headings {
border: none;
}
.vuecal--rounded-theme .vuecal__cell, .vuecal--rounded-theme .vuecal__cell:before {
background: none;
border: none;
}
.vuecal--rounded-theme .vuecal__cell--out-of-scope {
opacity: 0.4;
}
.vuecal--rounded-theme .vuecal__cell-content {
width: 30px;
height: 30px;
flex-grow: 0;
border: 1px solid transparent;
border-radius: 30px;
color: #333;
}
.vuecal--rounded-theme.vuecal--day-view .vuecal__cell-content {
width: auto;
background: none;
}
.vuecal--rounded-theme.vuecal--year-view .vuecal__cell {
width: 33.33%;
}
.vuecal--rounded-theme.vuecal--year-view .vuecal__cell-content {
width: 85px;
}
.vuecal--rounded-theme.vuecal--years-view .vuecal__cell-content {
width: 52px;
}
.vuecal--rounded-theme .vuecal__cell {
background-color: transparent !important;
}
.vuecal--rounded-theme.vuecal--green-theme:not(.vuecal--day-view) .vuecal__cell-content {
background-color: #f1faf7;
}
.vuecal--rounded-theme.vuecal--green-theme:not(.vuecal--day-view) .vuecal__cell--today .vuecal__cell-content {
background-color: #42b983;
color: #fff;
}
.vuecal--rounded-theme.vuecal--green-theme .vuecal--day-view .vuecal__cell--today:before {
background-color: rgba(66, 185, 131, 0.05);
}
.vuecal--rounded-theme.vuecal--green-theme:not(.vuecal--day-view) .vuecal__cell--selected .vuecal__cell-content {
border-color: #42b983;
}
.vuecal--rounded-theme.vuecal--green-theme .vuecal__cell--highlighted:not(.vuecal__cell--has-splits),
.vuecal--rounded-theme.vuecal--green-theme .vuecal__cell-split--highlighted {
background-color: rgba(195, 255, 225, 0.5);
}
.vuecal--rounded-theme.vuecal--blue-theme:not(.vuecal--day-view) .vuecal__cell-content {
background-color: rgba(100, 182, 255, 0.2);
}
.vuecal--rounded-theme.vuecal--blue-theme:not(.vuecal--day-view) .vuecal__cell--today .vuecal__cell-content {
background-color: #8fb7e4;
color: #fff;
}
.vuecal--rounded-theme.vuecal--blue-theme .vuecal--day-view .vuecal__cell--today:before {
background-color: rgba(143, 183, 228, 0.1);
}
.vuecal--rounded-theme.vuecal--blue-theme:not(.vuecal--day-view) .vuecal__cell--selected .vuecal__cell-content {
border-color: #61a9e0;
}
.vuecal--rounded-theme.vuecal--blue-theme .vuecal__cell--highlighted:not(.vuecal__cell--has-splits),
.vuecal--rounded-theme.vuecal--blue-theme .vuecal__cell-split--highlighted {
background-color: rgba(0, 165, 188, 0.06);
}
.vuecal--date-picker .vuecal__title-bar {
font-size: 1.2em;
}
.vuecal--date-picker .vuecal__heading {
height: 2.2em;
font-weight: 500;
opacity: 0.4;
}
.vuecal--date-picker .vuecal__weekdays-headings {
border: none;
}
.vuecal--date-picker .vuecal__body {
margin-left: 1px;
}
.vuecal--date-picker .vuecal__cell, .vuecal--date-picker .vuecal__cell:before {
background: none;
border: none;
}
.vuecal--date-picker .vuecal__cell-content {
height: 26px;
flex-grow: 0;
border: 1px solid transparent;
border-radius: 25px;
transition: background-color 0.2s cubic-bezier(0.39, 0.58, 0.57, 1);
}
.vuecal--date-picker.vuecal--years-view .vuecal__cell-content {
flex: 0;
padding: 0 4px;
height: 24px;
}
.vuecal--date-picker.vuecal--year-view .vuecal__cell-content {
flex: 0;
padding: 0 15px;
}
.vuecal--date-picker.vuecal--month-view .vuecal__cell-content {
width: 26px;
}
.vuecal--date-picker:not(.vuecal--day-view) .vuecal__cell-content:hover {
background-color: rgba(0, 0, 0, 0.1);
}
.vuecal--date-picker:not(.vuecal--day-view) .vuecal__cell--selected .vuecal__cell-content {
background-color: #42b982;
color: #fff;
}
.vuecal--date-picker:not(.vuecal--day-view) .vuecal__cell--current .vuecal__cell-content, .vuecal--date-picker:not(.vuecal--day-view) .vuecal__cell--today .vuecal__cell-content {
border-color: #42b982;
}/*# sourceMappingURL=styles.css.map */
@@ -1 +0,0 @@
{"version":3,"sources":["styles.scss","styles.css"],"names":[],"mappings":"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","file":"styles.css"}
@@ -3,8 +3,8 @@
<v-text-field v-model="form.email" variant="solo" bg-color="white" :hint="v$.form.email.$errors ? errorUtils.parseErrors(v$.form.email.$errors) : null" :class="{ error: v$.form.email.$errors.length }" class="mb-2" label="E-mail" autocomplete="email" /> <v-text-field v-model="form.email" variant="solo" bg-color="white" :hint="v$.form.email.$errors ? errorUtils.parseErrors(v$.form.email.$errors) : null" :class="{ error: v$.form.email.$errors.length }" class="mb-2" label="E-mail" autocomplete="email" />
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<v-btn class="button" color="#7F39FB" @click="submit()">Poslať kód</v-btn> <v-btn class="button" color="#7F39FB" @click="submit()">Send code</v-btn>
<p class="mt-5 text-center cursor-pointer" @click="$router.push({ name: 'Login' })">Spomenuli ste si na heslo? Prihláste sa</p> <p class="mt-5 text-center cursor-pointer" @click="$router.push({ name: 'Login' })">Did you remember your password? Log in</p>
</div> </div>
</v-form> </v-form>
</template> </template>
@@ -1,8 +1,8 @@
<template> <template>
<v-container> <v-container>
<div class="auth-card"> <div class="auth-card">
<h1>Zabudnuté heslo?</h1> <h1>Forgotten password?</h1>
<p class="mb-10">Na e-mail Vám odošleme overovací kód s inštrukciami, ako si obnoviť Vaše heslo</p> <p class="mb-10">We will send you a confirmation code on your email with the instructions</p>
<A-forgot-password-form /> <A-forgot-password-form />
</div> </div>
@@ -2,12 +2,12 @@
<v-form> <v-form>
<v-text-field v-model="form.email" label="E-mail" variant="solo" autocomplete="email" class="mb-2" bg-color="white" :hint="v$.form.email.$errors ? errorUtils.parseErrors(v$.form.email.$errors) : null" :class="{ error: v$.form.email.$errors.length }" /> <v-text-field v-model="form.email" label="E-mail" variant="solo" autocomplete="email" class="mb-2" bg-color="white" :hint="v$.form.email.$errors ? errorUtils.parseErrors(v$.form.email.$errors) : null" :class="{ error: v$.form.email.$errors.length }" />
<v-text-field v-model="form.password" :type="showPassword ? 'text' : 'password'" variant="solo" bg-color="white" class="mb-2" :counter="8" label="Heslo" autocomplete="current-password" :hint="v$.form.password.$errors ? errorUtils.parseErrors(v$.form.password.$errors) : null" <v-text-field v-model="form.password" :type="showPassword ? 'text' : 'password'" variant="solo" bg-color="white" class="mb-2" :counter="12" label="Heslo" autocomplete="current-password" :hint="v$.form.password.$errors ? errorUtils.parseErrors(v$.form.password.$errors) : null"
:class="{ error: v$.form.password.$errors.length }" :append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'" @click:append="showPassword = !showPassword" /> :class="{ error: v$.form.password.$errors.length }" :append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'" @click:append="showPassword = !showPassword" />
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<v-btn class="button" color="#7F39FB" @click="submit()">Prihlásiť sa</v-btn> <v-btn class="button" color="#7F39FB" @click="submit()">Log In</v-btn>
<p class="mt-5 text-center cursor-pointer" @click="$router.push({ name: 'Forgot password' })">Zabudli ste heslo?</p> <p class="mt-5 text-center cursor-pointer" @click="$router.push({ name: 'Forgot password' })">Forgotten password ?</p>
</div> </div>
</v-form> </v-form>
</template> </template>
@@ -31,7 +31,7 @@ export default {
return { return {
form: { form: {
email: {required, email }, email: {required, email },
password: {required, minLength: minLength(8)} password: {required, minLength: minLength(12)}
} }
} }
}, },
@@ -41,7 +41,7 @@ export default {
if (!(await this.v$.$validate())) return console.log(this.v$) if (!(await this.v$.$validate())) return console.log(this.v$)
try { try {
await this.$axios.post_data('v1/auth/login', this.form) await this.$store.dispatch('auth/login', this.form)
this.$router.push({ name: 'Overview - Ongoing tasks'}) this.$router.push({ name: 'Overview - Ongoing tasks'})
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error)
+1 -1
View File
@@ -1,7 +1,7 @@
<template> <template>
<v-container> <v-container>
<div class="auth-card"> <div class="auth-card">
<h1>Prihláste sa s vašim e-mailom</h1> <h1>Log In with your E-mail</h1>
<A-login-form /> <A-login-form />
</div> </div>
@@ -1,15 +1,15 @@
<template> <template>
<v-form> <v-form>
<v-text-field v-model="form.code" label="Kód" autocomplete="one-time-code" bg-color="white" variant="solo" type="number" class="mb-2" :hint="v$.form.code.$errors ? errorUtils.parseErrors(v$.form.code.$errors) : null" :counter="6" :class="{ error: v$.form.code.$errors.length }" /> <v-text-field v-model="form.code" label="Code" autocomplete="one-time-code" bg-color="white" variant="solo" type="number" class="mb-2" :hint="v$.form.code.$errors ? errorUtils.parseErrors(v$.form.code.$errors) : null" :counter="6" :class="{ error: v$.form.code.$errors.length }" />
<v-text-field v-model="form.email" label="E-mail" autocomplete="email" bg-color="white" variant="solo" type="email" class="mb-2" :hint="v$.form.email.$errors ? errorUtils.parseErrors(v$.form.email.$errors) : null" :class="{ error: v$.form.email.$errors.length }" /> <v-text-field v-model="form.email" label="E-mail" autocomplete="email" bg-color="white" variant="solo" type="email" class="mb-2" :hint="v$.form.email.$errors ? errorUtils.parseErrors(v$.form.email.$errors) : null" :class="{ error: v$.form.email.$errors.length }" />
<v-text-field v-model="form.password" label="Heslo" autocomplete="new-password" bg-color="white" variant="solo" :type="showPassword ? 'text' : 'password'" class="mb-2" :hint="v$.form.password.$errors ? errorUtils.parseErrors(v$.form.password.$errors) : null" :class="{ error: v$.form.password.$errors.length }" :counter="8" :append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'" @click:append="showPassword = !showPassword" /> <v-text-field v-model="form.password" label="Heslo" autocomplete="new-password" bg-color="white" variant="solo" :type="showPassword ? 'text' : 'password'" class="mb-2" :hint="v$.form.password.$errors ? errorUtils.parseErrors(v$.form.password.$errors) : null" :class="{ error: v$.form.password.$errors.length }" :counter="12" :append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'" @click:append="showPassword = !showPassword" />
<v-text-field v-model="form.password_confirmation" autocomplete="new-password" bg-color="white" variant="solo" label="Potvrdenie hesla" :type="showConfirmationPassword ? 'text' : 'password'" :counter="8" class="mb-2" :hint="v$.form.password_confirmation.$errors ? errorUtils.parseErrors(v$.form.password_confirmation.$errors) : null" :class="{ error: v$.form.password_confirmation.$errors.length }" :append-icon="showConfirmationPassword ? 'mdi-eye' : 'mdi-eye-off'" @click:append="showConfirmationPassword = !showConfirmationPassword" /> <v-text-field v-model="form.password_confirmation" autocomplete="new-password" bg-color="white" variant="solo" label="Potvrdenie hesla" :type="showConfirmationPassword ? 'text' : 'password'" :counter="12" class="mb-2" :hint="v$.form.password_confirmation.$errors ? errorUtils.parseErrors(v$.form.password_confirmation.$errors) : null" :class="{ error: v$.form.password_confirmation.$errors.length }" :append-icon="showConfirmationPassword ? 'mdi-eye' : 'mdi-eye-off'" @click:append="showConfirmationPassword = !showConfirmationPassword" />
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<v-btn class="button" color="#7F39FB" @click="submit()">Zmeniť heslo</v-btn> <v-btn class="button" color="#7F39FB" @click="submit()">Change password</v-btn>
</div> </div>
</v-form> </v-form>
</template> </template>
@@ -35,8 +35,8 @@ export default {
form: { form: {
code: { required, integer, minLength: minLength(6), maxLength: maxLength(6) }, code: { required, integer, minLength: minLength(6), maxLength: maxLength(6) },
email: { required, email }, email: { required, email },
password: { required, minLength: minLength(8) }, password: { required, minLength: minLength(12) },
password_confirmation: { required, minLength: minLength(8), sameAs: sameAs(this.form.password)} password_confirmation: { required, minLength: minLength(12), sameAs: sameAs(this.form.password)}
} }
} }
}, },
@@ -1,8 +1,8 @@
<template> <template>
<v-container> <v-container>
<div class="auth-card"> <div class="auth-card">
<h1>Resetovať heslo</h1> <h1>Reset password</h1>
<p class="mb-10">Overovací kód sme Vám odoslali na email. Môžete ho sem vložiť, alebo pokračovať pomocou odkazu v emaile.</p> <p class="mb-10">We have sent you a confirmation code on your email. You can insert him or continue with link in your email</p>
<A-reset-password-form /> <A-reset-password-form />
</div> </div>
@@ -0,0 +1,55 @@
<template>
<div>
<h1 class="px-3 py-3">Tasks</h1>
<v-table>
<tbody>
<tr v-for="task in tasks" :key="task.id">
<td>{{ task.project_code }}</td>
<td>{{ task.title }}</td>
<td>
<p>{{ task.user.name + task.user.surname }}</p>
<p class="employee-avatar d-flex justify-center align-center">
{{ task.user.name.charAt(0) }}
</p>
</td>
<td class="task-action">
<div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@dashboard/_components/_img/checkmark.svg')" alt="checkmark-icon">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon">
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon">
</div>
</td>
</tr>
</tbody>
</v-table>
</div>
</template>
<script>
export default {
props: {
tasks: {
type: Array,
required: true
}
},
}
</script>
<style lang="sass" scoped>
v-table, th, td
border: thin solid rgba(var(--v-border-color), var(--v-border-opacity))
.employee-avatar
background: #6200EE
color: #fff
border-radius: 50%
padding: 13px
font-size: 11.5px
height: 24px
width: 24px
.task-action
</style>
@@ -1,10 +0,0 @@
<template>
<div>
</div>
</template>
<script>
export default {
}
</script>
@@ -0,0 +1,63 @@
<template>
<div>
<h1 class="px-3 py-3">Teams</h1>
<v-table>
<tbody>
<tr v-for="team in teams" :key="team.id">
<td>{{ team.name }}</td>
<td class="task-action">
<div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editTeam(team)" />
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="deleteTeam(team)" />
</div>
</td>
</tr>
</tbody>
</v-table>
<Z-team-modal ref="z-team-modal" />
<!-- Kravarik: Aj tento modal prerob novym sposobom -->
<!-- <Z-delete-team-modal v-if="deleteModal" :visible="deleteModal ? true : false" :team="deleteModal.team" @close="(deleteModal = null)" /> -->
<Z-delete-team-modal ref="z-delete-team-modal" />
</div>
</template>
<script>
import ZDeleteTeamModal from '@/plugins/tm@modal/team/z-delete-team-modal.vue'
import ZTeamModal from '@/plugins/tm@modal/team/z-team-modal.vue'
export default {
components: {
ZDeleteTeamModal,
ZTeamModal
},
props: {
teams: {
type: Array,
required: true
}
},
data() {
return {
deleteModal: null
}
},
methods: {
editTeam(team) {
this.$refs['z-team-modal'].create(team)
},
deleteTeam(team) {
this.$refs['z-delete-team-modal'].delete(team)
}
}
}
</script>
<style lang="sass" scoped>
v-table, th, td
border: thin solid rgba(var(--v-border-color), var(--v-border-opacity))
</style>
+14 -5
View File
@@ -1,12 +1,13 @@
<template> <template>
<form> <form>
<A-search-result-team /> <A-search-result-team v-if="searchResults?.teams" :teams="searchResults.teams" />
<A-search-result-tasks v-if="searchResults?.tasks" :tasks="searchResults.tasks" />
</form> </form>
</template> </template>
<script> <script>
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
import ASearchResultTeam from '@/plugins/lib@search/search/_components/a-seach-result-team.vue' import ASearchResultTeam from '@/plugins/lib@search/search/_components/a-search-result-team.vue'
export default { export default {
components: { components: {
@@ -15,11 +16,19 @@ export default {
data() { data() {
return { return {
search: null searchResults: [],
search: ''
} }
}, },
created() { created() {
try {
this.searchResults = this.$axios.get_auth_data('v1/search')
console.log(this.searchResults)
} catch (error) {
this.$toast.error(error)
}
this.eventBus.on('onSearch', (search) => { this.eventBus.on('onSearch', (search) => {
this.search = search this.search = search
}) })
@@ -27,8 +36,8 @@ export default {
methods: { methods: {
debounceSearch: debounce(function () { debounceSearch: debounce(function () {
console.log("object") this.search
}, 2000), }, 300),
} }
} }
</script> </script>
@@ -359,7 +359,8 @@ export default {
border-radius: 16px border-radius: 16px
.vuecal__cell-split--weekend .vuecal__cell-split--weekend
background-color: #F2E7FE !important // background-color: #F2E7FE !important
background-color: rgba(255, 124, 124, .3) !important
border-radius: 16px border-radius: 16px
// EVENT // EVENT
@@ -30,27 +30,30 @@ export default {
filteredEvents: [] filteredEvents: []
} }
}, },
async created() { created() {
try { this._getData()
const events = await this.$axios.get_auth_data('v1/overview/projects')
this.events = events.map((item) => ({
id: item.id,
title: `${item.project_code} - ${item.name}`,
title_html: `${item.project_code} - <b>${item.name}</b>`,
start: item.starts_at,
end: item.deadline,
is_finished: item.is_finished,
project_code: item.project_code,
backgroundColor: item.color,
borderColor: item.color
}))
this.filteredEvents = this.events.filter((item) => !item.is_finished)
} catch (error) {
this.$toast.error(error)
}
}, },
methods: { methods: {
// Kravarik: TODO prepojit filtrovanie na BE async _getData() {
try {
const events = await this.$axios.get_auth_data('v1/overview/projects')
this.events = events.map((item) => ({
id: item.id,
title: `${item.project_code} - ${item.name}`,
title_html: `${item.project_code} - <b>${item.name}</b>`,
start: item.starts_at,
end: item.deadline,
is_finished: item.is_finished,
project_code: item.project_code,
backgroundColor: item.color,
borderColor: item.color
}))
this.filteredEvents = this.events.filter((item) => !item.is_finished)
} catch (error) {
this.$toast.error(error)
}
},
onFilterChanged(filterValues) { onFilterChanged(filterValues) {
this.filter = filterValues this.filter = filterValues
this.filteredEvents = this.events.filter((item) => this.filter.showFinishedTasks || item.is_finished == false) this.filteredEvents = this.events.filter((item) => this.filter.showFinishedTasks || item.is_finished == false)
@@ -4,7 +4,7 @@
v-model="selectedEmployee" v-model="selectedEmployee"
class="subheader-input" class="subheader-input"
:items="employees" :items="employees"
item-title="name" item-title="fullName"
item-value="id" item-value="id"
label="Zamestnanec" label="Zamestnanec"
variant="outlined" variant="outlined"
@@ -31,6 +31,7 @@
<script> <script>
import { addDays, subDays } from 'date-fns' import { addDays, subDays } from 'date-fns'
import { mapGetters } from 'vuex'
export default { export default {
props: { props: {
@@ -47,13 +48,14 @@ export default {
employees: [], employees: [],
selectedDate: "", selectedDate: "",
// Kaluza: Napojit funkcnost
selectedEmployee: '', selectedEmployee: '',
date: new Date() date: new Date()
} }
}, },
computed: { computed: {
...mapGetters('auth', ['user']),
time() { time() {
return this.unscheduledTime return this.unscheduledTime
} }
@@ -74,6 +76,10 @@ export default {
async _getEmployees() { async _getEmployees() {
this.employees = await this.$axios.get_auth_data('v1/employees') this.employees = await this.$axios.get_auth_data('v1/employees')
this.employees.forEach(employee => {
employee.fullName = `${employee.name} ${employee.surname}`
if (employee.id == this.user.id) this.selectedEmployee = employee
})
}, },
_getWeek(emitDataChanged = true) { _getWeek(emitDataChanged = true) {
@@ -31,7 +31,6 @@
<script> <script>
import { addDays, subDays } from 'date-fns' import { addDays, subDays } from 'date-fns'
import { mapGetters } from 'vuex'
export default { export default {
props: { props: {
@@ -47,8 +46,7 @@ export default {
return { return {
teams: [], teams: [],
// Kaluza: Napojit funkcionalitu selectedTeam: null,
selectedTeam: '',
selectedDate: new Date(), selectedDate: new Date(),
day: new Date(), day: new Date(),
@@ -57,8 +55,6 @@ export default {
}, },
computed: { computed: {
...mapGetters('auth', ['user']),
time() { time() {
return this.unscheduledTime return this.unscheduledTime
}, },
@@ -79,7 +75,7 @@ export default {
async _getTeams() { async _getTeams() {
this.teams = await this.$axios.get_auth_data('v1/teamsx') this.teams = await this.$axios.get_auth_data('v1/teamsx')
// this.selectedTeam() this.selectedTeam = this.teams[0]
}, },
_getDay(emitDataChanged = true) { _getDay(emitDataChanged = true) {
@@ -1,6 +1,6 @@
<template> <template>
<v-dialog v-model="visible" max-width="650" max-height="90%" height="700px"> <v-dialog v-model="visible" max-width="650" max-height="90%" height="700px">
<W-loadable :content="blocker && allEmployees" class="h-100"> <W-loadable :content="blocker" class="h-100">
<v-card height="100%" class="d-flex flex-column"> <v-card height="100%" class="d-flex flex-column">
<div class="d-flex justify-space-between align-center modal-header"> <div class="d-flex justify-space-between align-center modal-header">
<h1>{{ blocker.id ? 'Upraviť' : 'Vytvoriť'}} blocker</h1> <h1>{{ blocker.id ? 'Upraviť' : 'Vytvoriť'}} blocker</h1>
@@ -62,7 +62,6 @@
select-text="Vybrať" select-text="Vybrať"
cancel-text="Zrušiť" cancel-text="Zrušiť"
placeholder="Trvanie od - do" placeholder="Trvanie od - do"
:start-time="startTime"
range range
/> />
</v-card-actions> </v-card-actions>
@@ -139,18 +138,22 @@ export default {
methods: { methods: {
async create(blocker = null) { async create(blocker = null) {
this.visible = true
this.blocker = null
if (blocker) { if (blocker) {
this.blocker = blocker
await this._load() await this._load()
} else { } else {
this.blocker = { const blocker = {
name: '', name: '',
date: null, date: null,
employees: [] employees: []
} }
}
this.visible = true setTimeout(() => {
this.blocker = blocker
})
}
}, },
employeeSelected(selectedOption) { employeeSelected(selectedOption) {
@@ -171,14 +174,13 @@ export default {
this.close() this.close()
this.$router.push({ name: 'Dashboard - Tasks' }) this.$router.push({ name: 'Dashboard - Tasks' })
} catch (error) { } catch (error) {
console.log(error) this.$toast(error)
} }
}, },
close() { close() {
this.visible = false this.visible = false
this.$emit('close', this.blocker) this.$emit('close', this.blocker)
this.blocker = null
}, },
async _create() { async _create() {
@@ -1,6 +1,6 @@
<template> <template>
<v-dialog v-model="visible" max-width="650" max-height="90%" height="700px"> <v-dialog v-model="visible" max-width="650" max-height="90%" height="700px">
<W-loadable :content="masterTask && employees" class="h-100"> <W-loadable :content="masterTask" class="h-100">
<v-card v-if="editMode" height="100%" class="d-flex flex-column scrolling"> <v-card v-if="editMode" height="100%" class="d-flex flex-column scrolling">
<div class="d-flex justify-space-between align-center modal-header"> <div class="d-flex justify-space-between align-center modal-header">
<h1>{{ masterTask.id ? 'Upraviť master task' : 'Vytvoriť master task' }}</h1> <h1>{{ masterTask.id ? 'Upraviť master task' : 'Vytvoriť master task' }}</h1>
@@ -69,7 +69,9 @@
class="modal-input border-select" class="modal-input border-select"
label="Tím" label="Tím"
variant="solo" variant="solo"
:items="teamsOptions" :items="teams"
item-value="id"
item-title="name"
></v-select> ></v-select>
<v-text-field <v-text-field
@@ -170,7 +172,7 @@
</v-col> </v-col>
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2"> <v-sheet class="ma-2">
<p class="text-red-darken-4">{{ formattedDeadline }}</p> <p :class="`${compareDates ? 'text-black' : 'text-red-darken-4'}`">{{ formattedDeadline }}</p>
</v-sheet> </v-sheet>
</v-col> </v-col>
</v-row> </v-row>
@@ -212,7 +214,7 @@
</v-col> </v-col>
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2"> <v-sheet class="ma-2">
<p>{{ (masterTask.duration / 60 / 60).toFixed(2) }} h</p> <p>{{ (masterTask.duration).toFixed(2) }} h</p>
</v-sheet> </v-sheet>
</v-col> </v-col>
</v-row> </v-row>
@@ -230,7 +232,7 @@
</v-col> </v-col>
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2"> <v-sheet class="ma-2">
<p class="text-red-darken-4">{{ masterTask.worked_time }} h</p> <p :class="masterTask.worked_time > masterTask.duration ? 'text-red-darken-4': 'text-black'">{{ (masterTask.worked_time).toFixed(2) }} h</p>
</v-sheet> </v-sheet>
</v-col> </v-col>
</v-row> </v-row>
@@ -248,7 +250,7 @@
</v-col> </v-col>
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2"> <v-sheet class="ma-2">
<p class="text-red-darken-4">{{ masterTask.remaining_time }} h</p> <p :class="masterTask.worked_time > masterTask.duration ? 'text-red-darken-4': 'text-black'">{{ (masterTask.duration - masterTask.worked_time).toFixed(2) }} h</p>
</v-sheet> </v-sheet>
</v-col> </v-col>
</v-row> </v-row>
@@ -359,10 +361,14 @@ export default {
methods: { methods: {
async create(masterTaskId = null, editMode = false) { async create(masterTaskId = null, editMode = false) {
this.visible = true
this.masterTask = null
if (masterTaskId) { if (masterTaskId) {
await this._load(masterTaskId) await this._load(masterTaskId)
this.editMode = editMode || (!this.masterTask?.id)
} else { } else {
this.masterTask = { const masterTask = {
project_code: null, project_code: null,
name: null, name: null,
deadline: null, deadline: null,
@@ -372,10 +378,12 @@ export default {
employees: [], employees: [],
files: [] files: []
} }
}
this.editMode = editMode || (!this.masterTask.id) setTimeout(() => {
this.visible = true this.masterTask = masterTask
this.editMode = editMode || (!this.masterTask.id)
})
}
}, },
async save() { async save() {
@@ -391,14 +399,13 @@ export default {
this.close() this.close()
this.$router.push({ name: 'Dashboard - Tasks' }) this.$router.push({ name: 'Dashboard - Tasks' })
} catch (error) { } catch (error) {
console.log(error) this.$toast(error)
} }
}, },
close() { close() {
this.visible = false this.visible = false
this.$emit('close', this.masterTask) this.$emit('close', this.masterTask)
this.masterTask = null
}, },
async _load(masterTaskId) { async _load(masterTaskId) {
@@ -460,9 +467,6 @@ export default {
}, },
computed: { computed: {
teamsOptions() {
return this.teams.map(team => `${team.name} - ${team.id}`)
},
totalHours() { totalHours() {
let hours = 0 let hours = 0
@@ -470,7 +474,6 @@ export default {
this.masterTask.employees.forEach(function(employee) { this.masterTask.employees.forEach(function(employee) {
if(employee.hours > 0) hours += parseFloat(employee.hours) if(employee.hours > 0) hours += parseFloat(employee.hours)
}) })
console.log(hours)
return hours ? hours : 0 return hours ? hours : 0
}, },
@@ -495,12 +498,18 @@ export default {
let deadline = moment(this.masterTask.deadline) let deadline = moment(this.masterTask.deadline)
let date = deadline.format('DD.MM.yyyy') let date = deadline.format('DD.MM.yyyy')
return date return date
},
compareDates() {
const date1 = moment()
const date2 = moment(this.masterTask.deadline)
return moment(date1).isBefore(date2)
} }
}, },
watch: { watch: {
selectedTeam() { selectedTeam() {
this.masterTask.team = this.teams.find(team => `${team.name} - ${team.id}` == this.selectedTeam) this.masterTask.team = this.teams.find(team => team.id == this.selectedTeam)
this.masterTask.employees = this.masterTask.team.employees this.masterTask.employees = this.masterTask.team.employees
} }
} }
@@ -1,14 +1,10 @@
<template> <template>
<v-dialog v-model="visible" max-width="650" max-height="90%" height="700px"> <v-dialog v-model="visible" max-width="650" max-height="90%" height="700px">
<W-loadable :content="task && employees" class="h-100"> <W-loadable :content="task" class="h-100">
<v-card v-if="editMode" height="100%" class="d-flex flex-column scrolling"> <v-card v-if="editMode" height="100%" class="d-flex flex-column scrolling">
<div class="d-flex justify-space-between align-center modal-header"> <div class="d-flex justify-space-between align-center modal-header">
<h1>{{ task.id ? 'Upraviť task' : 'Vytvoriť task' }}</h1> <h1>{{ task.id ? 'Upraviť task' : 'Vytvoriť task' }}</h1>
<v-icon <v-icon @click.stop="close()" icon="mdi-close" size="large"></v-icon>
@click.stop="close()"
icon="mdi-close"
size="large"
></v-icon>
</div> </div>
<v-card-actions class="d-flex flex-column modal-content"> <v-card-actions class="d-flex flex-column modal-content">
@@ -27,38 +23,21 @@
class="modal-input border-select" class="modal-input border-select"
label="MasterTask" label="MasterTask"
variant="solo" variant="solo"
:items="masterTaskOptions" :items="masterTasks"
item-value="id"
item-title="name"
></v-select> ></v-select>
<p v-if="task.team.employees" class="d-flex justify-start align-center w-100 mb-3 text-grey">Priradení zamestnanci</p> <v-select
v-model="selectedEmployee"
<v-text-field
v-for="(employee, index) in task.employees"
:key="employee.id"
@focus="onInputFocus" @focus="onInputFocus"
class="modal-input" class="modal-input border-select"
:value="`${employee.name} ${employee.surname}`" label="Priradený"
variant="solo" variant="solo"
v-model="task.employees[index].name" :items="task.team.employees"
disabled item-value="id"
> item-title="_fullName"
<p class="employee-select-avatar d-flex justify-center align-center"> ></v-select>
{{ employee.name.charAt(0) + employee.surname.charAt(0) }}
</p>
</v-text-field>
<Z-autocomplete
v-if="showAddEmployeeInput"
:options="employeesOptions"
:validations="v$.task.employees"
:class="{ error: v$.task.employees.$errors.length }"
class="modal-input"
@option-selected="employeeSelected"
/>
<v-btn class="w-100 mb-5 add-employee-btn" :disabled="!task.team.employees" @click="showAddEmployeeInput = true">
<v-icon class="mx-1" icon="mdi-plus" />Pridať zamestnanca
</v-btn>
<Datepicker <Datepicker
class="modal-input mb-5" class="modal-input mb-5"
@@ -71,7 +50,6 @@
select-text="Vybrať" select-text="Vybrať"
cancel-text="Zrušiť" cancel-text="Zrušiť"
placeholder="Trvanie od - do" placeholder="Trvanie od - do"
:start-time="startTime"
range range
/> />
@@ -92,6 +70,7 @@
></v-text-field> ></v-text-field>
<v-textarea <v-textarea
v-model="task.description"
label="Popis" label="Popis"
class="modal-input" class="modal-input"
variant="solo" variant="solo"
@@ -101,13 +80,14 @@
? errorUtils.parseErrors(v$.task.description.$errors) ? errorUtils.parseErrors(v$.task.description.$errors)
: null : null
" "
v-model="task.description"
></v-textarea> ></v-textarea>
<Z-files-upload @files-uploaded="filesUploaded"/> <Z-files-upload @files-uploaded="filesUploaded" />
</v-card-actions> </v-card-actions>
<v-btn class="z-btn" @click="save()">{{ task.id ? 'UPRAVIŤ' : 'VYTVORIŤ' }}</v-btn> <v-btn class="z-btn" @click="save()">{{
task.id ? 'UPRAVIŤ' : 'VYTVORIŤ'
}}</v-btn>
</v-card> </v-card>
<v-card v-else height="100%" class="d-flex flex-column scrolling"> <v-card v-else height="100%" class="d-flex flex-column scrolling">
@@ -120,11 +100,23 @@
class="pb-5" class="pb-5"
></v-icon> ></v-icon>
</div> </div>
<div class="d-flex justify-space-between align-center modal-header border-bottom pb-4"> <div
class="d-flex justify-space-between align-center modal-header border-bottom pb-4"
>
<h1>{{ task.master_task }}</h1> <h1>{{ task.master_task }}</h1>
<div class="d-flex justify-start"> <div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editMode = !editMode" /> <img
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="deleteTask()"/> class="pencil-icon"
:src="require('@/plugins/tm@overview/_img/pencil-icon.svg')"
alt="pencil-icon"
@click.stop="editMode = !editMode"
/>
<img
class="trash-icon"
:src="require('@/plugins/tm@overview/_img/trash-icon.svg')"
alt="trash-icon"
@click.stop="deleteTask()"
/>
</div> </div>
</div> </div>
@@ -134,17 +126,16 @@
<v-col cols="5"> <v-col cols="5">
<v-sheet class="pa-2 ma-2"> <v-sheet class="pa-2 ma-2">
<div class="d-flex align-center"> <div class="d-flex align-center">
<v-icon <v-icon icon="mdi-link" size="large"></v-icon>
icon="mdi-link"
size="large"
></v-icon>
<p class="mx-3">Mastertask</p> <p class="mx-3">Mastertask</p>
</div> </div>
</v-sheet> </v-sheet>
</v-col> </v-col>
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2"> <v-sheet class="ma-2">
<p class="task-badge px-4 py-2 rounded-pill">{{ task.master_task }}</p> <p class="task-badge px-4 py-2 rounded-pill">
{{ task.master_task }}
</p>
</v-sheet> </v-sheet>
</v-col> </v-col>
</v-row> </v-row>
@@ -162,8 +153,18 @@
</v-col> </v-col>
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2"> <v-sheet class="ma-2">
<p v-if="task.is_finished" class="status-badge px-4 py-2 rounded-pill">Ukončený</p> <p
<p v-if="!task.is_finished" class="status-badge px-4 py-2 rounded-pill">Neukončený</p> v-if="task.is_finished"
class="status-badge px-4 py-2 rounded-pill"
>
Ukončený
</p>
<p
v-if="!task.is_finished"
class="status-badge px-4 py-2 rounded-pill"
>
Neukončený
</p>
</v-sheet> </v-sheet>
</v-col> </v-col>
</v-row> </v-row>
@@ -181,7 +182,11 @@
</v-col> </v-col>
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2"> <v-sheet class="ma-2">
<p v-html="`${formattedStartDate} - ${formattedEndDate}`" /> <p
v-html="
`${formattedStartDate} - ${formattedEndDate}`
"
/>
</v-sheet> </v-sheet>
</v-col> </v-col>
</v-row> </v-row>
@@ -199,11 +204,25 @@
</v-col> </v-col>
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2 d-flex flex-wrap"> <v-sheet class="ma-2 d-flex flex-wrap">
<div class="d-flex align-center mb-2 me-2" v-for="(employee, index) in task.employees" :key="employee.id"> <div
<p class="employee-selected-avatar d-flex justify-center align-center"> class="d-flex align-center mb-2 me-2"
{{ employee.name.charAt(0) + employee.surname.charAt(0) }} v-for="(employee, index) in task.employees"
:key="employee.id"
>
<p
class="employee-selected-avatar d-flex justify-center align-center"
>
{{
employee.name.charAt(0) +
employee.surname.charAt(0)
}}
</p> </p>
<p class="ml-2" v-html="`${task.employees[index].name} ${task.employees[index].surname}`" /> <p
class="ml-2"
v-html="
`${task.employees[index].name} ${task.employees[index].surname}`
"
/>
</div> </div>
</v-sheet> </v-sheet>
</v-col> </v-col>
@@ -241,11 +260,11 @@
<v-col cols="7"> <v-col cols="7">
<v-sheet class="ma-2"> <v-sheet class="ma-2">
<v-text-field <v-text-field
v-model="task.spent_time" v-model="task.spent_time"
class="modal-input" class="modal-input"
variant="solo" variant="solo"
type="number" type="number"
placeholder="h" placeholder="h"
></v-text-field> ></v-text-field>
</v-sheet> </v-sheet>
</v-col> </v-col>
@@ -270,20 +289,34 @@
</v-row> </v-row>
<div class="px-5 py-5 border-bottom"> <div class="px-5 py-5 border-bottom">
<p>Popis zadania</p> <p>Popis zadania</p>
<section class="description-detail px-2 py-2 w-100 rounded mt-2">{{ task.description }}</section> <section
class="description-detail px-2 py-2 w-100 rounded mt-2"
>
{{ task.description }}
</section>
<p class="mt-5">Prílohy</p> <p class="mt-5">Prílohy</p>
<div class="w-100 d-flex align-center"> <div class="w-100 d-flex align-center">
<div v-for="(file, index) in task.files" :key="file.id" class="d-flex align-center flex-wrap" :class="[index === 0 ? 'ml-0': 'ml-2']"> <div
v-for="(file, index) in task.files"
:key="file.id"
class="d-flex align-center flex-wrap"
:class="[index === 0 ? 'ml-0' : 'ml-2']"
>
<v-chip class="mt-2"> <v-chip class="mt-2">
{{ file.name }} {{ file.name }}
<v-icon class="mx-1" icon="mdi-paperclip"></v-icon> <v-icon
class="mx-1"
icon="mdi-paperclip"
></v-icon>
</v-chip> </v-chip>
</div> </div>
</div> </div>
</div> </div>
<div class="d-flex justify-start align-center mt-8"> <div class="d-flex justify-start align-center mt-8">
<v-btn class="done-btn">Dokončené</v-btn> <v-btn class="done-btn">Dokončené</v-btn>
<v-btn class="add-employee-btn" @click="save()">Uložiť zmeny</v-btn> <v-btn class="add-employee-btn" @click="save()"
>Uložiť zmeny</v-btn
>
</div> </div>
</div> </div>
</v-card-actions> </v-card-actions>
@@ -293,15 +326,12 @@
</template> </template>
<script> <script>
import Datepicker from '@vuepic/vue-datepicker' import Datepicker from '@vuepic/vue-datepicker';
import ZFilesUpload from '@/plugins/tm@_components/z-files-upload.vue' import ZFilesUpload from '@/plugins/tm@_components/z-files-upload.vue';
import useVuelidate from '@vuelidate/core' import useVuelidate from '@vuelidate/core';
import { required } from '@vuelidate/validators' import { required } from '@vuelidate/validators';
import errorUtils from '@/plugins/lib@auth/_utils/error.utils' import errorUtils from '@/plugins/lib@auth/_utils/error.utils';
import ZAutocomplete from '@/plugins/tm@_components/z-autocomplete.vue' import moment from 'moment';
import moment from 'moment'
const atLeastOne = (value) => value.length
export default { export default {
emits: ['close'], emits: ['close'],
@@ -309,7 +339,6 @@ export default {
components: { components: {
Datepicker, Datepicker,
ZFilesUpload, ZFilesUpload,
ZAutocomplete
}, },
data() { data() {
@@ -323,8 +352,9 @@ export default {
employees: null, employees: null,
selectedMasterTask: '', selectedMasterTask: '',
showAddEmployeeInput: false, showAddEmployeeInput: false,
masterTasks: null masterTasks: null,
} selectedEmployee: null,
};
}, },
validations() { validations() {
@@ -335,164 +365,178 @@ export default {
team: { required }, team: { required },
duration: { required }, duration: { required },
description: { required }, description: { required },
employees: { atLeastOne } employee: { required },
}, },
} };
}, },
async created() { async created() {
try { try {
this.masterTasks = await this.$axios.get_auth_data('v1/master-tasks') this.masterTasks = await this.$axios.get_auth_data('v1/master-tasks');
this.employees = await this.$axios.get_auth_data('v1/employees') this.employees = await this.$axios.get_auth_data('v1/employees');
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error);
} }
}, },
methods: { methods: {
async create(taskId = null, editMode = false) { async create(taskId = null, editMode = false) {
this.visible = true;
this.task = null;
if (taskId) { if (taskId) {
await this._load(taskId) await this._load(taskId);
this.editMode = editMode || !this.task?.id;
} else { } else {
this.task = { const task = {
project_code: null, project_code: null,
date: null, date: null,
team: {}, team: {},
employees: [], employee: null,
duration: null, duration: null,
description: null, description: null,
files: [] files: [],
} };
}
this.editMode = editMode || (!this.task.id) setTimeout(() => {
this.visible = true this.task = task;
this.editMode = editMode || !this.task.id;
});
}
}, },
async save() { async save() {
if (!(await this.v$.$validate())) if (!(await this.v$.$validate())) return;
return
try { try {
if (this.task.id) if (this.task.id) await this._update();
await this._update() else await this._create();
else
await this._create()
this.close() this.close();
this.$router.push({ name: 'Dashboard - Tasks' }) this.$router.push({ name: 'Dashboard - Tasks' });
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error);
} }
}, },
close() { close() {
this.visible = false this.visible = false;
this.$emit('close', this.task) this.$emit('close', this.task);
this.task = null
}, },
async _load(taskId) { async _load(taskId) {
try { try {
this.task = await this.$axios.get_auth_data(`v1/tasks/${taskId}`) this.task = await this.$axios.get_auth_data(`v1/tasks/${taskId}`);
console.log(this.task)
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error);
} }
}, },
async _create() { async _create() {
try { try {
await this.$axios.post_auth('v1/master-tasks') await this.$axios.post_auth('v1/master-tasks');
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error);
} }
}, },
async _update() { async _update() {
try { try {
await this.$axios.post_auth(`v1/master-tasks/${this.task.id}`) await this.$axios.post_auth(`v1/master-tasks/${this.task.id}`);
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error);
} }
}, },
async deleteTask(taskId) { async deleteTask(taskId) {
try { try {
await this.$axios.delete(`v1/tasks/${taskId}`) await this.$axios.delete(`v1/tasks/${taskId}`);
this.close() this.close();
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error);
} }
}, },
employeeSelected(selectedOption) { employeeSelected(selectedOption) {
const employee = this.employees.find((empl) => empl.id == selectedOption.key) const employee = this.employees.find((empl) => empl.id == selectedOption.key);
this.task.employees.push(employee) this.task.employees.push(employee);
this.showAddEmployeeInput = false this.showAddEmployeeInput = false;
}, },
// Vuetify input was automatically focus after date input was clicked. This will prevent this unwanted behavior // Vuetify input was automatically focus after date input was clicked. This will prevent this unwanted behavior
onDateFocus($event) { onDateFocus($event) {
if ($event == undefined) { if ($event == undefined) {
this.preventInputFocus = true this.preventInputFocus = true;
} }
}, },
onInputFocus($event) { onInputFocus($event) {
if (this.preventInputFocus) { if (this.preventInputFocus) {
$event.target.blur() $event.target.blur();
this.preventInputFocus = false this.preventInputFocus = false;
} }
}, },
filesUploaded(files) { filesUploaded(files) {
this.task.files = files this.task.files = files;
} },
}, },
computed: { computed: {
masterTaskOptions() {
return this.masterTasks.map(masterTask => `${masterTask.name} - ${masterTask.id}`)
},
employeesOptions() { employeesOptions() {
const selectedEmployeesIds = this.task.employees.map( const selectedEmployeesIds = this.task.employees.map(
(employee) => employee.id (employee) => employee.id
) );
const employees = this.employees.filter( const employees =
(employee) => !selectedEmployeesIds.includes(employee.id) this.employees.filter(
) || [] (employee) => !selectedEmployeesIds.includes(employee.id)
) || [];
return employees.map((employee) => { return employees.map((employee) => {
return { return {
key: employee.id, key: employee.id,
value: `${employee.name} ${employee.surname}`, value: `${employee.name} ${employee.surname}`,
} };
}) });
}, },
formattedStartDate() { formattedStartDate() {
let startDate = moment(this.task.starts_at) let startDate = moment(this.task.starts_at);
let date = startDate.format('DD.MM.yyyy, HH:mm') let date = startDate.format('DD.MM.yyyy, HH:mm');
return date return date;
}, },
formattedEndDate() { formattedEndDate() {
let endDate = moment(this.task.ends_at) let endDate = moment(this.task.ends_at);
let date = endDate.format('DD.MM.yyyy, HH:mm') let date = endDate.format('DD.MM.yyyy, HH:mm');
return date return date;
} },
}, },
watch: { watch: {
selectedMasterTask() { selectedMasterTask() {
this.task.team = this.masterTasks.find(masterTask => `${masterTask.name} - ${masterTask.id}` == this.selectedMasterTask) this.task.team = this.masterTasks.find(
this.task.employees = this.task.team.employees (masterTask) => masterTask.id == this.selectedMasterTask
this.task.project_code = this.masterTasks.filter(x => `${x.name} - ${x.id}` == this.selectedMasterTask)[0].project_code );
} console.log(this.task.team.employees)
} this.task.team.employees.forEach(
} (employee) => {
employee._fullName = `${employee.name} ${employee.surname}`
});
console.log(this.task.team.employees)
this.task.employee = null;
this.task.project_code = this.masterTasks.filter(
(x) => x.id == this.selectedMasterTask
)[0].project_code;
},
selectedEmployee() {
this.task.employee = this.task.team.employees.find(
(employee) => employee.id == this.selectedEmployee
);
},
},
};
</script> </script>
<style lang="sass" scoped> <style lang="sass" scoped>
@@ -558,4 +602,4 @@ export default {
color: #fff !important color: #fff !important
height: 50px height: 50px
width: 203px width: 203px
</style> </style>
@@ -1,17 +1,17 @@
<template> <template>
<v-dialog v-model="show" max-width="650"> <v-dialog v-model="visible" max-width="650">
<v-card> <v-card>
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1>Ste si istý, že chcete zmazať tím <b>{{ team.name }}</b>?</h1> <h1>
<v-icon Ste si istý, že chcete zmazať tím <b>{{ team.name }}</b
@click.stop="show = false" >?
icon="mdi-close" </h1>
size="large" <v-icon @click.stop="visible = false" icon="mdi-close" size="large"></v-icon>
></v-icon>
</div> </div>
<v-card-actions class="mt-10 d-flex justify-start align-center"> <v-card-actions class="mt-10 d-flex justify-start align-center">
<v-btn class="z-btn" variant="flat" @click="deleteTeam()">ÁNO</v-btn> <v-btn class="z-btn" variant="flat" @click="deleteTeam()">ÁNO</v-btn>
<v-btn class="ml-7 cancel-btn" @click.stop="show = false">ZRUŠIŤ</v-btn> <v-btn class="ml-7 cancel-btn" @click.stop="visible = false">ZRUŠIŤ</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
@@ -19,41 +19,31 @@
<script> <script>
export default { export default {
emits: ['delete-team', 'close'], emits: ['deleted'],
props: { data() {
visible: { return {
type: Boolean, visible: false,
required: true team: null,
}, };
team: {
type: Object,
required: true
}
},
computed: {
show: {
get() {
return this.visible
},
set(value) {
if (!value) this.$emit('close')
}
},
}, },
methods: { methods: {
async delete(team) {
this.team = team
this.visible = true
},
async deleteTeam() { async deleteTeam() {
try { try {
await this.$axios.delete(`v1/teams/${this.team.id}`) await this.$axios.delete(`v1/teams/${this.team.id}`)
this.show = false
this.visible = false
this.$emit('deleted', this.team)
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error)
} }
} },
} },
} };
</script> </script>
+13 -10
View File
@@ -116,28 +116,31 @@ export default {
this.close() this.close()
} catch (error) { } catch (error) {
console.log(error) this.$toast(error)
} }
}, },
async create(team = null) { async create(id = null) {
if (team) { this.visible = true
this.team = team this.team = null
if (id) {
await this._load() await this._load()
} else { } else {
this.team = { const team = {
name: '', name: '',
employees: [] employees: []
} }
}
this.visible = true setTimeout(() => {
this.team = team
})
}
}, },
close() { close() {
this.visible = false this.visible = false
this.$emit('close', this.team) this.$emit('close', this.team)
this.team = null
}, },
async _create() { async _create() {
@@ -156,9 +159,9 @@ export default {
} }
}, },
async _load() { async _load(id) {
try { try {
const team = await this.$axios.get_auth_data(`v1/teams/${this.team.id}`) const team = await this.$axios.get_auth_data(`v1/teams/${id}`)
team.employees = this._enrichEmployeesByFullName(team.employees) team.employees = this._enrichEmployeesByFullName(team.employees)
this.team = team this.team = team
@@ -4,8 +4,10 @@
v-model="selectedEmployee" v-model="selectedEmployee"
class="subheader-input" class="subheader-input"
variant="outlined" variant="outlined"
:items="allEmployees"
label="Zamestanec" label="Zamestanec"
:items="allEmployees"
item-title="fullName"
item-value="id"
></v-select> ></v-select>
<v-text-field <v-text-field
v-model="searchQuery" v-model="searchQuery"
@@ -23,7 +25,7 @@
export default { export default {
data() { data() {
return { return {
selectedEmployee: '', selectedEmployee: null,
employees: [], employees: [],
searchQuery: '' searchQuery: ''
} }
@@ -42,6 +44,9 @@ export default {
async created() { async created() {
try { try {
this.employees = await this.$axios.get_auth_data('v1/employees') this.employees = await this.$axios.get_auth_data('v1/employees')
this.employees.filter((employee) => {
employee.fullName = `${employee.name} ${employee.surname}`
})
} catch (error) { } catch (error) {
this.$toast.error(error) this.$toast.error(error)
} }
@@ -51,7 +56,13 @@ export default {
onInput() { onInput() {
this.$emit('queryChange', this.searchQuery) this.$emit('queryChange', this.searchQuery)
} }
} },
// watch: {
// selectedEmployee() {
// this.search()
// }
// }
} }
</script> </script>
@@ -14,7 +14,7 @@
<td class="task-action"> <td class="task-action">
<div class="d-flex justify-start"> <div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editTeam(team)" /> <img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editTeam(team)" />
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="deleteModal = { team }" /> <img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="deleteTeam(team)" />
</div> </div>
</td> </td>
</tr> </tr>
@@ -22,8 +22,7 @@
</v-table> </v-table>
<Z-team-modal ref="z-team-modal" /> <Z-team-modal ref="z-team-modal" />
<!-- Kravarik: Aj tento modal prerob novym sposobom --> <Z-delete-team-modal ref="z-delete-team-modal" @deleted="onTeamDeleted" />
<Z-delete-team-modal v-if="deleteModal" :visible="deleteModal ? true : false" :team="deleteModal.team" @close="(deleteModal = null)" />
</div> </div>
</template> </template>
@@ -32,6 +31,8 @@ import ZDeleteTeamModal from '@/plugins/tm@modal/team/z-delete-team-modal.vue'
import ZTeamModal from '@/plugins/tm@modal/team/z-team-modal.vue' import ZTeamModal from '@/plugins/tm@modal/team/z-team-modal.vue'
export default { export default {
emits: ['refresh'],
components: { components: {
ZDeleteTeamModal, ZDeleteTeamModal,
ZTeamModal ZTeamModal
@@ -52,7 +53,15 @@ export default {
methods: { methods: {
editTeam(team) { editTeam(team) {
this.$refs['z-team-modal'].create(team) this.$refs['z-team-modal'].create(team.id)
},
deleteTeam(team) {
this.$refs['z-delete-team-modal'].delete(team)
},
onTeamDeleted() {
this.$emit('refresh')
} }
} }
} }
+13 -5
View File
@@ -1,6 +1,6 @@
<template> <template>
<W-loadable :content="teams"> <W-loadable :content="teams">
<A-teams-table :teams="teams" /> <A-teams-table :teams="teams" @refresh="loadData" />
</W-loadable> </W-loadable>
</template> </template>
@@ -19,10 +19,18 @@ export default {
}, },
async created() { async created() {
try { await this.loadData()
this.teams = await this.$axios.get_auth_data('v1/teams') },
} catch (error) {
this.teams = {error} methods: {
async loadData() {
this.teams = null
try {
this.teams = await this.$axios.get_auth_data('v1/teamsx')
} catch (error) {
this.teams = {error}
}
} }
} }
} }
@@ -1,69 +1,65 @@
<template> <template>
<W-loadable :content="user ? true : false"> <div class="border-bottom py-5 px-5">
<div v-if="user"> <h1>Všeobecné informácie</h1>
<div class="border-bottom py-5 px-5"> <v-text-field
<h1>Všeobecné informácie</h1> class="w-75"
<v-text-field variant="solo"
class="w-75" label="Meno"
variant="solo" v-model="user.name"
label="Meno" :class="{ error: v$.user.name.$errors.length }"
v-model="user.name" :hint="
:class="{ error: v$.user.name.$errors.length }" v$.user.name.$errors
:hint=" ? errorUtils.parseErrors(v$.user.name.$errors)
v$.user.name.$errors : null
? errorUtils.parseErrors(v$.user.name.$errors) "
: null ></v-text-field>
" <v-text-field
></v-text-field> class="w-75"
<v-text-field variant="solo"
class="w-75" label="Priezvisko"
variant="solo" v-model="user.surname"
label="Priezvisko" :class="{ error: v$.user.surname.$errors.length }"
v-model="user.surname" :hint="
:class="{ error: v$.user.surname.$errors.length }" v$.user.surname.$errors
:hint=" ? errorUtils.parseErrors(v$.user.surname.$errors)
v$.user.surname.$errors : null
? errorUtils.parseErrors(v$.user.surname.$errors) "
: null ></v-text-field>
" </div>
></v-text-field> <div class="py-5 px-5 border-bottom">
</div> <h1>Pracovná doba</h1>
<div class="py-5 px-5 border-bottom"> <v-text-field
<h1>Pracovná doba</h1> class="w-75"
<v-text-field variant="solo"
class="w-75" label="Začiatok"
variant="solo" v-model="user.work_hours_from"
label="Začiatok" append-inner-icon="mdi-clock-outline"
v-model="user.work_hours_from" type="time"
append-inner-icon="mdi-clock-outline" :class="{ error: v$.user.work_hours_from.$errors.length }"
type="time" :hint="
:class="{ error: v$.user.work_hours_from.$errors.length }" v$.user.work_hours_from.$errors
:hint=" ? errorUtils.parseErrors(v$.user.work_hours_from.$errors)
v$.user.work_hours_from.$errors : null
? errorUtils.parseErrors(v$.user.work_hours_from.$errors) "
: null ></v-text-field>
" <v-text-field
></v-text-field> class="w-75"
<v-text-field variant="solo"
class="w-75" label="Koniec"
variant="solo" v-model="user.work_hours_to"
label="Koniec" append-inner-icon="mdi-clock-outline"
v-model="user.work_hours_to" :class="{ error: v$.user.work_hours_to.$errors.length }"
append-inner-icon="mdi-clock-outline" :hint="
:class="{ error: v$.user.work_hours_to.$errors.length }" v$.user.work_hours_to.$errors
:hint=" ? errorUtils.parseErrors(v$.user.work_hours_to.$errors)
v$.user.work_hours_to.$errors : null
? errorUtils.parseErrors(v$.user.work_hours_to.$errors) "
: null type="time"
" ></v-text-field>
type="time" </div>
></v-text-field> <div class="py-5 px-5">
</div> <v-btn class="z-btn" @click="updateUserInfo()">ULOŽIŤ ZMENY</v-btn>
<div class="py-5 px-5"> </div>
<v-btn class="z-btn" @click="updateUserInfo()">ULOŽIŤ ZMENY</v-btn>
</div>
</div>
</W-loadable>
</template> </template>
<script> <script>
@@ -99,7 +95,7 @@ export default {
async updateUserInfo() { async updateUserInfo() {
if (!(await this.v$.$validate())) return if (!(await this.v$.$validate())) return
try { try {
await this.$store.dispatch('wAuth/updateUserInfo', this.user) await this.$store.dispatch('auth/updateUserInfo', this.user)
this.$toast.success('Profil bol úspešne zmenený') this.$toast.success('Profil bol úspešne zmenený')
} catch (error) { } catch (error) {
+3 -1
View File
@@ -18,6 +18,8 @@ export default {
state.user = data.user state.user = data.user
localStorage.setItem('wzo_vue_user_user', JSON.stringify(data.user)) localStorage.setItem('wzo_vue_user_user', JSON.stringify(data.user))
} }
console.log(state)
}, },
auth_error(state: any) { auth_error(state: any) {
state.token = '' state.token = ''
@@ -158,7 +160,7 @@ export default {
return state.user return state.user
}, },
token: (state: any) => { token: (state: any) => {
return state.token return (state.token && state.token != undefined) ? state.token : null
} }
} }
} }
+4
View File
@@ -149,6 +149,10 @@ export default {
_config(config: any) { _config(config: any) {
if (config) console.error('NOT IMPLEMENTED') if (config) console.error('NOT IMPLEMENTED')
if (!store.getters['auth/token']) {
return {headers: {}}
}
return { return {
headers: { headers: {
Authorization: `Bearer ${store.getters['auth/token']}` Authorization: `Bearer ${store.getters['auth/token']}`
+6 -5
View File
@@ -1,8 +1,8 @@
import { Language, Options } from "../types" import { Language, Options } from "../types"
import { Ref, ref } from 'vue' import { Ref, ref } from 'vue'
import axios from 'axios' import axios from 'axios'
import { createI18n, I18n as I18nType } from 'vue-i18n' import { createI18n, I18n as I18nType } from 'vue-i18n'
import { Preferences } from '@capacitor/preferences' import { Preferences } from '@capacitor/preferences'
export class I18n { export class I18n {
@@ -25,7 +25,8 @@ export class I18n {
missing: this._missingTranslation, missing: this._missingTranslation,
postTranslation: this._postTranslation, postTranslation: this._postTranslation,
}) })
this.changeLanguage({title: "Slovenský", flag: "sk", value: "sk"})
this.initCurrentLanguage() this.initCurrentLanguage()
} }
@@ -26,22 +26,30 @@ export default {
} }
}, },
async created() {
created() { await this._startLoading()
this.startLoading()
}, },
methods: { methods: {
async startLoading() { async _startLoading() {
if (!this.content) this.loader = await this.$loading.show()
this.loader = await this.$loading.show() },
_stopLoading() {
this.loader.hide()
} }
}, },
watch: { watch: {
content(newValue) { content(value) {
if (newValue) console.log(`XX: ${value}`)
this.loader.hide()
if (value) {
this._stopLoading()
console.log(' STOP LOADING')
}
else
this._startLoading()
} }
} }
} }