Fix projects layout view

This commit is contained in:
Chris Veleris 2025-03-27 07:41:07 +02:00
parent 7a4022085c
commit 73e2e1497a
5 changed files with 88 additions and 14 deletions

View file

@ -294,7 +294,7 @@ useEffect(() => {
className={`${
viewMode === "cards"
? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"
: "flex flex-col space-y-4"
: "flex flex-col space-y-1"
}`}
>
{Object.keys(groupedProjects).length === 0 ? (

View file

@ -149,7 +149,7 @@ const TasksToday: React.FC = () => {
{metrics.tasks_due_today.length > 0 && (
<>
<h3 className="text-xl font-medium mt-6 mb-2">Tasks Due Today</h3>
<h3 className="text-xl font-medium mt-6 mb-2">Due Today</h3>
<TaskList
tasks={metrics.tasks_due_today}
onTaskUpdate={handleTaskUpdate}
@ -161,7 +161,7 @@ const TasksToday: React.FC = () => {
{metrics.tasks_in_progress.length > 0 && (
<>
<h3 className="text-xl font-medium mt-6 mb-2">Tasks In Progress</h3>
<h3 className="text-xl font-medium mt-6 mb-2">In Progress</h3>
<TaskList
tasks={metrics.tasks_in_progress}
onTaskUpdate={handleTaskUpdate}
@ -173,7 +173,7 @@ const TasksToday: React.FC = () => {
{metrics.suggested_tasks.length > 0 && (
<>
<h3 className="text-xl font-medium mt-6 mb-2">Suggested Tasks</h3>
<h3 className="text-xl font-medium mt-6 mb-2">Suggested</h3>
<TaskList
tasks={metrics.suggested_tasks}
onTaskUpdate={handleTaskUpdate}

View file

@ -11,6 +11,7 @@ import {
XMarkIcon,
ChevronDownIcon,
ChevronDoubleDownIcon,
MagnifyingGlassIcon,
} from "@heroicons/react/24/solid";
const capitalize = (str: string) => str.charAt(0).toUpperCase() + str.slice(1);
@ -22,8 +23,9 @@ const Tasks: React.FC = () => {
const [error, setError] = useState<string | null>(null);
const [dropdownOpen, setDropdownOpen] = useState<boolean>(false);
const [orderBy, setOrderBy] = useState<string>("due_date:asc");
const dropdownRef = useRef<HTMLDivElement>(null);
const [taskSearchQuery, setTaskSearchQuery] = useState<string>("");
const dropdownRef = useRef<HTMLDivElement>(null);
const location = useLocation();
const navigate = useNavigate();
const query = new URLSearchParams(location.search);
@ -198,6 +200,10 @@ const Tasks: React.FC = () => {
return status !== "done";
};
const filteredTasks = tasks.filter((task) =>
task.name.toLowerCase().includes(taskSearchQuery.toLowerCase())
);
return (
<div className="flex justify-center px-4 lg:px-2">
<div className="w-full max-w-5xl">
@ -268,10 +274,25 @@ const Tasks: React.FC = () => {
</div>
</div>
{/* Description */}
<p className="mb-6 text-sm text-gray-500 dark:text-gray-400">
{description}
</p>
{/* Search Bar */}
<div className="mb-4">
<div className="flex items-center bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm p-2">
<MagnifyingGlassIcon className="h-5 w-5 text-gray-500 dark:text-gray-400 mr-2" />
<input
type="text"
placeholder="Search tasks..."
value={taskSearchQuery}
onChange={(e) => setTaskSearchQuery(e.target.value)}
className="w-full bg-transparent border-none focus:ring-0 focus:outline-none dark:text-white"
/>
</div>
</div>
{loading ? (
<p>Loading...</p>
) : error ? (
@ -288,9 +309,9 @@ const Tasks: React.FC = () => {
)}
{/* Task List */}
{tasks.length > 0 ? (
{filteredTasks.length > 0 ? (
<TaskList
tasks={tasks}
tasks={filteredTasks}
onTaskCreate={handleTaskCreate}
onTaskUpdate={handleTaskUpdate}
onTaskDelete={handleTaskDelete}
@ -308,4 +329,4 @@ const Tasks: React.FC = () => {
);
};
export default Tasks;
export default Tasks;

View file

@ -79,7 +79,7 @@ class Task < ActiveRecord::Base
one_month_ago = Date.today - 30
tasks_pending_over_month = user.tasks.incomplete.where('created_at < ?', one_month_ago).count
tasks_in_progress = user.tasks.incomplete.where(status: statuses[:in_progress])
tasks_in_progress = user.tasks.incomplete.where(status: statuses[:in_progress]).order(priority: :desc)
tasks_in_progress_count = tasks_in_progress.count
# Calculate tasks due today including those due via projects
@ -108,8 +108,8 @@ class Task < ActiveRecord::Base
.limit(5)
# Combine both list of suggested tasks
suggested_tasks = tasks_in_expiring_projects + tasks_without_projects
suggested_tasks = sort_suggested_tasks(tasks_in_expiring_projects + tasks_without_projects)
{
total_open_tasks: total_open_tasks,
tasks_pending_over_month: tasks_pending_over_month,
@ -120,6 +120,59 @@ class Task < ActiveRecord::Base
}
end
def self.sort_suggested_tasks(tasks)
tasks.sort_by do |task|
# Parse or default the task due date
task_due_date = if task.due_date.is_a?(String)
Date.parse(task.due_date)
else
task.due_date || Date.new(9999, 12, 31)
end
# Parse or default the project due date
project_due_date = if (task.project&.due_date_at).is_a?(String)
Date.parse(task&.project&.due_date_at)
else
task.project&.due_date_at || Date.new(9999, 12, 31)
end
# Priority in descending order (sorted values should be negative for sort_by)
priority_value = -(Task.priorities.fetch(task.priority, -1))
# Determine sorting flags based on various criteria
is_high_priority_proj_with_due_date = (task.priority == 'high' && task&.project&.due_date_at) ? 0 : 1
is_high_priority_with_due_date = (task.priority == 'high' && task.due_date) ? 0 : 1
is_high_priority = (task.priority == 'high' && !task.due_date && !task&.project&.due_date_at) ? 0 : 1
is_medium_priority_proj_with_due_date = (task.priority == 'medium' && task&.project&.due_date_at) ? 0 : 1
is_medium_priority_with_due_date = (task.priority == 'medium' && task.due_date) ? 0 : 1
is_medium_priority = (task.priority == 'medium' && !task.due_date && !task&.project&.due_date_at) ? 0 : 1
is_low_priority_proj_with_due_date = (task.priority == 'low' && task&.project&.due_date_at) ? 0 : 1
is_low_priority_with_due_date = (task.priority == 'low' && task.due_date) ? 0 : 1
is_low_priority = (task.priority == 'low' && !task.due_date && !task&.project&.due_date_at) ? 0 : 1
# Primary sorting criteria
[
is_high_priority_proj_with_due_date,
is_high_priority_with_due_date,
is_high_priority,
is_medium_priority_proj_with_due_date,
is_medium_priority_with_due_date,
is_medium_priority,
is_low_priority_proj_with_due_date,
is_low_priority_with_due_date,
is_low_priority,
task_due_date,
project_due_date,
priority_value
]
end
end
def as_json(options = {})
super(options).merge(
'due_date' => due_date&.strftime('%Y-%m-%d')

File diff suppressed because one or more lines are too long