My-Weekly-ToDo-List/Version 01/src/components/CalendarGrid.tsx
mARTin d92a8c7210 feat: add task actions (notes/delete) and refine animation logic
- Added 'onDelete' and 'onNotes' support to TaskItem.
- Implemented hover actions (Delete and Notes icons) for tasks.
- Added Notes Modal for editing task markdown content.
- Simplified navigation animation to remove blank flash (single-phase slide-in).
- Fixed syntax error in updateTask function.
- Updated styles for modal and task actions.
2026-02-01 12:25:53 +01:00

198 lines
6.0 KiB
TypeScript

import React, { useState } from 'react';
import { Task } from '../types/task';
import TaskCard from './TaskCard';
interface CalendarGridProps {
tasks: Task[];
onTaskToggle: (id: string) => void;
onTaskEdit: (task: Task) => void;
onTaskDelete: (id: string) => void;
onAddTask: (date: Date) => void;
currentDate: Date;
onTaskMove?: (taskId: string, newDate: Date) => void;
}
const CalendarGrid: React.FC<CalendarGridProps> = ({
tasks,
onTaskToggle,
onTaskEdit,
onTaskDelete,
onAddTask,
currentDate,
onTaskMove
}) => {
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
// Generate days for the current week
const generateWeekDays = (startDate: Date) => {
const days = [];
const start = new Date(startDate);
start.setDate(start.getDate() - startDate.getDay()); // Start from Sunday
for (let i = 0; i < 7; i++) {
const day = new Date(start);
day.setDate(start.getDate() + i);
days.push(day);
}
return days;
};
const weekDays = generateWeekDays(currentDate);
// Group tasks by date
const groupTasksByDate = (tasks: Task[]) => {
const grouped: Record<string, Task[]> = {};
tasks.forEach(task => {
const dateKey = task.date.toISOString().split('T')[0];
if (!grouped[dateKey]) {
grouped[dateKey] = [];
}
grouped[dateKey].push(task);
});
return grouped;
};
const groupedTasks = groupTasksByDate(tasks);
const handleDateClick = (date: Date) => {
setSelectedDate(date);
onAddTask(date);
};
const formatDate = (date: Date) => {
return date.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' });
};
const isToday = (date: Date) => {
const today = new Date();
return date.toDateString() === today.toDateString();
};
// Handle drag start for task cards
const handleDragStart = (e: React.DragEvent, taskId: string, sourceDay: string) => {
e.dataTransfer.setData('taskId', taskId);
e.dataTransfer.setData('sourceDay', sourceDay);
};
// Handle drop on a day
const handleDrop = (e: React.DragEvent, targetDay: string) => {
e.preventDefault();
const taskId = e.dataTransfer.getData('taskId');
const sourceDay = e.dataTransfer.getData('sourceDay');
if (taskId && sourceDay !== targetDay && onTaskMove) {
// Convert targetDay string back to date
const targetDate = new Date(targetDay);
onTaskMove(taskId, targetDate);
}
};
// Allow drops on day cells
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
};
return (
<div className="bg-white rounded-lg shadow overflow-hidden">
{/* Week Navigation */}
<div className="flex justify-between items-center p-4 border-b">
<button
className="px-3 py-1 bg-gray-100 rounded hover:bg-gray-200"
onClick={() => {
const prevWeek = new Date(currentDate);
prevWeek.setDate(prevWeek.getDate() - 7);
// This would typically update the parent state
}}
>
Previous
</button>
<h2 className="text-lg font-semibold">
{weekDays[0].toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
</h2>
<button
className="px-3 py-1 bg-gray-100 rounded hover:bg-gray-200"
onClick={() => {
const nextWeek = new Date(currentDate);
nextWeek.setDate(nextWeek.getDate() + 7);
// This would typically update the parent state
}}
>
Next
</button>
</div>
{/* Day Headers */}
<div className="grid grid-cols-7 gap-0 border-b">
{weekDays.map((day, index) => (
<div
key={index}
className={`p-2 text-center ${
isToday(day) ? 'bg-blue-50 text-blue-700 font-bold' : ''
}`}
>
<div className="text-sm text-gray-500">
{day.toLocaleDateString('en-US', { weekday: 'short' })}
</div>
<div className={`text-lg ${isToday(day) ? 'bg-blue-500 text-white rounded-full w-8 h-8 flex items-center justify-center mx-auto' : ''}`}>
{day.getDate()}
</div>
</div>
))}
</div>
{/* Calendar Grid */}
<div className="grid grid-cols-7 gap-0">
{weekDays.map((day, dayIndex) => {
const dayKey = day.toISOString().split('T')[0];
const dayTasks = groupedTasks[dayKey] || [];
return (
<div
key={dayIndex}
className="border-r border-b min-h-32"
onClick={() => handleDateClick(day)}
onDrop={(e) => handleDrop(e, dayKey)}
onDragOver={handleDragOver}
>
<div className="p-2 text-right">
<span className={`inline-block w-6 h-6 text-center rounded-full ${
isToday(day) ? 'bg-blue-500 text-white' : ''
}`}>
{day.getDate()}
</span>
</div>
<div className="p-2 space-y-1">
{dayTasks.map(task => (
<TaskCard
key={task.id}
task={task}
onToggleComplete={onTaskToggle}
onEdit={onTaskEdit}
onDelete={onTaskDelete}
draggable={true}
onDragStart={(e) => handleDragStart(e, task.id, dayKey)}
/>
))}
<button
className="text-xs text-gray-400 hover:text-gray-600 w-full text-left p-1"
onClick={(e) => {
e.stopPropagation();
handleDateClick(day);
}}
>
+ Add task
</button>
</div>
</div>
);
})}
</div>
</div>
);
};
export default CalendarGrid;