feat: add CalendarEventDetails component and integrate it into Calendar for event management
This commit is contained in:
parent
55c61cbd80
commit
1c432d8610
2
frontend/components.d.ts
vendored
2
frontend/components.d.ts
vendored
@ -46,6 +46,7 @@ declare module 'vue' {
|
||||
BrandLogo: typeof import('./src/components/BrandLogo.vue')['default']
|
||||
BrandSettings: typeof import('./src/components/Settings/General/BrandSettings.vue')['default']
|
||||
BulkDeleteLinkedDocModal: typeof import('./src/components/BulkDeleteLinkedDocModal.vue')['default']
|
||||
CalendarEventDetails: typeof import('./src/components/Calendar/CalendarEventDetails.vue')['default']
|
||||
CalendarEventPanel: typeof import('./src/components/Calendar/CalendarEventPanel.vue')['default']
|
||||
CalendarIcon: typeof import('./src/components/Icons/CalendarIcon.vue')['default']
|
||||
CalendarModal: typeof import('./src/components/Modals/CalendarModal.vue')['default']
|
||||
@ -90,6 +91,7 @@ declare module 'vue' {
|
||||
DealsListView: typeof import('./src/components/ListViews/DealsListView.vue')['default']
|
||||
DeclinedCallIcon: typeof import('./src/components/Icons/DeclinedCallIcon.vue')['default']
|
||||
DeleteLinkedDocModal: typeof import('./src/components/DeleteLinkedDocModal.vue')['default']
|
||||
DescriptionIcon: typeof import('./src/components/Icons/DescriptionIcon.vue')['default']
|
||||
DesendingIcon: typeof import('./src/components/Icons/DesendingIcon.vue')['default']
|
||||
DesktopLayout: typeof import('./src/components/Layouts/DesktopLayout.vue')['default']
|
||||
DetailsIcon: typeof import('./src/components/Icons/DetailsIcon.vue')['default']
|
||||
|
||||
104
frontend/src/components/Calendar/CalendarEventDetails.vue
Normal file
104
frontend/src/components/Calendar/CalendarEventDetails.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div v-if="show" class="w-[352px] border-l">
|
||||
<div
|
||||
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">
|
||||
<Button variant="ghost" @click="editDetails">
|
||||
<template #icon>
|
||||
<EditIcon class="size-4" />
|
||||
</template>
|
||||
</Button>
|
||||
<Dropdown
|
||||
v-if="event.id"
|
||||
:options="[
|
||||
{
|
||||
label: __('Delete'),
|
||||
value: 'delete',
|
||||
icon: 'trash-2',
|
||||
onClick: deleteEvent,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<Button variant="ghost" icon="more-horizontal" />
|
||||
</Dropdown>
|
||||
<Button
|
||||
icon="x"
|
||||
variant="ghost"
|
||||
@click="
|
||||
() => {
|
||||
show = false
|
||||
activeEvent = ''
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-base">
|
||||
<div class="flex items-start gap-2 px-4.5 py-3 pb-0">
|
||||
<div
|
||||
class="mx-0.5 my-[5px] size-2.5 rounded-full cursor-pointer"
|
||||
:style="{
|
||||
backgroundColor: event.color || '#30A66D',
|
||||
}"
|
||||
/>
|
||||
<div class="flex flex-col gap-[3px]">
|
||||
<div class="text-ink-gray-8 font-semibold text-xl">
|
||||
{{ event.title || __('(No title)') }}
|
||||
</div>
|
||||
<div class="text-ink-gray-6 text-p-base">{{ formattedDateTime }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mx-4.5 my-2.5 border-t border-outline-gray-1" />
|
||||
<div>
|
||||
<div class="flex gap-2 items-center text-ink-gray-7 px-4.5 py-2">
|
||||
<DescriptionIcon class="size-4" />
|
||||
{{ __('Description') }}
|
||||
</div>
|
||||
<div class="px-4.5 py-2 text-ink-gray-7 text-p-base">
|
||||
<div
|
||||
v-if="event.description && event.description !== '<p></p>'"
|
||||
v-html="event.description"
|
||||
/>
|
||||
<div class="text-ink-gray-5" v-else>{{ __('(No description)') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import DescriptionIcon from '@/components/Icons/DescriptionIcon.vue'
|
||||
import EditIcon from '@/components/Icons/EditIcon.vue'
|
||||
import { Dropdown, CalendarActiveEvent as activeEvent, dayjs } from 'frappe-ui'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const show = defineModel()
|
||||
|
||||
const emit = defineEmits(['edit', 'delete'])
|
||||
|
||||
const formattedDateTime = computed(() => {
|
||||
if (props.event.isFullDay) {
|
||||
return `${__('All day')} - ${dayjs(props.event.fromDateTime).format('ddd, D MMM YYYY')}`
|
||||
}
|
||||
|
||||
const start = dayjs(props.event.fromDateTime)
|
||||
const end = dayjs(props.event.toDateTime)
|
||||
return `${start.format('h:mm a')} - ${end.format('h:mm a')} ${start.format('ddd, D MMM YYYY')}`
|
||||
})
|
||||
|
||||
function deleteEvent() {
|
||||
emit('delete', props.event.id)
|
||||
}
|
||||
|
||||
function editDetails() {
|
||||
emit('edit', props.event)
|
||||
}
|
||||
</script>
|
||||
@ -42,7 +42,7 @@
|
||||
<template #prefix>
|
||||
<Dropdown class="ml-1" :options="colors">
|
||||
<div
|
||||
class="ml-0.5 size-2 rounded-full cursor-pointer"
|
||||
class="ml-0.5 size-2.5 rounded-full cursor-pointer"
|
||||
:style="{
|
||||
backgroundColor: _event.color || '#30A66D',
|
||||
}"
|
||||
@ -125,7 +125,7 @@
|
||||
</TimePicker>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mx-4.5 my-2.5 border-t" />
|
||||
<div class="mx-4.5 my-2.5 border-t border-outline-gray-1" />
|
||||
<div class="px-4.5 py-3">
|
||||
<div class="flex items-center gap-x-2 border rounded py-1">
|
||||
<TextEditor
|
||||
@ -197,7 +197,7 @@ watch(
|
||||
error.value = null
|
||||
|
||||
if (newEvent && newEvent.id) {
|
||||
title.value = 'Event details'
|
||||
title.value = 'Editing event'
|
||||
} else {
|
||||
title.value = 'New event'
|
||||
}
|
||||
@ -265,7 +265,7 @@ const colors = Object.keys(colorMap).map((color) => ({
|
||||
label: color.charAt(0).toUpperCase() + color.slice(1),
|
||||
value: colorMap[color].color,
|
||||
icon: h('div', {
|
||||
class: '!size-2 rounded-full',
|
||||
class: '!size-2.5 rounded-full',
|
||||
style: { backgroundColor: colorMap[color].color },
|
||||
}),
|
||||
onClick: () => {
|
||||
|
||||
14
frontend/src/components/Icons/DescriptionIcon.vue
Normal file
14
frontend/src/components/Icons/DescriptionIcon.vue
Normal file
@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7.66699 12.7109C7.89499 12.7574 8.06641 12.9594 8.06641 13.2012C8.06625 13.4428 7.89489 13.6449 7.66699 13.6914L7.56641 13.7012H1.5C1.22406 13.7011 1.00018 13.4771 1 13.2012C1 12.9251 1.22395 12.7013 1.5 12.7012H7.56641L7.66699 12.7109ZM14.6006 9.24414C14.8284 9.29081 15 9.4928 15 9.73438C14.9999 9.97585 14.8283 10.178 14.6006 10.2246L14.5 10.2344H1.5C1.22403 10.2343 1.00013 10.0103 1 9.73438C1 9.4583 1.22395 9.23448 1.5 9.23438H14.5L14.6006 9.24414ZM3.56934 2.45996C3.78682 2.52747 3.96526 2.69406 4.04297 2.91699L5.2168 6.29199C5.31837 6.58437 5.10155 6.88965 4.79199 6.88965H4.77441C4.57659 6.88946 4.40241 6.75957 4.34473 6.57031L4.11133 5.80664H2.53613L2.30273 6.57129C2.24483 6.7604 2.06986 6.88965 1.87207 6.88965H1.85742C1.54804 6.88951 1.33114 6.5843 1.43262 6.29199L2.59961 2.93066C2.70432 2.62909 2.98841 2.42694 3.30762 2.42676H3.56934V2.45996ZM14.6006 5.77734C14.8283 5.82404 15 6.02602 15 6.26758C14.9999 6.50907 14.8283 6.71112 14.6006 6.75781L14.5 6.76758H7.56641C7.29038 6.7675 7.06648 6.5436 7.06641 6.26758C7.06641 5.99149 7.29033 5.76766 7.56641 5.76758H14.5L14.6006 5.77734ZM2.75 5.1084H3.89844L3.35254 3.31738H3.29688L2.75 5.1084ZM14.6006 2.31055C14.8283 2.35723 14.9999 2.55931 15 2.80078C15 3.04233 14.8283 3.24432 14.6006 3.29102L14.5 3.30078H7.56641C7.29033 3.3007 7.06641 3.07687 7.06641 2.80078C7.06651 2.52478 7.2904 2.30086 7.56641 2.30078H14.5L14.6006 2.31055Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
@ -89,6 +89,14 @@
|
||||
@save="saveEvent"
|
||||
@delete="deleteEvent"
|
||||
/>
|
||||
|
||||
<CalendarEventDetails
|
||||
v-if="showEventDetails"
|
||||
v-model="showEventDetails"
|
||||
:event="event"
|
||||
@edit="editDetails"
|
||||
@delete="deleteEvent"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
@ -181,6 +189,8 @@ function createEvent(_event) {
|
||||
onSuccess: (e) => {
|
||||
_event.id = e.name
|
||||
event.value = _event
|
||||
showEventPanel.value = false
|
||||
showEventDetails.value = true
|
||||
activeEvent.value = e.name
|
||||
},
|
||||
},
|
||||
@ -201,7 +211,10 @@ function updateEvent(_event) {
|
||||
color: _event.color,
|
||||
})
|
||||
|
||||
showEventPanel.value = false
|
||||
showEventDetails.value = true
|
||||
event.value = _event
|
||||
activeEvent.value = _event.id
|
||||
}
|
||||
|
||||
function deleteEvent(eventID) {
|
||||
@ -220,6 +233,8 @@ function deleteEvent(eventID) {
|
||||
onClick: (close) => {
|
||||
events.delete.submit(eventID)
|
||||
showEventPanel.value = false
|
||||
showEventDetails.value = false
|
||||
event.value = {}
|
||||
activeEvent.value = ''
|
||||
close()
|
||||
},
|
||||
@ -229,15 +244,22 @@ function deleteEvent(eventID) {
|
||||
}
|
||||
|
||||
const showEventPanel = ref(false)
|
||||
const showEventDetails = ref(false)
|
||||
const event = ref({})
|
||||
|
||||
function showDetails(e) {}
|
||||
function showDetails(e) {
|
||||
showEventPanel.value = false
|
||||
showEventDetails.value = true
|
||||
event.value = { ...e.calendarEvent }
|
||||
activeEvent.value = e.calendarEvent.id
|
||||
}
|
||||
|
||||
function editDetails(e) {
|
||||
let _e = e?.calendarEvent || e
|
||||
showEventDetails.value = false
|
||||
showEventPanel.value = true
|
||||
event.value = { ...e.calendarEvent }
|
||||
|
||||
activeEvent.value = e.calendarEvent.id
|
||||
event.value = { ..._e }
|
||||
activeEvent.value = _e.id
|
||||
}
|
||||
|
||||
function showEventPanelArea(e) {
|
||||
@ -246,6 +268,7 @@ function showEventPanelArea(e) {
|
||||
let fromDate = dayjs(e.date).format('YYYY-MM-DD')
|
||||
|
||||
activeEvent.value = ''
|
||||
showEventDetails.value = false
|
||||
showEventPanel.value = true
|
||||
event.value = {
|
||||
title: '',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user