PHP Classes

File: resources/js/pages/Notebook.vue

Recommend this page to a friend!
  Packages of Niko Peikrishvili   Ticker   resources/js/pages/Notebook.vue   Download  
File: resources/js/pages/Notebook.vue
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Ticker
Application to track and manage to do tasks
Author: By
Last change:
Date: 3 months ago
Size: 9,444 bytes
 

Contents

Class file image Download
<script setup> import { ref, computed, onMounted, onUnmounted } from 'vue'; import { Head } from '@inertiajs/vue3'; import axios from 'axios'; import TodoList from '@/components/TodoList.vue'; import TimeLogList from '@/components/TimeLogList.vue'; import TodoModal from '@/components/TodoModal.vue'; import TimeLogModal from '@/components/TimeLogModal.vue'; import SettingsModal from '@/components/SettingsModal.vue'; import RecurringTasksModal from '@/components/RecurringTasksModal.vue'; import CarryOverDialog from '@/components/CarryOverDialog.vue'; import AppSidebar from '@/components/AppSidebar.vue'; import { SidebarProvider, SidebarInset, SidebarTrigger } from '@/components/ui/sidebar'; import { Separator } from '@/components/ui/separator'; import { Card } from '@/components/ui/card'; import { useTodos } from '@/composables/useTodos'; import { useTimeLogs } from '@/composables/useTimeLogs'; import { useSettings } from '@/composables/useSettings'; import { useOnboarding } from '@/composables/useOnboarding'; const { addTodo, initializeDate, fetchTodos, fetchPendingFromPrevious, startWorking } = useTodos(); const { timeLogs, addTimeLog, navigateDay, goToToday, formattedDate, isToday, fetchTimeLogs, stopTimeLog } = useTimeLogs(); const { fetchSettings, serverDate, appearance, updateSetting, applyTheme } = useSettings(); const { checkAndStartTour } = useOnboarding(); const showTodoModal = ref(false); const showTimeLogModal = ref(false); const showSettingsModal = ref(false); const showRecurringTasksModal = ref(false); const showCarryOverDialog = ref(false); const pendingTasks = ref([]); const openTodoModal = () => { showTodoModal.value = true; }; const closeTodoModal = () => { showTodoModal.value = false; }; const openTimeLogModal = () => { showTimeLogModal.value = true; }; const closeTimeLogModal = () => { showTimeLogModal.value = false; }; const handleSaveTodo = async (data) => { const { content, priority } = typeof data === 'string' ? { content: data, priority: 3 } : data; await addTodo(content, 'todo', priority); closeTodoModal(); }; const handleSaveAndStartTodo = async (data) => { const { content, priority } = typeof data === 'string' ? { content: data, priority: 3 } : data; // Stop any running time logs first const runningLogs = timeLogs.value.filter(log => !log.end_time); for (const log of runningLogs) { await stopTimeLog(log.id); } // Create the task and start working on it const todo = await addTodo(content, 'in_progress', priority); if (todo && todo.id) { await startWorking(todo.id); } closeTodoModal(); }; const handleSaveTimeLog = async (logData) => { // Stop any running time logs first const runningLogs = timeLogs.value.filter(log => !log.end_time); for (const log of runningLogs) { await stopTimeLog(log.id); } await addTimeLog(logData); closeTimeLogModal(); }; const handleSidebarAction = (action) => { switch (action) { case 'prevDay': navigateDay(-1); break; case 'today': goToToday(); break; case 'nextDay': navigateDay(1); break; case 'newTodo': openTodoModal(); break; case 'newTimeLog': openTimeLogModal(); break; case 'recurring': showRecurringTasksModal.value = true; break; } }; const toggleDarkMode = async () => { const newTheme = appearance.value.theme === 'dark' ? 'light' : 'dark'; await updateSetting('appearance.theme', newTheme); applyTheme(newTheme); }; const handleKeyDown = (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { return; } if (e.key === 'Escape') { if (showTodoModal.value) { closeTodoModal(); } else if (showTimeLogModal.value) { closeTimeLogModal(); } else if (showSettingsModal.value) { showSettingsModal.value = false; } else if (showRecurringTasksModal.value) { showRecurringTasksModal.value = false; } else if (showCarryOverDialog.value) { showCarryOverDialog.value = false; } return; } if (showTodoModal.value || showTimeLogModal.value || showSettingsModal.value || showRecurringTasksModal.value || showCarryOverDialog.value) { return; } // Ignore shortcuts when modifier keys are pressed (allow browser shortcuts like Ctrl+R) if (e.ctrlKey || e.metaKey || e.altKey) { return; } if (e.key === 'ArrowLeft') { e.preventDefault(); navigateDay(-1); } else if (e.key === 'ArrowRight') { e.preventDefault(); navigateDay(1); } else if (e.key === 't' || e.key === 'T') { e.preventDefault(); goToToday(); } else if (e.key === 'a' || e.key === 'A') { e.preventDefault(); e.stopPropagation(); openTodoModal(); } else if (e.key === 's' || e.key === 'S') { e.preventDefault(); e.stopPropagation(); openTimeLogModal(); } else if (e.key === 'w' || e.key === 'W') { e.preventDefault(); window.location.href = '/weekly'; } else if (e.key === 'r' || e.key === 'R') { e.preventDefault(); showRecurringTasksModal.value = true; } else if (e.key === ',') { e.preventDefault(); showSettingsModal.value = true; } else if (e.key === 'd' || e.key === 'D') { e.preventDefault(); toggleDarkMode(); } }; // Dynamic CSS variables based on settings const cssVars = computed(() => ({ '--dot-opacity': appearance.value.dotOpacity, '--primary-color': appearance.value.primaryColor, '--bg-color': appearance.value.backgroundColor, '--text-color': appearance.value.textColor, '--secondary-text-color': appearance.value.secondaryTextColor, '--border-color': appearance.value.borderColor, })); onMounted(async () => { document.addEventListener('keydown', handleKeyDown, true); // Performance test const pingStart = performance.now(); await axios.get('/api/ping'); console.log(`[ping] ${Math.round(performance.now() - pingStart)}ms`); await fetchSettings(); // Initialize date from server (respects timezone setting) if (serverDate.value) { initializeDate(serverDate.value); // Fetch data after date is initialized await Promise.all([fetchTodos(), fetchTimeLogs()]); // Check for pending tasks from previous dates const pending = await fetchPendingFromPrevious(serverDate.value); if (pending.length > 0) { pendingTasks.value = pending; showCarryOverDialog.value = true; } else { // Only auto-start tour if no carry-over dialog is shown checkAndStartTour(); } } }); onUnmounted(() => { document.removeEventListener('keydown', handleKeyDown, true); }); </script> <template> <Head title="??????" /> <SidebarProvider :style="{ '--sidebar-width': '16rem', ...cssVars }"> <AppSidebar current-page="notebook" :show-settings="() => showSettingsModal = true" @action="handleSidebarAction" /> <SidebarInset> <header class="flex h-14 shrink-0 items-center gap-2 border-b px-4" data-tour="header"> <SidebarTrigger class="-ml-1" /> <Separator orientation="vertical" class="mr-2 h-4" /> <div class="flex items-center gap-2"> <span class="font-medium">{{ formattedDate }}</span> <span v-if="isToday" class="px-2 py-0.5 text-xs rounded-full bg-primary text-primary-foreground" > ???? </span> </div> </header> <div class="flex-1 p-4"> <!-- Notebook Container --> <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 h-[calc(100vh-88px)]"> <!-- LEFT PAGE: Todo List --> <div class="overflow-hidden flex flex-col"> <TodoList :on-open-modal="openTodoModal" /> </div> <!-- RIGHT PAGE: Time Log --> <Card class="p-6 overflow-hidden flex flex-col"> <TimeLogList :on-open-modal="openTimeLogModal" /> </Card> </div> </div> </SidebarInset> <!-- Modals --> <TodoModal :show="showTodoModal" @close="closeTodoModal" @save="handleSaveTodo" @save-and-start="handleSaveAndStartTodo" /> <TimeLogModal :show="showTimeLogModal" @close="closeTimeLogModal" @save="handleSaveTimeLog" /> <SettingsModal :show="showSettingsModal" @close="showSettingsModal = false" /> <RecurringTasksModal :show="showRecurringTasksModal" @close="showRecurringTasksModal = false" /> <CarryOverDialog :show="showCarryOverDialog" :pending-tasks="pendingTasks" @close="showCarryOverDialog = false" @carried-over="pendingTasks = []" /> </SidebarProvider> </template> <style scoped> kbd { font-family: monospace; } </style>