Skip to content

Commit 84e0198

Browse files
fix: meeting propasas prevent user interaction during operations
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
1 parent 03efbd6 commit 84e0198

1 file changed

Lines changed: 77 additions & 6 deletions

File tree

src/views/Proposal/ProposalEditor.vue

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@
1010
class="proposal-modal__content"
1111
:title="modalTitle"
1212
:size="modalSize"
13+
:close-button-contained="false"
14+
:can-close="!operationInProgress"
1315
@close="onModalClose()">
16+
<!-- Loading overlay -->
17+
<div v-if="operationInProgress" class="proposal-editor__loading-overlay">
18+
<NcLoadingIcon :size="64" />
19+
<p>{{ operationMessage }}</p>
20+
</div>
21+
1422
<!-- Show proposal viewer -->
1523
<div v-if="modalMode === 'view'" class="proposal-viewer__content">
1624
<div class="proposal-viewer__content-title">
@@ -260,6 +268,7 @@ import DeleteIcon from 'vue-material-design-icons/TrashCanOutline'
260268
// components
261269
import NcButton from '@nextcloud/vue/components/NcButton'
262270
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
271+
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
263272
import NcModal from '@nextcloud/vue/components/NcModal'
264273
import NcTextArea from '@nextcloud/vue/components/NcTextArea'
265274
import NcTextField from '@nextcloud/vue/components/NcTextField'
@@ -300,6 +309,7 @@ export default {
300309
components: {
301310
NcButton,
302311
NcCheckboxRadioSwitch,
312+
NcLoadingIcon,
303313
NcModal,
304314
NcTextField,
305315
NcTextArea,
@@ -338,6 +348,8 @@ export default {
338348
calendarSpanMin: 1, // Minimum days that can be shown
339349
calendarSpanDays: 7, // Currently applied span (derived)
340350
screenWidth: window.innerWidth, // Track screen width
351+
operationInProgress: false, // Lock to prevent concurrent operations
352+
operationMessage: '', // Message to display during operation
341353
}
342354
},
343355
@@ -583,36 +595,60 @@ export default {
583595
},
584596
585597
async onProposalDestroy(proposal: Proposal) {
598+
if (this.operationInProgress) {
599+
return
600+
}
601+
586602
if (!confirm(t('calendar', 'Are you sure you want to delete "{title}"?', { title: proposal.title ?? t('calendar', 'No title') }))) {
587603
return
588604
}
605+
606+
this.operationInProgress = true
607+
this.operationMessage = t('calendar', 'Deleting proposal...')
608+
589609
try {
590-
showSuccess(t('calendar', 'Deleting proposal "{title}"', { title: proposal.title ?? t('calendar', 'No title') }))
591610
await this.proposalStore.destroyProposal(proposal)
592611
showSuccess(t('calendar', 'Successfully deleted proposal'))
593612
this.onModalClose()
594613
} catch (error) {
595614
showError(t('calendar', 'Failed to delete proposal'))
596615
console.error('Failed to delete proposal:', error)
616+
} finally {
617+
this.operationInProgress = false
618+
this.operationMessage = ''
597619
}
598620
},
599621
600622
async onProposalSave() {
623+
if (this.operationInProgress) {
624+
return
625+
}
626+
627+
if (!this.selectedProposal) {
628+
return console.error('No proposal selected for this operation')
629+
}
630+
631+
this.operationInProgress = true
632+
this.operationMessage = t('calendar', 'Saving proposal...')
633+
601634
try {
602-
if (!this.selectedProposal) {
603-
return console.error('No proposal selected for this operation')
604-
}
605-
showSuccess(t('calendar', 'Saving proposal "{title}"', { title: this.selectedProposal.title ?? t('calendar', 'No title') }))
606635
await this.proposalStore.storeProposal(this.selectedProposal)
607636
showSuccess(t('calendar', 'Successfully saved proposal'))
608637
this.onModalClose()
609638
} catch (error) {
610639
showError(t('calendar', 'Failed to save proposal'))
611640
console.error('Failed to save proposal:', error)
641+
} finally {
642+
this.operationInProgress = false
643+
this.operationMessage = ''
612644
}
613645
},
614646
615647
async onProposalConvert(date: ProposalDate) {
648+
if (this.operationInProgress) {
649+
return
650+
}
651+
616652
if (!this.selectedProposal || !date.date) {
617653
return console.error('No proposal selected or invalid date for meeting conversion')
618654
}
@@ -623,14 +659,19 @@ export default {
623659
return
624660
}
625661
662+
this.operationInProgress = true
663+
this.operationMessage = t('calendar', 'Creating meeting...')
664+
626665
try {
627-
showSuccess(t('calendar', 'Creating meeting for {date}', { date: dateString }))
628666
await this.proposalStore.convertProposal(this.selectedProposal, date, this.userTimezone)
629667
showSuccess(t('calendar', 'Successfully created meeting for {date}', { date: dateString }))
630668
this.onModalClose()
631669
} catch (error) {
632670
showError(t('calendar', 'Failed to create a meeting for {date}', { date: dateString }))
633671
console.error('Failed to create a meeting:', error)
672+
} finally {
673+
this.operationInProgress = false
674+
this.operationMessage = ''
634675
}
635676
},
636677
@@ -1220,4 +1261,34 @@ export default {
12201261
/* Override background with striped pattern for better visibility */
12211262
background-image: repeating-linear-gradient(45deg, transparent 0px, transparent calc(var(--default-grid-baseline) * 1), var(--color-background-hover) calc(var(--default-grid-baseline) * 1), var(--color-background-hover) calc(var(--default-grid-baseline) * 4)) !important;
12221263
}
1264+
1265+
.proposal-editor__loading-overlay {
1266+
position: absolute;
1267+
top: 0;
1268+
left: 0;
1269+
right: 0;
1270+
bottom: 0;
1271+
background-color: rgba(255, 255, 255, 0.95);
1272+
display: flex;
1273+
flex-direction: column;
1274+
align-items: center;
1275+
justify-content: center;
1276+
gap: calc(var(--default-grid-baseline) * 4);
1277+
z-index: 10000;
1278+
border-radius: var(--border-radius-large);
1279+
1280+
p {
1281+
font-size: calc(var(--default-grid-baseline) * 4);
1282+
font-weight: 500;
1283+
color: var(--color-text-primary);
1284+
margin: 0;
1285+
}
1286+
}
1287+
1288+
// Dark mode support
1289+
@media (prefers-color-scheme: dark) {
1290+
.proposal-editor__loading-overlay {
1291+
background-color: rgba(0, 0, 0, 0.95);
1292+
}
1293+
}
12231294
</style>

0 commit comments

Comments
 (0)