Taskmanager / index.html
ssp31787's picture
I need an application which works in both android and windows to add my profession al and personal task .App which gives me reminder every hour until i complete the task .If it is professional below column required . Requestor, Project, concern ,Open/Close, Due days .Personal : Task Status .Due days. I need to export to excel all the profession task
9afba86 verified
Raw History Blame Contribute Delete
29.4 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TaskMagnet Pro+Life</title>
<meta name="theme-color" content="#4f46e5">
<link rel="manifest" href="/manifest.json">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
500: '#4f46e5',
600: '#4338ca',
},
secondary: {
500: '#f472b6',
600: '#ec4899',
}
}
}
}
}
</script>
<style>
@media (min-width: 1024px) {
.lg\:max-h-96 {
max-height: 24rem;
}
}
.checkbox:checked + .checkmark {
background-color: #4f46e5;
border-color: #4f46e5;
}
.checkbox:checked + .checkmark:after {
display: block;
}
.checkmark:after {
content: "";
position: absolute;
display: none;
left: 6px;
top: 2px;
width: 4px;
height: 8px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Header -->
<header class="py-6">
<div class="flex justify-between items-center">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 rounded-full bg-primary-500 flex items-center justify-center">
<i data-feather="check-circle" class="text-white"></i>
</div>
<h1 class="text-2xl font-bold text-gray-800">TaskMagnet</h1>
</div>
<div class="flex space-x-4">
<button class="p-2 rounded-full bg-gray-200 text-gray-700 hover:bg-gray-300 transition">
<i data-feather="bell"></i>
</button>
<button class="p-2 rounded-full bg-gray-200 text-gray-700 hover:bg-gray-300 transition">
<i data-feather="settings"></i>
</button>
</div>
</div>
</header>
<!-- Main Content -->
<main class="pb-16">
<!-- Tab Navigation -->
<div class="flex border-b border-gray-200">
<button id="professional-tab" class="flex-1 py-4 px-1 text-center border-b-2 font-medium text-sm border-primary-500 text-primary-600">
Professional Tasks
</button>
<button id="personal-tab" class="flex-1 py-4 px-1 text-center border-b-2 font-medium text-sm border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300">
Personal Tasks
</button>
</div>
<!-- Professional Tasks -->
<div id="professional-content" class="mt-6">
<div class="flex justify-between items-center mb-4">
<h2 class="text-lg font-medium text-gray-900">Professional Tasks</h2>
<button id="export-professional" class="px-4 py-2 bg-primary-500 text-white rounded-md hover:bg-primary-600 transition flex items-center space-x-2">
<i data-feather="download" class="w-4 h-4"></i>
<span>Export to Excel</span>
</button>
</div>
<!-- Add Professional Task -->
<div class="mb-6 bg-white rounded-lg shadow p-4">
<h3 class="text-md font-medium text-gray-900 mb-3">Add New Professional Task</h3>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4">
<div>
<label for="requestor" class="block text-sm font-medium text-gray-700">Requestor</label>
<input type="text" id="requestor" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm">
</div>
<div>
<label for="project" class="block text-sm font-medium text-gray-700">Project</label>
<input type="text" id="project" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm">
</div>
<div>
<label for="concern" class="block text-sm font-medium text-gray-700">Concern</label>
<input type="text" id="concern" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm">
</div>
<div>
<label for="status" class="block text-sm font-medium text-gray-700">Status</label>
<select id="status" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm">
<option>Open</option>
<option>Closed</option>
</select>
</div>
<div>
<label for="due-days" class="block text-sm font-medium text-gray-700">Due Days</label>
<input type="number" id="due-days" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm">
</div>
</div>
<div class="mt-4 flex justify-end">
<button id="add-professional" class="px-4 py-2 bg-primary-500 text-white rounded-md hover:bg-primary-600 transition">
Add Task
</button>
</div>
</div>
<!-- Professional Tasks List -->
<div class="bg-white shadow rounded-lg 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">Requestor</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Project</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Concern</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">Due Days</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 id="professional-tasks" class="bg-white divide-y divide-gray-200">
<!-- Tasks will be added here dynamically -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Personal Tasks (Hidden by default) -->
<div id="personal-content" class="mt-6 hidden">
<div class="flex justify-between items-center mb-4">
<h2 class="text-lg font-medium text-gray-900">Personal Tasks</h2>
</div>
<!-- Add Personal Task -->
<div class="mb-6 bg-white rounded-lg shadow p-4">
<h3 class="text-md font-medium text-gray-900 mb-3">Add New Personal Task</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="col-span-2">
<label for="task-description" class="block text-sm font-medium text-gray-700">Task Description</label>
<input type="text" id="task-description" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm">
</div>
<div>
<label for="personal-due-days" class="block text-sm font-medium text-gray-700">Due Days</label>
<input type="number" id="personal-due-days" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm">
</div>
</div>
<div class="mt-4 flex justify-end">
<button id="add-personal" class="px-4 py-2 bg-primary-500 text-white rounded-md hover:bg-primary-600 transition">
Add Task
</button>
</div>
</div>
<!-- Personal Tasks List -->
<div class="bg-white shadow rounded-lg overflow-hidden">
<ul id="personal-tasks" class="divide-y divide-gray-200">
<!-- Tasks will be added here dynamically -->
</ul>
</div>
</div>
</main>
<!-- Bottom Navigation -->
<div class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 shadow-lg">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-around">
<button class="py-3 px-4 flex flex-col items-center text-primary-500">
<i data-feather="home" class="w-5 h-5"></i>
<span class="text-xs mt-1">Home</span>
</button>
<button class="py-3 px-4 flex flex-col items-center text-gray-500">
<i data-feather="calendar" class="w-5 h-5"></i>
<span class="text-xs mt-1">Calendar</span>
</button>
<button class="py-3 px-4 flex flex-col items-center text-gray-500">
<i data-feather="pie-chart" class="w-5 h-5"></i>
<span class="text-xs mt-1">Stats</span>
</button>
<button class="py-3 px-4 flex flex-col items-center text-gray-500">
<i data-feather="user" class="w-5 h-5"></i>
<span class="text-xs mt-1">Profile</span>
</button>
</div>
</div>
</div>
</div>
<!-- Reminder Modal -->
<div id="reminder-modal" class="fixed inset-0 overflow-y-auto hidden z-50">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
<div>
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-yellow-100">
<i data-feather="clock" class="h-6 w-6 text-yellow-600"></i>
</div>
<div class="mt-3 text-center sm:mt-5">
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-title">
Task Reminder
</h3>
<div class="mt-2">
<p class="text-sm text-gray-500" id="reminder-task">
You have pending tasks that need your attention.
</p>
</div>
</div>
</div>
<div class="mt-5 sm:mt-6">
<button type="button" id="dismiss-reminder" class="inline-flex justify-center w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary-500 text-base font-medium text-white hover:bg-primary-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 sm:text-sm">
Dismiss
</button>
</div>
</div>
</div>
</div>
<script>
// Initialize Feather Icons
feather.replace();
// Tab Switching
document.getElementById('professional-tab').addEventListener('click', function() {
this.classList.add('border-primary-500', 'text-primary-600');
this.classList.remove('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300');
document.getElementById('personal-tab').classList.add('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300');
document.getElementById('personal-tab').classList.remove('border-primary-500', 'text-primary-600');
document.getElementById('professional-content').classList.remove('hidden');
document.getElementById('personal-content').classList.add('hidden');
});
document.getElementById('personal-tab').addEventListener('click', function() {
this.classList.add('border-primary-500', 'text-primary-600');
this.classList.remove('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300');
document.getElementById('professional-tab').classList.add('border-transparent', 'text-gray-500', 'hover:text-gray-700', 'hover:border-gray-300');
document.getElementById('professional-tab').classList.remove('border-primary-500', 'text-primary-600');
document.getElementById('personal-content').classList.remove('hidden');
document.getElementById('professional-content').classList.add('hidden');
});
// Task Management
let professionalTasks = [
// Sample data
{ id: 1, requestor: "John Doe", project: "Website Redesign", concern: "Homepage Layout", status: "Open", dueDays: 3 },
{ id: 2, requestor: "Jane Smith", project: "Mobile App", concern: "Login Bug", status: "Open", dueDays: 1 },
{ id: 3, requestor: "Mike Johnson", project: "Marketing", concern: "Campaign Review", status: "Closed", dueDays: 0 }
];
let personalTasks = [
// Sample data
{ id: 1, description: "Buy groceries", status: "pending", dueDays: 1 },
{ id: 2, description: "Call mom", status: "completed", dueDays: 0 },
{ id: 3, description: "Finish book", status: "pending", dueDays: 5 }
];
// Render Professional Tasks
function renderProfessionalTasks() {
const container = document.getElementById('professional-tasks');
container.innerHTML = '';
professionalTasks.forEach(task => {
const row = document.createElement('tr');
row.className = task.status === 'Closed' ? 'bg-gray-50' : '';
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${task.requestor}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${task.project}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${task.concern}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${task.status === 'Open' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}">
${task.status}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${task.dueDays}</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button class="text-primary-500 hover:text-primary-600 mr-3 edit-professional" data-id="${task.id}">Edit</button>
<button class="text-red-500 hover:text-red-600 delete-professional" data-id="${task.id}">Delete</button>
</td>
`;
container.appendChild(row);
});
}
// Render Personal Tasks
function renderPersonalTasks() {
const container = document.getElementById('personal-tasks');
container.innerHTML = '';
personalTasks.forEach(task => {
const item = document.createElement('li');
item.className = 'px-6 py-4';
item.innerHTML = `
<div class="flex items-center">
<label class="flex items-center">
<input type="checkbox" class="hidden checkbox" ${task.status === 'completed' ? 'checked' : ''} data-id="${task.id}">
<span class="w-4 h-4 border border-gray-300 rounded flex-shrink-0 checkmark relative ${task.status === 'completed' ? 'bg-primary-500 border-primary-500' : ''}"></span>
</label>
<div class="ml-3 flex-1">
<p class="text-sm font-medium ${task.status === 'completed' ? 'text-gray-500 line-through' : 'text-gray-900'}">${task.description}</p>
<p class="text-xs text-gray-500">Due in ${task.dueDays} days</p>
</div>
<div>
<button class="text-primary-500 hover:text-primary-600 mr-3 edit-personal" data-id="${task.id}">
<i data-feather="edit-2" class="w-4 h-4"></i>
</button>
<button class="text-red-500 hover:text-red-600 delete-personal" data-id="${task.id}">
<i data-feather="trash-2" class="w-4 h-4"></i>
</button>
</div>
</div>
`;
container.appendChild(item);
});
feather.replace();
}
// Add Professional Task
document.getElementById('add-professional').addEventListener('click', function() {
const requestor = document.getElementById('requestor').value;
const project = document.getElementById('project').value;
const concern = document.getElementById('concern').value;
const status = document.getElementById('status').value;
const dueDays = parseInt(document.getElementById('due-days').value) || 0;
if (requestor && project && concern) {
const newTask = {
id: professionalTasks.length + 1,
requestor,
project,
concern,
status,
dueDays
};
professionalTasks.push(newTask);
renderProfessionalTasks();
// Clear form
document.getElementById('requestor').value = '';
document.getElementById('project').value = '';
document.getElementById('concern').value = '';
document.getElementById('status').value = 'Open';
document.getElementById('due-days').value = '';
// Show success message
alert('Professional task added successfully!');
} else {
alert('Please fill in all required fields.');
}
});
// Add Personal Task
document.getElementById('add-personal').addEventListener('click', function() {
const description = document.getElementById('task-description').value;
const dueDays = parseInt(document.getElementById('personal-due-days').value) || 0;
if (description) {
const newTask = {
id: personalTasks.length + 1,
description,
status: 'pending',
dueDays
};
personalTasks.push(newTask);
renderPersonalTasks();
// Clear form
document.getElementById('task-description').value = '';
document.getElementById('personal-due-days').value = '';
// Show success message
alert('Personal task added successfully!');
} else {
alert('Please enter a task description.');
}
});
// Export to Excel
document.getElementById('export-professional').addEventListener('click', function() {
// In a real app, this would generate an Excel file
alert('Professional tasks exported to Excel (simulated). In a real app, this would download an Excel file with your tasks.');
});
// Checkbox toggles for personal tasks
document.addEventListener('click', function(e) {
if (e.target.classList.contains('checkbox') || e.target.closest('.checkbox')) {
const checkbox = e.target.classList.contains('checkbox') ? e.target : e.target.closest('.checkbox');
const taskId = parseInt(checkbox.dataset.id);
const task = personalTasks.find(t => t.id === taskId);
if (task) {
task.status = checkbox.checked ? 'completed' : 'pending';
renderPersonalTasks();
}
}
});
// Delete Professional Task
document.addEventListener('click', function(e) {
if (e.target.classList.contains('delete-professional') || e.target.closest('.delete-professional')) {
const button = e.target.classList.contains('delete-professional') ? e.target : e.target.closest('.delete-professional');
const taskId = parseInt(button.dataset.id);
if (confirm('Are you sure you want to delete this task?')) {
professionalTasks = professionalTasks.filter(t => t.id !== taskId);
renderProfessionalTasks();
}
}
});
// Delete Personal Task
document.addEventListener('click', function(e) {
if (e.target.classList.contains('delete-personal') || e.target.closest('.delete-personal')) {
const button = e.target.classList.contains('delete-personal') ? e.target : e.target.closest('.delete-personal');
const taskId = parseInt(button.dataset.id);
if (confirm('Are you sure you want to delete this task?')) {
personalTasks = personalTasks.filter(t => t.id !== taskId);
renderPersonalTasks();
}
}
});
// Edit Professional Task
document.addEventListener('click', function(e) {
if (e.target.classList.contains('edit-professional') || e.target.closest('.edit-professional')) {
const button = e.target.classList.contains('edit-professional') ? e.target : e.target.closest('.edit-professional');
const taskId = parseInt(button.dataset.id);
const task = professionalTasks.find(t => t.id === taskId);
if (task) {
document.getElementById('requestor').value = task.requestor;
document.getElementById('project').value = task.project;
document.getElementById('concern').value = task.concern;
document.getElementById('status').value = task.status;
document.getElementById('due-days').value = task.dueDays;
// Remove the task from the list
professionalTasks = professionalTasks.filter(t => t.id !== taskId);
renderProfessionalTasks();
alert('Task loaded into form. Make your changes and click "Add Task" to update.');
}
}
});
// Edit Personal Task
document.addEventListener('click', function(e) {
if (e.target.classList.contains('edit-personal') || e.target.closest('.edit-personal')) {
const button = e.target.classList.contains('edit-personal') ? e.target : e.target.closest('.edit-personal');
const taskId = parseInt(button.dataset.id);
const task = personalTasks.find(t => t.id === taskId);
if (task) {
document.getElementById('task-description').value = task.description;
document.getElementById('personal-due-days').value = task.dueDays;
// Remove the task from the list
personalTasks = personalTasks.filter(t => t.id !== taskId);
renderPersonalTasks();
alert('Task loaded into form. Make your changes and click "Add Task" to update.');
}
}
});
// Dismiss Reminder
document.getElementById('dismiss-reminder').addEventListener('click', function() {
document.getElementById('reminder-modal').classList.add('hidden');
});
// Initial render
renderProfessionalTasks();
renderPersonalTasks();
// Check for PWA capabilities
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('ServiceWorker registration successful');
}, err => {
console.log('ServiceWorker registration failed: ', err);
});
});
}
// Simulate hourly reminders for pending tasks
function checkForReminders() {
const pendingProfessionalTasks = professionalTasks.filter(t => t.status === 'Open');
const pendingPersonalTasks = personalTasks.filter(t => t.status === 'pending');
if (pendingProfessionalTasks.length > 0 || pendingPersonalTasks.length > 0) {
let message = 'You have pending tasks:\n\n';
if (pendingProfessionalTasks.length > 0) {
message += 'Professional:\n';
pendingProfessionalTasks.forEach(t => {
message += `- ${t.concern} (${t.project}, due in ${t.dueDays} days)\n`;
});
message += '\n';
}
if (pendingPersonalTasks.length > 0) {
message += 'Personal:\n';
pendingPersonalTasks.forEach(t => {
message += `- ${t.description} (due in ${t.dueDays} days)\n`;
});
}
document.getElementById('reminder-task').textContent = message;
document.getElementById('reminder-modal').classList.remove('hidden');
}
}
// Check every hour (in real app, this would use proper scheduling)
setInterval(checkForReminders, 3600000); // 1 hour in milliseconds
// First check after 5 seconds (for demo purposes)
setTimeout(checkForReminders, 5000);
</script>
</body>
</html>