Fix projects layout view
This commit is contained in:
parent
7a4022085c
commit
73e2e1497a
5 changed files with 88 additions and 14 deletions
|
|
@ -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 ? (
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue