build(production): added edit to timeblocks in subtask edit; fixed search for mastertasks in subtask; fixed calendar position in timeblocks

This commit is contained in:
Matej Glasnák committed 2025-10-14 19:36:50 +02:00
commit 4949c28ae6
25 files changed
+1654 -643

No files matched your search

@@ -1 +1 @@
.subheader[data-v-45dcb20a]{max-width:100%;margin:0;border-bottom:1px solid rgba(33,33,33,.08);gap:25px;flex-wrap:wrap;flex:0 0 auto}.subheader-input[data-v-45dcb20a]{max-width:250px!important;min-width:250px;height:56px}.subheader-input[data-v-45dcb20a] .v-input__control .v-field{height:50px!important;--v-input-control-height:50px!important;--v-input-padding-top:15px!important}.subheader-input[data-v-45dcb20a] .v-input__details{display:none}.subheader-input.disabled[data-v-45dcb20a]{pointer-events:none!important}@media(max-width:600px){.subheader[data-v-45dcb20a]{gap:15px;padding:20px!important}.subheader-input[data-v-45dcb20a]{max-width:100%!important;min-width:100%;margin-bottom:15px}}[data-v-45dcb20a] .v-select__selection-text{display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}td[data-v-7c46cac8],th[data-v-7c46cac8],v-table[data-v-7c46cac8]{border:thin solid rgba(var(--v-border-color),var(--v-border-opacity))}.office-icon[data-v-7c46cac8]{height:20px;margin-left:12px}@media screen and (max-width:496px){.task-action div[data-v-7c46cac8]{display:flex;flex-direction:column}.task-action div .pencil-icon[data-v-7c46cac8],.task-action div .trash-icon[data-v-7c46cac8]{border-radius:50%;margin:6px;padding:6px}}.disabled[data-v-7c46cac8]{opacity:.5;pointer-events:none}tbody tr[data-v-7c46cac8]:hover{background:rgba(0,0,0,.1)}
.subheader[data-v-45dcb20a]{max-width:100%;margin:0;border-bottom:1px solid rgba(33,33,33,.08);gap:25px;flex-wrap:wrap;flex:0 0 auto}.subheader-input[data-v-45dcb20a]{max-width:250px!important;min-width:250px;height:56px}.subheader-input[data-v-45dcb20a] .v-input__control .v-field{height:50px!important;--v-input-control-height:50px!important;--v-input-padding-top:15px!important}.subheader-input[data-v-45dcb20a] .v-input__details{display:none}.subheader-input.disabled[data-v-45dcb20a]{pointer-events:none!important}@media(max-width:600px){.subheader[data-v-45dcb20a]{gap:15px;padding:20px!important}.subheader-input[data-v-45dcb20a]{max-width:100%!important;min-width:100%;margin-bottom:15px}}[data-v-45dcb20a] .v-select__selection-text{display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}td[data-v-f717e9f4],th[data-v-f717e9f4],v-table[data-v-f717e9f4]{border:thin solid rgba(var(--v-border-color),var(--v-border-opacity))}.office-icon[data-v-f717e9f4]{height:20px;margin-left:12px}@media screen and (max-width:496px){.task-action div[data-v-f717e9f4]{display:flex;flex-direction:column}.task-action div .pencil-icon[data-v-f717e9f4],.task-action div .trash-icon[data-v-f717e9f4]{border-radius:50%;margin:6px;padding:6px}}.disabled[data-v-f717e9f4]{opacity:.5;pointer-events:none}tbody tr[data-v-f717e9f4]:hover{background:rgba(0,0,0,.1)}
@@ -4,4 +4,4 @@
* ress.css • v2.0.4
* MIT License
* github.com/filipelinhares/ress
*/html{box-sizing:border-box;overflow-y:scroll;word-break:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4}*,:after,:before{background-repeat:no-repeat;box-sizing:inherit}:after,:before{text-decoration:inherit;vertical-align:inherit}*{padding:0;margin:0}hr{overflow:visible;height:0}details,main{display:block}summary{display:list-item}small{font-size:80%}[hidden]{display:none}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}a:active,a:hover{outline-width:0}pre{font-size:1em}b,strong{font-weight:bolder}input{border-radius:0}[disabled]{cursor:default}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}textarea{resize:vertical}button,input,optgroup,select,textarea{font:inherit}optgroup{font-weight:700}button{overflow:visible}button,select{text-transform:none}[role=button],[type=button],[type=reset],[type=submit],button{cursor:pointer;color:inherit}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button:-moz-focusring{outline:1px dotted ButtonText}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}button,input,select,textarea{background-color:transparent;border-style:none}select{-moz-appearance:none;-webkit-appearance:none}select::-ms-expand{display:none}select::-ms-value{color:currentColor}legend{border:0;color:inherit;display:table;white-space:normal;max-width:100%}::-webkit-file-upload-button{-webkit-appearance:button;color:inherit;font:inherit}::-ms-clear,::-ms-reveal{display:none}img{border-style:none}progress{vertical-align:baseline}@media screen{[hidden~=screen]{display:inherit}[hidden~=screen]:not(:active):not(:focus):not(:target){position:absolute!important;clip:rect(0 0 0 0)!important}}[aria-busy=true]{cursor:progress}[aria-controls]{cursor:pointer}[aria-disabled=true]{cursor:default}.elevation-24{box-shadow:0 11px 15px -7px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 24px 38px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 9px 46px 8px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-23{box-shadow:0 11px 14px -7px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 23px 36px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 9px 44px 8px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-22{box-shadow:0 10px 14px -6px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 22px 35px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 8px 42px 7px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-21{box-shadow:0 10px 13px -6px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 21px 33px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 8px 40px 7px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-20{box-shadow:0 10px 13px -6px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 20px 31px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 8px 38px 7px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-19{box-shadow:0 9px 12px -6px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 19px 29px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 7px 36px 6px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-18{box-shadow:0 9px 11px -5px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 18px 28px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 7px 34px 6px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-17{box-shadow:0 8px 11px -5px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 17px 26px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 6px 32px 5px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-16{box-shadow:0 8px 10px -5px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 16px 24px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 6px 30px 5px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-15{box-shadow:0 8px 9px -5px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 15px 22px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 6px 28px 5px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-14{box-shadow:0 7px 9px -4px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 14px 21px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 5px 26px 4px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-13{box-shadow:0 7px 8px -4px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 13px 19px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.Line truncated
*/html{box-sizing:border-box;overflow-y:scroll;word-break:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4}*,:after,:before{background-repeat:no-repeat;box-sizing:inherit}:after,:before{text-decoration:inherit;vertical-align:inherit}*{padding:0;margin:0}hr{overflow:visible;height:0}details,main{display:block}summary{display:list-item}small{font-size:80%}[hidden]{display:none}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}a:active,a:hover{outline-width:0}pre{font-size:1em}b,strong{font-weight:bolder}input{border-radius:0}[disabled]{cursor:default}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}textarea{resize:vertical}button,input,optgroup,select,textarea{font:inherit}optgroup{font-weight:700}button{overflow:visible}button,select{text-transform:none}[role=button],[type=button],[type=reset],[type=submit],button{cursor:pointer;color:inherit}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button:-moz-focusring{outline:1px dotted ButtonText}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}button,input,select,textarea{background-color:transparent;border-style:none}select{-moz-appearance:none;-webkit-appearance:none}select::-ms-expand{display:none}select::-ms-value{color:currentColor}legend{border:0;color:inherit;display:table;white-space:normal;max-width:100%}::-webkit-file-upload-button{-webkit-appearance:button;color:inherit;font:inherit}::-ms-clear,::-ms-reveal{display:none}img{border-style:none}progress{vertical-align:baseline}@media screen{[hidden~=screen]{display:inherit}[hidden~=screen]:not(:active):not(:focus):not(:target){position:absolute!important;clip:rect(0 0 0 0)!important}}[aria-busy=true]{cursor:progress}[aria-controls]{cursor:pointer}[aria-disabled=true]{cursor:default}.elevation-24{box-shadow:0 11px 15px -7px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 24px 38px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 9px 46px 8px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-23{box-shadow:0 11px 14px -7px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 23px 36px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 9px 44px 8px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-22{box-shadow:0 10px 14px -6px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 22px 35px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 8px 42px 7px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-21{box-shadow:0 10px 13px -6px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 21px 33px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 8px 40px 7px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-20{box-shadow:0 10px 13px -6px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 20px 31px 3px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 8px 38px 7px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-19{box-shadow:0 9px 12px -6px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 19px 29px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 7px 36px 6px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-18{box-shadow:0 9px 11px -5px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 18px 28px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 7px 34px 6px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-17{box-shadow:0 8px 11px -5px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 17px 26px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 6px 32px 5px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-16{box-shadow:0 8px 10px -5px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 16px 24px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 6px 30px 5px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-15{box-shadow:0 8px 9px -5px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 15px 22px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 6px 28px 5px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-14{box-shadow:0 7px 9px -4px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 14px 21px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.14)),0 5px 26px 4px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.12))!important}.elevation-13{box-shadow:0 7px 8px -4px var(--v-shadow-key-umbra-opacity,rgba(0,0,0,.2)),0 13px 19px 2px var(--v-shadow-key-penumbra-opacity,rgba(0,0,0,.Line truncated
-1
View File
@@ -1 +0,0 @@
@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap);.close-icon[data-v-4aa4bee3]:hover{background:red;color:#fff!important}.upload-btn[data-v-a2a40214]{color:#6200ee;border-radius:4px;border:1px solid #e5e5e5}.hidden-input[data-v-a2a40214]{opacity:0;overflow:hidden;position:absolute;width:1px;height:1px}.gif-loader[data-v-a2a40214]{height:30px}.completed{background:#06dece}.width-100[data-v-f216d188]{width:100%}.gif-loader[data-v-f01fa1ac]{height:30px;margin-left:30px}.timeblock[data-v-2c730af8]{position:relative;border-top:1px solid #e0e0e0;padding:20px 0 5px 0}.timeblock .splitted-time-inputs[data-v-2c730af8]{display:flex!important;flex-direction:row!important;gap:15px;margin-bottom:-11px}.timeblock .x-button[data-v-2c730af8]{display:flex;justify-content:flex-end;align-items:center;position:relative;bottom:5px}.timeblock .x-button button[data-v-2c730af8]{margin-right:5px}.error input[data-v-2c730af8]{border:1px solid red!important}.datepicker-wrapper[data-v-2c730af8]{width:100%}.datepicker-wrapper .datepicker-input[data-v-2c730af8]{width:100%!important;pointer-events:none}.w-full[data-v-551d0bf6]{width:100%}.date-wrap[data-v-551d0bf6]{display:flex;flex-flow:row;width:100%;gap:20px;margin-bottom:20px}.date-wrap .dp__main[data-v-551d0bf6]{width:calc(50% - 10px)!important}.scrolling[data-v-551d0bf6]{overflow:hidden!important}.border-bottom[data-v-551d0bf6]{border-bottom:1px solid rgba(0,0,0,.1)}.done-btn[data-v-551d0bf6]{background:#7f39fb!important;border-radius:4px!important;color:#fff!important;height:50px;width:203px}.remove-employee[data-v-551d0bf6]{position:relative;width:100%}.remove-employee svg[data-v-551d0bf6]{position:absolute;right:205px;top:28px;z-index:5;opacity:.5}.remove-employee.hide-arrow[data-v-551d0bf6] .mdi-menu-down,.remove-employee.hide-arrow[data-v-551d0bf6] .mdi-menu-up{display:none}.employee-wrapper[data-v-551d0bf6]{position:relative;width:100%}.employee-wrapper svg[data-v-551d0bf6]{position:absolute;right:4px;top:28px;z-index:5;opacity:.5}.employee-wrapper.hide-arrow[data-v-551d0bf6] .mdi-menu-down,.employee-wrapper.hide-arrow[data-v-551d0bf6] .mdi-menu-up{display:none}@media screen and (max-width:522px){.files[data-v-551d0bf6]{margin-top:104px!important}}.timeblocks[data-v-551d0bf6]{display:flex;flex-direction:column;align-items:center;border-bottom:1px solid #e0e0e0}.timeblocks .end-button[data-v-551d0bf6]{width:100%;display:flex;justify-content:flex-end;align-items:center;border-top:1px solid #e0e0e0;height:70px}.timeblocks .end-button button[data-v-551d0bf6]{background:#7f39fb!important;border-radius:4px!important;color:#fff!important;height:50px;width:203px}.timeblocks .splitted-time-inputs[data-v-551d0bf6]{display:flex!important;flex-direction:row!important;gap:15px;margin-bottom:-11px}.timeblock[data-v-551d0bf6]{position:relative;border-top:1px solid #e0e0e0;padding:20px 0 10px 0}.timeblock .splitted-time-inputs[data-v-551d0bf6]{display:flex!important;flex-direction:row!important;gap:15px;margin-bottom:-11px}.datepicker-wrapper[data-v-551d0bf6]{width:70%}.datepicker-wrapper .datepicker-input[data-v-551d0bf6]{width:100%!important;pointer-events:none}tbody[data-v-753dec0e],v-table[data-v-753dec0e]{border-top:thin solid rgba(var(--v-border-color),var(--v-border-opacity));border-bottom:thin solid rgba(var(--v-border-color),var(--v-border-opacity))}td[data-v-753dec0e]:not(:last-child){border-right:thin solid rgba(var(--v-border-color),var(--v-border-opacity))}.office-icon[data-v-753dec0e]{height:20px;margin-left:12px}.line-clamp[data-v-753dec0e]{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.date-wrap[data-v-4b1eca40]{display:flex;flex-flow:row;width:100%;gap:20px}.date-wrap .dp__main[data-v-4b1eca40]{width:calc(50% - 10px)!important}.employee-select-avatar[data-v-4b1eca40]{background:#6200ee;color:#fff;border-radius:50%;font-size:11.5px;height:22px;width:22px;position:absolute;top:50%;right:12px;transform:translateY(-50%)}.remove-input[data-v-4b1eca40]{position:absolute;top:50%;right:0;transform:translate(-15px,-50%);color:#666!important;z-index:10;cursor:pointer}.scrolling[data-v-4b1eca40]{overflow:hidden!important}.border-bottom[data-v-4b1eca40]{border-bottom:1px solid rgba(0,0,0,.1)}.subtask-btn[data-v-4b1eca40]{border:thin solid rgba(var(--v-border-color),var(--v-border-opacity))!important;color:#7f39fb!important;height:53px;text-align:center}[data-v-4b1eca40] .v-field__clearable{opacity:1!important}.card-content[data-v-3c7fa7bc]{margin-top:20px;padding:20px}.card-actions[data-v-3c7fa7bc]{width:100%;display:grid;grid-template-columns:1fr 1fr;gap:10px}.finish-icon[data-v-3c7fa7bc]{cursor:pointer}.finish-icon.disabled[data-v-3c7fa7bc]{opacity:.5;pointer-events:none}.finish-icon.finished[data-v-3c7fa7bc]{background:#06dece}.vuecal__weekdays-headings{border-bottom:1px solid #ddd;margin-bottom:-1px}.vuecal--view-with-time .vuecal__weekdays-headings,.vuecal--week-numbers .vuecal__weekdaysLine truncated
+1
View File
@@ -0,0 +1 @@
@import url(https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap);.close-icon[data-v-d203e48e]:hover{background:red;color:#fff!important}.upload-btn[data-v-a2a40214]{color:#6200ee;border-radius:4px;border:1px solid #e5e5e5}.hidden-input[data-v-a2a40214]{opacity:0;overflow:hidden;position:absolute;width:1px;height:1px}.gif-loader[data-v-a2a40214]{height:30px}.completed{background:#06dece}.width-100[data-v-dc6acca2]{width:100%}.gif-loader[data-v-f01fa1ac]{height:30px;margin-left:30px}.timeblock[data-v-4d980d7a]{position:relative;border-top:1px solid #e0e0e0;padding:20px 0 5px 0}.timeblock .splitted-time-inputs[data-v-4d980d7a]{display:flex!important;flex-direction:row!important;gap:15px;margin-bottom:-11px}.timeblock .x-button[data-v-4d980d7a]{display:flex;justify-content:flex-end;align-items:center;position:relative;bottom:5px}.timeblock .x-button button[data-v-4d980d7a]{margin-right:5px}.error input[data-v-4d980d7a]{border:1px solid red!important}.datepicker-wrapper[data-v-4d980d7a]{width:100%}.datepicker-wrapper .datepicker-input[data-v-4d980d7a]{width:100%!important;pointer-events:none}.w-full[data-v-3db8381d]{width:100%}.date-wrap[data-v-3db8381d]{display:flex;flex-flow:row;width:100%;gap:20px;margin-bottom:20px}.date-wrap .dp__main[data-v-3db8381d]{width:calc(50% - 10px)!important}.scrolling[data-v-3db8381d]{overflow:hidden!important}.border-bottom[data-v-3db8381d]{border-bottom:1px solid rgba(0,0,0,.1)}.done-btn[data-v-3db8381d]{background:#7f39fb!important;border-radius:4px!important;color:#fff!important;height:50px;width:203px}.remove-employee[data-v-3db8381d]{position:relative;width:100%}.remove-employee svg[data-v-3db8381d]{position:absolute;right:205px;top:28px;z-index:5;opacity:.5}.remove-employee.hide-arrow[data-v-3db8381d] .mdi-menu-down,.remove-employee.hide-arrow[data-v-3db8381d] .mdi-menu-up{display:none}.employee-wrapper[data-v-3db8381d]{position:relative;width:100%}.employee-wrapper svg[data-v-3db8381d]{position:absolute;right:4px;top:28px;z-index:5;opacity:.5}.employee-wrapper.hide-arrow[data-v-3db8381d] .mdi-menu-down,.employee-wrapper.hide-arrow[data-v-3db8381d] .mdi-menu-up{display:none}@media screen and (max-width:522px){.files[data-v-3db8381d]{margin-top:104px!important}}.timeblocks[data-v-3db8381d]{display:flex;flex-direction:column;align-items:center;border-bottom:1px solid #e0e0e0}.timeblocks .end-button[data-v-3db8381d]{width:100%;display:flex;justify-content:flex-end;align-items:center;border-top:1px solid #e0e0e0;height:70px}.timeblocks .end-button button[data-v-3db8381d]{background:#7f39fb!important;border-radius:4px!important;color:#fff!important;height:50px;width:203px}.timeblocks .splitted-time-inputs[data-v-3db8381d]{display:flex!important;flex-direction:row!important;gap:15px;margin-bottom:-11px}.timeblock[data-v-3db8381d]{position:relative;border-top:1px solid #e0e0e0;padding:20px 0 10px 0}.timeblock .splitted-time-inputs[data-v-3db8381d]{display:flex!important;flex-direction:row!important;gap:15px;margin-bottom:-11px}.datepicker-wrapper[data-v-3db8381d]{width:70%}.datepicker-wrapper .datepicker-input[data-v-3db8381d]{width:100%!important;pointer-events:none}tbody[data-v-753dec0e],v-table[data-v-753dec0e]{border-top:thin solid rgba(var(--v-border-color),var(--v-border-opacity));border-bottom:thin solid rgba(var(--v-border-color),var(--v-border-opacity))}td[data-v-753dec0e]:not(:last-child){border-right:thin solid rgba(var(--v-border-color),var(--v-border-opacity))}.office-icon[data-v-753dec0e]{height:20px;margin-left:12px}.line-clamp[data-v-753dec0e]{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.date-wrap[data-v-ea627ecc]{display:flex;flex-flow:row;width:100%;gap:20px}.date-wrap .dp__main[data-v-ea627ecc]{width:calc(50% - 10px)!important}.employee-select-avatar[data-v-ea627ecc]{background:#6200ee;color:#fff;border-radius:50%;font-size:11.5px;height:22px;width:22px;position:absolute;top:50%;right:12px;transform:translateY(-50%)}.remove-input[data-v-ea627ecc]{position:absolute;top:50%;right:0;transform:translate(-15px,-50%);color:#666!important;z-index:10;cursor:pointer}.scrolling[data-v-ea627ecc]{overflow:hidden!important}.border-bottom[data-v-ea627ecc]{border-bottom:1px solid rgba(0,0,0,.1)}.subtask-btn[data-v-ea627ecc]{border:thin solid rgba(var(--v-border-color),var(--v-border-opacity))!important;color:#7f39fb!important;height:53px;text-align:center}[data-v-ea627ecc] .v-field__clearable{opacity:1!important}.datepicker-wrapper[data-v-ea627ecc]{width:100%}.datepicker-wrapper .datepicker-input[data-v-ea627ecc]{width:100%!important;height:100%;pointer-events:none}.card-content[data-v-f007e35e]{margin-top:20px;padding:20px}.card-actions[data-v-f007e35e]{width:100%;display:grid;grid-template-columns:1fr 1fr;gap:10px}.finish-icon[data-v-f007e35e]{cursor:pointer}.finish-icon.disabled[data-v-f007e35e]{opacity:.5;pointer-events:none}.finish-icon.finished[data-v-f007e35e]{background:#06dece}.vuecal__Line truncated
+1 -1
View File
@@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" href="/favicon/favicon.ico"/><title>ToDo by JANDL</title><script defer="defer" src="/js/chunk-vendors.54b37fd9.js"></script><script defer="defer" src="/js/index.e583b35f.js"></script><link href="/css/chunk-vendors.449f2bf6.css" rel="stylesheet"><link href="/css/index.3ee28f2f.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but ToDo by JANDL doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
<!doctype html><html lang=""><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" href="/favicon/favicon.ico"/><title>ToDo by JANDL</title><script defer="defer" src="/js/chunk-vendors.54b37fd9.js"></script><script defer="defer" src="/js/index.059a398f.js"></script><link href="/css/chunk-vendors.19043be7.css" rel="stylesheet"><link href="/css/index.e95c2c85.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but ToDo by JANDL doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
+2
View File
@@ -0,0 +1,2 @@
"use strict";(self["webpackChunkjandl"]=self["webpackChunkjandl"]||[]).push([[1277],{35299:function(e,t,s){s.d(t,{Z:function(){return k}});var a=s(73396),i=s(60988),n=s(16824),l=s(10240),r=s(45869);function o(e,t,s,o,d,c){return(0,a.wg)(),(0,a.j4)(n.o,{class:"px-10 py-8 subheader"},{default:(0,a.w5)((()=>[(0,a.Wm)(i.f,{"custom-filter":e.customFilter,"match-any":!0,modelValue:d.selectedEmployeeId,"onUpdate:modelValue":t[0]||(t[0]=e=>d.selectedEmployeeId=e),class:"subheader-input",variant:"outlined",label:"Zamestanec",items:e.enrichedEmployees,"item-title":"_fullName","item-value":"id"},null,8,["custom-filter","modelValue","items"]),(0,a.Wm)(r.hw,{modelValue:d.searchQuery,"onUpdate:modelValue":t[1]||(t[1]=e=>d.searchQuery=e),class:"subheader-input",variant:"outlined",placeholder:"Vyhľadávanie","prepend-inner-icon":"mdi-magnify",onInput:c.onInput,type:"text"},null,8,["modelValue","onInput"]),(0,a.Wm)(l.r,{modelValue:d.sortOrder,"onUpdate:modelValue":t[2]||(t[2]=e=>d.sortOrder=e),class:"subheader-input",items:d.sortOptions,variant:"outlined",label:"Zoradiť podľa","item-title":"text","item-value":"value"},null,8,["modelValue","items"])])),_:1})}var d=s(20065),c=s(83299),u={mixins:[c.Z],emits:["search","employee-selected","update-sort-order"],data(){return{selectedEmployeeId:null,searchQuery:"",sortOrder:null,sortOptions:[{text:"Zrušiť filter",value:null},{text:"Názov (A-Z)",value:"nameAsc"},{text:"Názov (Z-A)",value:"nameDesc"},{text:"Dátum (Najnovší - Najstarší)",value:"deadlineDesc"},{text:"Dátum (Najstarší - Najnovší)",value:"deadlineAsc"}]}},mounted(){this.selectedEmployeeId=this.$store.getters["auth/user"].id},computed:{...(0,d.Se)("tm",["enrichedEmployees"])},methods:{onInput(){this.$emit("search",this.searchQuery)}},watch:{selectedEmployeeId(){this.$emit("employee-selected",this.selectedEmployeeId)},sortOrder(e){this.$emit("update-sort-order",e)}}},m=s(40089);const h=(0,m.Z)(u,[["render",o],["__scopeId","data-v-45dcb20a"]]);var k=h},21277:function(e,t,s){s.r(t),s.d(t,{default:function(){return A}});var a=s(73396);function i(e,t,s,i,n,l){const r=(0,a.up)("Z-tasks-search"),o=(0,a.up)("A-ongoing-table"),d=(0,a.up)("W-loadable");return(0,a.wg)(),(0,a.iD)("div",null,[(0,a.Wm)(r,{onSearch:l.onSearch,onEmployeeSelected:l.onEmployeeSelected,onUpdateSortOrder:l.onUpdateSortOrder},null,8,["onSearch","onEmployeeSelected","onUpdateSortOrder"]),(0,a.Wm)(d,{content:l.filteredOngoingTasks,emptyMessage:n.searchQuery.length?"Neboli nájdené žiadne úlohy":"Nenašli sa žiadne záznamy"},{default:(0,a.w5)((()=>[(0,a.Wm)(o,{subtasks:l.filteredOngoingTasks},null,8,["subtasks"])])),_:1},8,["content","emptyMessage"])])}var n=s(35299),l=s(20065),r=s(49242),o=s(87139),d=s(4413),c=s(80678);const u=e=>((0,a.dD)("data-v-f717e9f4"),e=e(),(0,a.Cn)(),e),m=u((()=>(0,a._)("th",{class:"text-left"},"Názov",-1))),h=u((()=>(0,a._)("th",{class:"text-left"},"Deadline",-1))),k=u((()=>(0,a._)("th",{class:"text-left"},"Najbližší neuzavretý",-1))),p=u((()=>(0,a._)("th",{class:"text-left"},"Naplánované",-1))),f=u((()=>(0,a._)("th",{class:"text-left"},"Zostávajúce",-1))),y=u((()=>(0,a._)("th",{class:"text-left"},"Akcia",-1))),g=["onClick"],_={key:0},b={class:"task-action"},D={class:"d-flex justify-start align-center"},w=["src","onClick"],v=["src","onClick"],S=["src"],C=["src","onClick"],M=["src","onClick"];function T(e,t,s,i,n,l){return(0,a.wg)(),(0,a.j4)(d.Y,null,{default:(0,a.w5)((()=>[(0,a._)("thead",null,[(0,a._)("tr",null,[(0,a._)("th",{onClick:t[0]||(t[0]=(...e)=>l.getSelectedTimeblockDeadline&&l.getSelectedTimeblockDeadline(...e)),class:"text-left"}," Kód projektu "),m,h,k,p,f,y])]),(0,a._)("tbody",null,[((0,a.wg)(!0),(0,a.iD)(a.HY,null,(0,a.Ko)(s.subtasks,(e=>((0,a.wg)(),(0,a.iD)("tr",{class:"cursor-pointer",key:e.id,onClick:(0,r.iM)((t=>l.editTask(e,!1)),["stop"])},[(0,a._)("td",null,(0,o.zw)(e.project_code),1),(0,a._)("td",null,(0,o.zw)(e.title??e.master_task),1),e.deadline?((0,a.wg)(),(0,a.iD)("td",_,(0,o.zw)(l.getDeadline(e)),1)):(0,a.kq)("",!0),(0,a.Wm)(c.N,{text:"Deadline z Mastertasku",location:"end"},{activator:(0,a.w5)((({props:t})=>[e.deadline?(0,a.kq)("",!0):((0,a.wg)(),(0,a.iD)("td",(0,o.vs)((0,a.dG)({key:0},t)),(0,o.zw)(l.getDeadline(e))+"* ",17))])),_:2},1024),(0,a._)("td",null,(0,o.zw)(l.displayTimeblock(e)),1),(0,a._)("td",null,(0,o.zw)(e.duration)+" h",1),(0,a._)("td",null,(0,o.zw)((e.duration-e.spent_time).toFixed(2))+" h",1),(0,a._)("td",b,[(0,a._)("div",D,[(0,a._)("img",{class:(0,o.C_)(["pencil-icon mr-3",{disabled:n.loadingSubtask[e.id]}]),src:n.checkmarkDouble,onClick:(0,r.iM)((t=>l.handleCompleteTask(e)),["stop"])},null,10,w),"office365"==e.type?((0,a.wg)(),(0,a.iD)(a.HY,{key:0},[(0,a._)("img",{class:"pencil-icon",src:n.eye,onClick:(0,r.iM)((t=>l.editTask(e,!1)),["stop"])},null,8,v),(0,a._)("img",{class:"office-icon",src:n.office365},null,8,S)],64)):((0,a.wg)(),(0,a.iD)(a.HY,{key:1},[(0,a._)("img",{class:"pencil-icon",src:n.eye,onClick:(0,r.iM)((t=>l.editTask(e,!1)),["stop"])},null,8,C),Line truncated
//# sourceMappingURL=1277.95db0fe3.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"js/1277.95db0fe3.js","mappings":"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 truncated
-2
View File
@@ -1,2 +0,0 @@
"use strict";(self["webpackChunkjandl"]=self["webpackChunkjandl"]||[]).push([[2885],{35299:function(e,t,s){s.d(t,{Z:function(){return k}});var a=s(73396),l=s(60988),n=s(16824),i=s(10240),r=s(45869);function o(e,t,s,o,d,c){return(0,a.wg)(),(0,a.j4)(n.o,{class:"px-10 py-8 subheader"},{default:(0,a.w5)((()=>[(0,a.Wm)(l.f,{"custom-filter":e.customFilter,"match-any":!0,modelValue:d.selectedEmployeeId,"onUpdate:modelValue":t[0]||(t[0]=e=>d.selectedEmployeeId=e),class:"subheader-input",variant:"outlined",label:"Zamestanec",items:e.enrichedEmployees,"item-title":"_fullName","item-value":"id"},null,8,["custom-filter","modelValue","items"]),(0,a.Wm)(r.hw,{modelValue:d.searchQuery,"onUpdate:modelValue":t[1]||(t[1]=e=>d.searchQuery=e),class:"subheader-input",variant:"outlined",placeholder:"Vyhľadávanie","prepend-inner-icon":"mdi-magnify",onInput:c.onInput,type:"text"},null,8,["modelValue","onInput"]),(0,a.Wm)(i.r,{modelValue:d.sortOrder,"onUpdate:modelValue":t[2]||(t[2]=e=>d.sortOrder=e),class:"subheader-input",items:d.sortOptions,variant:"outlined",label:"Zoradiť podľa","item-title":"text","item-value":"value"},null,8,["modelValue","items"])])),_:1})}var d=s(20065),c=s(83299),u={mixins:[c.Z],emits:["search","employee-selected","update-sort-order"],data(){return{selectedEmployeeId:null,searchQuery:"",sortOrder:null,sortOptions:[{text:"Zrušiť filter",value:null},{text:"Názov (A-Z)",value:"nameAsc"},{text:"Názov (Z-A)",value:"nameDesc"},{text:"Dátum (Najnovší - Najstarší)",value:"deadlineDesc"},{text:"Dátum (Najstarší - Najnovší)",value:"deadlineAsc"}]}},mounted(){this.selectedEmployeeId=this.$store.getters["auth/user"].id},computed:{...(0,d.Se)("tm",["enrichedEmployees"])},methods:{onInput(){this.$emit("search",this.searchQuery)}},watch:{selectedEmployeeId(){this.$emit("employee-selected",this.selectedEmployeeId)},sortOrder(e){this.$emit("update-sort-order",e)}}},m=s(40089);const h=(0,m.Z)(u,[["render",o],["__scopeId","data-v-45dcb20a"]]);var k=h},72885:function(e,t,s){s.r(t),s.d(t,{default:function(){return A}});var a=s(73396);function l(e,t,s,l,n,i){const r=(0,a.up)("Z-tasks-search"),o=(0,a.up)("A-ongoing-table"),d=(0,a.up)("W-loadable");return(0,a.wg)(),(0,a.iD)("div",null,[(0,a.Wm)(r,{onSearch:i.onSearch,onEmployeeSelected:i.onEmployeeSelected,onUpdateSortOrder:i.onUpdateSortOrder},null,8,["onSearch","onEmployeeSelected","onUpdateSortOrder"]),(0,a.Wm)(d,{content:i.filteredOngoingTasks,emptyMessage:n.searchQuery.length?"Neboli nájdené žiadne úlohy":"Nenašli sa žiadne záznamy"},{default:(0,a.w5)((()=>[(0,a.Wm)(o,{subtasks:i.filteredOngoingTasks},null,8,["subtasks"])])),_:1},8,["content","emptyMessage"])])}var n=s(35299),i=s(20065),r=s(49242),o=s(87139),d=s(4413),c=s(80678);const u=e=>((0,a.dD)("data-v-7c46cac8"),e=e(),(0,a.Cn)(),e),m=u((()=>(0,a._)("th",{class:"text-left"},"Názov",-1))),h=u((()=>(0,a._)("th",{class:"text-left"},"Deadline",-1))),k=u((()=>(0,a._)("th",{class:"text-left"},"Najbližší neuzavretý",-1))),p=u((()=>(0,a._)("th",{class:"text-left"},"Naplánované",-1))),y=u((()=>(0,a._)("th",{class:"text-left"},"Zostávajúce",-1))),f=u((()=>(0,a._)("th",{class:"text-left"},"Akcia",-1))),g=["onClick"],_={key:0},b={class:"task-action"},D={class:"d-flex justify-start align-center"},w=["src","onClick"],v=["src","onClick"],S=["src"],C=["src","onClick"],T=["src","onClick"];function O(e,t,s,l,n,i){return(0,a.wg)(),(0,a.j4)(d.Y,null,{default:(0,a.w5)((()=>[(0,a._)("thead",null,[(0,a._)("tr",null,[(0,a._)("th",{onClick:t[0]||(t[0]=(...e)=>i.getSelectedTimeblockDeadline&&i.getSelectedTimeblockDeadline(...e)),class:"text-left"},"Kód projektu"),m,h,k,p,y,f])]),(0,a._)("tbody",null,[((0,a.wg)(!0),(0,a.iD)(a.HY,null,(0,a.Ko)(s.subtasks,(e=>((0,a.wg)(),(0,a.iD)("tr",{class:"cursor-pointer",key:e.id,onClick:(0,r.iM)((t=>i.editTask(e,!1)),["stop"])},[(0,a._)("td",null,(0,o.zw)(e.project_code),1),(0,a._)("td",null,(0,o.zw)(e.title??e.master_task),1),e.deadline?((0,a.wg)(),(0,a.iD)("td",_,(0,o.zw)(i.getDeadline(e)),1)):(0,a.kq)("",!0),(0,a.Wm)(c.N,{text:"Deadline z Mastertasku",location:"end"},{activator:(0,a.w5)((({props:t})=>[e.deadline?(0,a.kq)("",!0):((0,a.wg)(),(0,a.iD)("td",(0,o.vs)((0,a.dG)({key:0},t)),(0,o.zw)(i.getDeadline(e))+"*",17))])),_:2},1024),(0,a._)("td",null,(0,o.zw)(i.displayTimeblock(e)),1),(0,a._)("td",null,(0,o.zw)(e.duration)+" h",1),(0,a._)("td",null,(0,o.zw)((e.duration-e.spent_time).toFixed(2))+" h",1),(0,a._)("td",b,[(0,a._)("div",D,[(0,a._)("img",{class:(0,o.C_)(["pencil-icon mr-3",{disabled:n.loadingSubtask[e.id]}]),src:n.checkmarkDouble,onClick:(0,r.iM)((t=>i.handleCompleteTask(e)),["stop"])},null,10,w),"office365"==e.type?((0,a.wg)(),(0,a.iD)(a.HY,{key:0},[(0,a._)("img",{class:"pencil-icon",src:n.eye,onClick:(0,r.iM)((t=>i.editTask(e,!1)),["stop"])},null,8,v),(0,a._)("img",{class:"office-icon",src:n.office365},null,8,S)],64)):((0,a.wg)(),(0,a.iD)(a.HY,{key:1},[(0,a._)("img",{class:"pencil-icon",src:n.eye,onClick:(0,r.iM)((t=>i.editTask(e,!1)),["stop"])},null,8,C),(0,Line truncated
//# sourceMappingURL=2885.d75b7a04.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"js/2885.d75b7a04.js","mappings":"gPACCA,EAAAA,EAAAA,IA4BQC,EAAAA,EAAAA,CA5BDC,MAAM,wBAAsB,C,kBAClC,IAQE,EARFC,EAAAA,EAAAA,IAQEC,EAAAA,EAAAA,CARe,gBAAeC,EAAAA,aAAe,aAAW,E,WAChDC,EAAAA,mB,qCAAAA,EAAAA,mBAAkB,GAC3BJ,MAAM,kBACNK,QAAQ,WACRC,MAAM,aACLC,MAAOJ,EAAAA,kBACR,aAAW,YACX,aAAW,M,gDAEZF,EAAAA,EAAAA,IAQgBO,EAAAA,GAAAA,C,WAPNJ,EAAAA,Y,qCAAAA,EAAAA,YAAW,GACpBJ,MAAM,kBACNK,QAAQ,WACRI,YAAY,eACZ,qBAAmB,cAClBC,QAAOC,EAAAA,QACRC,KAAK,Q,kCAENX,EAAAA,EAAAA,IAQYY,EAAAA,EAAAA,C,WAPFT,EAAAA,U,qCAAAA,EAAAA,UAAS,GAClBJ,MAAM,kBACLO,MAAOH,EAAAA,YACRC,QAAQ,WACRC,MAAM,gBACN,aAAW,OACX,aAAW,S,kEASd,GACCQ,OAAQ,CAACC,EAAAA,GACTC,MAAO,CAAC,SAAU,oBAAqB,qBAEvCC,OACC,MAAO,CACNC,mBAAoB,KACpBC,YAAa,GACbC,UAAW,KACXC,YAAa,CACZ,CAAEC,KAAM,gBAAiBC,MAAO,MAChC,CAAED,KAAM,cAAeC,MAAO,WAC9B,CAAED,KAAM,cAAeC,MAAO,YAC9B,CAAED,KAAM,+BAAgCC,MAAO,gBAC/C,CAAED,KAAM,+BAAgCC,MAAO,gBAGlD,EAEAC,UACCC,KAAKP,mBAAqBO,KAAKC,OAAOC,QAAQ,aAAaC,EAC5D,EAEAC,SAAU,KACNC,EAAAA,EAAAA,IAAW,KAAM,CAAC,uBAGtBC,QAAS,CACRrB,UACCe,KAAKO,MAAM,SAAUP,KAAKN,YAC3B,GAGDc,MAAO,CACNf,qBACCO,KAAKO,MAAM,oBAAqBP,KAAKP,mBACtC,EAEAE,UAAUG,GACTE,KAAKO,MAAM,oBAAqBT,EACjC,I,WCrEF,MAAMW,GAA2B,OAAgB,EAAQ,CAAC,CAAC,SAASC,GAAQ,CAAC,YAAY,qBAEzF,O,wNCRCC,EAAAA,EAAAA,IAQM,aANLnC,EAAAA,EAAAA,IAAoHoC,EAAAA,CAAnGC,SAAQ3B,EAAAA,SAAW4B,mBAAmB5B,EAAAA,mBAAqB6B,kBAAmB7B,EAAAA,mB,+DAE/FV,EAAAA,EAAAA,IAEawC,EAAAA,CAFAC,QAAS/B,EAAAA,qBAAuBgC,aAAcvC,EAAAA,YAAYwC,OAAS,8BAAgC,6B,mBAC/G,IAAoD,EAApD3C,EAAAA,EAAAA,IAAoD4C,EAAAA,CAAlCC,SAAUnC,EAAAA,sBAAoB,wB,gLCD/CoC,EAAAA,EAAAA,GAAgC,MAA5B/C,MAAM,aAAY,SAAK,K,UAC3B+C,EAAAA,EAAAA,GAAmC,MAA/B/C,MAAM,aAAY,YAAQ,K,UAC9B+C,EAAAA,EAAAA,GAA+C,MAA3C/C,MAAM,aAAY,wBAAoB,K,UAC1C+C,EAAAA,EAAAA,GAAsC,MAAlC/C,MAAM,aAAY,eAAW,K,UACjC+C,EAAAA,EAAAA,GAAsC,MAAlC/C,MAAM,aAAY,eAAW,K,UACjC+C,EAAAA,EAAAA,GAAgC,MAA5B/C,MAAM,aAAY,SAAK,K,2BAkBvBA,MAAM,e,GACJA,MAAM,qC,oIA5BfF,EAAAA,EAAAA,IA8CUkD,EAAAA,EAAAA,KAAAA,C,kBA7CT,IAUQ,EAVRD,EAAAA,EAAAA,GAUQ,eATPA,EAAAA,EAAAA,GAQK,YAPJA,EAAAA,EAAAA,GAA6E,MAAxEE,QAAK,oBAAEtC,EAAAA,8BAAAA,EAAAA,gCAAAA,IAA8BX,MAAM,aAAY,gBAC5DkD,EACAC,EACAC,EACAC,EACAC,EACAC,OAIFR,EAAAA,EAAAA,GA8BQ,6BA7BPX,EAAAA,EAAAA,IA4BKoB,EAAAA,GAAAA,MAAAA,EAAAA,EAAAA,IA5BwCC,EAAAA,UAAXC,K,WAAlCtB,EAAAA,EAAAA,IA4BK,MA5BDpC,MAAM,iBAA8C2D,IAAKD,EAAQ9B,GAAKqB,SAAK,YAAOtC,EAAAA,SAAS+C,GAAS,IAAF,W,EACrGX,EAAAA,EAAAA,GAAmC,mBAA5BW,EAAQE,cAAY,IAC3Bb,EAAAA,EAAAA,GAAmD,mBAA5CW,EAAQG,OAASH,EAAQI,aAAW,GACjCJ,EAAQK,WAAQ,WAA1B3B,EAAAA,EAAAA,IAA2D,gBAA5BzB,EAAAA,YAAY+C,IAAO,qBAClDzD,EAAAA,EAAAA,IAIY+D,EAAAA,EAAAA,CAJD1C,KAAK,yBAAyB2C,SAAS,O,CAChCC,WAAS,SACzB,EAD6BC,WAAK,CACvBT,EAAQK,UAAoD,iBAA5C,WAA3B3B,EAAAA,EAAAA,IAA4E,wBAAAuB,IAAAA,GAAvCQ,KAAK,QAAKxD,EAAAA,YAAY+C,IAAW,IAAC,Q,YAGzEX,EAAAA,EAAAA,GAAwC,mBAAjCpC,EAAAA,iBAAiB+C,IAAO,IAC/BX,EAAAA,EAAAA,GAAiC,mBAA1BW,EAAQU,UAAW,KAAE,IAC5BrB,EAAAA,EAAAA,GAAmE,oBAA3DW,EAAQU,SAAWV,EAAQW,YAAYC,QAAQ,IAAK,KAAE,IAE9DvB,EAAAA,EAAAA,GAcK,KAdLwB,EAcK,EAbJxB,EAAAA,EAAAA,GAYM,MAZNyB,EAYM,EAXLzB,EAAAA,EAAAA,GAAiJ,OAA5I/C,OAAK,SAAC,mBAAkB,UAAsBI,EAAAA,eAAesD,EAAQ9B,OAAO6C,IAAKrE,EAAAA,gBAAkB6C,SAAK,YAAOtC,EAAAA,mBAAmB+C,IAAO,W,WAE9G,aAAhBA,EAAQ9C,OAAI,WAA5BwB,EAAAA,EAAAA,IAGWoB,EAAAA,GAAAA,CAAAG,IAAAA,GAAA,EAFVZ,EAAAA,EAAAA,GAA2E,OAAtE/C,MAAM,cAAeyE,IAAKrE,EAAAA,IAAM6C,SAAK,YAAOtC,EAAAA,SAAS+C,GAAS,IAAF,W,WACjEX,EAAAA,EAAAA,GAA4C,OAAvC/C,MAAM,cAAeyE,IAAKrE,EAAAA,W,6BAGhCgC,EAAAA,EAAAA,IAGWoB,EAAAA,GAAAA,CAAAG,IAAAA,GAAA,EAFVZ,EAAAA,EAAAA,GAA2E,OAAtE/C,MAAM,cAAeyE,IAAKrE,EAAAA,IAAM6C,SAAK,YAAOtC,EAAAA,SAAS+C,GAAS,IAAF,W,WACjEX,EAAAA,EAAAA,GAAuE,OAAlE/C,MAAM,aAAcyE,IAAKrE,EAAAA,IAAM6C,SAAK,YAAOtC,EAAAA,WAAW+C,IAAO,W,iFAiBzE,GACCS,MAAO,CACNrB,SAAU,CACTlC,KAAM8D,MACNC,UAAU,IAIZ1D,OACC,MAAO,CACN2D,IAAG,KACHC,IAAG,KACHC,UAAS,KACTC,gBAAe,KACfC,eAAgB,CAAC,EAEnB,EAEAnD,SAAU,KACNC,EAAAA,EAAAA,IAAW,KAAM,CAAC,iBAGtBC,QAAS,CACRkD,SAASvB,EAASwB,GAAW,GAC5BzD,KAAK0D,QAAQC,KAAK,qBAAsB,CAAC1B,UAASwB,YACnD,EAEAG,yBAAyB3B,GACxB,MAAM4B,EAA2B5B,EAAQ6B,WAAWC,OAAMC,GAAMA,EAAGC,cAE9DJ,QAGE7D,KAAKkE,eAAejC,GAF1BjC,KAAK0D,QAAQC,KAAK,qCAAsC,CAAE1B,WAI5D,EAEAkC,WAAWlC,GACV,GAAoB,aAAhBA,EAAQ9C,KACX,OAAOa,KAAK0D,QAAQC,KAAK,wCAAyC,CAAES,KAAM,WAE3EpE,KAAK0D,QAAQC,KAAK,yBAA0B,CAAC1B,WAC9C,EAEAoC,YAAYpC,GACX,OAAIA,GAASK,SACLgC,IAAOrC,EAAQK,UAAUiC,OAAO,cAEjCD,IAAOrC,EAAQuC,sBAAsBD,OAAO,aACpD,EAEAE,6BAA6BX,GAC5B,MAAMY,EAAcJ,MAEdK,EAAuBb,EAAWc,QAAOZ,GAAyB,IAAnBA,EAAGC,cACxD,GAAIU,EAAqBxD,OAAS,EAAG,OAAOmD,IAAOK,EAAqB,GAAGE,KAAKN,OAAO,qBAEvF,MAAMO,EAAqBhB,EACzBc,QAAOZ,GAAMM,IAAON,EAAGa,KAAKE,QAAQL,KACpCM,MAAK,CAACC,EAAGC,IAAMZ,IAAOW,EAAEJ,KAAKM,KAAKb,IAAOY,EAAEL,QAE7C,OAAIC,EAAmB3D,OAAS,GAAwC,IAAnC2D,EAAmBb,YAA0BK,IAAOQ,EAAmB,GAAGD,KAAKN,OAAO,qBAEpH,EACR,EAEAa,iBAAiBnD,GAChB,MAAMoD,EAAoBrF,KAAKyE,6BAA6BxC,EAAQ6B,YAEpE,MAA6B,KAAtBuB,EAA2BA,EAAoB,eACvD,EAEAzB,qBAAqB3B,GACpB,MAAMqD,EAAc,IAAIrD,EAASgC,YAAa,EAAGsB,WAAYtD,GAASsD,WAAWC,KAAKC,WAC9EA,EAAUC,cACVD,MACF,IAEN,IACCzF,KAAKuD,eAAetB,EAAQ9B,KAAM,QAC5BH,KAAK2F,OAAOC,SAAU,eAAcN,EAAYnF,KAAMmF,GAE5DtF,KAAKC,OAAO4F,SAAS,0BAA2B5D,EAAQ9B,IACxDH,KAAK0D,QAAQC,KAAK,oBAAqB1B,EAQxC,CAPE,MAAO6D,GACR9F,KAAK+F,OAAOD,MAAMA,EAAME,SAAWF,EAIpC,CAAE,Line truncated
+2
View File
@@ -0,0 +1,2 @@
(function(){var e={41993:function(e){function t(e){return Promise.resolve().then((function(){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}))}t.keys=function(){return[]},t.resolve=t,t.id=41993,e.exports=t},46700:function(e,t,s){var a={"./af":63906,"./af.js":63906,"./ar":40902,"./ar-dz":3853,"./ar-dz.js":3853,"./ar-kw":20299,"./ar-kw.js":20299,"./ar-ly":96825,"./ar-ly.js":96825,"./ar-ma":66379,"./ar-ma.js":66379,"./ar-sa":87700,"./ar-sa.js":87700,"./ar-tn":2059,"./ar-tn.js":2059,"./ar.js":40902,"./az":76043,"./az.js":76043,"./be":7936,"./be.js":7936,"./bg":34078,"./bg.js":34078,"./bm":14014,"./bm.js":14014,"./bn":29554,"./bn-bd":17114,"./bn-bd.js":17114,"./bn.js":29554,"./bo":6529,"./bo.js":6529,"./br":65437,"./br.js":65437,"./bs":19647,"./bs.js":19647,"./ca":59951,"./ca.js":59951,"./cs":26113,"./cs.js":26113,"./cv":37965,"./cv.js":37965,"./cy":35858,"./cy.js":35858,"./da":33515,"./da.js":33515,"./de":62831,"./de-at":6263,"./de-at.js":6263,"./de-ch":51127,"./de-ch.js":51127,"./de.js":62831,"./dv":4510,"./dv.js":4510,"./el":68616,"./el.js":68616,"./en-au":24595,"./en-au.js":24595,"./en-ca":73545,"./en-ca.js":73545,"./en-gb":79609,"./en-gb.js":79609,"./en-ie":43727,"./en-ie.js":43727,"./en-il":93302,"./en-il.js":93302,"./en-in":46305,"./en-in.js":46305,"./en-nz":39128,"./en-nz.js":39128,"./en-sg":84569,"./en-sg.js":84569,"./eo":50650,"./eo.js":50650,"./es":26358,"./es-do":64214,"./es-do.js":64214,"./es-mx":38639,"./es-mx.js":38639,"./es-us":30232,"./es-us.js":30232,"./es.js":26358,"./et":47279,"./et.js":47279,"./eu":15515,"./eu.js":15515,"./fa":27981,"./fa.js":27981,"./fi":37090,"./fi.js":37090,"./fil":79208,"./fil.js":79208,"./fo":2799,"./fo.js":2799,"./fr":23463,"./fr-ca":2213,"./fr-ca.js":2213,"./fr-ch":52848,"./fr-ch.js":52848,"./fr.js":23463,"./fy":41468,"./fy.js":41468,"./ga":88163,"./ga.js":88163,"./gd":2898,"./gd.js":2898,"./gl":76312,"./gl.js":76312,"./gom-deva":20682,"./gom-deva.js":20682,"./gom-latn":49178,"./gom-latn.js":49178,"./gu":31400,"./gu.js":31400,"./he":52795,"./he.js":52795,"./hi":17009,"./hi.js":17009,"./hr":46506,"./hr.js":46506,"./hu":69565,"./hu.js":69565,"./hy-am":93864,"./hy-am.js":93864,"./id":5626,"./id.js":5626,"./is":36649,"./is.js":36649,"./it":90151,"./it-ch":95348,"./it-ch.js":95348,"./it.js":90151,"./ja":79830,"./ja.js":79830,"./jv":33751,"./jv.js":33751,"./ka":63365,"./ka.js":63365,"./kk":85980,"./kk.js":85980,"./km":99571,"./km.js":99571,"./kn":25880,"./kn.js":25880,"./ko":16809,"./ko.js":16809,"./ku":96773,"./ku.js":96773,"./ky":65505,"./ky.js":65505,"./lb":50553,"./lb.js":50553,"./lo":51237,"./lo.js":51237,"./lt":91563,"./lt.js":91563,"./lv":61057,"./lv.js":61057,"./me":96495,"./me.js":96495,"./mi":83096,"./mi.js":83096,"./mk":43874,"./mk.js":43874,"./ml":46055,"./ml.js":46055,"./mn":87747,"./mn.js":87747,"./mr":17113,"./mr.js":17113,"./ms":8687,"./ms-my":7948,"./ms-my.js":7948,"./ms.js":8687,"./mt":14532,"./mt.js":14532,"./my":4655,"./my.js":4655,"./nb":56961,"./nb.js":56961,"./ne":2512,"./ne.js":2512,"./nl":48448,"./nl-be":72936,"./nl-be.js":72936,"./nl.js":48448,"./nn":49031,"./nn.js":49031,"./oc-lnc":5174,"./oc-lnc.js":5174,"./pa-in":30118,"./pa-in.js":30118,"./pl":93448,"./pl.js":93448,"./pt":33518,"./pt-br":62447,"./pt-br.js":62447,"./pt.js":33518,"./ro":70817,"./ro.js":70817,"./ru":10262,"./ru.js":10262,"./sd":58990,"./sd.js":58990,"./se":43842,"./se.js":43842,"./si":37711,"./si.js":37711,"./sk":80756,"./sk.js":80756,"./sl":3772,"./sl.js":3772,"./sq":6187,"./sq.js":6187,"./sr":40732,"./sr-cyrl":75713,"./sr-cyrl.js":75713,"./sr.js":40732,"./ss":99455,"./ss.js":99455,"./sv":69770,"./sv.js":69770,"./sw":80959,"./sw.js":80959,"./ta":36459,"./ta.js":36459,"./te":25302,"./te.js":25302,"./tet":67975,"./tet.js":67975,"./tg":71294,"./tg.js":71294,"./th":2385,"./th.js":2385,"./tk":24613,"./tk.js":24613,"./tl-ph":58668,"./tl-ph.js":58668,"./tlh":58190,"./tlh.js":58190,"./tr":74506,"./tr.js":74506,"./tzl":63440,"./tzl.js":63440,"./tzm":69852,"./tzm-latn":42350,"./tzm-latn.js":42350,"./tzm.js":69852,"./ug-cn":70730,"./ug-cn.js":70730,"./uk":40099,"./uk.js":40099,"./ur":72100,"./ur.js":72100,"./uz":96002,"./uz-latn":26322,"./uz-latn.js":26322,"./uz.js":96002,"./vi":14207,"./vi.js":14207,"./x-pseudo":24674,"./x-pseudo.js":24674,"./yo":10570,"./yo.js":10570,"./zh-cn":73644,"./zh-cn.js":73644,"./zh-hk":22591,"./zh-hk.js":22591,"./zh-mo":89503,"./zh-mo.js":89503,"./zh-tw":88080,"./zh-tw.js":88080};function i(e){var t=n(e);return s(t)}function n(e){if(!s.o(a,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return a[e]}i.keys=function(){return Object.keys(a)},i.resolve=n,e.exports=i,i.id=46700},27791:function(e,t,s){"use strict";s.d(t,{$t:function(){return Nr}});var a=s(49242),i=s(74973);async function n(){const e=await s.e(3657).then(s.t.bind(s,33657,23));e.load({google:{families:["Roboto:100,300,400,500,700,900&display=swap"]}})}var l=s(38685),o=(s(29773),(0,l.Rd)()),r=(s(57658),s(96149));function d(){const e=r.CLine truncated
//# sourceMappingURL=index.059a398f.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"js/index.059a398f.js","mappings":"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 truncated
-2
View File
@@ -1,2 +0,0 @@
(function(){var e={41993:function(e){function t(e){return Promise.resolve().then((function(){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}))}t.keys=function(){return[]},t.resolve=t,t.id=41993,e.exports=t},46700:function(e,t,s){var a={"./af":63906,"./af.js":63906,"./ar":40902,"./ar-dz":3853,"./ar-dz.js":3853,"./ar-kw":20299,"./ar-kw.js":20299,"./ar-ly":96825,"./ar-ly.js":96825,"./ar-ma":66379,"./ar-ma.js":66379,"./ar-sa":87700,"./ar-sa.js":87700,"./ar-tn":2059,"./ar-tn.js":2059,"./ar.js":40902,"./az":76043,"./az.js":76043,"./be":7936,"./be.js":7936,"./bg":34078,"./bg.js":34078,"./bm":14014,"./bm.js":14014,"./bn":29554,"./bn-bd":17114,"./bn-bd.js":17114,"./bn.js":29554,"./bo":6529,"./bo.js":6529,"./br":65437,"./br.js":65437,"./bs":19647,"./bs.js":19647,"./ca":59951,"./ca.js":59951,"./cs":26113,"./cs.js":26113,"./cv":37965,"./cv.js":37965,"./cy":35858,"./cy.js":35858,"./da":33515,"./da.js":33515,"./de":62831,"./de-at":6263,"./de-at.js":6263,"./de-ch":51127,"./de-ch.js":51127,"./de.js":62831,"./dv":4510,"./dv.js":4510,"./el":68616,"./el.js":68616,"./en-au":24595,"./en-au.js":24595,"./en-ca":73545,"./en-ca.js":73545,"./en-gb":79609,"./en-gb.js":79609,"./en-ie":43727,"./en-ie.js":43727,"./en-il":93302,"./en-il.js":93302,"./en-in":46305,"./en-in.js":46305,"./en-nz":39128,"./en-nz.js":39128,"./en-sg":84569,"./en-sg.js":84569,"./eo":50650,"./eo.js":50650,"./es":26358,"./es-do":64214,"./es-do.js":64214,"./es-mx":38639,"./es-mx.js":38639,"./es-us":30232,"./es-us.js":30232,"./es.js":26358,"./et":47279,"./et.js":47279,"./eu":15515,"./eu.js":15515,"./fa":27981,"./fa.js":27981,"./fi":37090,"./fi.js":37090,"./fil":79208,"./fil.js":79208,"./fo":2799,"./fo.js":2799,"./fr":23463,"./fr-ca":2213,"./fr-ca.js":2213,"./fr-ch":52848,"./fr-ch.js":52848,"./fr.js":23463,"./fy":41468,"./fy.js":41468,"./ga":88163,"./ga.js":88163,"./gd":2898,"./gd.js":2898,"./gl":76312,"./gl.js":76312,"./gom-deva":20682,"./gom-deva.js":20682,"./gom-latn":49178,"./gom-latn.js":49178,"./gu":31400,"./gu.js":31400,"./he":52795,"./he.js":52795,"./hi":17009,"./hi.js":17009,"./hr":46506,"./hr.js":46506,"./hu":69565,"./hu.js":69565,"./hy-am":93864,"./hy-am.js":93864,"./id":5626,"./id.js":5626,"./is":36649,"./is.js":36649,"./it":90151,"./it-ch":95348,"./it-ch.js":95348,"./it.js":90151,"./ja":79830,"./ja.js":79830,"./jv":33751,"./jv.js":33751,"./ka":63365,"./ka.js":63365,"./kk":85980,"./kk.js":85980,"./km":99571,"./km.js":99571,"./kn":25880,"./kn.js":25880,"./ko":16809,"./ko.js":16809,"./ku":96773,"./ku.js":96773,"./ky":65505,"./ky.js":65505,"./lb":50553,"./lb.js":50553,"./lo":51237,"./lo.js":51237,"./lt":91563,"./lt.js":91563,"./lv":61057,"./lv.js":61057,"./me":96495,"./me.js":96495,"./mi":83096,"./mi.js":83096,"./mk":43874,"./mk.js":43874,"./ml":46055,"./ml.js":46055,"./mn":87747,"./mn.js":87747,"./mr":17113,"./mr.js":17113,"./ms":8687,"./ms-my":7948,"./ms-my.js":7948,"./ms.js":8687,"./mt":14532,"./mt.js":14532,"./my":4655,"./my.js":4655,"./nb":56961,"./nb.js":56961,"./ne":2512,"./ne.js":2512,"./nl":48448,"./nl-be":72936,"./nl-be.js":72936,"./nl.js":48448,"./nn":49031,"./nn.js":49031,"./oc-lnc":5174,"./oc-lnc.js":5174,"./pa-in":30118,"./pa-in.js":30118,"./pl":93448,"./pl.js":93448,"./pt":33518,"./pt-br":62447,"./pt-br.js":62447,"./pt.js":33518,"./ro":70817,"./ro.js":70817,"./ru":10262,"./ru.js":10262,"./sd":58990,"./sd.js":58990,"./se":43842,"./se.js":43842,"./si":37711,"./si.js":37711,"./sk":80756,"./sk.js":80756,"./sl":3772,"./sl.js":3772,"./sq":6187,"./sq.js":6187,"./sr":40732,"./sr-cyrl":75713,"./sr-cyrl.js":75713,"./sr.js":40732,"./ss":99455,"./ss.js":99455,"./sv":69770,"./sv.js":69770,"./sw":80959,"./sw.js":80959,"./ta":36459,"./ta.js":36459,"./te":25302,"./te.js":25302,"./tet":67975,"./tet.js":67975,"./tg":71294,"./tg.js":71294,"./th":2385,"./th.js":2385,"./tk":24613,"./tk.js":24613,"./tl-ph":58668,"./tl-ph.js":58668,"./tlh":58190,"./tlh.js":58190,"./tr":74506,"./tr.js":74506,"./tzl":63440,"./tzl.js":63440,"./tzm":69852,"./tzm-latn":42350,"./tzm-latn.js":42350,"./tzm.js":69852,"./ug-cn":70730,"./ug-cn.js":70730,"./uk":40099,"./uk.js":40099,"./ur":72100,"./ur.js":72100,"./uz":96002,"./uz-latn":26322,"./uz-latn.js":26322,"./uz.js":96002,"./vi":14207,"./vi.js":14207,"./x-pseudo":24674,"./x-pseudo.js":24674,"./yo":10570,"./yo.js":10570,"./zh-cn":73644,"./zh-cn.js":73644,"./zh-hk":22591,"./zh-hk.js":22591,"./zh-mo":89503,"./zh-mo.js":89503,"./zh-tw":88080,"./zh-tw.js":88080};function i(e){var t=l(e);return s(t)}function l(e){if(!s.o(a,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return a[e]}i.keys=function(){return Object.keys(a)},i.resolve=l,e.exports=i,i.id=46700},66246:function(e,t,s){"use strict";s.d(t,{$t:function(){return Br}});var a=s(49242),i=s(74973);async function l(){const e=await s.e(3657).then(s.t.bind(s,33657,23));e.load({google:{families:["Roboto:100,300,400,500,700,900&display=swap"]}})}var n=s(38685),o=(s(29773),(0,n.Rd)()),r=(s(57658),s(96149));function d(){const e=r.CLine truncated
//# sourceMappingURL=index.e583b35f.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"file":"js/index.e583b35f.js","mappings":"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 truncated
+25 -12
View File
@@ -1,32 +1,45 @@
import moment from 'moment'
import moment from 'moment';
export default {
enrichEmployees(employees) {
return employees.map(employee => ({
return employees.map((employee) => ({
...employee,
_fullName: `${employee.name} ${employee.surname}`,
_initials: employee.name.charAt(0) + employee.surname.charAt(0)
}))
_initials: employee.name.charAt(0) + employee.surname.charAt(0),
}));
},
formatDateTime(date) {
moment(date)
return moment(date).format('DD.MM.yyyy, HH:mm')
moment(date);
return moment(date).format('DD.MM.yyyy, HH:mm');
},
formatTimeblockDateTime(timeblock) {
// Handle new format with separate date and time fields
if (timeblock.date && timeblock.starts_at_time) {
const dateStr = moment(timeblock.date).format('DD.MM.yyyy');
return `${dateStr}, ${timeblock.starts_at_time}`;
}
// Fallback to old format
if (timeblock.start) {
return this.formatDateTime(timeblock.start);
}
return '';
},
formatDateTimeForBackend(date) {
return moment(date).format('YYYY-MM-DD HH:mm:ss')
return moment(date).format('YYYY-MM-DD HH:mm:ss');
},
formatDate(date) {
return moment(date).format('DD.MM.yyyy')
return moment(date).format('DD.MM.yyyy');
},
isBefore(date, compareTo = null) {
return moment(date).isBefore(moment(compareTo))
return moment(date).isBefore(moment(compareTo));
},
isAfter(date, compareTo = moment()) {
return moment(date).isAfter(moment(compareTo))
}
}
return moment(date).isAfter(moment(compareTo));
},
};
@@ -3,6 +3,7 @@ export default {
data() {
return {
preventInputFocus: false,
savedScrollPosition: null,
};
},
@@ -20,18 +21,44 @@ export default {
},
onDateOpen($event) {
if ($event == undefined) {
// $event should be the element reference (or any truthy value to trigger saving)
if ($event) {
// Find the scrollable modal container
const modalContent = document.querySelector('.v-dialog .modal-content');
if (modalContent) {
this.savedScrollPosition = modalContent.scrollTop;
}
this.preventInputFocus = true;
// Reset after datepicker is opened
setTimeout(() => {
this.preventInputFocus = false;
this.savedScrollPosition = null;
}, 500);
}
},
onInputFocus($event) {
// If we have a saved scroll position and an unwanted focus happened
if (this.preventInputFocus && this.savedScrollPosition !== null) {
const target = $event.target;
// Only intercept text input focus (autocomplete fields)
if (target.tagName === 'INPUT' && target.type === 'text') {
// Blur the focused element
setTimeout(() => {
if (this.preventInputFocus) {
$event.target.blur();
this.preventInputFocus = false;
target.blur();
const modalContent = document.querySelector(
'.v-dialog .modal-content',
);
if (modalContent && this.savedScrollPosition !== null) {
modalContent.scrollTop = this.savedScrollPosition;
}
}, 0);
}
}
}, 100);
},
},
};
@@ -1,78 +1,283 @@
<template>
<v-dialog v-model="visible" max-width="750" max-height="90%" height="700px" persistent>
<v-dialog
v-model="visible"
max-width="750"
max-height="90%"
height="700px"
persistent
>
<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">
<h1>{{ mastertask?.id ? 'Upraviť master task' : 'Vytvoriť master task' }}</h1>
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large"></v-icon>
<h1>
{{
mastertask?.id ? 'Upraviť master task' : 'Vytvoriť master task'
}}
</h1>
<v-icon
@click.stop="closeModal()"
icon="mdi-close"
size="large"
></v-icon>
</div>
<v-card-actions class="d-flex flex-column modal-content">
<v-autocomplete :custom-filter="customFilter" :match-any="true" v-model="mastertask.project_id" :label="$t('Project code')" :class="{ error: v$.mastertask.project_id.$errors.length }" :items="projectsOptions" item-title="code" item-value="id" variant="solo" class="modal-input" clearable @update:search="projectCodeSearch = $event" />
<v-autocomplete
:custom-filter="customFilter"
:match-any="true"
v-model="mastertask.project_id"
:label="$t('Project code')"
:class="{ error: v$.mastertask.project_id.$errors.length }"
:items="projectsOptions"
item-title="code"
item-value="id"
variant="solo"
class="modal-input"
clearable
@update:search="projectCodeSearch = $event"
/>
<v-text-field v-model="mastertask.name" @focus="onInputFocus" class="modal-input" label="Názov mastertasku" variant="solo" :class="{ error: v$.mastertask.name.$errors.length }" :hint="v$.mastertask.name.$errors ? errorUtils.parseErrors(v$.mastertask.name.$errors) : null"></v-text-field>
<v-text-field
v-model="mastertask.name"
@focus="onInputFocus"
class="modal-input"
label="Názov mastertasku"
variant="solo"
:class="{ error: v$.mastertask.name.$errors.length }"
:hint="
v$.mastertask.name.$errors
? errorUtils.parseErrors(v$.mastertask.name.$errors)
: null
"
></v-text-field>
<div class="splitted-inputs">
<!-- TODO: Bialko validacie -->
<Datepicker v-model="mastertask.deadline" :auto-apply="true" @focus="onDateFocus" :min-date="new Date()" class="modal-input left" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Dátum" :class="{ error: v$.mastertask.deadline.$errors?.length }" :validations="v$.mastertask.deadline" />
<v-text-field class="modal-input right" variant="solo" v-model="mastertask._deadline_time" label="Čas" append-inner-icon="mdi-clock-outline" type="time" @focus="onInputFocus" :class="{ error: v$.mastertask._deadline_time.$errors.length }" :hint="v$.mastertask._deadline_time.$errors ? errorUtils.parseErrors(v$.mastertask._deadline_time.$errors) : null" />
<div
@click="handleDatepickerClick"
class="datepicker-wrapper left"
ref="datepicker-wrapper"
>
<Datepicker
v-model="mastertask.deadline"
ref="datepicker"
:auto-apply="true"
:min-date="new Date()"
class="modal-input datepicker-input"
format="dd.MM.yyyy"
locale="sk"
select-text="Vybrať"
cancel-text="Zrušiť"
placeholder="Dátum"
:class="{ error: v$.mastertask.deadline.$errors?.length }"
:validations="v$.mastertask.deadline"
/>
</div>
<v-text-field v-model="mastertask.estimated_duration" @focus="onInputFocus" class="modal-input" variant="solo" type="number" label="Nacenené hodiny" :class="{ error: v$.mastertask.estimated_duration.$errors.length }" :hint="v$.mastertask.estimated_duration.$errors ? errorUtils.parseErrors(v$.mastertask.estimated_duration.$errors) : null"></v-text-field>
<v-text-field
class="modal-input right"
variant="solo"
v-model="mastertask._deadline_time"
label="Čas"
append-inner-icon="mdi-clock-outline"
type="time"
@focus="onInputFocus"
:class="{ error: v$.mastertask._deadline_time.$errors.length }"
:hint="
v$.mastertask._deadline_time.$errors
? errorUtils.parseErrors(v$.mastertask._deadline_time.$errors)
: null
"
/>
</div>
<v-text-field v-model="mastertask.duration" @focus="onInputFocus" class="modal-input" variant="solo" type="number" :label="`${mastertask.duration} h`" :disabled="true"></v-text-field>
<v-text-field
v-model="mastertask.estimated_duration"
@focus="onInputFocus"
class="modal-input"
variant="solo"
type="number"
label="Nacenené hodiny"
:class="{ error: v$.mastertask.estimated_duration.$errors.length }"
:hint="
v$.mastertask.estimated_duration.$errors
? errorUtils.parseErrors(
v$.mastertask.estimated_duration.$errors,
)
: null
"
></v-text-field>
<v-select v-model="mastertask.team_id" @focus="onInputFocus" class="modal-input border-select" :class="{ error: v$.mastertask.employees.$errors.length }" label="Tím" variant="solo" :items="teams" item-value="id" item-title="name" :disabled="!!mastertask.id" :clearable="true" />
<v-text-field
v-model="mastertask.duration"
@focus="onInputFocus"
class="modal-input"
variant="solo"
type="number"
:label="`${mastertask.duration} h`"
:disabled="true"
></v-text-field>
<v-select
v-model="mastertask.team_id"
@focus="onInputFocus"
class="modal-input border-select"
:class="{ error: v$.mastertask.employees.$errors.length }"
label="Tím"
variant="solo"
:items="teams"
item-value="id"
item-title="name"
:disabled="!!mastertask.id"
:clearable="true"
/>
<template v-if="!mastertask.id">
<v-text-field v-for="(employee, index) in mastertask.employees" :key="employee.id" @focus="onInputFocus" class="modal-input" :class="{ error: employee.invalid }" :label="`${employee.name} ${employee.surname}`" variant="solo" placeholder="h" v-model="mastertask.employees[index].duration" type="number" min="1" @input="onEmployeeDurationChanged">
<p class="employee-select-avatar d-flex justify-center align-center">
<v-text-field
v-for="(employee, index) in mastertask.employees"
:key="employee.id"
@focus="onInputFocus"
class="modal-input"
:class="{ error: employee.invalid }"
:label="`${employee.name} ${employee.surname}`"
variant="solo"
placeholder="h"
v-model="mastertask.employees[index].duration"
type="number"
min="1"
@input="onEmployeeDurationChanged"
>
<p
class="employee-select-avatar d-flex justify-center align-center"
>
{{ employee?.name.charAt(0) + employee?.surname.charAt(0) }}
</p>
<v-icon @click.stop="removeEmployee(employee)" class="remove-input" icon="mdi-close-circle" size="default"></v-icon>
<v-icon
@click.stop="removeEmployee(employee)"
class="remove-input"
icon="mdi-close-circle"
size="default"
></v-icon>
</v-text-field>
</template>
<!-- mastertask._allEmployees is used in edit to combine team employees with extra employees and subtask durations -->
<template v-else>
<v-text-field v-for="employee in mastertask._allEmployees" :key="employee.id" class="modal-input" :label="`${employee.name} ${employee.surname}`" variant="solo" placeholder="h" v-model="employee.duration" type="number" :disabled="true">
<p class="employee-select-avatar d-flex justify-center align-center">
<v-text-field
v-for="employee in mastertask._allEmployees"
:key="employee.id"
class="modal-input"
:label="`${employee.name} ${employee.surname}`"
variant="solo"
placeholder="h"
v-model="employee.duration"
type="number"
:disabled="true"
>
<p
class="employee-select-avatar d-flex justify-center align-center"
>
{{ employee?.name.charAt(0) + employee?.surname.charAt(0) }}
</p>
<v-icon @click.stop="removeEmployee(employee)" class="remove-input" icon="mdi-close-circle" size="default"></v-icon>
<v-icon
@click.stop="removeEmployee(employee)"
class="remove-input"
icon="mdi-close-circle"
size="default"
></v-icon>
</v-text-field>
</template>
<v-autocomplete :custom-filter="customFilter" :match-any="true" v-if="showAddEmployeeInput" :label="$t('Search for employee')" :class="{ error: v$.mastertask.project_id.$errors.length }" :items="employeesOptions" item-title="_fullName" item-value="id" variant="solo" class="modal-input" clearable @update:model-value="onEmployeeSelected" />
<v-autocomplete
:custom-filter="customFilter"
:match-any="true"
v-if="showAddEmployeeInput"
:label="$t('Search for employee')"
:class="{ error: v$.mastertask.project_id.$errors.length }"
:items="employeesOptions"
item-title="_fullName"
item-value="id"
variant="solo"
class="modal-input"
clearable
@update:model-value="onEmployeeSelected"
/>
<!-- <Z-autocomplete label="Vyhľadať zamestnanca" :options="employeesOptions" class="modal-input" @option-selected="onEmployeeSelected" /> -->
<v-btn :disabled="!!mastertask.id" class="w-100 mb-5 button secondary" :class="{ error: v$.mastertask.project_id.$errors.length }" @click="showAddEmployeeInput = true"> <v-icon class="mx-1" icon="mdi-plus" />Pridať zamestnanca </v-btn>
<v-btn
:disabled="!!mastertask.id"
class="w-100 mb-5 button secondary"
:class="{ error: v$.mastertask.project_id.$errors.length }"
@click="showAddEmployeeInput = true"
>
<v-icon class="mx-1" icon="mdi-plus" />Pridať zamestnanca
</v-btn>
<div class="w-100 modal-input" :class="{ error: v$.mastertask.description.$errors.length }">
<QuillEditor ref="description" v-model="mastertask.description" placeholder="Popis" theme="snow" class="rich-text-editor" @keyup="onQuillEditorInput" />
<div
class="w-100 modal-input"
:class="{ error: v$.mastertask.description.$errors.length }"
>
<QuillEditor
ref="description"
v-model="mastertask.description"
placeholder="Popis"
theme="snow"
class="rich-text-editor"
@keyup="onQuillEditorInput"
/>
</div>
<Z-files-upload class="mt-15 files" :files="mastertask.files" @files-uploaded="filesUploaded" :is-saving="isSaving" />
<Z-files-upload
class="mt-15 files"
:files="mastertask.files"
@files-uploaded="filesUploaded"
:is-saving="isSaving"
/>
</v-card-actions>
<v-btn class="button primary" v-if="!isSaving" @click="save()">{{ mastertask.id ? 'ULOŽIŤ' : 'VYTVORIŤ' }}</v-btn>
<v-btn class="button primary disabled" v-else disabled>{{ $t('Ukladám...') }}</v-btn>
<v-btn class="button primary" v-if="!isSaving" @click="save()">{{
mastertask.id ? 'ULOŽIŤ' : 'VYTVORIŤ'
}}</v-btn>
<v-btn class="button primary disabled" v-else disabled>{{
$t('Ukladám...')
}}</v-btn>
</v-card>
<v-card v-else height="100%" class="d-flex flex-column scrolling">
<div class="d-flex justify-space-between align-center">
<p>{{ mastertask.project_code }}</p>
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large" class="pb-5"></v-icon>
<v-icon
@click.stop="closeModal()"
icon="mdi-close"
size="large"
class="pb-5"
></v-icon>
</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>{{ mastertask.name }}</h1>
<div class="d-flex justify-start">
<img v-if="!mastertask.is_finished" class="icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="editMode = !editMode" />
<img class="icon trash" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="openDeleteMasterTaskModal(mastertask)" />
<img
v-if="!mastertask.is_finished"
class="icon"
:src="require('@/plugins/app/_img/icons/pencil.svg')"
alt="pencil-icon"
@click.stop="editMode = !editMode"
/>
<img
class="icon trash"
:src="require('@/plugins/app/_img/icons/bin.svg')"
alt="trash-icon"
@click.stop="openDeleteMasterTaskModal(mastertask)"
/>
</div>
</div>
@@ -81,13 +286,23 @@
<A-mastertask-description :mastertask="mastertask" />
<div class="d-flex justify-start align-center mt-8">
<v-btn class="button primary" @click="toggleIsFinished(mastertask)">{{ mastertask.is_finished ? 'Otvoriť mastertask' : 'Ukončiť mastertask' }}</v-btn>
<v-btn
class="button primary"
@click="toggleIsFinished(mastertask)"
>{{
mastertask.is_finished
? 'Otvoriť mastertask'
: 'Ukončiť mastertask'
}}</v-btn
>
</div>
<A-tasks-table :subtasks="mastertask.subtasks" />
<div class="d-flex align-center">
<v-btn class="subtask-btn w-100" @click="addTask()"><v-icon class="mx-1" icon="mdi-plus" />Pridať sub task</v-btn>
<v-btn class="subtask-btn w-100" @click="addTask()"
><v-icon class="mx-1" icon="mdi-plus" />Pridať sub task</v-btn
>
</div>
</div>
</v-card-actions>
@@ -97,25 +312,25 @@
</template>
<script>
import Datepicker from '@vuepic/vue-datepicker'
import ZFilesUpload from '@/plugins/tm@_components/z-files-upload.vue'
import useVuelidate from '@vuelidate/core'
import { required, minLength } from '@vuelidate/validators'
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
import Datepicker from '@vuepic/vue-datepicker';
import ZFilesUpload from '@/plugins/tm@_components/z-files-upload.vue';
import useVuelidate from '@vuelidate/core';
import { required, minLength } from '@vuelidate/validators';
import errorUtils from '@/plugins/lib@auth/_utils/error.utils';
// import ZAutocomplete from '@/plugins/tm@_components/z-autocomplete.vue'
import VuetifyFixFocusMixin from '@/plugins/tm@modal/_mixins/vuetify-fix-focus'
import moment from 'moment'
import { QuillEditor } from '@vueup/vue-quill'
import VuetifyFixFocusMixin from '@/plugins/tm@modal/_mixins/vuetify-fix-focus';
import moment from 'moment';
import { QuillEditor } from '@vueup/vue-quill';
// import tmUtils from '@/plugins/tm@_utils/tm.utils'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import '@vueup/vue-quill/dist/vue-quill.snow.css'
import '@vueup/vue-quill/dist/vue-quill.snow.css';
import SelectsMixin from './_mixins/selects.mixin'
import ATasksTable from './_components/a-tasks-table.vue'
import AMastertaskDescription from './_components/a-mastertask-description.vue'
import { mapGetters } from 'vuex'
import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin'
import SelectsMixin from './_mixins/selects.mixin';
import ATasksTable from './_components/a-tasks-table.vue';
import AMastertaskDescription from './_components/a-mastertask-description.vue';
import { mapGetters } from 'vuex';
import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin';
export default {
// MIXINS
@@ -132,7 +347,7 @@ export default {
Datepicker,
ZFilesUpload,
// ZAutocomplete,
QuillEditor
QuillEditor,
},
data() {
@@ -146,90 +361,116 @@ export default {
isSaving: false,
showAddEmployeeInput: false,
date: null,
projectCodeSearch: null
}
projectCodeSearch: null,
};
},
computed: {
...mapGetters('tm', ['teams', 'projects', 'enrichedEmployees']),
enrichedSubtasks() {
if (!this.mastertask?.subtasks) return null
if (!this.mastertask?.subtasks) return null;
return this.mastertask.subtasks
.map((subtask) => {
const employee = this.enrichedEmployees.find((employee) => employee.id == subtask.employee_id)
const employee = this.enrichedEmployees.find(
(employee) => employee.id == subtask.employee_id,
);
return {
...subtask,
_initials: employee ? employee.name.charAt(0) + employee.surname.charAt(0) : '?',
_fullName: employee ? `${employee.name} ${employee.surname}` : ''
}
_initials: employee
? employee.name.charAt(0) + employee.surname.charAt(0)
: '?',
_fullName: employee ? `${employee.name} ${employee.surname}` : '',
};
})
.filter((subtask) => subtask !== null)
}
.filter((subtask) => subtask !== null);
},
},
validations() {
const quillEditorRequired = (value) => {
if (!value || !value.length || !value.replace(/<[^>]*>/g, '').length) return false
if (!value || !value.length || !value.replace(/<[^>]*>/g, '').length)
return false;
return true
}
return true;
};
return {
mastertask: {
employees: { required, minLength: minLength(1), $each: { duration: { required } } },
employees: {
required,
minLength: minLength(1),
$each: { duration: { required } },
},
project_id: { required },
name: { required },
description: { quillEditorRequired },
deadline: { required },
estimated_duration: { required },
_deadline_time: { required }
}
}
_deadline_time: { required },
},
};
},
mounted() {
this.$events.on('close-both-modals', this.closeBothModals)
this.$events.on('close-both-modals', this.closeBothModals);
this.$events.on('master-task:team-member-deleted', ({ teamId, memberId }) => {
if (this.mastertask.team_id != teamId) return
this.$events.on(
'master-task:team-member-deleted',
({ teamId, memberId }) => {
if (this.mastertask.team_id != teamId) return;
this.mastertask.employees = this.mastertask.employees.filter((employee) => employee.id != memberId)
}),
this.mastertask.employees = this.mastertask.employees.filter(
(employee) => employee.id != memberId,
);
},
),
this.$events.on('on-mastertask-deleted', (mastertask) => {
if (mastertask?.id == this.mastertask?.id) this.closeModal()
})
if (mastertask?.id == this.mastertask?.id) this.closeModal();
});
this.$events.on('on-subtask-deleted', (task) => {
if (!this.mastertask) return
this.mastertask.subtasks = this.mastertask.subtasks.filter((subtask) => subtask.id != task.id)
})
if (!this.mastertask) return;
this.mastertask.subtasks = this.mastertask.subtasks.filter(
(subtask) => subtask.id != task.id,
);
});
this.$events.on('on-subtask-edited', (task) => {
if (!this.mastertask?.subtasks) return
if (!this.mastertask?.subtasks) return;
if (this.mastertask.subtasks.find((subtask) => subtask.id == task.id)) {
this.mastertask.subtasks = this.mastertask.subtasks.map((t) => (t.id == task.id ? task : t))
this.mastertask.subtasks = this.mastertask.subtasks.map((t) =>
t.id == task.id ? task : t,
);
} else {
this.mastertask.subtasks.push(task)
this.mastertask.subtasks.push(task);
}
})
});
},
beforeUnmount() {
this.$events.off('on-mastertask-deleted')
this.$events.off('on-subtask-deleted')
this.$events.off('on-subtask-edited')
this.$events.off('master-task:team-member-deleted')
this.$events.off('close-both-modals', this.closeBothModals)
this.$events.off('on-mastertask-deleted');
this.$events.off('on-subtask-deleted');
this.$events.off('on-subtask-edited');
this.$events.off('master-task:team-member-deleted');
this.$events.off('close-both-modals', this.closeBothModals);
},
methods: {
handleDatepickerClick() {
// Pass the datepicker wrapper element reference to the mixin
const scrollTarget = this.$refs['datepicker-wrapper'];
this.onDateOpen(scrollTarget);
// Open the datepicker
this.$refs['datepicker'].openMenu();
},
closeBothModals() {
this.$emit('close')
this.visible = false
this.$emit('close');
this.visible = false;
},
removeEmployee({ id }) {
@@ -240,210 +481,251 @@ export default {
// this.mastertask.team = null
// }
this.mastertask.employees = this.mastertask.employees.filter((employee) => employee.id != id)
this.mastertask.employees = this.mastertask.employees.filter(
(employee) => employee.id != id,
);
},
removeMemberAlert(member) {
const team = this.mastertask.team
this.$events.emit('show-delete-team-member-modal', { member, team })
const team = this.mastertask.team;
this.$events.emit('show-delete-team-member-modal', { member, team });
},
async loadMastertask(id) {
try {
this.mastertask = await this.$axios.get_auth_data(`v1/mastertasks/${id}`)
this.mastertask = await this.$axios.get_auth_data(
`v1/mastertasks/${id}`,
);
// TODO zmazat ked zacne prichadzat project_id a team_id
const project = this.projects.find((project) => project.code == this.mastertask.project_code)
this.mastertask.project_id = project?.id || null
this.mastertask.team_id = this.mastertask.team?.id || null
const project = this.projects.find(
(project) => project.code == this.mastertask.project_code,
);
this.mastertask.project_id = project?.id || null;
this.mastertask.team_id = this.mastertask.team?.id || null;
this.mastertask._allEmployees = this.mastertask.subtasks
.map(({ employee_id, duration }) => {
const employee = this.enrichedEmployees.find(({ id }) => id == employee_id)
const employee = this.enrichedEmployees.find(
({ id }) => id == employee_id,
);
if (!employee) {
return null
return null;
}
employee.duration = duration
employee.duration = duration;
return employee
return employee;
})
.filter((employee) => employee !== null)
.filter((employee) => employee !== null);
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
}
},
async showModal({ mastertask, editMode = false }) {
this.isSaving = false
this.editMode = null
this.visible = true
this.mastertask = null
this.isSaving = false;
this.editMode = null;
this.visible = true;
this.mastertask = null;
this.$nextTick(() => {
this.setFocusEvent()
this.v$.$reset()
})
this.setFocusEvent();
this.v$.$reset();
});
try {
if (mastertask?.id) {
await this.loadMastertask(mastertask.id)
await this.loadMastertask(mastertask.id);
// this.mastertask.project_code = project.code
} else {
const savedMastertask = localStorage.getItem('mastertaskData')
const savedMastertask = localStorage.getItem('mastertaskData');
try {
if (savedMastertask) {
const parsedMastertask = JSON.parse(savedMastertask)
this.mastertask = parsedMastertask
const parsedMastertask = JSON.parse(savedMastertask);
this.mastertask = parsedMastertask;
// If the parsed result is not an object, reset to default
if (typeof this.mastertask !== 'object' || this.mastertask === null) {
throw new Error('Parsed mastertask is not an object')
if (
typeof this.mastertask !== 'object' ||
this.mastertask === null
) {
throw new Error('Parsed mastertask is not an object');
}
this.$nextTick(() => {
this.$refs['description']?.setHTML(this.mastertask.description || '')
})
this.$refs['description']?.setHTML(
this.mastertask.description || '',
);
});
} else {
throw new Error('mastertaskData is null or undefined')
throw new Error('mastertaskData is null or undefined');
}
} catch (error) {
console.error('Error parsing mastertaskData:', error)
this.mastertask = { employees: [], duration: 0, _deadline_time: '17:00' }
console.error('Error parsing mastertaskData:', error);
this.mastertask = {
employees: [],
duration: 0,
_deadline_time: '17:00',
};
}
}
this.editMode = editMode || !this.mastertask.id
this.editMode = editMode || !this.mastertask.id;
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development') console.log('[z-master-task-modal.vue] Error: ', error)
if (process.env.NODE_ENV === 'development')
console.log('[z-master-task-modal.vue] Error: ', error);
}
},
toggleIsFinished() {
this.$events.emit('show-complete-master-task-modal', { mastertask: this.mastertask })
this.$events.emit('show-complete-master-task-modal', {
mastertask: this.mastertask,
});
},
async save() {
if (this.mastertask.id) {
this.mastertask.employees = this.mastertask.employees.map((employee) => {
const { duration } = this.mastertask.subtasks.find(({ employee_id }) => employee_id == employee.id) || {}
employee.duration = duration
return employee
})
this.mastertask.employees = this.mastertask.employees.map(
(employee) => {
const { duration } =
this.mastertask.subtasks.find(
({ employee_id }) => employee_id == employee.id,
) || {};
employee.duration = duration || 0;
return employee;
},
);
}
const vuelidateValid = await this.v$.$validate()
const employeesValid = await this._validateEmployees()
const vuelidateValid = await this.v$.$validate();
const employeesValid = await this._validateEmployees();
if (!vuelidateValid || !employeesValid) return
if (!vuelidateValid || !employeesValid) return;
if (this.$refs['description']) this.mastertask.description = this.$refs['description'].getHTML()
if (this.$refs['description'])
this.mastertask.description = this.$refs['description'].getHTML();
this._mergeDeadlineTimeDate()
this._mergeDeadlineTimeDate();
try {
this.isSaving = true
this.mastertask.deadline = moment(this.mastertask.deadline).format('YYYY-MM-DD HH:MM:SS')
if (this.mastertask.id) await this.$axios.patch_auth_form(`v1/mastertasks/${this.mastertask.id}`, this.mastertask)
else await this.$axios.post_auth_data('v1/mastertasks', this.mastertask)
localStorage.removeItem('mastertaskData')
this.isSaving = true;
this.mastertask.deadline = moment(this.mastertask.deadline).format(
'YYYY-MM-DD HH:MM:SS',
);
if (this.mastertask.id)
await this.$axios.patch_auth_form(
`v1/mastertasks/${this.mastertask.id}`,
this.mastertask,
);
else
await this.$axios.post_auth_data('v1/mastertasks', this.mastertask);
localStorage.removeItem('mastertaskData');
this.$emit('master-task-edited', this.mastertask)
this.closeModal()
this.$emit('master-task-edited', this.mastertask);
this.closeModal();
} catch (error) {
this.$toast.error(this.$parseError(error))
this.$toast.error(this.$parseError(error));
if (process.env.NODE_ENV === 'development') console.log('[z-master-task-modal.vue] Error: ', error)
if (process.env.NODE_ENV === 'development')
console.log('[z-master-task-modal.vue] Error: ', error);
} finally {
this.isSaving = false
this.isSaving = false;
}
},
filesUploaded(files) {
this.mastertask.files = files
this.mastertask.files = files;
},
closeModal() {
this.visible = false
this.visible = false;
},
openDeleteMasterTaskModal(mastertask) {
this.$events.emit('show-delete-master-task-modal', { mastertask })
this.$events.emit('show-delete-master-task-modal', { mastertask });
},
addTask() {
this.$events.emit('show-subtask-modal', {
subtask: {
master_task_id: this.mastertask.id,
project_code: this.mastertask.project_code
}
})
project_code: this.mastertask.project_code,
},
});
},
onQuillEditorInput() {
this.mastertask.description = this.$refs['description'].getHTML()
this.mastertask.description = this.$refs['description'].getHTML();
},
_mergeDeadlineTimeDate() {
const date = new Date(this.mastertask.deadline)
console.log('z-master-task-modal', this.subtask)
const timeParts = this.mastertask._deadline_time.split(':')
date.setHours(parseInt(timeParts[0]))
date.setMinutes(parseInt(timeParts[1]))
const date = new Date(this.mastertask.deadline);
console.log('z-master-task-modal', this.subtask);
const timeParts = this.mastertask._deadline_time.split(':');
date.setHours(parseInt(timeParts[0]));
date.setMinutes(parseInt(timeParts[1]));
this.mastertask.deadline = date
this.mastertask.deadline = date;
},
_validateEmployees() {
let isValid = true
let isValid = true;
this.mastertask.employees = this.mastertask.employees.map((employee) => {
if (!employee.duration) {
employee.invalid = true
isValid = false
if (employee.duration === null || employee.duration === undefined) {
employee.invalid = true;
isValid = false;
}
return employee
})
return employee;
});
return isValid
}
return isValid;
},
},
watch: {
editMode() {
this.$nextTick(() => {
this.$refs['description']?.setHTML(this.mastertask.description || '')
this.$refs['description']?.setHTML(this.mastertask.description || '');
if (!this.mastertask?.id) return
if (!this.mastertask?.id) return;
const date = new Date(this.mastertask.deadline)
const hours = date.getHours()
const minutes = date.getMinutes()
const date = new Date(this.mastertask.deadline);
const hours = date.getHours();
const minutes = date.getMinutes();
this.mastertask._deadline_time = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`
})
this.mastertask._deadline_time = `${hours
.toString()
.padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
});
},
mastertask: {
handler(val) {
if (this.editMode && !this.mastertask?.id) {
localStorage.setItem('mastertaskData', JSON.stringify(val))
localStorage.setItem('mastertaskData', JSON.stringify(val));
}
},
deep: true
deep: true,
},
'mastertask.team_id': {
handler(value, oldValue) {
if (this.editMode && !value && oldValue) {
// Removes only employees from the old team when team_id is removed
const oldTeamEmployeesIds = this.teams.find((team) => team.id == oldValue)?.employees.map((employee) => employee?.id) || []
const employeesNotInOldTeam = this.mastertask.employees.filter((employee) => !oldTeamEmployeesIds.includes(employee?.id))
this.mastertask.employees = employeesNotInOldTeam
const oldTeamEmployeesIds =
this.teams
.find((team) => team.id == oldValue)
?.employees.map((employee) => employee?.id) || [];
const employeesNotInOldTeam = this.mastertask.employees.filter(
(employee) => !oldTeamEmployeesIds.includes(employee?.id),
);
this.mastertask.employees = employeesNotInOldTeam;
}
},
deep: true
deep: true,
},
'$route.query': {
handler(_, oldValue) {
@@ -453,8 +735,8 @@ export default {
},
deep: true,
},
}
}
},
};
</script>
<style lang="sass" scoped>
@@ -502,4 +784,11 @@ export default {
:deep(.v-field__clearable)
opacity: 1 !important
.datepicker-wrapper
width: 100%
.datepicker-input
width: 100% !important
height: 100%
pointer-events: none
</style>
@@ -16,18 +16,34 @@
<v-sheet class="py-3">
<div class="d-flex align-center mb-3">
<v-icon @click="showModal = true" class="add-date cursor-pointer mr-2" icon="mdi-plus" size="medium" />
<v-icon
@click="showModal = true"
class="add-date cursor-pointer mr-2"
icon="mdi-plus"
size="medium"
/>
<p class="task-badge rounded-pill">Pridať záznam</p>
</div>
<template v-if="subtask.timesheets.length">
<div v-for="timesheet in subtask.timesheets" :key="timesheet.id" class="d-flex align-center mb-3">
<v-icon @click.stop="deleteTimesheet(timesheet)" class="circle-border cursor-pointer mr-2" icon="mdi-minus" size="medium" />
<div
v-for="timesheet in subtask.timesheets"
:key="timesheet.id"
class="d-flex align-center mb-3"
>
<v-icon
@click.stop="deleteTimesheet(timesheet)"
class="circle-border cursor-pointer mr-2"
icon="mdi-minus"
size="medium"
/>
<div class="d-flex align-center flex-start width-100">
<p class="task-badge rounded-pill">{{ timesheet.time }}</p>
<!-- <p class="ml-5">{{ timesheet.employee_name }} ({{ moment(timesheet.timestamp).format('D.M.YYYY') }})</p> -->
<p class="ml-5">{{ timesheet.employee_name }} ({{ timesheet.timestamp }})</p>
<p class="ml-5">
{{ timesheet.employee_name }} ({{ timesheet.timestamp }})
</p>
</div>
</div>
</template>
@@ -40,10 +56,27 @@
<div class="d-flex justify-space-between align-center">
<h1>Pridať odpracovaný čas</h1>
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large"></v-icon>
<v-icon
@click.stop="closeModal()"
icon="mdi-close"
size="large"
></v-icon>
</div>
<v-card-actions class="mt-10 d-flex justify-start align-center">
<v-text-field v-model="form.hours" variant="solo" bg-color="white" type="number" :hint="v$.form.hours.$errors ? errorUtils.parseErrors(v$.form.hours.$errors) : null" :class="{ error: v$.form.hours.$errors.length }" class="mb-2" label="Odpracovaný čas" />
<v-text-field
v-model="form.hours"
variant="solo"
bg-color="white"
type="number"
:hint="
v$.form.hours.$errors
? errorUtils.parseErrors(v$.form.hours.$errors)
: null
"
:class="{ error: v$.form.hours.$errors.length }"
class="mb-2"
label="Odpracovaný čas"
/>
</v-card-actions>
<v-btn @click="submit()" class="button primary mt-5">Potvrdiť</v-btn>
</v-card>
@@ -51,26 +84,26 @@
</template>
<script>
import moment from 'moment'
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
import useVuelidate from '@vuelidate/core'
import { required, numeric, minValue } from '@vuelidate/validators'
import tmUtils from '@/plugins/tm@_utils/tm.utils'
import { mapGetters } from 'vuex'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import moment from 'moment';
import errorUtils from '@/plugins/lib@auth/_utils/error.utils';
import useVuelidate from '@vuelidate/core';
import { required, numeric, minValue } from '@vuelidate/validators';
import tmUtils from '@/plugins/tm@_utils/tm.utils';
import { mapGetters } from 'vuex';
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
export default {
mixins: [modalMixin],
props: {
hours: {
type: Number,
required: true
required: true,
},
subtask: {
type: Object,
required: true
}
required: true,
},
},
data() {
@@ -80,88 +113,129 @@ export default {
errorUtils,
showModal: false,
form: {
hours: null
}
}
hours: null,
},
};
},
validations() {
return {
form: {
hours: {required, numeric, minValue: minValue(0.1)}
}
}
hours: { required, numeric, minValue: minValue(0.1) },
},
};
},
computed: {
...mapGetters('auth', ['user'])
...mapGetters('auth', ['user']),
},
methods: {
async submit() {
if (!await this.v$.$validate())
return
if (!(await this.v$.$validate())) return;
const subtask = JSON.parse(JSON.stringify(this.subtask))
const subtask = JSON.parse(JSON.stringify(this.subtask));
subtask.timesheets.push({
id: null,
employee_id: this.user.id,
time: typeof this.form.hours == 'string' ? parseFloat(this.form.hours) : this.form.hours
})
time:
typeof this.form.hours == 'string'
? parseFloat(this.form.hours)
: this.form.hours,
});
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(this._mergeDeadlineTimeDate())
if (subtask.deadline)
subtask.deadline = tmUtils.formatDateTimeForBackend(
this._mergeDeadlineTimeDate(),
);
this._update(subtask)
this._update(subtask);
},
async deleteTimesheet({ id }) {
const subtask = JSON.parse(JSON.stringify(this.subtask))
subtask.timesheets = subtask.timesheets.filter(timesheet => timesheet.id != id)
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(this._mergeDeadlineTimeDate())
const subtask = JSON.parse(JSON.stringify(this.subtask));
subtask.timesheets = subtask.timesheets.filter(
(timesheet) => timesheet.id != id,
);
if (subtask.deadline)
subtask.deadline = tmUtils.formatDateTimeForBackend(
this._mergeDeadlineTimeDate(),
);
this._update(subtask)
this._update(subtask);
},
closeModal() {
this.form = {
hours: null
}
hours: null,
};
this.showModal = false
this.$nextTick(() => this.v$.$reset())
this.showModal = false;
this.$nextTick(() => this.v$.$reset());
},
async _update(data) {
try {
data.timesheets = data.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
})
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${data.id}`, data)
const timesheets = data.timesheets.map((timesheet) => {
delete timesheet.employee_name;
return timesheet;
});
this.closeModal()
this.$events.emit('on-subtask-edited', subtask)
// Convert timeblocks from internal format to BE format
const timeblocks = (data.timeblocks || [])
.filter((timeblock) => {
// Filter timeblocks that have either old format (date) or new format (start)
return timeblock.date || timeblock.start;
})
.map((timeblock) => {
// If already in BE format (has start field), return as is
if (timeblock.start && !timeblock.date) {
return {
id: timeblock.id || null,
start: timeblock.start,
end: timeblock.end,
is_finished: timeblock.is_finished || 0,
};
}
// Convert from internal format to BE format
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
return {
id: timeblock.id || null,
start: `${dateStr} ${timeblock.starts_at_time}:00`,
end: `${dateStr} ${timeblock.ends_at_time}:00`,
is_finished: timeblock.is_finished || 0,
};
});
const { subtask } = await this.$axios.put_auth(
`v1/subtasks/${data.id}`,
{ ...data, timesheets, timeblocks },
);
this.closeModal();
this.$events.emit('on-subtask-edited', subtask);
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development')
console.log('[a-task-spent-time.vue] Error: ', error)
console.log('[a-task-spent-time.vue] Error: ', error);
}
},
_mergeDeadlineTimeDate() {
const date = new Date(this.subtask.deadline)
console.log('a-task-spent-time', this.subtask)
const timeParts = this.subtask._deadline_time.split(':')
const date = new Date(this.subtask.deadline);
console.log('a-task-spent-time', this.subtask);
const timeParts = this.subtask._deadline_time.split(':');
date.setHours(parseInt(timeParts[0]))
date.setMinutes(parseInt(timeParts[1]))
date.setHours(parseInt(timeParts[0]));
date.setMinutes(parseInt(timeParts[1]));
return date
return date;
},
}
}
},
};
</script>
<style lang="sass" scoped>
@@ -12,14 +12,47 @@
<v-col cols="7">
<v-sheet class="py-3">
<div class="d-flex align-center mb-3" v-if="!isOffice365Task">
<v-icon @click="showModal = true" class="add-date cursor-pointer mr-2" icon="mdi-plus" size="medium" />
<v-icon
@click="showModal = true"
class="add-date cursor-pointer mr-2"
icon="mdi-plus"
size="medium"
/>
<p class="task-badge rounded-pill">Pridať záznam</p>
</div>
<div v-for="(timeblock, index) in timeblocks" :key="timeblock.id" class="d-flex align-center mb-3">
<v-icon v-if="!isOffice365Task" @click.stop="subtask.id ? deleteTimeblock(timeblock) : deleteTimeblockWithoutId(index)" class="circle-border cursor-pointer mr-2" icon="mdi-minus" size="medium" />
<p class="task-badge rounded-pill" :class="{'strike-through': timeblock.is_finished}">{{ tmUtils.formatDateTime(timeblock.start) }} - {{ tmUtils.formatDateTime(timeblock.end) }}</p>
<v-icon v-if="!isOffice365Task" v-show="subtask.id" @click.stop="toggleTimeblockIsFinished(timeblock)" class="circle-border cursor-pointer ml-2" :class="{'completed': timeblock.is_finished}" icon="mdi-check" size="medium" />
<div
v-for="(timeblock, index) in timeblocks"
:key="timeblock.id"
class="d-flex align-center mb-3"
>
<v-icon
v-if="!isOffice365Task"
@click.stop="
subtask.id
? deleteTimeblock(timeblock)
: deleteTimeblockWithoutId(index)
"
class="circle-border cursor-pointer mr-2"
icon="mdi-minus"
size="medium"
/>
<p
class="task-badge rounded-pill"
:class="{ 'strike-through': timeblock.is_finished }"
>
{{ formatTimeblockStart(timeblock) }} -
{{ formatTimeblockEnd(timeblock) }}
</p>
<v-icon
v-if="!isOffice365Task"
v-show="subtask.id"
@click.stop="toggleTimeblockIsFinished(timeblock)"
class="circle-border cursor-pointer ml-2"
:class="{ completed: timeblock.is_finished }"
icon="mdi-check"
size="medium"
/>
</div>
</v-sheet>
</v-col>
@@ -29,13 +62,54 @@
<v-card>
<div class="d-flex justify-space-between align-center">
<h1>Pridať dátum</h1>
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large"></v-icon>
<v-icon
@click.stop="closeModal()"
icon="mdi-close"
size="large"
></v-icon>
</div>
<v-card-actions class="mt-10 d-flex flex-column modal-content">
<Datepicker v-model="form.date" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Dátum" :auto-apply="true" :enable-time-picker="false" class="mb-5 modal-input" :class="{error: v$.form.date.$errors.length}" />
<v-text-field v-model="form.starts_at_time" type="time" variant="solo" bg-color="white" :hint="v$.form.starts_at_time.$errors ? errorUtils.parseErrors(v$.form.starts_at_time.$errors) : null" :class="{ error: v$.form.starts_at_time.$errors.length }" class="mb-1 modal-input" label="Začiatok" />
<v-text-field v-model="form.ends_at_time" type="time" variant="solo" bg-color="white" :hint="v$.form.ends_at_time.$errors ? errorUtils.parseErrors(v$.form.ends_at_time.$errors) : null" :class="{ error: v$.form.ends_at_time.$errors.length }" class="modal-input" label="Koniec" />
<Datepicker
v-model="form.date"
format="dd.MM.yyyy"
locale="sk"
select-text="Vybrať"
cancel-text="Zrušiť"
placeholder="Dátum"
:auto-apply="true"
:enable-time-picker="false"
class="mb-5 modal-input"
:class="{ error: v$.form.date.$errors.length }"
/>
<v-text-field
v-model="form.starts_at_time"
type="time"
variant="solo"
bg-color="white"
:hint="
v$.form.starts_at_time.$errors
? errorUtils.parseErrors(v$.form.starts_at_time.$errors)
: null
"
:class="{ error: v$.form.starts_at_time.$errors.length }"
class="mb-1 modal-input"
label="Začiatok"
/>
<v-text-field
v-model="form.ends_at_time"
type="time"
variant="solo"
bg-color="white"
:hint="
v$.form.ends_at_time.$errors
? errorUtils.parseErrors(v$.form.ends_at_time.$errors)
: null
"
:class="{ error: v$.form.ends_at_time.$errors.length }"
class="modal-input"
label="Koniec"
/>
</v-card-actions>
<v-btn @click="submit()" class="button primary mt-5">Potvrdiť</v-btn>
@@ -44,7 +118,10 @@
<v-dialog v-model="visible" max-width="750" persistent>
<v-card>
<div class="d-flex justify-space-between align-center">
<h1 class="text-red">Ste si istý, že chcete pridať timeblock po deadline <br> <b class="text-black">z mastertasku {{ subtask?.project_code }} ?</b></h1>
<h1 class="text-red">
Ste si istý, že chcete pridať timeblock po deadline <br />
<b class="text-black">z mastertasku {{ subtask?.project_code }} ?</b>
</h1>
<v-icon
@click.stop="visible = false"
@@ -53,44 +130,51 @@
class="mb-15"
></v-icon>
</div>
<v-card-actions class="mt-10 d-flex justify-start align-center mobile-view">
<v-btn class="button primary half" variant="flat" @click.stop="confirmSubmit()">ÁNO</v-btn>
<v-btn class="button primary half outline" @click.stop="visible = false">ZRUŠIŤ</v-btn>
<v-card-actions
class="mt-10 d-flex justify-start align-center mobile-view"
>
<v-btn
class="button primary half"
variant="flat"
@click.stop="confirmSubmit()"
>ÁNO</v-btn
>
<v-btn class="button primary half outline" @click.stop="visible = false"
>ZRUŠIŤ</v-btn
>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import tmUtils from '@/plugins/tm@_utils/tm.utils'
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import Datepicker from '@vuepic/vue-datepicker'
import moment from 'moment'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import { mapGetters } from 'vuex'
import tmUtils from '@/plugins/tm@_utils/tm.utils';
import errorUtils from '@/plugins/lib@auth/_utils/error.utils';
import useVuelidate from '@vuelidate/core';
import { required } from '@vuelidate/validators';
import Datepicker from '@vuepic/vue-datepicker';
import moment from 'moment';
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import { mapGetters } from 'vuex';
export default {
mixins: [modalMixin],
emits: ['update-subtask'],
components: {
Datepicker
Datepicker,
},
props: {
timeblocks: {
type: Array,
required: true
required: true,
},
subtask: {
type: Object,
required: true
}
required: true,
},
},
data() {
@@ -103,9 +187,9 @@ export default {
form: {
date: null,
starts_at_time: '09:00',
ends_at_time: '16:00'
}
}
ends_at_time: '16:00',
},
};
},
validations() {
@@ -113,194 +197,296 @@ export default {
form: {
date: { required },
starts_at_time: { required },
ends_at_time: { required }
}
}
ends_at_time: { required },
},
};
},
computed: {
...mapGetters('tm', ['mastertasks']),
isOffice365Task() {
return this.subtask.type == 'office365'
}
return this.subtask.type == 'office365';
},
},
methods: {
formatTimeblockStart(timeblock) {
// Handle internal format with date and time fields
if (timeblock.date && timeblock.starts_at_time) {
const dateStr = moment(timeblock.date).format('DD.MM.yyyy');
return `${dateStr}, ${timeblock.starts_at_time}`;
}
// Fallback to backend format
if (timeblock.start) {
return tmUtils.formatDateTime(timeblock.start);
}
return '';
},
formatTimeblockEnd(timeblock) {
// Handle internal format with date and time fields
if (timeblock.date && timeblock.ends_at_time) {
return timeblock.ends_at_time;
}
// Fallback to backend format
if (timeblock.end) {
return tmUtils.formatDateTime(timeblock.end);
}
return '';
},
async submit() {
if (!await this.v$.$validate())
return
if (!(await this.v$.$validate())) return;
const subtask = JSON.parse(JSON.stringify(this.subtask))
const splittedStartsAtTime = this.form.starts_at_time.split(':')
const splittedEndsAtTime = this.form.ends_at_time.split(':')
const start = moment(this.form.date).hours(parseInt(splittedStartsAtTime[0])).minutes(parseInt(splittedStartsAtTime[1])).toISOString()
const end = moment(this.form.date).hours(parseInt(splittedEndsAtTime[0])).minutes(parseInt(splittedEndsAtTime[1])).toISOString()
const subtask = JSON.parse(JSON.stringify(this.subtask));
if (!subtask?.timeblocks) { subtask.timeblocks = [] }
if (!subtask?.timesheets) { subtask.timesheets = [] }
if (!subtask?.is_finished) { subtask.is_finished = 0 }
if (!subtask?.timeblocks) {
subtask.timeblocks = [];
}
if (!subtask?.timesheets) {
subtask.timesheets = [];
}
if (!subtask?.is_finished) {
subtask.is_finished = 0;
}
// Add timeblock in internal format
subtask.timeblocks.push({
end: tmUtils.formatDateTimeForBackend(end),
id: null,
date: this.form.date,
starts_at_time: this.form.starts_at_time,
ends_at_time: this.form.ends_at_time,
is_finished: 0,
start: tmUtils.formatDateTimeForBackend(start)
})
});
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(this._mergeDeadlineTimeDate())
if (subtask.deadline)
subtask.deadline = tmUtils.formatDateTimeForBackend(
this._mergeDeadlineTimeDate(),
);
const isAfterDeadline = this.isAfterDeadline()
const isAfterDeadline = this.isAfterDeadline();
if (isAfterDeadline) {
this.visible = true
this.visible = true;
} else {
if (!subtask.id) {
this.$emit('update-unfinished-subtask', subtask)
this.$emit('update-unfinished-subtask', subtask);
this.closeModal();
} else {
this._update(subtask)
this._update(subtask);
}
}
},
async confirmSubmit() {
const subtask = JSON.parse(JSON.stringify(this.subtask))
const splittedStartsAtTime = this.form.starts_at_time.split(':')
const splittedEndsAtTime = this.form.ends_at_time.split(':')
const start = moment(this.form.date).hours(parseInt(splittedStartsAtTime[0])).minutes(parseInt(splittedStartsAtTime[1])).toISOString()
const end = moment(this.form.date).hours(parseInt(splittedEndsAtTime[0])).minutes(parseInt(splittedEndsAtTime[1])).toISOString()
const subtask = JSON.parse(JSON.stringify(this.subtask));
if (!subtask?.timeblocks) { subtask.timeblocks = [] }
if (!subtask?.timesheets) { subtask.timesheets = [] }
if (!subtask?.is_finished) { subtask.is_finished = 0 }
subtask.timeblocks.push({
end: tmUtils.formatDateTimeForBackend(end),
id: null,
is_finished: 0,
start: tmUtils.formatDateTimeForBackend(start)
})
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(this._mergeDeadlineTimeDate())
if (!subtask.id) {
this.$emit('update-unfinished-subtask', subtask)
this.closeModal()
return
if (!subtask?.timeblocks) {
subtask.timeblocks = [];
}
if (!subtask?.timesheets) {
subtask.timesheets = [];
}
if (!subtask?.is_finished) {
subtask.is_finished = 0;
}
this.visible = false
this._update(subtask)
// Add timeblock in internal format
subtask.timeblocks.push({
id: null,
date: this.form.date,
starts_at_time: this.form.starts_at_time,
ends_at_time: this.form.ends_at_time,
is_finished: 0,
});
if (subtask.deadline)
subtask.deadline = tmUtils.formatDateTimeForBackend(
this._mergeDeadlineTimeDate(),
);
if (!subtask.id) {
this.$emit('update-unfinished-subtask', subtask);
this.closeModal();
return;
}
this.visible = false;
this._update(subtask);
},
async toggleTimeblockIsFinished(originalTimeblock) {
// TODO: Pridat odpracovany cas modal?
console.log('toggleTimeblockIsFinished 5', this.subtask)
const subtask = JSON.parse(JSON.stringify(this.subtask))
const timeblock = JSON.parse(JSON.stringify(originalTimeblock))
const subtask = JSON.parse(JSON.stringify(this.subtask));
const timeblock = JSON.parse(JSON.stringify(originalTimeblock));
timeblock.is_finished = timeblock.is_finished == 1 ? 0 : 1
timeblock.is_finished = timeblock.is_finished == 1 ? 0 : 1;
try {
const {data: newTimeblock} = await this.$axios.put_auth(`v1/timeblocks/${timeblock.id}`, timeblock)
// Convert timeblock to backend format before sending
const timeblockForBackend = {
id: timeblock.id,
is_finished: timeblock.is_finished,
};
subtask.timeblocks = subtask.timeblocks.map(originalTimeblock => {
if (originalTimeblock.id == newTimeblock.id)
return newTimeblock
// If timeblock is in internal format, convert it
if (timeblock.date) {
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
timeblockForBackend.start = `${dateStr} ${timeblock.starts_at_time}:00`;
timeblockForBackend.end = `${dateStr} ${timeblock.ends_at_time}:00`;
} else {
// Already in backend format
timeblockForBackend.start = timeblock.start;
timeblockForBackend.end = timeblock.end;
}
return originalTimeblock
})
const { data: newTimeblock } = await this.$axios.put_auth(
`v1/timeblocks/${timeblock.id}`,
timeblockForBackend,
);
this.$events.emit('on-subtask-edited', subtask)
this.$emit('update-subtask', subtask)
// Convert returned timeblock from backend format to internal format
const startMoment = moment(newTimeblock.start, 'YYYY-MM-DD HH:mm:ss');
const endMoment = moment(newTimeblock.end, 'YYYY-MM-DD HH:mm:ss');
const convertedTimeblock = {
id: newTimeblock.id,
date: startMoment.toDate(),
starts_at_time: startMoment.format('HH:mm'),
ends_at_time: endMoment.format('HH:mm'),
is_finished: newTimeblock.is_finished,
};
subtask.timeblocks = subtask.timeblocks.map((originalTimeblock) => {
if (originalTimeblock.id == convertedTimeblock.id)
return convertedTimeblock;
return originalTimeblock;
});
this.$events.emit('on-subtask-edited', subtask);
this.$emit('update-subtask', subtask);
if (timeblock.is_finished)
this.$events.emit('show-task-add-time-modal', { subtask })
this.$events.emit('show-task-add-time-modal', { subtask });
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development')
console.log('[a-task-timeblocks.vue] Error: ', error)
console.log('[a-task-timeblocks.vue] Error: ', error);
}
},
async deleteTimeblock({ id }) {
const subtask = JSON.parse(JSON.stringify(this.subtask))
const subtask = JSON.parse(JSON.stringify(this.subtask));
subtask.timeblocks = subtask.timeblocks.filter(timeblock => timeblock.id != id)
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(this._mergeDeadlineTimeDate())
subtask.timeblocks = subtask.timeblocks.filter(
(timeblock) => timeblock.id != id,
);
if (subtask.deadline)
subtask.deadline = tmUtils.formatDateTimeForBackend(
this._mergeDeadlineTimeDate(),
);
this._update(subtask)
this._update(subtask);
},
deleteTimeblockWithoutId(i) {
this.$emit('delete-timeblock')
this.$emit('delete-timeblock');
},
async _update(data) {
try {
const timesheets = data.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
delete timesheet.employee_name;
return timesheet;
});
// Convert timeblocks from internal format to BE format
const timeblocks = (data.timeblocks || [])
.filter((timeblock) => {
// Filter timeblocks that have either old format (date) or new format (start)
return timeblock.date || timeblock.start;
})
.map((timeblock) => {
// If already in BE format (has start field), return as is
if (timeblock.start && !timeblock.date) {
return {
id: timeblock.id || null,
start: timeblock.start,
end: timeblock.end,
is_finished: timeblock.is_finished || 0,
};
}
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${data.id}`, {...data, timesheets})
// Convert from internal format to BE format
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
return {
id: timeblock.id || null,
start: `${dateStr} ${timeblock.starts_at_time}:00`,
end: `${dateStr} ${timeblock.ends_at_time}:00`,
is_finished: timeblock.is_finished || 0,
};
});
this.closeModal()
this.$events.emit('on-subtask-edited', subtask)
const { subtask } = await this.$axios.put_auth(
`v1/subtasks/${data.id}`,
{ ...data, timesheets, timeblocks },
);
this.closeModal();
this.$events.emit('on-subtask-edited', subtask);
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development')
console.log('[a-task-timeblocks.vue] Error: ', error)
console.log('[a-task-timeblocks.vue] Error: ', error);
}
},
isAfterDeadline() {
const deadline = this.getDeadline(this.subtask)
const deadline = this.getDeadline(this.subtask);
if (!deadline)
return
if (!deadline) return;
const mDate = moment(this.form.date)
const mDeadline = moment(deadline)
const mDate = moment(this.form.date);
const mDeadline = moment(deadline);
const [hours, minutes] = this.form.ends_at_time.split(':').map(Number)
const [hours, minutes] = this.form.ends_at_time.split(':').map(Number);
mDate.hours(hours)
mDate.minutes(minutes)
mDate.hours(hours);
mDate.minutes(minutes);
return mDate.isAfter(mDeadline)
return mDate.isAfter(mDeadline);
},
getDeadline(subtask) {
if (subtask?.deadline)
return subtask.deadline
if (subtask?.deadline) return subtask.deadline;
return subtask.master_task_deadline
return subtask.master_task_deadline;
},
_mergeDeadlineTimeDate() {
const date = new Date(this.subtask.deadline)
const timeParts = this.subtask._deadline_time.split(':')
const date = new Date(this.subtask.deadline);
const timeParts = this.subtask._deadline_time.split(':');
date.setHours(parseInt(timeParts[0]))
date.setMinutes(parseInt(timeParts[1]))
date.setHours(parseInt(timeParts[0]));
date.setMinutes(parseInt(timeParts[1]));
return date
return date;
},
closeModal() {
this.form = {
date: null,
starts_at_time: '09:00',
ends_at_time: '16:00'
}
ends_at_time: '16:00',
};
this.showModal = false
this.$nextTick(() => this.v$.$reset())
}
}
}
this.showModal = false;
this.$nextTick(() => this.v$.$reset());
},
},
};
</script>
<style lang="sass">
@@ -4,14 +4,13 @@
<button @click="$emit('removeTimeblock')" class="x-button">x</button>
</div>
<div
@click="openDatepicker('datepicker')"
@click="handleDatepickerClick"
class="datepicker-wrapper"
ref="datepicker-wrapper"
:ref="`timeblock-datepicker-wrapper-${index}`"
>
<Datepicker
:model-value="timeblock.date"
ref="datepicker"
@open="onDateOpen"
:ref="`timeblock-datepicker-${index}`"
@update:model-value="updateDate"
format="dd.MM.yyyy"
locale="sk"
@@ -27,7 +26,6 @@
<v-text-field
:value="timeblock.starts_at_time"
@input="updateStartTime"
@focus="onInputFocus"
:class="{ error: v$?.timeblock.starts_at_time.$errors.length }"
type="time"
variant="solo"
@@ -37,7 +35,6 @@
<v-text-field
:value="timeblock.ends_at_time"
@input="updateEndTime"
@focus="onInputFocus"
:class="{ error: v$?.timeblock.ends_at_time.$errors.length }"
type="time"
variant="solo"
@@ -88,6 +85,10 @@ export default {
type: Function,
default: () => ({}),
},
index: {
type: Number,
},
},
data() {
@@ -106,23 +107,63 @@ export default {
},
methods: {
handleDatepickerClick() {
// Pass the datepicker wrapper element reference to the mixin
const scrollTarget =
this.$refs[`timeblock-datepicker-wrapper-${this.index}`];
this.onDateOpen(scrollTarget);
// Open the datepicker
this.openDatepicker(`timeblock-datepicker-${this.index}`);
setTimeout(() => {
const calendar = document.querySelector(
'.dp__menu.dp__menu_index.dp__theme_light',
);
if (!calendar) return;
// Get the datepicker wrapper element
const datepickerWrapper =
this.$refs[`timeblock-datepicker-wrapper-${this.index}`];
// Get the modal container
const modalContainer = document.querySelector('.v-overlay__content');
if (!datepickerWrapper || !modalContainer) return;
// Get bounding rectangles
const wrapperRect = datepickerWrapper.getBoundingClientRect();
const modalRect = modalContainer.getBoundingClientRect();
// Calculate position relative to modal
const topPosition =
wrapperRect.top - modalRect.top + wrapperRect.height;
const leftPosition = wrapperRect.left - modalRect.left;
// Apply positioning
// calendar.style.position = 'absolute';
calendar.style.top = `${topPosition + 210}px`;
// calendar.style.left = `${leftPosition}px`;
}, 100);
},
async openDatepicker(ref) {
this.$refs[ref].openMenu();
},
updateDate(date) {
const timeblock = { ...this.timeblock };
if (date) timeblock.date = date;
this.$emit('updateTimeblock', timeblock);
const updated = { ...this.timeblock, date };
this.$emit('updateTimeblock', updated);
},
updateStartTime(event) {
const timeblock = { ...this.timeblock };
timeblock.starts_at_time = event.target.value;
this.$emit('updateTimeblock', timeblock);
const updated = { ...this.timeblock, starts_at_time: event.target.value };
this.$emit('updateTimeblock', updated);
},
updateEndTime(event) {
const timeblock = { ...this.timeblock };
timeblock.ends_at_time = event.target.value;
this.$emit('updateTimeblock', timeblock);
const updated = { ...this.timeblock, ends_at_time: event.target.value };
this.$emit('updateTimeblock', updated);
},
},
};
@@ -158,4 +199,3 @@ export default {
width: 100% !important
pointer-events: none
</style>
e
@@ -2,23 +2,36 @@
<v-dialog v-model="visible" max-width="750" persistent>
<v-card>
<div class="d-flex justify-space-between align-center">
<h1>Ste si istý, že chcete {{ subtask.is_finished ? 'znovu otvoriť' : 'dokončiť' }} sub task, z mastertasku <b>{{ subtask?.master_task?.name || subtask.master_task }}</b>?</h1>
<h1>
Ste si istý, že chcete
{{ subtask.is_finished ? 'znovu otvoriť' : 'dokončiť' }} sub task, z
mastertasku
<b>{{ subtask?.master_task?.name || subtask.master_task }}</b
>?
</h1>
<v-icon
@click.stop="closeModal()"
icon="mdi-close"
size="large"
></v-icon>
</div>
<v-card-actions class="mt-10 d-flex justify-start align-center mobile-view">
<v-btn class="button primary half" variant="flat" @click="complete()">ÁNO</v-btn>
<v-btn class="button primary half outline" @click.stop="visible = false">ZRUŠIŤ</v-btn>
<v-card-actions
class="mt-10 d-flex justify-start align-center mobile-view"
>
<v-btn class="button primary half" variant="flat" @click="complete()"
>ÁNO</v-btn
>
<v-btn class="button primary half outline" @click.stop="visible = false"
>ZRUŠIŤ</v-btn
>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import moment from 'moment';
export default {
mixins: [modalMixin],
@@ -27,37 +40,75 @@ export default {
data() {
return {
visible: false,
subtask: null
}
subtask: null,
};
},
methods: {
async showModal({ subtask }) {
this.subtask = subtask
this.visible = true
this.subtask = subtask;
this.visible = true;
},
async complete() {
try {
const tempSubtask = {...this.subtask, is_finished: this.subtask.is_finished ? 0 : 1, timesheets: this.subtask.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
})}
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${tempSubtask.id}`, tempSubtask)
const timesheets = this.subtask.timesheets.map((timesheet) => {
delete timesheet.employee_name;
return timesheet;
});
this.visible = false
this.$emit('on-subtask-edited', subtask)
// Convert timeblocks from internal format to BE format
const timeblocks = (this.subtask.timeblocks || [])
.filter((timeblock) => {
// Filter timeblocks that have either old format (date) or new format (start)
return timeblock.date || timeblock.start;
})
.map((timeblock) => {
// If already in BE format (has start field), return as is
if (timeblock.start && !timeblock.date) {
return {
id: timeblock.id || null,
start: timeblock.start,
end: timeblock.end,
is_finished: timeblock.is_finished || 0,
};
}
// Convert from internal format to BE format
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
return {
id: timeblock.id || null,
start: `${dateStr} ${timeblock.starts_at_time}:00`,
end: `${dateStr} ${timeblock.ends_at_time}:00`,
is_finished: timeblock.is_finished || 0,
};
});
const tempSubtask = {
...this.subtask,
is_finished: this.subtask.is_finished ? 0 : 1,
timesheets,
timeblocks,
};
const { subtask } = await this.$axios.put_auth(
`v1/subtasks/${tempSubtask.id}`,
tempSubtask,
);
this.visible = false;
this.$emit('on-subtask-edited', subtask);
} catch (error) {
this.$toast.error(this.$parseError(error))
this.$toast.error(this.$parseError(error));
if (process.env.NODE_ENV === 'development')
console.log('[z-complete-task-modal.vue] Error: ', error)
console.log('[z-complete-task-modal.vue] Error: ', error);
}
},
closeModal() {
this.visible = false
}
}
}
this.visible = false;
},
},
};
</script>
@@ -10,17 +10,37 @@
size="large"
></v-icon>
</div>
<div v-for="(timeblock, index) in subtask.timeblocks" :key="timeblock.id" class="d-flex align-center justify-center mb-3 mt-3">
<p class="task-badge rounded-pill" :class="{'strike-through': timeblock.is_finished}">{{ tmUtils.formatDateTime(timeblock.start) }} - {{ tmUtils.formatDateTime(timeblock.end) }}</p>
<v-icon @click.stop="subtask.id ? deleteTimeblock(timeblock) : deleteTimeblockWithoutId(index)" class="close-icon circle-border cursor-pointer ml-3 text-red" icon="mdi-close" size="medium" />
<div
v-for="(timeblock, index) in subtask.timeblocks"
:key="timeblock.id"
class="d-flex align-center justify-center mb-3 mt-3"
>
<p
class="task-badge rounded-pill"
:class="{ 'strike-through': timeblock.is_finished }"
>
{{ tmUtils.formatDateTime(timeblock.start) }} -
{{ tmUtils.formatDateTime(timeblock.end) }}
</p>
<v-icon
@click.stop="
subtask.id
? deleteTimeblock(timeblock)
: deleteTimeblockWithoutId(index)
"
class="close-icon circle-border cursor-pointer ml-3 text-red"
icon="mdi-close"
size="medium"
/>
</div>
</v-card>
</v-dialog>
</template>
<script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import tmUtils from '@/plugins/tm@_utils/tm.utils'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import tmUtils from '@/plugins/tm@_utils/tm.utils';
import moment from 'moment';
export default {
mixins: [modalMixin],
@@ -31,52 +51,85 @@ export default {
visible: false,
subtask: null,
isDeleting: false,
tmUtils
}
tmUtils,
};
},
methods: {
async showModal({ subtask }) {
this.subtask = subtask
this.visible = true
this.subtask = subtask;
this.visible = true;
},
closeModal() {
this.visible = false
this.visible = false;
},
async deleteTimeblock({ id }) {
const subtask = JSON.parse(JSON.stringify(this.subtask))
subtask.timeblocks = subtask.timeblocks.filter(timeblock => timeblock.id != id)
if(subtask.deadline) subtask.deadline = tmUtils.formatDateTimeForBackend(subtask.deadline)
const subtask = JSON.parse(JSON.stringify(this.subtask));
subtask.timeblocks = subtask.timeblocks.filter(
(timeblock) => timeblock.id != id,
);
if (subtask.deadline)
subtask.deadline = tmUtils.formatDateTimeForBackend(subtask.deadline);
this._update(subtask)
this._update(subtask);
},
deleteTimeblockWithoutId(i) {
this.$emit('delete-timeblock')
this.$emit('delete-timeblock');
},
async _update(data) {
try {
const timesheets = data.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
delete timesheet.employee_name;
return timesheet;
});
// Convert timeblocks from internal format to BE format
const timeblocks = (data.timeblocks || [])
.filter((timeblock) => {
// Filter timeblocks that have either old format (date) or new format (start)
return timeblock.date || timeblock.start;
})
.map((timeblock) => {
// If already in BE format (has start field), return as is
if (timeblock.start && !timeblock.date) {
return {
id: timeblock.id || null,
start: timeblock.start,
end: timeblock.end,
is_finished: timeblock.is_finished || 0,
};
}
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${data.id}`, {...data, timesheets})
// Convert from internal format to BE format
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
return {
id: timeblock.id || null,
start: `${dateStr} ${timeblock.starts_at_time}:00`,
end: `${dateStr} ${timeblock.ends_at_time}:00`,
is_finished: timeblock.is_finished || 0,
};
});
this.closeModal()
this.$events.emit('on-subtask-edited', subtask)
const { subtask } = await this.$axios.put_auth(
`v1/subtasks/${data.id}`,
{ ...data, timesheets, timeblocks },
);
this.closeModal();
this.$events.emit('on-subtask-edited', subtask);
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development')
console.log('[z-delete-timeblock-modal.vue] Error: ', error)
console.log('[z-delete-timeblock-modal.vue] Error: ', error);
}
},
}
}
},
};
</script>
<style lang="sass" scoped>
@@ -4,10 +4,27 @@
<div class="d-flex justify-space-between align-center">
<h1>Pridať odpracovaný čas</h1>
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large"></v-icon>
<v-icon
@click.stop="closeModal()"
icon="mdi-close"
size="large"
></v-icon>
</div>
<v-card-actions class="mt-10 d-flex justify-start align-center">
<v-text-field v-model="form.hours" variant="solo" bg-color="white" type="number" :hint="v$.form.hours.$errors ? errorUtils.parseErrors(v$.form.hours.$errors) : null" :class="{ error: v$.form.hours.$errors.length }" class="mb-2" label="Odpracovaný čas" />
<v-text-field
v-model="form.hours"
variant="solo"
bg-color="white"
type="number"
:hint="
v$.form.hours.$errors
? errorUtils.parseErrors(v$.form.hours.$errors)
: null
"
:class="{ error: v$.form.hours.$errors.length }"
class="mb-2"
label="Odpracovaný čas"
/>
</v-card-actions>
<v-btn @click="submit()" class="button primary mt-5">Potvrdiť</v-btn>
</v-card>
@@ -15,11 +32,12 @@
</template>
<script>
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
import useVuelidate from '@vuelidate/core'
import { required, numeric, minValue } from '@vuelidate/validators'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import tmUtils from '@/plugins/tm@_utils/tm.utils'
import errorUtils from '@/plugins/lib@auth/_utils/error.utils';
import useVuelidate from '@vuelidate/core';
import { required, numeric, minValue } from '@vuelidate/validators';
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import tmUtils from '@/plugins/tm@_utils/tm.utils';
import moment from 'moment';
export default {
mixins: [modalMixin],
@@ -32,64 +50,102 @@ export default {
visible: false,
subtask: null,
form: {
hours: null
}
}
hours: null,
},
};
},
validations() {
return {
form: {
hours: {required, numeric, minValue: minValue(0.1)}
}
}
hours: { required, numeric, minValue: minValue(0.1) },
},
};
},
methods: {
async showModal({ subtask }) {
this.subtask = subtask
this.visible = true
this.form.hours = null
this.$nextTick(() => this.v$.$reset())
this.subtask = subtask;
this.visible = true;
this.form.hours = null;
this.$nextTick(() => this.v$.$reset());
},
async submit() {
if (!await this.v$.$validate())
return
if (!(await this.v$.$validate())) return;
if (this.subtask.deadline) this.subtask.deadline = tmUtils.formatDateTimeForBackend(this.subtask.deadline)
if (this.subtask.deadline)
this.subtask.deadline = tmUtils.formatDateTimeForBackend(
this.subtask.deadline,
);
this.subtask.timesheets.push({
id: null,
employee_id: this.subtask.employee_id,
time: typeof this.form.hours == 'string' ? parseFloat(this.form.hours) : this.form.hours
time:
typeof this.form.hours == 'string'
? parseFloat(this.form.hours)
: this.form.hours,
});
const timesheets = this.subtask.timesheets.map((timesheet) => {
delete timesheet.employee_name;
return timesheet;
});
// Convert timeblocks from internal format to BE format
const timeblocks = (this.subtask.timeblocks || [])
.filter((timeblock) => {
// Filter timeblocks that have either old format (date) or new format (start)
return timeblock.date || timeblock.start;
})
.map((timeblock) => {
// If already in BE format (has start field), return as is
if (timeblock.start && !timeblock.date) {
return {
id: timeblock.id || null,
start: timeblock.start,
end: timeblock.end,
is_finished: timeblock.is_finished || 0,
};
}
// Convert from internal format to BE format
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
return {
id: timeblock.id || null,
start: `${dateStr} ${timeblock.starts_at_time}:00`,
end: `${dateStr} ${timeblock.ends_at_time}:00`,
is_finished: timeblock.is_finished || 0,
};
});
const payload = {
...this.subtask,
timesheets: this.subtask.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
})
}
timesheets,
timeblocks,
};
try {
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${this.subtask.id}`, payload)
const { subtask } = await this.$axios.put_auth(
`v1/subtasks/${this.subtask.id}`,
payload,
);
this.closeModal()
this.$events.emit('on-subtask-edited', subtask)
this.closeModal();
this.$events.emit('on-subtask-edited', subtask);
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development')
console.log('[z-task-add-time-modal.vue] Error: ', error)
console.log('[z-task-add-time-modal.vue] Error: ', error);
}
},
closeModal() {
this.visible = false
this.v$.$reset()
}
}
}
this.visible = false;
this.v$.$reset();
},
},
};
</script>
+147 -64
View File
@@ -38,8 +38,8 @@
v-model="subtask.master_task_id"
label="Master task"
:class="{ error: v$.subtask.master_task_id.$errors.length }"
:items="mastertasks"
:item-title="(item) => item.name + ' [' + item.project_code + ']'"
:items="enrichedMastertasks"
:item-title="(item) => item._fullName || item.name"
item-value="id"
variant="solo"
class="modal-input"
@@ -234,70 +234,23 @@
</div>
</template>
<template v-if="!subtask.id">
<div class="timeblocks w-100">
<A-timeblock
v-for="(timeblock, index) in timeblocks"
v-for="(timeblock, index) in editableTimeblocks"
:key="index"
@updateTimeblock="(val) => updateTimeblock(val, index)"
@removeTimeblock="removeTimeblock(index)"
:timeblock="timeblock"
:deletable="index > 0"
editable
:editable="true"
:ref="`timetable-${index}`"
:prevent-input-focus="preventInputFocus"
:on-input-focus="onInputFocus"
:on-date-open="onDateOpen"
:index="index"
/>
<div class="end-button w-100">
<button
@click="
timeblocks.push({
date: null,
starts_at_time: null,
ends_at_time: null,
})
"
>
Pridať časový blok
</button>
</div>
</div>
</template>
<div
v-else
v-for="(timeblock, index) in subtask.timeblocks"
:key="index"
class="timeblock w-100"
>
<Datepicker
:model-value="timeblock.start.substring(0, 10)"
format="dd.MM.yyyy"
locale="sk"
select-text="Vybrať"
cancel-text="Zrušiť"
placeholder="Dátum"
:auto-apply="true"
:enable-time-picker="false"
readonly
class="mb-5 modal-input"
/>
<div class="splitted-time-inputs w-100">
<v-text-field
:value="timeblock.start.substring(11, 16)"
type="time"
variant="solo"
bg-color="white"
label="Začiatok"
/>
<v-text-field
:value="timeblock.end.substring(11, 16)"
type="time"
variant="solo"
bg-color="white"
label="Koniec"
/>
<div class="end-button w-100" v-if="!subtask.id">
<button @click="addTimeblock">Pridať časový blok</button>
</div>
</div>
@@ -397,7 +350,6 @@
<script>
import Datepicker from '@vuepic/vue-datepicker';
import ZFilesUpload from '@/plugins/tm@_components/z-files-upload.vue';
import ATaskTimeblocks from '@/plugins/tm@modal/task/_components/_components/a-task-timeblocks.vue';
import useVuelidate from '@vuelidate/core';
import { required, requiredIf, optional } from '@vuelidate/validators';
import errorUtils from '@/plugins/lib@auth/_utils/error.utils';
@@ -453,6 +405,33 @@ export default {
computed: {
...mapGetters('tm', ['mastertasks', 'enrichedEmployees']),
enrichedMastertasks() {
return this.mastertasks.map((mastertask) => ({
...mastertask,
_fullName: `${mastertask.name} [${mastertask.project_code}]`,
}));
},
// Unified timeblocks for both create and update modes
editableTimeblocks: {
get() {
if (this.subtask?.id) {
// Update mode: use subtask.timeblocks (from BE)
return this.subtask.timeblocks || [];
}
// Create mode: use this.timeblocks (local state)
return this.timeblocks;
},
set(value) {
if (this.subtask?.id) {
// Update mode: update subtask.timeblocks (Vue 3 reactivity)
this.subtask.timeblocks = value;
} else {
// Create mode: update this.timeblocks
this.timeblocks = value;
}
},
},
},
validations() {
@@ -487,10 +466,36 @@ export default {
data.deadline = splittedDeadline[0];
data._deadline_time = splittedDeadline[1];
// Convert BE format timeblocks to internal format
const convertedTimeblocks = [];
if (data.timeblocks && data.timeblocks.length > 0) {
data.timeblocks.forEach((timeblock) => {
// If already in internal format, keep as is
if (timeblock.date) {
convertedTimeblocks.push(timeblock);
return;
}
// Convert from BE format to internal format
if (timeblock.start && timeblock.end) {
const startMoment = moment(timeblock.start, 'YYYY-MM-DD HH:mm:ss');
const endMoment = moment(timeblock.end, 'YYYY-MM-DD HH:mm:ss');
convertedTimeblocks.push({
id: timeblock.id || null,
date: startMoment.toDate(),
starts_at_time: startMoment.format('HH:mm'),
ends_at_time: endMoment.format('HH:mm'),
is_finished: timeblock.is_finished || 0,
});
}
});
}
data.timeblocks = convertedTimeblocks;
this.subtask = this._enrichTask(data);
// TODO: Remove? riesil som neodstranovanie jedineho zanamu v trvani a odpracovanom case
console.log('2', this.subtask);
this.$forceUpdate();
});
@@ -514,11 +519,42 @@ export default {
},
updateTimeblock(val, index) {
if (this.subtask?.id) {
// Update mode: direct assignment (Vue 3 reactivity)
this.subtask.timeblocks[index] = val;
} else {
// Create mode: direct assignment
this.timeblocks[index] = val;
}
},
addTimeblock() {
const newTimeblock = {
date: null,
starts_at_time: null,
ends_at_time: null,
};
if (this.subtask?.id) {
// Update mode
if (!this.subtask.timeblocks) {
this.subtask.timeblocks = [];
}
this.subtask.timeblocks.push(newTimeblock);
} else {
// Create mode
this.timeblocks.push(newTimeblock);
}
},
removeTimeblock(index) {
if (this.subtask?.id) {
// Update mode
this.subtask.timeblocks.splice(index, 1);
} else {
// Create mode
this.timeblocks.splice(index, 1);
}
},
async showModal({ subtask, editMode = false, mastertask = {} }) {
@@ -543,6 +579,35 @@ export default {
`v1/subtasks/${subtask.id}`,
);
// Convert BE format timeblocks to internal format
const convertedTimeblocks = [];
if (data.timeblocks && data.timeblocks.length > 0) {
data.timeblocks.forEach((timeblock) => {
// If already in internal format, keep as is
if (timeblock.date) {
convertedTimeblocks.push(timeblock);
return;
}
// Convert from BE format to internal format
if (timeblock.start && timeblock.end) {
const startMoment = moment(
timeblock.start,
'YYYY-MM-DD HH:mm:ss',
);
const endMoment = moment(timeblock.end, 'YYYY-MM-DD HH:mm:ss');
convertedTimeblocks.push({
id: timeblock.id || null,
date: startMoment.toDate(),
starts_at_time: startMoment.format('HH:mm'),
ends_at_time: endMoment.format('HH:mm'),
is_finished: timeblock.is_finished || 0,
});
}
});
}
data.timeblocks = convertedTimeblocks;
if (!data.deadline) {
this.editMode = editMode || !data.id;
return (this.subtask = this._enrichTask(data));
@@ -618,9 +683,7 @@ export default {
async validateAllFields() {
const employeesValid = await this._validateEmployees();
const timeblocksValid = this.subtask?.id
? true
: await this._validateTimeblocks();
const timeblocksValid = await this._validateTimeblocks();
if (!(await this.v$.$validate())) return;
if (!employeesValid || !timeblocksValid) return;
@@ -655,9 +718,22 @@ export default {
return timesheet;
});
// Convert timeblocks from internal format to BE format for update
const timeblocks = (this.subtask.timeblocks || [])
.filter((timeblock) => timeblock.date) // Only send timeblocks with dates
.map((timeblock) => {
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
return {
id: timeblock.id || null,
start: `${dateStr} ${timeblock.starts_at_time}:00`,
end: `${dateStr} ${timeblock.ends_at_time}:00`,
is_finished: timeblock.is_finished || 0,
};
});
const { subtask } = await this.$axios.patch_auth_form(
`v1/subtasks/${this.subtask.id}`,
{ ...this.subtask, timesheets },
{ ...this.subtask, timesheets, timeblocks },
);
localStorage.removeItem('subtaskData');
@@ -803,12 +879,19 @@ export default {
},
async _validateTimeblocks() {
let invalid = false;
for (let i = 0; i < this.timeblocks.length; i++) {
let valid = true;
const timeblocks = this.editableTimeblocks;
for (let i = 0; i < timeblocks.length; i++) {
const ref = this.$refs[`timetable-${i}`];
invalid = (await ref[0].v$.$validate()) || invalid;
if (ref && ref[0]) {
const isValid = await ref[0].v$.$validate();
if (!isValid) {
valid = false;
}
return invalid;
}
}
return valid;
},
_enrichTask(subtask) {
@@ -12,23 +12,48 @@
</div>
<div class="card-content">
<div v-for="(timeblock) in subtask?.timeblocks" :key="timeblock.id" class="d-flex align-center mb-3">
<p class="task-badge rounded-pill" :class="{'strike-through': timeblock.is_finished}">{{ tmUtils.formatDateTime(timeblock.start) }} - {{ tmUtils.formatDateTime(timeblock.end) }}</p>
<v-icon @click.stop="handleFinishTimeblock(timeblock)" class="finish-icon circle-border cursor-pointer ml-2" :class="{'disabled': loadingTimeblocks[timeblock.id] || loadingCloseAll, 'finished': timeblock.is_finished}" icon="mdi-check" size="medium" />
<div
v-for="timeblock in subtask?.timeblocks"
:key="timeblock.id"
class="d-flex align-center mb-3"
>
<p
class="task-badge rounded-pill"
:class="{ 'strike-through': timeblock.is_finished }"
>
{{ tmUtils.formatDateTime(timeblock.start) }} -
{{ tmUtils.formatDateTime(timeblock.end) }}
</p>
<v-icon
@click.stop="handleFinishTimeblock(timeblock)"
class="finish-icon circle-border cursor-pointer ml-2"
:class="{
disabled: loadingTimeblocks[timeblock.id] || loadingCloseAll,
finished: timeblock.is_finished,
}"
icon="mdi-check"
size="medium"
/>
</div>
</div>
<div class="card-actions">
<v-btn @click="closeModal()" class="button secondary">Zrušiť</v-btn>
<v-btn @click="handleFinishAllTimeblocks()" :loading="loadingCloseAll" class="button primary">Uzatvoriť všetky</v-btn>
<v-btn
@click="handleFinishAllTimeblocks()"
:loading="loadingCloseAll"
class="button primary"
>Uzatvoriť všetky</v-btn
>
</div>
</v-card>
</v-dialog>
</template>
<script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'
import tmUtils from '@/plugins/tm@_utils/tm.utils'
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import tmUtils from '@/plugins/tm@_utils/tm.utils';
import moment from 'moment';
export default {
mixins: [modalMixin],
@@ -37,8 +62,8 @@ export default {
props: {
mode: {
type: String,
default: 'edit' // edit or delete
}
default: 'edit', // edit or delete
},
},
data() {
@@ -47,88 +72,130 @@ export default {
visible: false,
subtask: null,
loadingTimeblocks: {},
loadingCloseAll: false
}
loadingCloseAll: false,
};
},
methods: {
async showModal({ subtask }) {
this.subtask = subtask
this.visible = true
this.subtask = subtask;
this.visible = true;
},
async complete() {
console.log('complete')
console.log('complete');
},
closeModal() {
this.visible = false
this.visible = false;
},
async handleFinishTimeblock(timeblock) {
const subtask = JSON.parse(JSON.stringify(this.subtask))
const subtask = JSON.parse(JSON.stringify(this.subtask));
try {
this.loadingTimeblocks[timeblock.id] = true
await this.$axios.put_auth(`v1/timeblocks/${timeblock.id}`, {...timeblock, is_finished: 1})
timeblock.is_finished = 1
this.loadingTimeblocks[timeblock.id] = true;
await this.$axios.put_auth(`v1/timeblocks/${timeblock.id}`, {
...timeblock,
is_finished: 1,
});
timeblock.is_finished = 1;
const areAllTimeblocksFinished = subtask.timeblocks.every(timeblock => timeblock.is_finished)
const areAllTimeblocksFinished = subtask.timeblocks.every(
(timeblock) => timeblock.is_finished,
);
if (areAllTimeblocksFinished) {
await this._finishSubtask()
this.$store.dispatch('tm/removeOngoingSubtask', this.subtask.id)
await this._finishSubtask();
this.$store.dispatch('tm/removeOngoingSubtask', this.subtask.id);
}
this.$events.emit('on-subtask-edited', subtask)
this.closeModal()
this.$events.emit('on-subtask-edited', subtask);
this.closeModal();
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development')
console.log('[a-task-timeblocks.vue] Error: ', error)
console.log('[a-task-timeblocks.vue] Error: ', error);
} finally {
this.loadingTimeblocks[timeblock.id] = false
this.loadingTimeblocks[timeblock.id] = false;
}
},
async handleFinishAllTimeblocks() {
this.loadingCloseAll = true
this.loadingCloseAll = true;
try {
const promises = this.subtask.timeblocks.map(timeblock => {
return this.$axios.put_auth(`v1/timeblocks/${timeblock.id}`, {...timeblock, is_finished: 1})
})
const promises = this.subtask.timeblocks.map((timeblock) => {
return this.$axios.put_auth(`v1/timeblocks/${timeblock.id}`, {
...timeblock,
is_finished: 1,
});
});
await Promise.all(promises)
await Promise.all(promises);
this.subtask.timeblocks = this.subtask.timeblocks.map(timeblock => {
timeblock.is_finished = 1
return timeblock
})
this.subtask.timeblocks = this.subtask.timeblocks.map((timeblock) => {
timeblock.is_finished = 1;
return timeblock;
});
await this._finishSubtask()
await this._finishSubtask();
this.$store.dispatch('tm/removeOngoingSubtask', this.subtask.id)
this.$events.emit('on-subtask-edited', this.subtask)
this.closeModal()
this.$store.dispatch('tm/removeOngoingSubtask', this.subtask.id);
this.$events.emit('on-subtask-edited', this.subtask);
this.closeModal();
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
} finally {
this.loadingCloseAll = false
this.loadingCloseAll = false;
}
},
async _finishSubtask() {
const tempSubtask = {...this.subtask, is_finished: 1, timesheets: this.subtask.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
})}
const timesheets = this.subtask.timesheets.map((timesheet) => {
delete timesheet.employee_name;
return timesheet;
});
return this.$axios.put_auth(`v1/subtasks/${tempSubtask.id}`, tempSubtask)
}
}
// Convert timeblocks from internal format to BE format
const timeblocks = (this.subtask.timeblocks || [])
.filter((timeblock) => {
// Filter timeblocks that have either old format (date) or new format (start)
return timeblock.date || timeblock.start;
})
.map((timeblock) => {
// If already in BE format (has start field), return as is
if (timeblock.start && !timeblock.date) {
return {
id: timeblock.id || null,
start: timeblock.start,
end: timeblock.end,
is_finished: timeblock.is_finished || 0,
};
}
// Convert from internal format to BE format
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
return {
id: timeblock.id || null,
start: `${dateStr} ${timeblock.starts_at_time}:00`,
end: `${dateStr} ${timeblock.ends_at_time}:00`,
is_finished: timeblock.is_finished || 0,
};
});
const tempSubtask = {
...this.subtask,
is_finished: 1,
timesheets,
timeblocks,
};
return this.$axios.put_auth(`v1/subtasks/${tempSubtask.id}`, tempSubtask);
},
},
};
</script>
<style lang="scss" scoped>
@@ -2,7 +2,9 @@
<v-table>
<thead>
<tr>
<th @click="getSelectedTimeblockDeadline" class="text-left">Kód projektu</th>
<th @click="getSelectedTimeblockDeadline" class="text-left">
Kód projektu
</th>
<th class="text-left">Názov</th>
<th class="text-left">Deadline</th>
<th class="text-left">Najbližší neuzavretý</th>
@@ -13,13 +15,20 @@
</thead>
<tbody>
<tr class="cursor-pointer" v-for="subtask in subtasks" :key="subtask.id" @click.stop="editTask(subtask, false)">
<tr
class="cursor-pointer"
v-for="subtask in subtasks"
:key="subtask.id"
@click.stop="editTask(subtask, false)"
>
<td>{{ subtask.project_code }}</td>
<td>{{ subtask.title ?? subtask.master_task }}</td>
<td v-if="subtask.deadline">{{ getDeadline(subtask) }}</td>
<v-tooltip text="Deadline z Mastertasku" location="end">
<template v-slot:activator="{ props }">
<td v-if="!subtask.deadline" v-bind="props">{{ getDeadline(subtask) }}*</td>
<td v-if="!subtask.deadline" v-bind="props">
{{ getDeadline(subtask) }}*
</td>
</template>
</v-tooltip>
<td>{{ displayTimeblock(subtask) }}</td>
@@ -28,38 +37,53 @@
<td class="task-action">
<div class="d-flex justify-start align-center">
<img class="pencil-icon mr-3" :class="{'disabled': loadingSubtask[subtask.id]}" :src="checkmarkDouble" @click.stop="handleCompleteTask(subtask)">
<img
class="pencil-icon mr-3"
:class="{ disabled: loadingSubtask[subtask.id] }"
:src="checkmarkDouble"
@click.stop="handleCompleteTask(subtask)"
/>
<template v-if="subtask.type == 'office365'">
<img class="pencil-icon" :src="eye" @click.stop="editTask(subtask, false)">
<img
class="pencil-icon"
:src="eye"
@click.stop="editTask(subtask, false)"
/>
<img class="office-icon" :src="office365" />
</template>
<template v-else>
<img class="pencil-icon" :src="eye" @click.stop="editTask(subtask, false)">
<img class="trash-icon" :src="bin" @click.stop="deleteTask(subtask)" />
<img
class="pencil-icon"
:src="eye"
@click.stop="editTask(subtask, false)"
/>
<img
class="trash-icon"
:src="bin"
@click.stop="deleteTask(subtask)"
/>
</template>
</div>
</td>
</tr>
</tbody>
</v-table>
</template>
<script>
import { bin, eye, office365, checkmarkDouble } from '@/plugins/app/_img'
import { bin, eye, office365, checkmarkDouble } from '@/plugins/app/_img';
import { mapGetters } from 'vuex'
import moment from 'moment'
import { mapGetters } from 'vuex';
import moment from 'moment';
export default {
props: {
subtasks: {
type: Array,
required: true
}
required: true,
},
},
data() {
@@ -68,87 +92,135 @@ export default {
bin,
office365,
checkmarkDouble,
loadingSubtask: {}
}
loadingSubtask: {},
};
},
computed: {
...mapGetters('tm', ['mastertasks'])
...mapGetters('tm', ['mastertasks']),
},
methods: {
editTask(subtask, editMode = false) {
this.$events.emit('show-subtask-modal', {subtask, editMode})
this.$events.emit('show-subtask-modal', { subtask, editMode });
},
async handleCompleteTask(subtask) {
const areAllTimeBlocksFinished = subtask.timeblocks.every(tb => tb.is_finished)
const areAllTimeBlocksFinished = subtask.timeblocks.every(
(tb) => tb.is_finished,
);
if (!areAllTimeBlocksFinished) {
this.$events.emit('show-unable-to-complete-task-modal', { subtask })
this.$events.emit('show-unable-to-complete-task-modal', { subtask });
} else {
await this._finishSubtask(subtask)
await this._finishSubtask(subtask);
}
},
deleteTask(subtask) {
if (subtask.type == 'office365')
return this.$events.emit('show-unable-to-edit-office-task-modal', { mode: 'delete' })
return this.$events.emit('show-unable-to-edit-office-task-modal', {
mode: 'delete',
});
this.$events.emit('show-delete-task-modal', {subtask})
this.$events.emit('show-delete-task-modal', { subtask });
},
getDeadline(subtask) {
if (subtask?.deadline)
return moment(subtask.deadline).format('DD.MM.yyyy')
return moment(subtask.deadline).format('DD.MM.yyyy');
return moment(subtask.master_task_deadline).format('DD.MM.yyyy')
return moment(subtask.master_task_deadline).format('DD.MM.yyyy');
},
getSelectedTimeblockDeadline(timeblocks) {
const currentDate = moment()
const currentDate = moment();
const unfinishedTimeblocks = timeblocks.filter(tb => tb.is_finished === 0)
if (unfinishedTimeblocks.length > 0) return moment(unfinishedTimeblocks[0].end).format('DD.MM.yyyy, HH:mm')
const unfinishedTimeblocks = timeblocks.filter(
(tb) => tb.is_finished === 0,
);
if (unfinishedTimeblocks.length > 0)
return moment(unfinishedTimeblocks[0].end).format('DD.MM.yyyy, HH:mm');
const upcomingTimeblocks = timeblocks
.filter(tb => moment(tb.end).isAfter(currentDate))
.sort((a, b) => moment(a.end).diff(moment(b.end)))
.filter((tb) => moment(tb.end).isAfter(currentDate))
.sort((a, b) => moment(a.end).diff(moment(b.end)));
if (upcomingTimeblocks.length > 0 && upcomingTimeblocks.is_finished === 0) return moment(upcomingTimeblocks[0].end).format('DD.MM.yyyy, HH:mm')
if (upcomingTimeblocks.length > 0 && upcomingTimeblocks.is_finished === 0)
return moment(upcomingTimeblocks[0].end).format('DD.MM.yyyy, HH:mm');
return ''
return '';
},
displayTimeblock(subtask) {
const timeblockDeadline = this.getSelectedTimeblockDeadline(subtask.timeblocks)
const timeblockDeadline = this.getSelectedTimeblockDeadline(
subtask.timeblocks,
);
return timeblockDeadline !== '' ? timeblockDeadline : 'Žiadny termín'
return timeblockDeadline !== '' ? timeblockDeadline : 'Žiadny termín';
},
async _finishSubtask(subtask) {
const tempSubtask = {...subtask, is_finished: 1, timesheets: subtask?.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
}) || []}
const timesheets =
subtask?.timesheets.map((timesheet) => {
delete timesheet.employee_name;
return timesheet;
}) || [];
// Convert timeblocks from internal format to BE format
const timeblocks = (subtask.timeblocks || [])
.filter((timeblock) => {
// Filter timeblocks that have either old format (date) or new format (start)
return timeblock.date || timeblock.start;
})
.map((timeblock) => {
// If already in BE format (has start field), return as is
if (timeblock.start && !timeblock.date) {
return {
id: timeblock.id || null,
start: timeblock.start,
end: timeblock.end,
is_finished: timeblock.is_finished || 0,
};
}
// Convert from internal format to BE format
const dateStr = moment(timeblock.date).format('YYYY-MM-DD');
return {
id: timeblock.id || null,
start: `${dateStr} ${timeblock.starts_at_time}:00`,
end: `${dateStr} ${timeblock.ends_at_time}:00`,
is_finished: timeblock.is_finished || 0,
};
});
const tempSubtask = {
...subtask,
is_finished: 1,
timesheets,
timeblocks,
};
try {
this.loadingSubtask[subtask.id] = true
await this.$axios.put_auth(`v1/subtasks/${tempSubtask.id}`, tempSubtask)
this.loadingSubtask[subtask.id] = true;
await this.$axios.put_auth(
`v1/subtasks/${tempSubtask.id}`,
tempSubtask,
);
this.$store.dispatch('tm/removeOngoingSubtask', subtask.id)
this.$events.emit('on-subtask-edited', subtask)
this.$store.dispatch('tm/removeOngoingSubtask', subtask.id);
this.$events.emit('on-subtask-edited', subtask);
} catch (error) {
this.$toast.error(error.message || error)
this.$toast.error(error.message || error);
if (process.env.NODE_ENV === 'development')
console.log('[a-ongoing-table.vue] Error: ', error)
console.log('[a-ongoing-table.vue] Error: ', error);
} finally {
this.loadingSubtask[subtask.id] = false
}
}
}
this.loadingSubtask[subtask.id] = false;
}
},
},
};
</script>
<style lang="sass" scoped>