Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Task Manager</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .sidebar-item.active { | |
| background-color: #f3f4f6; | |
| border-left: 4px solid #3b82f6; | |
| } | |
| .status-approved { | |
| background-color: #d1fae5; | |
| color: #065f46; | |
| } | |
| .status-pending { | |
| background-color: #fef3c7; | |
| color: #92400e; | |
| } | |
| .status-rework { | |
| background-color: #fee2e2; | |
| color: #991b1b; | |
| } | |
| .task-checkbox:checked + .task-item { | |
| background-color: #eff6ff; | |
| } | |
| .tab-active { | |
| border-bottom: 2px solid #3b82f6; | |
| color: #3b82f6; | |
| } | |
| .modal { | |
| transition: opacity 0.3s ease, transform 0.3s ease; | |
| } | |
| .modal-enter { | |
| opacity: 0; | |
| transform: translateY(-20px); | |
| } | |
| .modal-enter-active { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| .task-row { | |
| cursor: pointer; | |
| transition: background-color 0.2s; | |
| } | |
| .task-row:hover { | |
| background-color: #f9fafb; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 font-sans"> | |
| <div class="flex h-screen overflow-hidden"> | |
| <!-- Sidebar --> | |
| <div class="w-64 bg-white border-r border-gray-200 flex flex-col"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h1 class="text-xl font-bold text-blue-600">Task Manager</h1> | |
| </div> | |
| <nav class="flex-1 overflow-y-auto"> | |
| <div class="p-4"> | |
| <div class="sidebar-item active mb-1 px-3 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-tachometer-alt mr-3 text-gray-500"></i> | |
| <span>Overview</span> | |
| </div> | |
| <div class="sidebar-item mb-1 px-3 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-tasks mr-3 text-gray-500"></i> | |
| <span>Tasks</span> | |
| </div> | |
| <div class="sidebar-item mb-1 px-3 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-users mr-3 text-gray-500"></i> | |
| <span>Your Team</span> | |
| </div> | |
| <div class="sidebar-item mb-1 px-3 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-envelope mr-3 text-gray-500"></i> | |
| <span>Messages</span> | |
| </div> | |
| <div class="sidebar-item mb-1 px-3 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-cog mr-3 text-gray-500"></i> | |
| <span>Settings</span> | |
| </div> | |
| </div> | |
| </nav> | |
| <div class="p-4 border-t border-gray-200"> | |
| <div class="flex items-center"> | |
| <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Profile" class="w-10 h-10 rounded-full mr-3"> | |
| <div> | |
| <div class="font-medium">Jane Smith</div> | |
| <div class="text-sm text-gray-500">Admin</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="flex-1 flex flex-col overflow-hidden"> | |
| <!-- Header --> | |
| <header class="bg-white border-b border-gray-200 p-4 flex justify-between items-center"> | |
| <div class="flex items-center"> | |
| <div class="relative"> | |
| <input type="text" placeholder="Search tasks..." class="pl-10 pr-4 py-2 border border-gray-300 rounded-lg w-64 focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> | |
| </div> | |
| </div> | |
| <div class="flex items-center"> | |
| <div class="mr-4 relative"> | |
| <i class="fas fa-bell text-gray-500 text-xl cursor-pointer"></i> | |
| <span class="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">3</span> | |
| </div> | |
| <div class="flex items-center"> | |
| <div class="mr-3 text-right"> | |
| <div class="font-medium">Jane Smith</div> | |
| <div class="text-sm text-gray-500">Admin</div> | |
| </div> | |
| <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Profile" class="w-10 h-10 rounded-full"> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Content --> | |
| <main class="flex-1 overflow-y-auto p-6"> | |
| <div class="mb-6 flex justify-between items-center"> | |
| <h2 class="text-2xl font-bold">Tasks</h2> | |
| <button id="createTaskBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-plus mr-2"></i> Create Task | |
| </button> | |
| </div> | |
| <!-- Tabs --> | |
| <div class="mb-6 border-b border-gray-200"> | |
| <div class="flex space-x-8"> | |
| <div class="tab tab-active pb-2 font-medium cursor-pointer" data-tab="all">All Tasks</div> | |
| <div class="tab pb-2 font-medium cursor-pointer" data-tab="approved">Approved</div> | |
| <div class="tab pb-2 font-medium cursor-pointer" data-tab="pending">Pending</div> | |
| <div class="tab pb-2 font-medium cursor-pointer" data-tab="completed">Completed</div> | |
| <div class="tab pb-2 font-medium cursor-pointer" data-tab="assigned">Assigned</div> | |
| </div> | |
| </div> | |
| <!-- Task Table --> | |
| <div class="bg-white rounded-lg shadow overflow-hidden"> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | |
| <input type="checkbox" class="rounded text-blue-600 focus:ring-blue-500"> | |
| </th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Task Name</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Created Date</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Due Date</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Activity</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200" id="taskTableBody"> | |
| <!-- Tasks will be loaded here --> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <!-- Submit Button --> | |
| <div class="mt-4 flex justify-end"> | |
| <button id="submitForApprovalBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-paper-plane mr-2"></i> Submit for Approval | |
| </button> | |
| </div> | |
| </main> | |
| </div> | |
| </div> | |
| <!-- Create Task Modal --> | |
| <div id="createTaskModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
| <div class="bg-white rounded-lg shadow-xl w-full max-w-md modal"> | |
| <div class="p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-lg font-medium">Create New Task</h3> | |
| <button id="closeModalBtn" class="text-gray-400 hover:text-gray-500"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <form id="taskForm"> | |
| <div class="mb-4"> | |
| <label for="taskTitle" class="block text-sm font-medium text-gray-700 mb-1">Task Title</label> | |
| <input type="text" id="taskTitle" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" required> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="taskDescription" class="block text-sm font-medium text-gray-700 mb-1">Description</label> | |
| <textarea id="taskDescription" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="taskDueDate" class="block text-sm font-medium text-gray-700 mb-1">Due Date</label> | |
| <input type="date" id="taskDueDate" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="taskStatus" class="block text-sm font-medium text-gray-700 mb-1">Status</label> | |
| <select id="taskStatus" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"> | |
| <option value="Pending">Pending</option> | |
| <option value="Approved">Approved</option> | |
| <option value="Re work">Re work</option> | |
| </select> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="taskFile" class="block text-sm font-medium text-gray-700 mb-1">Attach File</label> | |
| <div class="mt-1 flex items-center"> | |
| <input type="file" id="taskFile" class="hidden"> | |
| <label for="taskFile" class="cursor-pointer bg-gray-100 hover:bg-gray-200 px-3 py-2 rounded-md text-sm font-medium text-gray-700"> | |
| <i class="fas fa-paperclip mr-2"></i>Choose File | |
| </label> | |
| <span id="fileName" class="ml-2 text-sm text-gray-500">No file chosen</span> | |
| </div> | |
| </div> | |
| <div class="flex justify-end space-x-3"> | |
| <button type="button" id="cancelTaskBtn" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"> | |
| Cancel | |
| </button> | |
| <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-md text-sm font-medium hover:bg-blue-700"> | |
| Create Task | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Task Details Modal --> | |
| <div id="taskDetailsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
| <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl modal"> | |
| <div class="p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-xl font-medium" id="taskDetailsTitle">Task Details</h3> | |
| <button id="closeDetailsModalBtn" class="text-gray-400 hover:text-gray-500"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6"> | |
| <div> | |
| <h4 class="text-sm font-medium text-gray-500 mb-1">Status</h4> | |
| <p id="taskDetailsStatus" class="text-sm font-medium"></p> | |
| </div> | |
| <div> | |
| <h4 class="text-sm font-medium text-gray-500 mb-1">Created Date</h4> | |
| <p id="taskDetailsCreated" class="text-sm"></p> | |
| </div> | |
| <div> | |
| <h4 class="text-sm font-medium text-gray-500 mb-1">Due Date</h4> | |
| <p id="taskDetailsDue" class="text-sm"></p> | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <h4 class="text-sm font-medium text-gray-500 mb-1">Description</h4> | |
| <p id="taskDetailsDescription" class="text-sm text-gray-700 bg-gray-50 p-3 rounded-md"></p> | |
| </div> | |
| <div class="mb-6"> | |
| <h4 class="text-sm font-medium text-gray-500 mb-1">Attachments</h4> | |
| <div id="taskDetailsAttachment" class="flex items-center mt-2"> | |
| <i class="fas fa-file text-gray-400 mr-2"></i> | |
| <span class="text-sm text-gray-700">No attachments</span> | |
| </div> | |
| </div> | |
| <div class="flex justify-between items-center border-t border-gray-200 pt-4"> | |
| <div> | |
| <h4 class="text-sm font-medium text-gray-500 mb-1">Assigned To</h4> | |
| <div class="flex items-center"> | |
| <img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Profile" class="w-8 h-8 rounded-full mr-2"> | |
| <span id="taskDetailsAssigned" class="text-sm">Jane Smith</span> | |
| </div> | |
| </div> | |
| <div class="flex space-x-3"> | |
| <button id="editTaskBtn" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"> | |
| <i class="fas fa-edit mr-2"></i>Edit | |
| </button> | |
| <button id="deleteTaskBtn" class="px-4 py-2 bg-red-600 text-white rounded-md text-sm font-medium hover:bg-red-700"> | |
| <i class="fas fa-trash mr-2"></i>Delete | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Sample task data | |
| const tasks = [ | |
| { | |
| id: '1', | |
| title: 'Design Homepage Mockup', | |
| description: 'Create wireframes and high-fidelity mockups for the new homepage design following brand guidelines.', | |
| fileName: 'design.pdf', | |
| createdDate: '2023-05-15', | |
| dueDate: '2023-06-10', | |
| lastActivity: '2023-05-20', | |
| status: 'Approved', | |
| assignedTo: 'John Doe' | |
| }, | |
| { | |
| id: '2', | |
| title: 'Implement User Authentication', | |
| description: 'Set up JWT authentication for the API and implement login/signup flows in the frontend.', | |
| fileName: 'auth.js', | |
| createdDate: '2023-05-18', | |
| dueDate: '2023-06-05', | |
| lastActivity: '2023-05-22', | |
| status: 'Pending', | |
| assignedTo: 'Jane Smith' | |
| }, | |
| { | |
| id: '3', | |
| title: 'Database Schema Review', | |
| description: 'Review the proposed database schema and provide feedback on normalization and indexing.', | |
| fileName: 'schema.sql', | |
| createdDate: '2023-05-10', | |
| dueDate: '2023-05-25', | |
| lastActivity: '2023-05-15', | |
| status: 'Re work', | |
| assignedTo: 'Mike Johnson' | |
| }, | |
| { | |
| id: '4', | |
| title: 'Mobile App UI Design', | |
| description: 'Design the mobile app interface with a focus on intuitive navigation and accessibility.', | |
| fileName: 'mobile-ui.fig', | |
| createdDate: '2023-05-20', | |
| dueDate: '2023-06-15', | |
| lastActivity: '2023-05-25', | |
| status: 'Pending', | |
| assignedTo: 'Sarah Williams' | |
| }, | |
| { | |
| id: '5', | |
| title: 'API Documentation', | |
| description: 'Document all API endpoints with examples for request/response formats and error codes.', | |
| fileName: 'api-docs.md', | |
| createdDate: '2023-05-12', | |
| dueDate: '2023-05-30', | |
| lastActivity: '2023-05-18', | |
| status: 'Approved', | |
| assignedTo: 'David Brown' | |
| } | |
| ]; | |
| // DOM elements | |
| const taskTableBody = document.getElementById('taskTableBody'); | |
| const createTaskBtn = document.getElementById('createTaskBtn'); | |
| const closeModalBtn = document.getElementById('closeModalBtn'); | |
| const cancelTaskBtn = document.getElementById('cancelTaskBtn'); | |
| const createTaskModal = document.getElementById('createTaskModal'); | |
| const taskForm = document.getElementById('taskForm'); | |
| const tabs = document.querySelectorAll('.tab'); | |
| const submitForApprovalBtn = document.getElementById('submitForApprovalBtn'); | |
| const taskFileInput = document.getElementById('taskFile'); | |
| const fileNameDisplay = document.getElementById('fileName'); | |
| // Task details modal elements | |
| const taskDetailsModal = document.getElementById('taskDetailsModal'); | |
| const closeDetailsModalBtn = document.getElementById('closeDetailsModalBtn'); | |
| const taskDetailsTitle = document.getElementById('taskDetailsTitle'); | |
| const taskDetailsStatus = document.getElementById('taskDetailsStatus'); | |
| const taskDetailsCreated = document.getElementById('taskDetailsCreated'); | |
| const taskDetailsDue = document.getElementById('taskDetailsDue'); | |
| const taskDetailsDescription = document.getElementById('taskDetailsDescription'); | |
| const taskDetailsAttachment = document.getElementById('taskDetailsAttachment'); | |
| const taskDetailsAssigned = document.getElementById('taskDetailsAssigned'); | |
| const editTaskBtn = document.getElementById('editTaskBtn'); | |
| const deleteTaskBtn = document.getElementById('deleteTaskBtn'); | |
| // Current filter and selected task | |
| let currentFilter = 'all'; | |
| let selectedTaskId = null; | |
| // Initialize the app | |
| function init() { | |
| renderTasks(); | |
| setupEventListeners(); | |
| } | |
| // Render tasks based on current filter | |
| function renderTasks() { | |
| taskTableBody.innerHTML = ''; | |
| const filteredTasks = tasks.filter(task => { | |
| if (currentFilter === 'all') return true; | |
| if (currentFilter === 'approved') return task.status === 'Approved'; | |
| if (currentFilter === 'pending') return task.status === 'Pending'; | |
| if (currentFilter === 'completed') return task.status === 'Completed'; | |
| if (currentFilter === 'assigned') return task.assignedTo === 'Jane Smith'; | |
| return true; | |
| }); | |
| if (filteredTasks.length === 0) { | |
| taskTableBody.innerHTML = ` | |
| <tr> | |
| <td colspan="7" class="px-6 py-4 text-center text-gray-500"> | |
| No tasks found | |
| </td> | |
| </tr> | |
| `; | |
| return; | |
| } | |
| filteredTasks.forEach(task => { | |
| const fileIcon = getFileIcon(task.fileName); | |
| const statusClass = getStatusClass(task.status); | |
| const row = document.createElement('tr'); | |
| row.className = 'task-row hover:bg-gray-50'; | |
| row.setAttribute('data-id', task.id); | |
| row.innerHTML = ` | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <input type="checkbox" class="task-checkbox rounded text-blue-600 focus:ring-blue-500"> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="flex items-center"> | |
| <div class="flex-shrink-0 h-10 w-10 flex items-center justify-center rounded-md bg-gray-100 text-gray-500"> | |
| ${fileIcon} | |
| </div> | |
| <div class="ml-4"> | |
| <div class="text-sm font-medium text-gray-900">${task.title}</div> | |
| <div class="text-sm text-gray-500">${task.fileName}</div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="text-sm text-gray-900">${formatDate(task.createdDate)}</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="text-sm text-gray-900">${formatDate(task.dueDate)}</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <div class="text-sm text-gray-900">${formatDate(task.lastActivity)}</div> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass}"> | |
| ${task.status} | |
| </span> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> | |
| <button class="text-blue-600 hover:text-blue-900 mr-3 edit-task" data-id="${task.id}"> | |
| <i class="fas fa-edit"></i> | |
| </button> | |
| <button class="text-red-600 hover:text-red-900 delete-task" data-id="${task.id}"> | |
| <i class="fas fa-trash"></i> | |
| </button> | |
| </td> | |
| `; | |
| taskTableBody.appendChild(row); | |
| }); | |
| // Add event listeners to task rows | |
| document.querySelectorAll('.task-row').forEach(row => { | |
| row.addEventListener('click', (e) => { | |
| // Don't trigger if clicking on checkbox or action buttons | |
| if (e.target.tagName === 'INPUT' || e.target.closest('.edit-task') || e.target.closest('.delete-task')) { | |
| return; | |
| } | |
| const taskId = row.getAttribute('data-id'); | |
| showTaskDetails(taskId); | |
| }); | |
| }); | |
| // Add event listeners to edit and delete buttons | |
| document.querySelectorAll('.edit-task').forEach(btn => { | |
| btn.addEventListener('click', (e) => { | |
| e.stopPropagation(); | |
| const taskId = e.currentTarget.getAttribute('data-id'); | |
| editTask(taskId); | |
| }); | |
| }); | |
| document.querySelectorAll('.delete-task').forEach(btn => { | |
| btn.addEventListener('click', (e) => { | |
| e.stopPropagation(); | |
| const taskId = e.currentTarget.getAttribute('data-id'); | |
| deleteTask(taskId); | |
| }); | |
| }); | |
| } | |
| // Show task details in modal | |
| function showTaskDetails(taskId) { | |
| const task = tasks.find(t => t.id === taskId); | |
| if (!task) return; | |
| selectedTaskId = taskId; | |
| // Update modal content | |
| taskDetailsTitle.textContent = task.title; | |
| taskDetailsStatus.textContent = task.status; | |
| taskDetailsStatus.className = 'text-sm font-medium ' + getStatusClass(task.status); | |
| taskDetailsCreated.textContent = formatDate(task.createdDate); | |
| taskDetailsDue.textContent = formatDate(task.dueDate); | |
| taskDetailsDescription.textContent = task.description || 'No description provided'; | |
| taskDetailsAssigned.textContent = task.assignedTo; | |
| // Update attachment display | |
| if (task.fileName) { | |
| const fileIcon = getFileIcon(task.fileName); | |
| taskDetailsAttachment.innerHTML = ` | |
| ${fileIcon} | |
| <span class="text-sm text-gray-700 ml-2">${task.fileName}</span> | |
| `; | |
| } else { | |
| taskDetailsAttachment.innerHTML = ` | |
| <i class="fas fa-file text-gray-400 mr-2"></i> | |
| <span class="text-sm text-gray-700">No attachments</span> | |
| `; | |
| } | |
| // Show modal | |
| taskDetailsModal.classList.remove('hidden'); | |
| } | |
| // Get appropriate file icon | |
| function getFileIcon(fileName) { | |
| if (!fileName) return ''; | |
| const extension = fileName.split('.').pop().toLowerCase(); | |
| switch(extension) { | |
| case 'pdf': | |
| return '<i class="fas fa-file-pdf text-red-500"></i>'; | |
| case 'js': | |
| return '<i class="fab fa-js-square text-yellow-400"></i>'; | |
| case 'sql': | |
| return '<i class="fas fa-database text-blue-500"></i>'; | |
| case 'fig': | |
| return '<i class="fas fa-palette text-purple-500"></i>'; | |
| case 'md': | |
| return '<i class="fas fa-file-alt text-gray-500"></i>'; | |
| default: | |
| return '<i class="fas fa-file text-gray-500"></i>'; | |
| } | |
| } | |
| // Get status class for styling | |
| function getStatusClass(status) { | |
| switch(status) { | |
| case 'Approved': | |
| return 'status-approved'; | |
| case 'Pending': | |
| return 'status-pending'; | |
| case 'Re work': | |
| return 'status-rework'; | |
| default: | |
| return 'bg-gray-100 text-gray-800'; | |
| } | |
| } | |
| // Format date for display | |
| function formatDate(dateString) { | |
| const options = { year: 'numeric', month: 'short', day: 'numeric' }; | |
| return new Date(dateString).toLocaleDateString(undefined, options); | |
| } | |
| // Set up event listeners | |
| function setupEventListeners() { | |
| // Create task button | |
| createTaskBtn.addEventListener('click', () => { | |
| createTaskModal.classList.remove('hidden'); | |
| }); | |
| // Close modal buttons | |
| closeModalBtn.addEventListener('click', closeModal); | |
| cancelTaskBtn.addEventListener('click', closeModal); | |
| closeDetailsModalBtn.addEventListener('click', () => { | |
| taskDetailsModal.classList.add('hidden'); | |
| }); | |
| // Form submission | |
| taskForm.addEventListener('submit', (e) => { | |
| e.preventDefault(); | |
| createNewTask(); | |
| }); | |
| // Tab switching | |
| tabs.forEach(tab => { | |
| tab.addEventListener('click', () => { | |
| tabs.forEach(t => t.classList.remove('tab-active')); | |
| tab.classList.add('tab-active'); | |
| currentFilter = tab.getAttribute('data-tab'); | |
| renderTasks(); | |
| }); | |
| }); | |
| // Submit for approval button | |
| submitForApprovalBtn.addEventListener('click', () => { | |
| const selectedTasks = document.querySelectorAll('.task-checkbox:checked'); | |
| if (selectedTasks.length === 0) { | |
| alert('Please select at least one task to submit for approval'); | |
| return; | |
| } | |
| // In a real app, this would make an API call | |
| alert(`Submitting ${selectedTasks.length} task(s) for approval`); | |
| // Reset checkboxes | |
| document.querySelectorAll('.task-checkbox').forEach(checkbox => { | |
| checkbox.checked = false; | |
| }); | |
| }); | |
| // File input change | |
| taskFileInput.addEventListener('change', (e) => { | |
| if (e.target.files.length > 0) { | |
| fileNameDisplay.textContent = e.target.files[0].name; | |
| } else { | |
| fileNameDisplay.textContent = 'No file chosen'; | |
| } | |
| }); | |
| // Edit task button in details modal | |
| editTaskBtn.addEventListener('click', () => { | |
| if (selectedTaskId) { | |
| taskDetailsModal.classList.add('hidden'); | |
| editTask(selectedTaskId); | |
| } | |
| }); | |
| // Delete task button in details modal | |
| deleteTaskBtn.addEventListener('click', () => { | |
| if (selectedTaskId) { | |
| taskDetailsModal.classList.add('hidden'); | |
| deleteTask(selectedTaskId); | |
| } | |
| }); | |
| } | |
| // Close modal | |
| function closeModal() { | |
| createTaskModal.classList.add('hidden'); | |
| taskForm.reset(); | |
| fileNameDisplay.textContent = 'No file chosen'; | |
| } | |
| // Create new task | |
| function createNewTask() { | |
| const title = document.getElementById('taskTitle').value; | |
| const description = document.getElementById('taskDescription').value; | |
| const dueDate = document.getElementById('taskDueDate').value; | |
| const status = document.getElementById('taskStatus').value; | |
| const fileName = taskFileInput.files.length > 0 ? taskFileInput.files[0].name : ''; | |
| // In a real app, this would make an API call to the backend | |
| const newTask = { | |
| id: (tasks.length + 1).toString(), | |
| title, | |
| description, | |
| fileName, | |
| createdDate: new Date().toISOString().split('T')[0], | |
| dueDate, | |
| lastActivity: new Date().toISOString().split('T')[0], | |
| status, | |
| assignedTo: 'Jane Smith' | |
| }; | |
| tasks.unshift(newTask); | |
| renderTasks(); | |
| closeModal(); | |
| } | |
| // Edit task | |
| function editTask(taskId) { | |
| const task = tasks.find(t => t.id === taskId); | |
| if (!task) return; | |
| // In a real app, this would open an edit form/modal | |
| alert(`Editing task: ${task.title}\nThis would open an edit form in a real application.`); | |
| } | |
| // Delete task | |
| function deleteTask(taskId) { | |
| if (confirm('Are you sure you want to delete this task?')) { | |
| // In a real app, this would make an API call to delete | |
| const index = tasks.findIndex(t => t.id === taskId); | |
| if (index !== -1) { | |
| tasks.splice(index, 1); | |
| renderTasks(); | |
| } | |
| } | |
| } | |
| // Initialize the app | |
| init(); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=hharris928/task-manager" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |