EhsonKH/tasktamer-jira-inspired-task-wizardry
0
1// Shared functionality across pages2document.addEventListener('DOMContentLoaded', () => {3 // Initialize tooltips4 if (window.tippy) {5 tippy('[data-tippy-content]', {6 arrow: true,7 animation: 'scale',8 duration: 200,9 theme: 'light'10 });11 }12// Load tasks from API or localStorage13if (typeof loadTasks !== 'function') {14 window.loadTasks = async () => {15 try {16 // In a real app, this would fetch from an API17 const mockTasks = [18 { 19 id: 1, 20 title: 'Design homepage', 21 status: 'In Progress', 22 priority: 'High', 23 assignee: 'Alex',24 project: 'Website Redesign',25 dueDate: '2023-04-15'26 },27 { 28 id: 2, 29 title: 'Implement auth system', 30 status: 'To Do', 31 priority: 'Critical', 32 assignee: 'Sam',33 project: 'Mobile App',34 dueDate: '2023-04-20'35 },36 { 37 id: 3, 38 title: 'Write API documentation', 39 status: 'Done', 40 priority: 'Medium', 41 assignee: 'Taylor',42 project: 'Mobile App',43 dueDate: '2023-04-10'44 },45 { 46 id: 4, 47 title: 'Create marketing assets', 48 status: 'Overdue', 49 priority: 'High', 50 assignee: 'Taylor',51 project: 'Marketing Campaign',52 dueDate: '2023-04-05'53 }54 ];55 56 // Save to localStorage if not exists57 if (!localStorage.getItem('tasks')) {58 localStorage.setItem('tasks', JSON.stringify(mockTasks));59 }60 61 return JSON.parse(localStorage.getItem('tasks')) || mockTasks;62 } catch (error) {63 console.error('Error loading tasks:', error);64 return [];65 }66 };67}68 69// Load projects data70window.loadProjects = async () => {71 try {72 const mockProjects = [73 {74 id: 1,75 name: 'Website Redesign',76 status: 'Active',77 description: 'Complete redesign of company website with new branding',78 startDate: '2023-03-15',79 dueDate: '2023-05-15',80 team: ['Alex', 'Sam', 'Taylor'],81 progress: 65,82 color: 'indigo'83 },84 {85 id: 2,86 name: 'Mobile App',87 status: 'In Development',88 description: 'New cross-platform mobile application for iOS and Android',89 startDate: '2023-04-01',90 dueDate: '2023-06-30',91 team: ['Sam', 'Jordan', 'Casey'],92 progress: 42,93 color: 'blue'94 },95 {96 id: 3,97 name: 'Marketing Campaign',98 status: 'Planning',99 description: 'Q3 marketing campaign for new product launch',100 startDate: '2023-05-01',101 dueDate: '2023-08-01',102 team: ['Taylor', 'Alex', 'Morgan'],103 progress: 15,104 color: 'purple'105 }106 ];107 108 if (!localStorage.getItem('projects')) {109 localStorage.setItem('projects', JSON.stringify(mockProjects));110 }111 112 return JSON.parse(localStorage.getItem('projects')) || mockProjects;113 } catch (error) {114 console.error('Error loading projects:', error);115 return [];116 }117};118 119// Load activity feed120window.loadActivity = async () => {121 try {122 const mockActivity = [123 {124 id: 1,125 user: 'Alex Johnson',126 action: 'commented',127 target: 'Homepage Design',128 message: 'The layout looks great, but we should adjust the spacing between sections.',129 timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString() // 2 hours ago130 },131 {132 id: 2,133 user: 'Sam Wilson',134 action: 'completed',135 target: 'Implement user authentication',136 message: '',137 timestamp: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString() // 1 day ago138 },139 {140 id: 3,141 user: 'Taylor Swift',142 action: 'uploaded',143 target: 'Marketing assets',144 message: '',145 timestamp: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString() // 2 days ago146 },147 {148 id: 4,149 user: 'Project Bot',150 action: 'created',151 target: 'Mobile App project',152 message: '',153 timestamp: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString() // 3 days ago154 }155 ];156 157 if (!localStorage.getItem('activity')) {158 localStorage.setItem('activity', JSON.stringify(mockActivity));159 }160 161 return JSON.parse(localStorage.getItem('activity')) || mockActivity;162 } catch (error) {163 console.error('Error loading activity:', error);164 return [];165 }166};167});168 169// Drag and drop functionality for tasks170function setupDragAndDrop() {171 const draggables = document.querySelectorAll('.task-card');172 const containers = document.querySelectorAll('.task-column');173 174 draggables.forEach(draggable => {175 draggable.addEventListener('dragstart', () => {176 draggable.classList.add('dragging');177 });178 179 draggable.addEventListener('dragend', () => {180 draggable.classList.remove('dragging');181 });182 });183 184 containers.forEach(container => {185 container.addEventListener('dragover', e => {186 e.preventDefault();187 const afterElement = getDragAfterElement(container, e.clientY);188 const draggable = document.querySelector('.dragging');189 190 if (afterElement == null) {191 container.appendChild(draggable);192 } else {193 container.insertBefore(draggable, afterElement);194 }195 });196 });197 198 function getDragAfterElement(container, y) {199 const draggableElements = [...container.querySelectorAll('.task-card:not(.dragging)')];200 201 return draggableElements.reduce((closest, child) => {202 const box = child.getBoundingClientRect();203 const offset = y - box.top - box.height / 2;204 205 if (offset < 0 && offset > closest.offset) {206 return { offset: offset, element: child };207 } else {208 return closest;209 }210 }, { offset: Number.NEGATIVE_INFINITY }).element;211 }212}