feat(modal): enhance modal functionality with resizing support and improved layout

This commit is contained in:
Matej Glasnák committed 2026-01-07 09:15:52 +01:00
1 parent 54e12a1713
commit 9c32c0d99f
23 files changed
+416 -178

No files matched your search

@@ -2,9 +2,7 @@
<v-table> <v-table>
<thead> <thead>
<tr> <tr>
<th class="text-left"> <th class="text-left">Kód projektu</th>
Kód projektu
</th>
<th class="text-left">Názov</th> <th class="text-left">Názov</th>
<th class="text-left">Deadline</th> <th class="text-left">Deadline</th>
<th class="text-left">Najbližší neuzavretý</th> <th class="text-left">Najbližší neuzavretý</th>
@@ -36,7 +34,7 @@
<td>{{ (subtask.duration - subtask.spent_time).toFixed(2) }} h</td> <td>{{ (subtask.duration - subtask.spent_time).toFixed(2) }} h</td>
<td class="task-action"> <td class="task-action">
<div class="d-flex justify-start align-center"> <div class="d-flex justify-start align-center" style="gap: 10px">
<template v-if="subtask.type == 'office365'"> <template v-if="subtask.type == 'office365'">
<img <img
class="pencil-icon" class="pencil-icon"
@@ -58,7 +56,7 @@
@click.stop="editTask(subtask, false)" @click.stop="editTask(subtask, false)"
/> />
<img <img
class="trash-icon" class="trash-icon ml-0"
:src="bin" :src="bin"
@click.stop="deleteTask(subtask)" @click.stop="deleteTask(subtask)"
/> />
@@ -176,4 +174,3 @@ tbody
tr:hover tr:hover
background: rgba(0,0,0,.1) background: rgba(0,0,0,.1)
</style> </style>
+42 -36
View File
@@ -1,38 +1,39 @@
import modalResizeUtils from '@/plugins/tm@modal/_utils/modal-resize.utils' import modalResizeUtils from '@/plugins/tm@modal/_utils/modal-resize.utils';
export default { export default {
data() { data() {
return { return {
modalWidth: '100%', modalWidth: undefined, // Should be set by component
modalHeight: '100%', modalHeight: undefined, // Should be set by component
modalName: '' // Should be set by component modalName: '', // Should be set by component
} modalSize: 'medium' as 'small' | 'medium' | 'large', // Size preset: small, medium, or large
};
}, },
computed: { computed: {
modalWidthPx() { modalWidthPx() {
return this.modalWidth return this.modalWidth;
}, },
modalHeightPx() { modalHeightPx() {
return this.modalHeight return this.modalHeight;
} },
}, },
mounted() { mounted() {
window.addEventListener('keydown', this.handleKeyDown) window.addEventListener('keydown', this.handleKeyDown);
window.addEventListener('resize', this.handleWindowResize) window.addEventListener('resize', this.handleWindowResize);
this.initModalSize() this.initModalSize();
}, },
beforeUnmount() { beforeUnmount() {
window.removeEventListener('keydown', this.handleKeyDown) window.removeEventListener('keydown', this.handleKeyDown);
window.removeEventListener('resize', this.handleWindowResize) window.removeEventListener('resize', this.handleWindowResize);
}, },
methods: { methods: {
handleKeyDown(event) { handleKeyDown(event) {
// if (event.keyCode === 27) this.closeModal() // if (event.keyCode === 27) this.closeModal()
if (event.keyCode === 27) this.visible = false if (event.keyCode === 27) this.visible = false;
}, },
/** /**
@@ -40,13 +41,18 @@ export default {
*/ */
initModalSize() { initModalSize() {
if (!this.modalName) { if (!this.modalName) {
console.warn('Modal name not set for resize functionality') console.warn('Modal name not set for resize functionality');
return return;
} }
const size = modalResizeUtils.getModalSize(this.modalName) const size = modalResizeUtils.getModalSize(
this.modalWidth = typeof size.width === 'number' ? `${size.width}px` : size.width this.modalName,
this.modalHeight = typeof size.height === 'number' ? `${size.height}px` : size.height this.modalSize,
);
this.modalWidth =
typeof size.width === 'number' ? `${size.width}px` : size.width;
this.modalHeight =
typeof size.height === 'number' ? `${size.height}px` : size.height;
}, },
/** /**
@@ -54,11 +60,11 @@ export default {
*/ */
handleWindowResize() { handleWindowResize() {
if (modalResizeUtils.isMobile()) { if (modalResizeUtils.isMobile()) {
this.modalWidth = '100%' this.modalWidth = '100%';
this.modalHeight = '100%' this.modalHeight = '100%';
} else { } else {
// Reload stored or default size on desktop // Reload stored or default size on desktop
this.initModalSize() this.initModalSize();
} }
}, },
@@ -67,12 +73,12 @@ export default {
*/ */
handleModalResize({ width, height }) { handleModalResize({ width, height }) {
if (modalResizeUtils.isMobile()) { if (modalResizeUtils.isMobile()) {
return // Don't resize on mobile return; // Don't resize on mobile
} }
const constrained = modalResizeUtils.constrainSize(width, height) const constrained = modalResizeUtils.constrainSize(width, height);
this.modalWidth = `${constrained.width}px` this.modalWidth = `${constrained.width}px`;
this.modalHeight = `${constrained.height}px` this.modalHeight = `${constrained.height}px`;
}, },
/** /**
@@ -80,15 +86,15 @@ export default {
*/ */
handleResizeEnd() { handleResizeEnd() {
if (!this.modalName || modalResizeUtils.isMobile()) { if (!this.modalName || modalResizeUtils.isMobile()) {
return return;
} }
// Parse current dimensions // Parse current dimensions
const width = parseFloat(this.modalWidth) const width = parseFloat(this.modalWidth);
const height = parseFloat(this.modalHeight) const height = parseFloat(this.modalHeight);
if (!isNaN(width) && !isNaN(height)) { if (!isNaN(width) && !isNaN(height)) {
modalResizeUtils.saveSize(this.modalName, width, height) modalResizeUtils.saveSize(this.modalName, width, height);
} }
}, },
@@ -97,11 +103,11 @@ export default {
*/ */
resetModalSize() { resetModalSize() {
if (!this.modalName) { if (!this.modalName) {
return return;
} }
modalResizeUtils.resetSize(this.modalName) modalResizeUtils.resetSize(this.modalName);
this.initModalSize() this.initModalSize();
} },
} },
} };
@@ -1,49 +1,69 @@
interface ModalSize { interface ModalSize {
width: string | number width: string | number;
height: string | number height: string | number;
} }
interface StoredModalSize { interface StoredModalSize {
width: number width: number;
height: number height: number;
timestamp: number timestamp: number;
} }
const MOBILE_BREAKPOINT = 768 const MOBILE_BREAKPOINT = 768;
const DEFAULT_DESKTOP_WIDTH_PERCENT = 80
const DEFAULT_DESKTOP_MAX_WIDTH = 1440 // Size presets
const DEFAULT_DESKTOP_HEIGHT_PERCENT = 90 const SIZE_PRESETS = {
small: {
width: 600,
height: 'fit-content',
maxWidth: 600,
},
medium: {
width: 900,
height: 'fit-content',
maxWidth: 900,
},
large: {
width: '75%',
height: '90%',
maxWidth: '85%',
},
};
export default { export default {
/** /**
* Check if the current viewport is mobile * Check if the current viewport is mobile
*/ */
isMobile(): boolean { isMobile(): boolean {
return window.innerWidth <= MOBILE_BREAKPOINT return window.innerWidth <= MOBILE_BREAKPOINT;
}, },
/** /**
* Get default modal size based on viewport * Get default modal size based on viewport and size preset
*/ */
getDefaultSize(): ModalSize { getDefaultSize(size: 'small' | 'medium' | 'large' = 'medium'): ModalSize {
if (this.isMobile()) { if (this.isMobile()) {
return { return {
width: '100%', width: '100%',
height: '100%' height: '100%',
} };
} }
const viewportWidth = window.innerWidth const preset = SIZE_PRESETS[size];
const calculatedWidth = Math.min(
(viewportWidth * DEFAULT_DESKTOP_WIDTH_PERCENT) / 100,
DEFAULT_DESKTOP_MAX_WIDTH
)
const calculatedHeight = (window.innerHeight * DEFAULT_DESKTOP_HEIGHT_PERCENT) / 100
// For large size, use percentages; for small/medium use fixed px values
if (size === 'large') {
return { return {
width: calculatedWidth, width: preset.width,
height: calculatedHeight height: preset.height,
};
} }
// For small and medium, return the px values directly
return {
width: preset.width,
height: preset.height,
};
}, },
/** /**
@@ -51,27 +71,31 @@ export default {
*/ */
getStoredSize(modalName: string): ModalSize | null { getStoredSize(modalName: string): ModalSize | null {
try { try {
const key = `modal-size-${modalName}` const key = `modal-size-${modalName}`;
const stored = localStorage.getItem(key) const stored = localStorage.getItem(key);
if (!stored) { if (!stored) {
return null return null;
} }
const parsed: StoredModalSize = JSON.parse(stored) const parsed: StoredModalSize = JSON.parse(stored);
// Return stored size if it exists and is valid // Return stored size if it exists and is valid
if (parsed && typeof parsed.width === 'number' && typeof parsed.height === 'number') { if (
parsed &&
typeof parsed.width === 'number' &&
typeof parsed.height === 'number'
) {
return { return {
width: parsed.width, width: parsed.width,
height: parsed.height height: parsed.height,
} };
} }
return null return null;
} catch (error) { } catch (error) {
console.error('Error reading stored modal size:', error) console.error('Error reading stored modal size:', error);
return null return null;
} }
}, },
@@ -80,15 +104,15 @@ export default {
*/ */
saveSize(modalName: string, width: number, height: number): void { saveSize(modalName: string, width: number, height: number): void {
try { try {
const key = `modal-size-${modalName}` const key = `modal-size-${modalName}`;
const data: StoredModalSize = { const data: StoredModalSize = {
width, width,
height, height,
timestamp: Date.now() timestamp: Date.now(),
} };
localStorage.setItem(key, JSON.stringify(data)) localStorage.setItem(key, JSON.stringify(data));
} catch (error) { } catch (error) {
console.error('Error saving modal size:', error) console.error('Error saving modal size:', error);
} }
}, },
@@ -97,33 +121,36 @@ export default {
*/ */
resetSize(modalName: string): void { resetSize(modalName: string): void {
try { try {
const key = `modal-size-${modalName}` const key = `modal-size-${modalName}`;
localStorage.removeItem(key) localStorage.removeItem(key);
} catch (error) { } catch (error) {
console.error('Error resetting modal size:', error) console.error('Error resetting modal size:', error);
} }
}, },
/** /**
* Get modal size (stored or default) * Get modal size (stored or default)
*/ */
getModalSize(modalName: string): ModalSize { getModalSize(
modalName: string,
size: 'small' | 'medium' | 'large' = 'medium',
): ModalSize {
// On mobile, always return 100% // On mobile, always return 100%
if (this.isMobile()) { if (this.isMobile()) {
return { return {
width: '100%', width: '100%',
height: '100%' height: '100%',
} };
} }
// Check for stored size // Check for stored size
const storedSize = this.getStoredSize(modalName) const storedSize = this.getStoredSize(modalName);
if (storedSize) { if (storedSize) {
return storedSize return storedSize;
} }
// Return default size // Return default size based on preset
return this.getDefaultSize() return this.getDefaultSize(size);
}, },
/** /**
@@ -131,32 +158,34 @@ export default {
*/ */
normalizeSize(size: string | number): number { normalizeSize(size: string | number): number {
if (typeof size === 'number') { if (typeof size === 'number') {
return size return size;
} }
// If it's a percentage, calculate pixel value // If it's a percentage, calculate pixel value
if (size.includes('%')) { if (size.includes('%')) {
const percent = parseFloat(size) const percent = parseFloat(size);
return (window.innerWidth * percent) / 100 return (window.innerWidth * percent) / 100;
} }
// If it's already pixels, parse it // If it's already pixels, parse it
return parseFloat(size) return parseFloat(size);
}, },
/** /**
* Constrain size within reasonable bounds * Constrain size within reasonable bounds
*/ */
constrainSize(width: number, height: number): { width: number; height: number } { constrainSize(
const minWidth = 400 width: number,
const minHeight = 300 height: number,
const maxWidth = window.innerWidth ): { width: number; height: number } {
const maxHeight = window.innerHeight const minWidth = 400;
const minHeight = 300;
const maxWidth = window.innerWidth;
const maxHeight = window.innerHeight;
return { return {
width: Math.max(minWidth, Math.min(width, maxWidth)), width: Math.max(minWidth, Math.min(width, maxWidth)),
height: Math.max(minHeight, Math.min(height, maxHeight)) height: Math.max(minHeight, Math.min(height, maxHeight)),
} };
} },
} };
@@ -7,14 +7,17 @@
:retain-focus="false" :retain-focus="false"
> >
<W-loadable :content="blocker" class="h-100"> <W-loadable :content="blocker" class="h-100">
<v-card height="100%" class="d-flex flex-column"> <v-card
style="position: relative; height: 100%"
class="d-flex flex-column"
>
<div class="d-flex justify-space-between align-center modal-header"> <div class="d-flex justify-space-between align-center modal-header">
<h1>{{ blocker.id ? 'Upraviť' : 'Vytvoriť' }} blocker</h1> <h1>{{ blocker.id ? 'Upraviť' : 'Vytvoriť' }} blocker</h1>
<v-icon
icon="mdi-close" <div class="d-flex align-center">
size="large" <a-reset-size-button @reset="resetModalSize" />
@click.stop="closeModal()" <a-close-button @close="closeModal()" />
></v-icon> </div>
</div> </div>
<v-card-actions class="d-flex flex-column modal-content"> <v-card-actions class="d-flex flex-column modal-content">
@@ -92,6 +95,12 @@
<v-btn class="button primary" @click="save()">{{ <v-btn class="button primary" @click="save()">{{
blocker.id ? 'UPRAVIŤ' : 'VYTVORIŤ' blocker.id ? 'UPRAVIŤ' : 'VYTVORIŤ'
}}</v-btn> }}</v-btn>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</W-loadable> </W-loadable>
</v-dialog> </v-dialog>
@@ -106,11 +115,17 @@ import { mapGetters } from 'vuex';
import moment from 'moment'; import moment from 'moment';
import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin'; import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin';
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
ZDatepicker, ZDatepicker,
// ZAutocomplete // ZAutocomplete
AResizeHandle,
AResetSizeButton,
ACloseButton,
}, },
mixins: [AutocompleteMixin, modalMixin], mixins: [AutocompleteMixin, modalMixin],
@@ -126,6 +141,8 @@ export default {
starts_at_time: null, starts_at_time: null,
ends_at_time: null, ends_at_time: null,
employee: null, employee: null,
modalName: 'z-blocker-modal',
modalSize: 'large',
}; };
}, },
@@ -6,14 +6,14 @@
persistent persistent
:retain-focus="false" :retain-focus="false"
> >
<v-card style="position: relative"> <v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1> <h1>
Ste si istý, že chcete zmazať <b>{{ blocker.name }}</b Ste si istý, že chcete zmazať <b>{{ blocker.name }}</b
>? >?
</h1> </h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" /> <a-reset-size-button @reset="resetModalSize" />
<a-close-button class="mb-15" @close="closeModal()" /> <a-close-button class="mb-15" @close="closeModal()" />
</div> </div>
@@ -63,6 +63,7 @@ export default {
blocker: null, blocker: null,
isDeleting: false, isDeleting: false,
modalName: 'z-delete-blocker-modal', modalName: 'z-delete-blocker-modal',
modalSize: 'small',
}; };
}, },
@@ -6,7 +6,7 @@
persistent persistent
:retain-focus="false" :retain-focus="false"
> >
<v-card style="position: relative"> <v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1> <h1>
Ste si istý, že chcete Ste si istý, že chcete
@@ -14,7 +14,7 @@
<b>{{ mastertask?.name }}</b <b>{{ mastertask?.name }}</b
>? >?
</h1> </h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" /> <a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="() => (visible = false)" /> <a-close-button @close="() => (visible = false)" />
</div> </div>
@@ -59,6 +59,7 @@ export default {
visible: false, visible: false,
mastertask: null, mastertask: null,
modalName: 'z-complete-master-task-modal', modalName: 'z-complete-master-task-modal',
modalSize: 'small',
}; };
}, },
@@ -6,14 +6,14 @@
persistent persistent
:retain-focus="false" :retain-focus="false"
> >
<v-card style="position: relative"> <v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1> <h1>
Ste si istý, že chcete zmazať <b>{{ mastertask.name }}</b Ste si istý, že chcete zmazať <b>{{ mastertask.name }}</b
>? >?
</h1> </h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" /> <a-reset-size-button @reset="resetModalSize" />
<a-close-button class="mb-15" @close="closeModal()" /> <a-close-button class="mb-15" @close="closeModal()" />
</div> </div>
@@ -63,6 +63,7 @@ export default {
mastertask: null, mastertask: null,
isDeleting: false, isDeleting: false,
modalName: 'z-delete-master-task-modal', modalName: 'z-delete-master-task-modal',
modalSize: 'small',
}; };
}, },
@@ -6,10 +6,10 @@
persistent persistent
:retain-focus="false" :retain-focus="false"
> >
<v-card style="position: relative"> <v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1 class="text-h5">Chcete túto osobu odstrániť z tímu?</h1> <h1 class="text-h5">Chcete túto osobu odstrániť z tímu?</h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" /> <a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="closeModal()" /> <a-close-button @close="closeModal()" />
</div> </div>
@@ -58,6 +58,7 @@ export default {
member: null, member: null,
team: null, team: null,
modalName: 'z-delete-team-member-modal', modalName: 'z-delete-team-member-modal',
modalSize: 'small',
}; };
}, },
@@ -9,9 +9,8 @@
<W-loadable :content="mastertask" class="h-100"> <W-loadable :content="mastertask" class="h-100">
<v-card <v-card
v-if="editMode" v-if="editMode"
height="100%" style="position: relative; height: 100%"
class="d-flex flex-column scrolling" class="d-flex flex-column scrolling"
style="position: relative"
> >
<div class="d-flex justify-space-between align-center modal-header"> <div class="d-flex justify-space-between align-center modal-header">
<h1> <h1>
@@ -249,9 +248,8 @@
<v-card <v-card
v-else v-else
height="100%" style="position: relative; height: 100%"
class="d-flex flex-column scrolling" class="d-flex flex-column scrolling"
style="position: relative"
> >
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<p>{{ mastertask.project_code }}</p> <p>{{ mastertask.project_code }}</p>
@@ -378,6 +376,7 @@ export default {
date: null, date: null,
projectCodeSearch: null, projectCodeSearch: null,
modalName: 'z-master-task-modal', modalName: 'z-master-task-modal',
modalSize: 'large',
}; };
}, },
@@ -1,15 +1,23 @@
<template> <template>
<v-dialog v-model="visible" :width="modalWidth" :height="modalHeight" persistent :retain-focus="false" > <v-dialog
<v-card style="position: relative"> v-model="visible"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1>Vytvoriť</h1> <h1>Vytvoriť</h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" /> <a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="closeModal()" /> <a-close-button @close="closeModal()" />
</div> </div>
</div> </div>
<v-card-actions class="mt-10 d-flex justify-start align-center mobile-view"> <v-card-actions
class="mt-10 d-flex justify-start align-center mobile-view"
>
<v-btn class="button primary half outline" @click.stop="createTask()" <v-btn class="button primary half outline" @click.stop="createTask()"
>SUB TASK</v-btn >SUB TASK</v-btn
> >
@@ -17,22 +25,27 @@
>BLOCKER</v-btn >BLOCKER</v-btn
> >
</v-card-actions> </v-card-actions>
<a-resize-handle :current-width="modalWidthPx" :current-height="modalHeightPx" @resize="handleModalResize" @resize-end="handleResizeEnd" /> <a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
<script> <script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin' import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue' import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue' import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue' import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
AResizeHandle, AResizeHandle,
AResetSizeButton, ACloseButton, AResetSizeButton,
ACloseButton,
}, },
mixins: [modalMixin], mixins: [modalMixin],
props: { props: {
@@ -48,7 +61,8 @@ export default {
visible: false, visible: false,
localData: null, localData: null,
modalName: 'z-show-menu-modal', modalName: 'z-show-menu-modal',
} modalSize: 'small',
};
}, },
mounted() { mounted() {
@@ -51,16 +51,21 @@
</v-col> </v-col>
</v-row> </v-row>
<v-dialog v-model="showModal" width="750" persistent :retain-focus="false"> <v-dialog
v-model="showModal"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card> <v-card>
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1>Pridať odpracovaný čas</h1> <h1>Pridať odpracovaný čas</h1>
<v-icon <div class="d-flex align-start">
icon="mdi-close" <a-reset-size-button @reset="resetModalSize" />
size="large" <a-close-button @close="closeModal()" />
@click.stop="closeModal()" </div>
></v-icon>
</div> </div>
<v-card-actions class="mt-10 d-flex justify-start align-center"> <v-card-actions class="mt-10 d-flex justify-start align-center">
<v-text-field <v-text-field
@@ -79,6 +84,12 @@
/> />
</v-card-actions> </v-card-actions>
<v-btn class="button primary mt-5" @click="submit()">Potvrdiť</v-btn> <v-btn class="button primary mt-5" @click="submit()">Potvrdiť</v-btn>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
@@ -91,8 +102,16 @@ import { required, numeric, minValue } from '@vuelidate/validators';
import tmUtils from '@/plugins/tm@_utils/tm.utils'; import tmUtils from '@/plugins/tm@_utils/tm.utils';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: {
AResizeHandle,
AResetSizeButton,
ACloseButton,
},
mixins: [modalMixin], mixins: [modalMixin],
props: { props: {
hours: { hours: {
@@ -115,6 +134,8 @@ export default {
form: { form: {
hours: null, hours: null,
}, },
modalName: 'a-task-spent-time-modal',
modalSize: 'medium',
}; };
}, },
@@ -86,18 +86,21 @@
<v-dialog <v-dialog
v-model="showModal" v-model="showModal"
max-width="900" :width="modalWidth"
:height="modalHeight"
persistent persistent
:retain-focus="false" :retain-focus="false"
> >
<v-card class="add-timeblock-modal"> <v-card
style="position: relative; height: 100%"
class="add-timeblock-modal"
>
<div class="d-flex justify-space-between align-center pa-4"> <div class="d-flex justify-space-between align-center pa-4">
<h1>Pridať dátum</h1> <h1>Pridať dátum</h1>
<v-icon <div class="d-flex align-start">
icon="mdi-close" <a-reset-size-button @reset="resetModalSize" />
size="large" <a-close-button @close="closeModal()" />
@click.stop="closeModal()" </div>
></v-icon>
</div> </div>
<v-card-text class="pa-4"> <v-card-text class="pa-4">
@@ -116,9 +119,21 @@
Potvrdiť Potvrdiť
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
<v-dialog v-model="visible" max-width="750" persistent :retain-focus="false"> <v-dialog
v-model="visible"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card> <v-card>
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1 class="text-red"> <h1 class="text-red">
@@ -126,12 +141,10 @@
<b class="text-black">z mastertasku {{ subtask?.project_code }} ?</b> <b class="text-black">z mastertasku {{ subtask?.project_code }} ?</b>
</h1> </h1>
<v-icon <div class="d-flex align-start">
icon="mdi-close" <a-reset-size-button @reset="resetModalSize" />
size="large" <a-close-button @close="closeModal()" />
class="mb-15" </div>
@click.stop="visible = false"
></v-icon>
</div> </div>
<v-card-actions <v-card-actions
class="mt-10 d-flex justify-start align-center mobile-view" class="mt-10 d-flex justify-start align-center mobile-view"
@@ -142,10 +155,16 @@
@click.stop="confirmSubmit()" @click.stop="confirmSubmit()"
>ÁNO</v-btn >ÁNO</v-btn
> >
<v-btn class="button primary half outline" @click.stop="visible = false" <v-btn class="button primary half outline" @click.stop="closeModal()"
>ZRUŠIŤ</v-btn >ZRUŠIŤ</v-btn
> >
</v-card-actions> </v-card-actions>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
@@ -163,11 +182,17 @@ import {
getCollisionSegments, getCollisionSegments,
calculateTimeblockDuration, calculateTimeblockDuration,
} from '@/plugins/tm@_utils/timeblock.utils'; } from '@/plugins/tm@_utils/timeblock.utils';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
export default { export default {
components: { components: {
AEmployeeTimeblock, AEmployeeTimeblock,
// AEmployeeTimeblockTimeline, // AEmployeeTimeblockTimeline,
AResetSizeButton,
ACloseButton,
AResizeHandle,
}, },
mixins: [modalMixin], mixins: [modalMixin],
@@ -204,6 +229,8 @@ export default {
HOUR_WIDTH_MOBILE: 50, HOUR_WIDTH_MOBILE: 50,
// Existing timeblocks timeline data // Existing timeblocks timeline data
existingTimeblocksData: {}, // { [index]: { tasks: [], loading: false } } existingTimeblocksData: {}, // { [index]: { tasks: [], loading: false } }
modalName: 'a-task-timeblocks-modal',
modalSize: 'medium',
}; };
}, },
@@ -1,6 +1,12 @@
<template> <template>
<v-dialog v-model="visible" max-width="750" persistent :retain-focus="false"> <v-dialog
<v-card style="position: relative"> v-model="visible"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1> <h1>
Ste si istý, že chcete Ste si istý, že chcete
@@ -9,7 +15,8 @@
<b>{{ subtask?.master_task?.name || subtask.master_task }}</b <b>{{ subtask?.master_task?.name || subtask.master_task }}</b
>? >?
</h1> </h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="closeModal()" /> <a-close-button @close="closeModal()" />
</div> </div>
</div> </div>
@@ -23,6 +30,12 @@
>ZRUŠIŤ</v-btn >ZRUŠIŤ</v-btn
> >
</v-card-actions> </v-card-actions>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
@@ -30,10 +43,14 @@
<script> <script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import moment from 'moment'; import moment from 'moment';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue'; import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
AResizeHandle,
AResetSizeButton,
ACloseButton, ACloseButton,
}, },
mixins: [modalMixin], mixins: [modalMixin],
@@ -44,6 +61,7 @@ export default {
visible: false, visible: false,
subtask: null, subtask: null,
modalName: 'z-complete-task-modal', modalName: 'z-complete-task-modal',
modalSize: 'small',
}; };
}, },
@@ -1,6 +1,12 @@
<template> <template>
<v-dialog v-model="visible" max-width="750" persistent :retain-focus="false"> <v-dialog
<v-card style="position: relative"> v-model="visible"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1> <h1>
Ste si istý, že chcete zmazať sub task z mastertasku Ste si istý, že chcete zmazať sub task z mastertasku
@@ -8,7 +14,8 @@
>? >?
</h1> </h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" />
<a-close-button class="mb-15" @close="closeModal()" /> <a-close-button class="mb-15" @close="closeModal()" />
</div> </div>
</div> </div>
@@ -26,16 +33,26 @@
>ZRUŠIŤ</v-btn >ZRUŠIŤ</v-btn
> >
</v-card-actions> </v-card-actions>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
<script> <script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue'; import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
AResizeHandle,
AResetSizeButton,
ACloseButton, ACloseButton,
}, },
mixins: [modalMixin], mixins: [modalMixin],
@@ -47,6 +64,7 @@ export default {
subtask: null, subtask: null,
isDeleting: false, isDeleting: false,
modalName: 'z-delete-task-modal', modalName: 'z-delete-task-modal',
modalSize: 'small',
}; };
}, },
@@ -1,10 +1,17 @@
<template> <template>
<v-dialog v-model="visible" max-width="750" persistent :retain-focus="false"> <v-dialog
<v-card style="position: relative"> v-model="visible"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h4 class="mt-3">Vyberte časový úsek, ktorý chcete odstrániť</h4> <h4 class="mt-3">Vyberte časový úsek, ktorý chcete odstrániť</h4>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="closeModal()" /> <a-close-button @close="closeModal()" />
</div> </div>
</div> </div>
@@ -31,6 +38,12 @@
" "
/> />
</div> </div>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
@@ -39,10 +52,14 @@
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import tmUtils from '@/plugins/tm@_utils/tm.utils'; import tmUtils from '@/plugins/tm@_utils/tm.utils';
import moment from 'moment'; import moment from 'moment';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue'; import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
AResizeHandle,
AResetSizeButton,
ACloseButton, ACloseButton,
}, },
mixins: [modalMixin], mixins: [modalMixin],
@@ -55,6 +72,7 @@ export default {
isDeleting: false, isDeleting: false,
tmUtils, tmUtils,
modalName: 'z-delete-timeblock-modal', modalName: 'z-delete-timeblock-modal',
modalSize: 'medium',
}; };
}, },
@@ -1,12 +1,19 @@
<template> <template>
<v-dialog v-model="visible" max-width="750" persistent :retain-focus="false"> <v-dialog
<v-card style="position: relative"> v-model="visible"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1> <h1>
Naozaj chcete odstrániť tohto zamestnanca a všetky jeho timeblocks? Naozaj chcete odstrániť tohto zamestnanca a všetky jeho timeblocks?
</h1> </h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" />
<a-close-button class="mb-15" @close="closeModal()" /> <a-close-button class="mb-15" @close="closeModal()" />
</div> </div>
</div> </div>
@@ -20,16 +27,26 @@
>ZRUŠIŤ</v-btn >ZRUŠIŤ</v-btn
> >
</v-card-actions> </v-card-actions>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
<script> <script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue'; import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
AResizeHandle,
AResetSizeButton,
ACloseButton, ACloseButton,
}, },
mixins: [modalMixin], mixins: [modalMixin],
@@ -39,6 +56,7 @@ export default {
return { return {
visible: false, visible: false,
modalName: 'z-remove-employee-modal', modalName: 'z-remove-employee-modal',
modalSize: 'small',
}; };
}, },
@@ -1,10 +1,17 @@
<template> <template>
<v-dialog v-model="visible" max-width="750" persistent :retain-focus="false"> <v-dialog
<v-card style="position: relative"> v-model="visible"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1>Naozaj chcete odstrániť tento timeblock?</h1> <h1>Naozaj chcete odstrániť tento timeblock?</h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" />
<a-close-button class="mb-15" @close="closeModal()" /> <a-close-button class="mb-15" @close="closeModal()" />
</div> </div>
</div> </div>
@@ -18,16 +25,26 @@
>ZRUŠIŤ</v-btn >ZRUŠIŤ</v-btn
> >
</v-card-actions> </v-card-actions>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
<script> <script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue'; import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
AResizeHandle,
AResetSizeButton,
ACloseButton, ACloseButton,
}, },
mixins: [modalMixin], mixins: [modalMixin],
@@ -36,6 +53,7 @@ export default {
return { return {
visible: false, visible: false,
modalName: 'z-remove-timeblock-modal', modalName: 'z-remove-timeblock-modal',
modalSize: 'small',
onConfirmCallback: null, onConfirmCallback: null,
}; };
}, },
@@ -1,10 +1,17 @@
<template> <template>
<v-dialog v-model="visible" max-width="750" persistent :retain-focus="false"> <v-dialog
<v-card style="position: relative"> v-model="visible"
:width="modalWidth"
:height="modalHeight"
persistent
:retain-focus="false"
>
<v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1>Pridať odpracovaný čas</h1> <h1>Pridať odpracovaný čas</h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="closeModal()" /> <a-close-button @close="closeModal()" />
</div> </div>
</div> </div>
@@ -25,6 +32,12 @@
/> />
</v-card-actions> </v-card-actions>
<v-btn class="button primary mt-5" @click="submit()">Potvrdiť</v-btn> <v-btn class="button primary mt-5" @click="submit()">Potvrdiť</v-btn>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
@@ -36,10 +49,14 @@ import { required, numeric, minValue } from '@vuelidate/validators';
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import tmUtils from '@/plugins/tm@_utils/tm.utils'; import tmUtils from '@/plugins/tm@_utils/tm.utils';
import moment from 'moment'; import moment from 'moment';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue'; import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
AResizeHandle,
AResetSizeButton,
ACloseButton, ACloseButton,
}, },
mixins: [modalMixin], mixins: [modalMixin],
@@ -55,6 +72,7 @@ export default {
hours: null, hours: null,
}, },
modalName: 'z-task-add-time-modal', modalName: 'z-task-add-time-modal',
modalSize: 'medium',
}; };
}, },
@@ -322,6 +322,7 @@ export default {
deletedTimeblockIds: [], // Track IDs of saved timeblocks that have been deleted deletedTimeblockIds: [], // Track IDs of saved timeblocks that have been deleted
wasFormValidationTriggered: false, wasFormValidationTriggered: false,
modalName: 'z-task-modal', modalName: 'z-task-modal',
modalSize: 'large',
employeeRefs: [], employeeRefs: [],
pendingRemoveEmployeeId: undefined, pendingRemoveEmployeeId: undefined,
pendingRemoveEmployeeIndex: undefined, pendingRemoveEmployeeIndex: undefined,
@@ -6,11 +6,11 @@
persistent persistent
:retain-focus="false" :retain-focus="false"
> >
<v-card style="position: relative"> <v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1>Sub Task má nedokončené úlohy</h1> <h1>Sub Task má nedokončené úlohy</h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" /> <a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="closeModal()" /> <a-close-button @close="closeModal()" />
</div> </div>
@@ -94,6 +94,7 @@ export default {
loadingTimeblocks: {}, loadingTimeblocks: {},
loadingCloseAll: false, loadingCloseAll: false,
modalName: 'z-unable-to-complete-task-modal', modalName: 'z-unable-to-complete-task-modal',
modalSize: 'medium',
}; };
}, },
@@ -6,7 +6,7 @@
persistent persistent
:retain-focus="false" :retain-focus="false"
> >
<v-card style="position: relative"> <v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1 v-if="mode === 'edit'"> <h1 v-if="mode === 'edit'">
Sub Task zosynchronizovaný z Office365 sa nedá upravovat. Upravte ho Sub Task zosynchronizovaný z Office365 sa nedá upravovat. Upravte ho
@@ -17,20 +17,31 @@
svojom kalendári a pockajte na zosynchronizovanie s Task Managerom svojom kalendári a pockajte na zosynchronizovanie s Task Managerom
</h1> </h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="closeModal()" /> <a-close-button @close="closeModal()" />
</div> </div>
</div> </div>
<a-resize-handle
:current-width="modalWidthPx"
:current-height="modalHeightPx"
@resize="handleModalResize"
@resize-end="handleResizeEnd"
/>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
<script> <script>
import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin'; import modalMixin from '@/plugins/tm@modal/_mixins/modal.mixin';
import AResizeHandle from '@/plugins/tm@modal/_components/a-resize-handle.vue';
import AResetSizeButton from '@/plugins/tm@modal/_components/a-reset-size-button.vue';
import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue'; import ACloseButton from '@/plugins/tm@modal/_components/a-close-button.vue';
export default { export default {
components: { components: {
AResizeHandle,
AResetSizeButton,
ACloseButton, ACloseButton,
}, },
@@ -49,6 +60,7 @@ export default {
visible: false, visible: false,
subtask: null, subtask: null,
modalName: 'z-unable-to-edit-office-task-modal', modalName: 'z-unable-to-edit-office-task-modal',
modalSize: 'small',
}; };
}, },
@@ -6,13 +6,13 @@
persistent persistent
:retain-focus="false" :retain-focus="false"
> >
<v-card style="position: relative"> <v-card style="position: relative; height: 100%">
<div class="d-flex justify-space-between align-center"> <div class="d-flex justify-space-between align-center">
<h1> <h1>
Ste si istý, že chcete zmazať tím <b>{{ team.name }}</b Ste si istý, že chcete zmazať tím <b>{{ team.name }}</b
>? >?
</h1> </h1>
<div class="d-flex align-center"> <div class="d-flex align-start">
<a-reset-size-button @reset="resetModalSize" /> <a-reset-size-button @reset="resetModalSize" />
<a-close-button @close="closeModal()" /> <a-close-button @close="closeModal()" />
</div> </div>
@@ -63,6 +63,7 @@ export default {
team: null, team: null,
isDeleting: false, isDeleting: false,
modalName: 'z-delete-team-modal', modalName: 'z-delete-team-modal',
modalSize: 'small',
}; };
}, },
@@ -117,6 +117,7 @@ export default {
employeeSelect: null, employeeSelect: null,
team: null, team: null,
modalName: 'z-team-modal', modalName: 'z-team-modal',
modalSize: 'medium',
}; };
}, },