Connect CalDAV todos to DB-Items, finish todo component and add it to pipeline items
This commit is contained in:
@@ -4,7 +4,7 @@ import { Badge } from '@/components/ui/crm-badge/'
|
||||
import AppLayout from '@/layouts/AppLayout.vue'
|
||||
import { daysFromNow, isSoon, isToday, toCurrency, toDuration } from '@/lib/utils'
|
||||
import { Head } from '@inertiajs/vue3'
|
||||
import { Calendar, ClipboardCheck, MessageCircle, CircleHelp, Plus, Trash2 } from 'lucide-vue-next'
|
||||
import { Calendar, ClipboardCheck, MessageCircle, CircleHelp, Plus, Trash2, Check, SquareCheckBig, MessageSquare } from 'lucide-vue-next'
|
||||
import { ref, computed } from 'vue'
|
||||
import axios from 'axios'
|
||||
import draggable from 'vuedraggable'
|
||||
@@ -18,9 +18,11 @@ import TextEditor from '@/components/TextEditor.vue'
|
||||
import Todos from '@/components/Todos.vue';
|
||||
import Notes from '@/components/Notes.vue'
|
||||
import NotesService from '@/services/NotesService'
|
||||
import TodoService from '@/services/TodoService'
|
||||
import NumberInput from '@/components/ui/crm-number-input/NumberInput.vue';
|
||||
import { alertStore } from '@/stores/alertStore'
|
||||
import PipelineService from '@/services/PipelineService'
|
||||
import { cva } from "class-variance-authority"
|
||||
|
||||
interface Props {
|
||||
pipeline: PipelineLane[]
|
||||
@@ -42,7 +44,6 @@ const dragOptions = ref({
|
||||
dragClass: "drag", // Class name for the dragging item
|
||||
})
|
||||
const editorDialogOpen = ref(false)
|
||||
const todos = ref<Todo[]>([])
|
||||
const alert = alertStore()
|
||||
|
||||
const laneSums = computed(() => {
|
||||
@@ -123,31 +124,35 @@ const getLaneIdFromEl = (el: any): number | null => {
|
||||
}
|
||||
|
||||
const cardClasses = (item: PipelineItem): string => {
|
||||
// Due date
|
||||
if (item.dueDate && daysFromNow(item.dueDate) < 0) return "border-l-4 border-destructive"
|
||||
else if (item.dueDate && isSoon(item.dueDate)) return "border-l-4 border-warning"
|
||||
return ""
|
||||
// Destructive
|
||||
if (item.dueDate && daysFromNow(item.dueDate) < 0 ||
|
||||
item.nextTodoDueDate && daysFromNow(item.nextTodoDueDate) < 0
|
||||
) return "border-l-4 border-destructive"
|
||||
|
||||
// Warning
|
||||
if (item.dueDate && isSoon(item.dueDate) ||
|
||||
item.nextTodoDueDate && isSoon(item.nextTodoDueDate)
|
||||
) return "border-l-4 border-warning"
|
||||
}
|
||||
|
||||
const badgeVariant = (item: PipelineItem): "default" | "secondary" | "destructive" | "warning" | "outline" | null | undefined => {
|
||||
const badgeVariant = (date: string | null): "default" | "secondary" | "destructive" | "warning" | "outline" | null | undefined => {
|
||||
// Due date
|
||||
if (item.dueDate && daysFromNow(item.dueDate) < 0) return "destructive"
|
||||
else if (item.dueDate && isSoon(item.dueDate)) return "warning"
|
||||
if (date && daysFromNow(date) < 0) return "destructive"
|
||||
else if (date && isSoon(date)) return "warning"
|
||||
return "secondary"
|
||||
}
|
||||
|
||||
const editItem = async (item: PipelineItem) => {
|
||||
// Load Todos
|
||||
// try {
|
||||
// let response = await axios.get('/api/todos')
|
||||
// todos.value = response.data
|
||||
// } catch (error) {
|
||||
// toast.error('Fehler beim Laden der Daten', { description: (error as AxiosError).message })
|
||||
// }
|
||||
// Load todos lazily
|
||||
if (item.id !== 0 && (item.todos === undefined || item.todos.length === 0)) {
|
||||
TodoService.getTodosForModel('PipelineItem', item.id).then(todos => {
|
||||
if (todos) item.todos = todos
|
||||
})
|
||||
}
|
||||
|
||||
// Load notes lazily
|
||||
if (item.id !== 0 && (item.notes === undefined || item.notes.length === 0)) {
|
||||
NotesService.getAllNotes('PipelineItem', item.id).then(notes => {
|
||||
NotesService.getNotesForModel('PipelineItem', item.id).then(notes => {
|
||||
if (notes) item.notes = notes
|
||||
})
|
||||
}
|
||||
@@ -177,6 +182,14 @@ const deleteItem = (item: PipelineItem | undefined) => {
|
||||
}
|
||||
)
|
||||
}
|
||||
const saveItem = (item: PipelineItem | undefined) => {
|
||||
if (!item) return
|
||||
if (item.id === 0) {
|
||||
PipelineService.createPipelineItem(item);
|
||||
} else {
|
||||
PipelineService.updatePipelineItem(item);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -185,6 +198,7 @@ const deleteItem = (item: PipelineItem | undefined) => {
|
||||
<Head title="Vertriebspipeline" />
|
||||
|
||||
<AppLayout title="Vertriebspipeline">
|
||||
|
||||
<div class="flex flex-col h-full">
|
||||
|
||||
<!-- Header -->
|
||||
@@ -263,22 +277,30 @@ const deleteItem = (item: PipelineItem | undefined) => {
|
||||
toCurrency(item.expectedRevenue) }}</p>
|
||||
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<Badge variant="secondary" v-if="item.actions">
|
||||
<ClipboardCheck /> {{ item.actions }}
|
||||
</Badge>
|
||||
|
||||
<Badge v-if="item.dueDate" :variant="badgeVariant(item)">
|
||||
<Badge v-if="item.dueDate" :variant="badgeVariant(item.dueDate)">
|
||||
<Calendar />
|
||||
<span v-if="isToday(item.dueDate)">Heute</span>
|
||||
<span v-else>{{ toDuration(item.dueDate) }}</span>
|
||||
</Badge>
|
||||
|
||||
<Badge v-if="item.todos && item.todos.length > 0"
|
||||
:variant="badgeVariant(item.todos[item.todos.length - 1]?.dueDate || null)">
|
||||
<SquareCheckBig /> {{item.todos.filter(todo => todo.status.toLowerCase() !==
|
||||
'completed').length}}
|
||||
</Badge>
|
||||
<Badge v-else-if="item.todosCount > 0"
|
||||
:variant="badgeVariant(item.nextTodoDueDate)">
|
||||
<SquareCheckBig /> {{ item.todosCount }}
|
||||
</Badge>
|
||||
|
||||
<Badge variant="secondary" v-if="item.notes && item.notes.length > 0">
|
||||
<MessageCircle /> {{ item.notes.length }}
|
||||
<MessageSquare /> {{ item.notes.length }}
|
||||
</Badge>
|
||||
<Badge variant="secondary" v-else-if="item.notesCount > 0">
|
||||
<MessageCircle /> {{ item.notesCount }}
|
||||
<MessageSquare /> {{ item.notesCount }}
|
||||
</Badge>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -317,7 +339,8 @@ const deleteItem = (item: PipelineItem | undefined) => {
|
||||
</template>
|
||||
|
||||
<template v-slot:content>
|
||||
<TextEditor :model-value="selectedItem?.description" @change:model-value="console.log"
|
||||
<TextEditor :model-value="selectedItem?.description"
|
||||
@change:model-value="value => { selectedItem!.description = value; saveItem(selectedItem) }"
|
||||
ref="description-editor" />
|
||||
<Notes v-if="selectedItem" title="Protokoll" :notableId="selectedItem.id" notableType="PipelineItem"
|
||||
:modelValue="selectedItem.notes" />
|
||||
@@ -326,7 +349,7 @@ const deleteItem = (item: PipelineItem | undefined) => {
|
||||
<template v-slot:sidebar>
|
||||
<NumberInput label="Erwarteter Umsatz" :modelValue="selectedItem?.expectedRevenue as number" suffix=" €"
|
||||
@update:model-value="console.log" />
|
||||
<Todos :modelValue="todos" :show-completed="false" />
|
||||
<Todos v-if="selectedItem" title="Aufgaben" :modelValue="selectedItem.todos" :show-completed="false" />
|
||||
</template>
|
||||
|
||||
</EditorDialog>
|
||||
|
||||
Reference in New Issue
Block a user