feat: add duplicate functionality to CalendarEventDetails and CalendarEventPanel components

This commit is contained in:
Shariq Ansari 2025-08-06 17:41:53 +05:30
parent 1cc972ea8b
commit 38b838ec97
4 changed files with 69 additions and 21 deletions

View File

@ -191,8 +191,10 @@ declare module 'vue' {
ListRows: typeof import('./src/components/ListViews/ListRows.vue')['default']
LoadingIndicator: typeof import('./src/components/Icons/LoadingIndicator.vue')['default']
LostReasonModal: typeof import('./src/components/Modals/LostReasonModal.vue')['default']
LucideChevronLeft: typeof import('~icons/lucide/chevron-left')['default']
LucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
LucideEarth: typeof import('~icons/lucide/earth')['default']
LucideLetterText: typeof import('~icons/lucide/letter-text')['default']
LucidePlus: typeof import('~icons/lucide/plus')['default']
LucideText: typeof import('~icons/lucide/text')['default']
LucideX: typeof import('~icons/lucide/x')['default']

View File

@ -4,24 +4,24 @@
class="flex items-center justify-between p-4.5 text-ink-gray-7 text-lg font-medium"
>
<div>{{ __('Event details') }}</div>
<div class="flex items-center gap-x-2">
<div class="flex items-center gap-x-1">
<Button variant="ghost" @click="editDetails">
<template #icon>
<EditIcon class="size-4" />
</template>
</Button>
<Button icon="trash-2" variant="ghost" @click="deleteEvent" />
<Dropdown
v-if="event.id"
:options="[
{
label: __('Delete'),
value: 'delete',
icon: 'trash-2',
onClick: deleteEvent,
label: __('Duplicate'),
icon: 'copy',
onClick: duplicateEvent,
},
]"
>
<Button variant="ghost" icon="more-horizontal" />
<Button variant="ghost" icon="more-vertical" />
</Dropdown>
<Button
icon="x"
@ -98,6 +98,10 @@ function deleteEvent() {
emit('delete', props.event.id)
}
function duplicateEvent() {
emit('duplicate', props.event)
}
function editDetails() {
emit('edit', props.event)
}

View File

@ -3,20 +3,32 @@
<div
class="flex items-center justify-between p-4.5 text-ink-gray-7 text-lg font-medium"
>
<div>{{ __(title) }}</div>
<div class="flex items-center gap-x-2">
<div
class="flex items-center gap-x-2"
:class="event.id && 'cursor-pointer hover:text-ink-gray-8'"
@click="event.id && goToDetails()"
>
<LucideChevronLeft v-if="event.id" class="size-4" />
{{ __(title) }}
</div>
<div class="flex items-center gap-x-1">
<Button
v-if="event.id"
icon="trash-2"
variant="ghost"
@click="deleteEvent"
/>
<Dropdown
v-if="event.id"
:options="[
{
label: __('Delete'),
value: 'delete',
icon: 'trash-2',
onClick: deleteEvent,
label: __('Duplicate'),
icon: 'copy',
onClick: duplicateEvent,
},
]"
>
<Button variant="ghost" icon="more-horizontal" />
<Button variant="ghost" icon="more-vertical" />
</Dropdown>
<Button
icon="x"
@ -177,7 +189,7 @@ const props = defineProps({
},
})
const emit = defineEmits(['save', 'delete'])
const emit = defineEmits(['save', 'delete', 'goToDetails'])
const show = defineModel()
@ -198,11 +210,18 @@ watch(
if (newEvent && newEvent.id) {
title.value = 'Editing event'
} else {
} else if (!newEvent.title) {
title.value = 'New event'
} else {
title.value = 'Duplicate event'
}
nextTick(() => (_event.value = { ...newEvent }))
nextTick(() => {
_event.value = { ...newEvent }
if (title.value == 'Duplicate event') {
_event.value.title = `${_event.value.title} (Copy)`
}
})
setTimeout(() => eventTitle.value?.el?.focus(), 100)
},
{ immediate: true },
@ -257,10 +276,23 @@ function saveEvent() {
emit('save', _event.value)
}
function duplicateEvent() {
props.event.id = ''
title.value = 'Duplicate event'
_event.value = { ...props.event }
_event.value.title = `${_event.value.title} (Copy)`
nextTick(() => eventTitle.value?.el?.focus())
}
function deleteEvent() {
emit('delete', _event.value.id)
}
function goToDetails() {
show.value = false
emit('goToDetails', _event.value)
}
const colors = Object.keys(colorMap).map((color) => ({
label: color.charAt(0).toUpperCase() + color.slice(1),
value: colorMap[color].color,

View File

@ -4,7 +4,7 @@
<ViewBreadcrumbs routeName="Calendar" />
</template>
<template #right-header>
<Button variant="solid" :label="__('Create')" @click="showEventPanelArea">
<Button variant="solid" :label="__('Create')" @click="newEvent">
<template #prefix><FeatherIcon name="plus" class="h-4" /></template>
</Button>
</template>
@ -29,7 +29,7 @@
@delete="(eventID) => deleteEvent(eventID)"
:onClick="showDetails"
:onDblClick="editDetails"
:onCellDblClick="showEventPanelArea"
:onCellDblClick="newEvent"
>
<template
#header="{
@ -88,6 +88,7 @@
:event="event"
@save="saveEvent"
@delete="deleteEvent"
@goToDetails="showDetails"
/>
<CalendarEventDetails
@ -96,6 +97,7 @@
:event="event"
@edit="editDetails"
@delete="deleteEvent"
@duplicate="duplicateEvent"
/>
</div>
</template>
@ -249,10 +251,11 @@ const showEventDetails = ref(false)
const event = ref({})
function showDetails(e) {
let _e = e?.calendarEvent || e
showEventPanel.value = false
showEventDetails.value = true
event.value = { ...e.calendarEvent }
activeEvent.value = e.calendarEvent.id
event.value = { ..._e }
activeEvent.value = _e.id
}
function editDetails(e) {
@ -263,7 +266,7 @@ function editDetails(e) {
activeEvent.value = _e.id
}
function showEventPanelArea(e) {
function newEvent(e) {
let [fromTime, toTime] = getFromToTime(e.time)
let fromDate = dayjs(e.date).format('YYYY-MM-DD')
@ -284,6 +287,13 @@ function showEventPanelArea(e) {
}
}
function duplicateEvent(e) {
showEventDetails.value = false
showEventPanel.value = true
e.id = ''
event.value = { ...e }
}
// utils
function getFromToTime(time) {
let currentTime = dayjs().format('HH:mm') || '00:00'