178 lines
7.0 KiB
JavaScript
178 lines
7.0 KiB
JavaScript
import { useState, useEffect } from 'react';
|
|
import { getUserTasks } from '@/api/users.service';
|
|
import { Button } from '@/components/ui/button';
|
|
import { cn } from '@/lib/utils';
|
|
import styles from '@/lib/styles';
|
|
import { Plus } from 'lucide-react';
|
|
|
|
export default function Calendar() {
|
|
const [tasksFromBackend, setTasksFromBackend] = useState([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// Fetch tasks when component mounts
|
|
useEffect(() => {
|
|
const fetchTasks = async () => {
|
|
try {
|
|
console.log('Calendar: Fetching user tasks...');
|
|
const response = await getUserTasks(1);
|
|
console.log('Calendar: Tasks from backend:', response);
|
|
setTasksFromBackend(response);
|
|
} catch (error) {
|
|
console.error('Calendar: Failed to fetch tasks:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchTasks();
|
|
}, []);
|
|
|
|
const today = new Date();
|
|
const currentDay = today.getDay();
|
|
|
|
|
|
const currentDate = new Date(today);
|
|
const dayOffset = currentDay === 0 ? -6 : 1 - currentDay;
|
|
currentDate.setDate(today.getDate() + dayOffset);
|
|
|
|
|
|
const groupTasksByDay = (tasks) => {
|
|
const grouped = {};
|
|
|
|
tasks.forEach(task => {
|
|
const taskDate = new Date(task.due_date);
|
|
const dateKey = taskDate.toDateString();
|
|
|
|
if (!grouped[dateKey]) {
|
|
grouped[dateKey] = [];
|
|
}
|
|
|
|
grouped[dateKey].push({
|
|
id: task.id,
|
|
title: task.title,
|
|
priority: task.priority,
|
|
completed: task.status === 'closed' || task.status === 'completed',
|
|
dueDate: task.due_date
|
|
});
|
|
});
|
|
|
|
return grouped;
|
|
};
|
|
|
|
const groupedTasks = groupTasksByDay(tasksFromBackend);
|
|
|
|
|
|
const daysOfWeek = [
|
|
'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'
|
|
].map((name, index) => {
|
|
const date = new Date(currentDate);
|
|
date.setDate(currentDate.getDate() + index);
|
|
const dateKey = date.toDateString();
|
|
|
|
return {
|
|
name,
|
|
date: date.getDate(),
|
|
month: date.toLocaleDateString('en-US', { month: 'short' }),
|
|
fullDate: date,
|
|
tasks: groupedTasks[dateKey] || []
|
|
};
|
|
});
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className={cn(styles.card.elevated, "flex-[3]")}>
|
|
<div className="flex items-center justify-center p-8">
|
|
<p className={styles.text.body}>Loading tasks...</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={cn(
|
|
styles.utility.glass,
|
|
"p-6 rounded-2xl flex-3",
|
|
styles.utility.transitionSlow
|
|
)}>
|
|
<div className="flex gap-3 h-full overflow-x-auto px-3">
|
|
{daysOfWeek.map((day) => {
|
|
const isToday = day.fullDate.toDateString() === today.toDateString();
|
|
|
|
return (
|
|
<div
|
|
key={day.name}
|
|
className={cn(
|
|
"flex-1 min-w-[180px] max-w-[200px] flex flex-col rounded-2xl p-4 transition-all duration-300",
|
|
isToday
|
|
? "bg-primary/10 border-2 border-primary neon-glow-soft"
|
|
: "bg-background border border-border"
|
|
)}
|
|
>
|
|
{/* Header */}
|
|
<div className="text-center pb-3 border-b border-border mb-3">
|
|
<h3 className={cn(
|
|
styles.text.small,
|
|
"font-semibold mb-1",
|
|
isToday && "text-primary font-bold"
|
|
)}>
|
|
{day.name}
|
|
</h3>
|
|
<p className={cn(
|
|
styles.text.smallMuted,
|
|
|
|
isToday && "text-primary font-semibold"
|
|
)}>
|
|
{day.month} {day.date}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Tasks */}
|
|
<div className="flex-1 flex flex-col gap-2 overflow-y-auto pt-1">
|
|
{day.tasks.map((task) => (
|
|
<div
|
|
key={task.id}
|
|
className={cn(
|
|
styles.card.task,
|
|
task.completed && "opacity-60 line-through"
|
|
)}
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
{/* Priority indicator */}
|
|
<span
|
|
className={cn(
|
|
"w-1.5 h-1.5 rounded-full flex-shrink-0",
|
|
task.priority === 'low' && "bg-green-500",
|
|
task.priority === 'medium' && "bg-yellow-500",
|
|
task.priority === 'high' && "bg-orange-500",
|
|
task.priority === 'critical' && "bg-red-500"
|
|
)}
|
|
/>
|
|
<p className={cn(styles.text.small, "flex-1")}>
|
|
{task.title}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
))}
|
|
|
|
|
|
{/* Add button */}
|
|
<button
|
|
className={cn(
|
|
styles.button.iconNeon,
|
|
"mt-2 w-full flex items-center justify-center gap-2",
|
|
)}
|
|
onClick={() => {
|
|
console.log('Add task clicked for', day.name);
|
|
}}
|
|
>
|
|
<Plus className="w-4 h-4" />
|
|
<span className="text-xs">Add Task</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |