Added UI and functionality for profiles
This commit is contained in:
311
index.php
311
index.php
@@ -144,8 +144,19 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.profile-select {
|
||||
height: 32px; /* match your header-action-btn buttons */
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700; /* or 700 for stronger bold */
|
||||
padding-right: 2.5rem; /* key: reserve space for the arrow */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.add-project-btn {
|
||||
font-size: 1.4rem;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600; /* or 700 for stronger bold */
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
@@ -259,37 +270,36 @@
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
|
||||
<!-- Add Project -->
|
||||
<button class="btn btn-success btn-lg header-action-btn"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#addProjectModal">
|
||||
<i class="bi bi-plus-lg"></i>
|
||||
</button>
|
||||
|
||||
<!-- User Dropdown -->
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-lg header-action-btn"
|
||||
type="button"
|
||||
id="menuButton"
|
||||
data-bs-toggle="dropdown">
|
||||
<i class="bi bi-person-circle"></i>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<select id="profileSelect" class="form-select btn-lg profile-select" style="width: 140px;"></select>
|
||||
<!-- Add Project -->
|
||||
<button class="btn btn-success btn-lg header-action-btn"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#addProjectModal">
|
||||
<i class="bi bi-plus-lg"></i>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu-end custom-dropdown" aria-labelledby="menuButton">
|
||||
<li class="dropdown-item-text fw-semibold fs-5" id="dropdownUserEmail"></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<button class="dropdown-item fs-5" type="button" id="logoutBtn">
|
||||
<i class="bi bi-box-arrow-right"></i>
|
||||
<span>Logout</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- User Dropdown -->
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary btn-lg header-action-btn"
|
||||
type="button"
|
||||
id="menuButton"
|
||||
data-bs-toggle="dropdown">
|
||||
<i class="bi bi-person-circle"></i>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<ul class="dropdown-menu dropdown-menu-end custom-dropdown" aria-labelledby="menuButton">
|
||||
<li class="dropdown-item-text fw-semibold fs-5" id="dropdownUserEmail"></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<button class="dropdown-item fs-5" type="button" id="logoutBtn">
|
||||
<i class="bi bi-box-arrow-right"></i>
|
||||
<span>Logout</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</h1>
|
||||
|
||||
|
||||
@@ -538,131 +548,149 @@
|
||||
favicon.type = "image/svg+xml";
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function loadProfiles() {
|
||||
fetch('get_profiles.php')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.success) return;
|
||||
|
||||
const sel = document.getElementById('profileSelect');
|
||||
sel.innerHTML = '';
|
||||
|
||||
data.profiles.forEach(p => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = p.id;
|
||||
opt.textContent = p.name;
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
|
||||
if (data.active_profile_id) {
|
||||
sel.value = String(data.active_profile_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fetchProjects() {
|
||||
fetch('get_data.php')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
function fetchProjects() {
|
||||
fetch('get_data.php')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
if (data && data.error === 'Not authenticated') {
|
||||
new bootstrap.Modal(document.getElementById('loginModal')).show();
|
||||
return;
|
||||
}
|
||||
console.error('get_data.php returned non-array:', data);
|
||||
if (!Array.isArray(data)) {
|
||||
if (data && data.error === 'Not authenticated') {
|
||||
new bootstrap.Modal(document.getElementById('loginModal')).show();
|
||||
return;
|
||||
}
|
||||
console.error('get_data.php returned non-array:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
const container = document.getElementById('projectGrid');
|
||||
container.innerHTML = '';
|
||||
const container = document.getElementById('projectGrid');
|
||||
container.innerHTML = '';
|
||||
|
||||
data.forEach((project, idx) => {
|
||||
|
||||
const projectId = `project-${project.id}`;
|
||||
const colorClass = `project-color-${idx % 10}`;
|
||||
|
||||
const col = document.createElement('div');
|
||||
data.forEach((project, idx) => {
|
||||
|
||||
const projectId = `project-${project.id}`;
|
||||
const colorClass = `project-color-${idx % 10}`;
|
||||
|
||||
const col = document.createElement('div');
|
||||
|
||||
col.className = `col-12 col-sm-6 col-md-4 col-lg-2 col-xl-2 col-xxl-1 g-2 m-0 project-column`;
|
||||
col.dataset.projectId = project.id;
|
||||
col.classList.add("draggable-project");
|
||||
col.innerHTML = `
|
||||
<div class="project-card ${colorClass}">
|
||||
<div class="project-header">
|
||||
<span class="project-title">${project.name}</span>
|
||||
<div class="d-flex align-items-center">
|
||||
<button class="btn-icon add-task-btn" data-project-id="${project.id}" title="Add Task">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
<button class="btn-icon text-danger delete-project-btn" data-project-id="${project.id}" title="Delete Project">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-body">
|
||||
${project.tasks.map(task => `
|
||||
<div class="d-flex justify-content-between align-items-center small-text mb-1 task-text">
|
||||
<span class="${task.highlighted == 1 ? 'highlighted' : ''} ${task.highlighted == 2 ? 'completed' : ''}".trim()
|
||||
data-task-id="${task.id}">${task.name}</span>
|
||||
<div class="d-flex">
|
||||
<button class="btn-icon add-subtask-btn" data-task-id="${task.id}" title="Add Subtask">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
<button class="btn-icon text-danger delete-task-btn" data-task-id="${task.id}" title="Delete Task">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ms-3">
|
||||
${task.subtasks.map(sub => `
|
||||
<div class="d-flex justify-content-between align-items-center small-text mb-1">
|
||||
<span class="${sub.highlighted == 1 ? 'highlighted' : ''} ${sub.highlighted == 2 ? 'completed' : ''}".trim()
|
||||
data-subtask-id="${sub.id}">${sub.name}</span>
|
||||
<button class="btn-icon text-danger delete-subtask-btn" data-subtask-id="${sub.id}" title="Delete Subtask">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
col.className = `col-12 col-sm-6 col-md-4 col-lg-2 col-xl-2 col-xxl-1 g-2 m-0 project-column`;
|
||||
col.dataset.projectId = project.id;
|
||||
col.classList.add("draggable-project");
|
||||
col.innerHTML = `
|
||||
<div class="project-card ${colorClass}">
|
||||
<div class="project-header">
|
||||
<span class="project-title">${project.name}</span>
|
||||
<div class="d-flex align-items-center">
|
||||
<button class="btn-icon add-task-btn" data-project-id="${project.id}" title="Add Task">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
<button class="btn-icon text-danger delete-project-btn" data-project-id="${project.id}" title="Delete Project">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-body">
|
||||
${project.tasks.map(task => `
|
||||
<div class="d-flex justify-content-between align-items-center small-text mb-1 task-text">
|
||||
<span class="${task.highlighted == 1 ? 'highlighted' : ''} ${task.highlighted == 2 ? 'completed' : ''}".trim()
|
||||
data-task-id="${task.id}">${task.name}</span>
|
||||
<div class="d-flex">
|
||||
<button class="btn-icon add-subtask-btn" data-task-id="${task.id}" title="Add Subtask">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
<button class="btn-icon text-danger delete-task-btn" data-task-id="${task.id}" title="Delete Task">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ms-3">
|
||||
${task.subtasks.map(sub => `
|
||||
<div class="d-flex justify-content-between align-items-center small-text mb-1">
|
||||
<span class="${sub.highlighted == 1 ? 'highlighted' : ''} ${sub.highlighted == 2 ? 'completed' : ''}".trim()
|
||||
data-subtask-id="${sub.id}">${sub.name}</span>
|
||||
<button class="btn-icon text-danger delete-subtask-btn" data-subtask-id="${sub.id}" title="Delete Subtask">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(col);
|
||||
});
|
||||
container.appendChild(col);
|
||||
});
|
||||
|
||||
|
||||
// Create the drop indicator element
|
||||
const placeholder = document.createElement('div');
|
||||
placeholder.className = 'project-column';
|
||||
placeholder.innerHTML = `<div class="project-placeholder"></div>`;
|
||||
// Create the drop indicator element
|
||||
const placeholder = document.createElement('div');
|
||||
placeholder.className = 'project-column';
|
||||
placeholder.innerHTML = `<div class="project-placeholder"></div>`;
|
||||
|
||||
|
||||
// Setup drag events for project reordering
|
||||
document.querySelectorAll('.project-column').forEach(col => {
|
||||
col.setAttribute('draggable', 'true');
|
||||
// Setup drag events for project reordering
|
||||
document.querySelectorAll('.project-column').forEach(col => {
|
||||
col.setAttribute('draggable', 'true');
|
||||
|
||||
col.addEventListener('dragstart', (e) => {
|
||||
e.dataTransfer.setData('text/plain', col.dataset.projectId);
|
||||
col.classList.add('dragging');
|
||||
});
|
||||
col.addEventListener('dragstart', (e) => {
|
||||
e.dataTransfer.setData('text/plain', col.dataset.projectId);
|
||||
col.classList.add('dragging');
|
||||
});
|
||||
|
||||
col.addEventListener('dragend', () => {
|
||||
col.classList.remove('dragging');
|
||||
placeholder.remove();
|
||||
});
|
||||
col.addEventListener('dragend', () => {
|
||||
col.classList.remove('dragging');
|
||||
placeholder.remove();
|
||||
});
|
||||
|
||||
col.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
const dragging = document.querySelector('.dragging');
|
||||
if (!dragging || dragging === col) return;
|
||||
col.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
const dragging = document.querySelector('.dragging');
|
||||
if (!dragging || dragging === col) return;
|
||||
|
||||
const bounding = col.getBoundingClientRect();
|
||||
const offset = e.clientY - bounding.top;
|
||||
const bounding = col.getBoundingClientRect();
|
||||
const offset = e.clientY - bounding.top;
|
||||
|
||||
if (offset < bounding.height / 2) {
|
||||
col.parentNode.insertBefore(placeholder, col);
|
||||
} else {
|
||||
col.parentNode.insertBefore(placeholder, col.nextSibling);
|
||||
}
|
||||
});
|
||||
if (offset < bounding.height / 2) {
|
||||
col.parentNode.insertBefore(placeholder, col);
|
||||
} else {
|
||||
col.parentNode.insertBefore(placeholder, col.nextSibling);
|
||||
}
|
||||
});
|
||||
|
||||
col.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
const dragging = document.querySelector('.dragging');
|
||||
if (placeholder && placeholder.parentNode) {
|
||||
placeholder.parentNode.insertBefore(dragging, placeholder);
|
||||
placeholder.remove();
|
||||
updateProjectOrder(); // This already exists in your code
|
||||
}
|
||||
});
|
||||
});
|
||||
col.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
const dragging = document.querySelector('.dragging');
|
||||
if (placeholder && placeholder.parentNode) {
|
||||
placeholder.parentNode.insertBefore(dragging, placeholder);
|
||||
placeholder.remove();
|
||||
updateProjectOrder(); // This already exists in your code
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Enable drag-and-drop sorting
|
||||
@@ -956,7 +984,23 @@ document.querySelectorAll('.project-column').forEach(col => {
|
||||
err.style.display = 'block';
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
document.getElementById('profileSelect').addEventListener('change', () => {
|
||||
const profileId = parseInt(document.getElementById('profileSelect').value, 10);
|
||||
|
||||
fetch('set_profile.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ profile_id: profileId })
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.success) return;
|
||||
fetchProjects();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
loadSettings();
|
||||
|
||||
@@ -979,6 +1023,7 @@ document.querySelectorAll('.project-column').forEach(col => {
|
||||
document.querySelectorAll('.settings-btn').forEach(b => b.style.display = 'none');
|
||||
}
|
||||
|
||||
loadProfiles();
|
||||
fetchProjects();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user